Creating a key value message in Smalltalk/Pharo that take blocks as argument - error-handling

I have a scenario where a class holds two instance variables that are mutually exclusive. That is only one can be instantiated at a time. To be precise, I have a Promise class (trying to add promises to Pharo) and it holds promiseError and promiseValue instance variables. I then want to implement the method "then: catch:".
This method should work as follows:
promiseObject := [10/0] promiseValue.
promiseObject then : [ : result | Transcript crShow : result ]
catch : [ : failure | Transcript crShow : failure ] .
I got an idea on how to implement methods that take a block as an argument from method that accepts a block and the block accepts an argument.
My attempt below will obviously not work but I have no idea on how to make it work.
then:aBlock catch: anotherBlock
|segment|
promiseValue ifNil: [ segment := promiseError ] ifNotNil: [ segment := promiseValue ].
promiseValue ifNil: [ segment := promiseValue ] ifNotNil: [ segment := promiseError ].
aBlock value:segment.
anotherBlock value: segment
This should work analogously to a try-catch block.

Have you tried something like this?
then: aBlock catch: anotherBlock
promiseError notNil ifTrue: [^anotherBlock value: promiseError].
^aBlock value: promiseValue
Note that the code does not rely on promiseValue being nil or not because nil could be a valid answer of the promise. However, if there is some promiseError, we know the promise failed, and succeeded otherwise.
Of course, here I'm assuming that this message will get sent once the promise has been successfully or unsuccessfully finished. If this is not the case, then the code should be waiting on the promise semaphore.

Related

Generate test method with their body in pharo

I advanced a little in my code but I find myself facing another problem for two days. I would like to generate a test method using only the source code. But I have no idea how to do it.
I have a method that allows me to build the name of a test method but I can't write in it.
buildSelectorFor: aMethod
^ String streamContents: [:i || capitalize |
capitalize := true.
i << 'test'.
aMethod selector do: [:charactar |
charactar= $:
ifTrue: [ capitalize := true ]
ifFalse: [ capitalize
ifTrue: [
capitalize := false.
i << charactar asUppercase. ]
ifFalse:[ i << charactar ]]]]
so if I execute this method with this for example:
buildSelectorFor:Car>>#speed:mark:
I get this:
testSpeedMark
my goal is to get something like
testSpeedMark
self assert:....equals:...
I added a method writeTestMethod.
writeTestMethod: aMethod with: anObject
^(self buildTestSelectorFor: aMethod),'
|classMethod setter instObject method|
classMethod := aMethod methodClass.
setter := (classMethod allSelectorsInProtocol: #setter) asArray.
instObject := classMethod new.
(setter with: anObject do: [:set :ivar | instObject perform: set with: ivar]).
self assert: instObject class equals: (classMethod new) class.'
So here is what I get:
I don't know how to integrate the parameters of writetestMethod in the code I want to generate

How can I refresh a JSON file for a certain period in pharo

Basically I connected to a server with pharo using identification. Then I used Znclient to get to myserver/json file which contains a collection of key and value. How can I refresh this Json file every 40 sec without running out of memory and How can I iterate over it to collect a specific key?
This is what I did so far
" Login "
"********************************************************"
|a data|
a := ZnClient new.
a get: 'https://MyServer'.
a
headerAt: 'referer' put: 'MyServer';
formAt: 'email' add: 'myEmail';
formAt: 'password' add: 'myPassword'.
a post.
a get: 'MyServer/json'.
" get Json file "
"*******************************************************
data := NeoJSONReader fromString: a contents
You can create a loop that does the work and waits 40 seconds:
process := [ [ self shouldStillRun ] whileTrue: [
self fetchDataAndDoWork.
40 seconds asDelay wait. ] ]
forkAt: Processor userBackgroundPriority
named: '<processName>'.
Above I assume that shouldStillRun and fetchDataAndDoWork are methods in a class containing these code. If you want to play with this code in the Playground replace them with some custom snippets of code. For example:
shouldStillRun := true.
process := [ [ shouldStillRun ] whileTrue: [
| data |
'<create the client>'
data := NeoJSONReader fromString: a contents.
40 seconds asDelay wait. ] ]
forkAt: Processor userBackgroundPriority
named: '<processName>'.
As long as you do not store all the data return by each call you should not have a memory problem.
If your data represents a dictionary then NeoJSON will return a dictionary object, and you can just use the at: message to get the value. You can inspect the data object to see what you get back.
I meant using the block do: every: of the class TaskScheduler. will that also work?
scheduler := TaskScheduler new.
scheduler start.
"refresh every 40 seconds"
scheduler
do: [a get: 'https://MyServer/json'.
Transcript show: 'Refreshing......'; cr.
data := NeoJSONReader fromString: a contents; cr.
every: 60 seconds

Blocks and ifTrue statement

I want to create a method that gets a block as an argument, and the block gets a parameter as well.
If the block returns true it should do something ( for example return 1), and if it returns false it should do something else.
this is what I did.. but I am getting syntax error on the ifTrue...
is this the way I should get as a parameter a block that receives an argument?
Mymethod: Block
Block value: 'argument'
ifTrue: [ ^1].
ifFalse: [^2].
and the call to the method :
object := myClass new.
argument :=1
boolValue := object Mymethod : [:argument | argument ==1 ]
the way you wrote it means that #value:ifTrue: message to the Block, and then you are sending #ifFalse: message to nothing (which is not possible at all. If you want to do it in one line, you should use parenthesis:
(Block value: 'argument')
ifTrue: [ ^1]
ifFalse: [^2]
Also in smalltalk it's a convention to name variables with uncapitalized, like block or aBlock

smalltalk block - can I explicitly set the returning value and stop executing the block?

The return value of #value: message, when sent to a block, is the value of the last sentence in that block. So [ 1 + 2. 3 + 4. ] value evaluates to 7.
I find that hard to use sometimes. Is there a way to explicitly set the returning value and stop executing the block?
For exercise, try rewriting this block without using my imaginary #return: message and see how ugly it gets. I must be missing something.
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [ self return: nil ] ifFalse: [ self return: true ] ].
two ifNil: [ self return: false ].
(one > two)
ifTrue: [ self return: true ]
ifFalse: [ (one < two)
ifTrue: [ self return: false ]
ifFalse: [ self return: nil ]
].
]
EDIT: self return: sth really is nonsense, but it does make sense at some level :)
There's nothing like a guard clause - blah ifTrue: [^ foo] - inside a block, because ^ is a non-local return, returning from the method calling the block rather than the block itself.
Big blocks - like big anythings - should be refactored into smaller, more understandable/tractable subparts, but sometimes that's not always possible. I mean this answer to suggest options to try when you can't really simplify in the usual ways.
If your block is really that complicated, and you can't get it simpler (splitting it up delocalises the information too much, for instance) then perhaps you can use an explicit return value. In particular, if your block doesn't return nil you could do something like
[:one :two | | result |
result := (one isNil and: [two isNil]) ifTrue: [false].
result ifNil: ["do one thing, possibly setting result"].
result]
If your block can return nil, you'll need another sentinel value:
[:one :two | | result marker |
result := marker := Object new.
(result == marker) ifTrue: ["do one thing, possibly setting result"].
result]
Lastly - and I hesitate to suggest this - you could do this:
[1 + 2.
thisContext return: 5.
3 + 4] value
which returns 5.
(Verifying how this interacts with ^ and inlined selectors like #ifTrue:ifFalse: left as an exercise for the reader.)
It seems that your code tries to handles nil like an infinity value when comparing one and two. The following code may be more readable depending on the context:
a := [:one :two |
| x y |
x := one ifNil: [Float infinity].
y := two ifNil: [Float infinity].
(x = y) ifTrue: [nil] ifFalse: [x > y]]
A useful feature of #ifTrue:ifFalse:, #ifNil:ifNotNil: and similar testing methods is that they return the value of the block that gets evaluated. e.g. (4 > 1) ifTrue: ['greater'] ifFalse: ['not-greater'] evaluates to 'greater'. This feature often makes it possible to return a value from a nested block in tail position.
When the code inside a block gets too complicated I suggest your refactor it to a method. But see Frank's answer for workarounds.
Edit:
As pointed out in the comments the code above assumes numbers. I also came up with something that works with other comparable objects:
a:=
[ :one :two |
true caseOf: {
[one = two]->[nil].
[one isNil]->[true].
[two isNil]->[false]
} otherwise: [one>two]]
That #caseOf: construct is rarely used but it's certainly better than thisContext return:
You'd like to implement some break, continue, exit...
The usual way to control flow in Smalltalk is with blocks.
So one funny solution is to use a helper method with a Block return value to break the flow, like described here .
Object>>exitThru: aBlock
^aBlock value: [:result | ^result]
Now, let see how to use it:
| aBlock |
aBlock := [ :one :two |
self exitThru: [:exit |
one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ].
two isNil ifTrue: [ exit value: false ].
one > two ifTrue: [ exit value: true ].
one < two ifTrue: [ exit value: false ].
exit value: nil] ].
#(('abc' nil) (nil nil) (nil 'def') ('y' 'abc') ('y' 'y') ('y' 'z'))
collect:
[:pair |
aBlock value: pair first value: pair last ]
-> #(false nil true true nil false)
EDIT my first version was unnecessarily complex, can't remember what lead me to an additional indirection:
| aBlock |
aBlock := [:wrapOne :wrapTwo |
self exitThru: [:exit |
[ :one :two |
one isNil ifTrue: [ two isNil ifTrue: [exit value: nil ] ifFalse: [ exit value: true ] ].
two isNil ifTrue: [ exit value: false ].
one > two ifTrue: [ exit value: true ].
one < two ifTrue: [ exit value: false ].
exit value: nil ]
value: wrapOne value: wrapTwo ] ].
Well, more funny than usefull, I hope you will find more simple and expressive way to code.

Smalltalk and Assertions

Tryng out some smalltalk + TDD + "good practices" I've run into a kinda ugly block:
How do I do an assertion in GNU Smalltalk?
I'm just looking for a simple ifFalse: [Die] kind of thing
This is the code for assert: from Squeak (which I recommend you use rather than GNU):
assert: aBlock
"Throw an assertion error if aBlock does not evaluates to true."
aBlock value
ifFalse: [AssertionFailure signal: 'Assertion failed']
as well as
self assert: [ ... some block ]
works for blocks & non-blocks, since sending #value to Object returns self.
It has been suggested above to add #assert: to Object, but rather I'd add #assert to BlockClosure (or whatever [] class is in GNU Smalltalk).
assert
this value ifFalse: [AssertionFailure signal: 'Assertion failed']
and thus use as in
[ value notNil ] assert.
[ value > 0 ] assert.
[ list isEmpty not ] assert.
etcetera.
It is simple. In your test methods you write:
self assert: 1 + 1 = 2
But first you need to create a test class as a subclass of TestCase (in Squeak), for example:
TestCase subclass: #MyTest
Here you write testing methods, which names must always start with 'test', for instance :
testBasicArithmetics
self assert: 1 + 1 = 2