A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-tonyg.1148.mcz
==================== Summary ====================
Name: Kernel-tonyg.1148
Author: tonyg
Time: 31 January 2018, 11:37:21.27021 pm
UUID: 2a675301-406b-4222-9599-84358a7cc506
Ancestors: Kernel-eem.1147
Brings the Promise implementation closer to Javascript/A+ promises in two ways:
* Resolving a Promise with another Promise causes them to be chained together
* Resolving or Rejecting a Promise that is not pending is a no-op, like the Firefox/Chrome/etc in-browser promise implementations.
The tests have been changed in KernelTests-tonyg.331 accordingly.
=============== Diff against Kernel-eem.1147 ===============
Item was changed:
Object subclass: #Promise
+ instanceVariableNames: 'value resolvers mutex state error rejecters'
- instanceVariableNames: 'onError value resolvers mutex state error rejectors rejecters'
classVariableNames: ''
poolDictionaries: ''
category: 'Kernel-Processes'!
+ !Promise commentStamp: 'tonyg 1/31/2018 23:34' prior: 0!
- !Promise commentStamp: 'fbs 5/17/2013 18:23' prior: 0!
I represent the result of an asynchronous message. Once the message is processed, I will be resolved to a value. I am typically instantiated by invocations of #futureSend:at:args: (and not by #futureDo:atArgs:).
See class-comment of FutureNode.
I also implement the Promises/A+ Javascript specification. This allows you to chain my instances to perform arbitrarily complex asynchronous tasks with error handling baked in.
+ A Promise may be in one of three possible states: #pending, #fulfilled or #rejected. A Promise may move from #pending -> #fulfilled (by way of the resolveWith: message), or from #pending -> #rejected (by way of rejectWith:). No other state changes may occur.
+
+ Once #fulfilled or #rejected, a Promise's value must not change. In keeping with the major Javascript Promise implementations' interpretations of this, calls to resolveWith: or rejectWith: when a Promise is in #fulfilled or #rejected state are simply ignored - an error is not signalled. (See test cases PromiseTest testFirstResolutionWins, testCannotRejectFulfilledPromise and testCannotResolveaRejectedPromise.)!
- A Promise may be in one of three possible states: #pending, #fulfilled or #rejected. A Promise may move from #pending -> #fulfilled, or from #pending -> #rejected. No other state changes may occur. Once #fulfilled or #rejected, a Promise's value must change.!
Item was changed:
----- Method: Promise>>rejectWith: (in category 'resolving') -----
rejectWith: anObject
"Reject this promise."
mutex critical: [
+ (state == #pending) ifTrue: [
+ error := anObject.
+ state := #rejected.
+ rejecters do: [:r | self evaluateRejecter: r]]]!
- (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
- (state == #rejected) ifTrue: [self error: 'Promise was already rejected'].
- error := anObject.
- state := #rejected.
- rejecters do: [:r | self evaluateRejecter: r]].!
Item was changed:
----- Method: Promise>>resolveWith: (in category 'resolving') -----
resolveWith: arg
+ "Resolve this promise. If arg is itself a Promise, make this promise depend upon it,
+ as detailed in the Promises/A+ spec:
+ https://promisesaplus.com/#the-promise-resolution-procedure"
+
+ (arg isKindOf: Promise)
+ ifTrue: [
+ arg whenResolved: [:v | self resolveWith: v].
+ arg whenRejected: [:e | self rejectWith: e]]
+ ifFalse: [
+ mutex critical: [
+ (state == #pending) ifTrue: [
+ value := arg.
+ state := #fulfilled.
+ resolvers do: [:r | self evaluateResolver: r]]]]!
- "Resolve this promise"
- mutex critical: [
- (state == #fulfilled) ifTrue: [self error: 'Promise was already resolved'].
- (state == #rejected) ifTrue: [self error: 'Promise was already resolved'].
- value := arg.
- state := #fulfilled.
- resolvers do: [:r |
- self evaluateResolver: r]].!
Item was changed:
----- Method: Promise>>then: (in category 'monad') -----
then: resolvedBlock
+ ^ self then: resolvedBlock ifRejected: [:e | "Pass rejection reason along" e].!
- ^ self then: resolvedBlock ifRejected: [:ignored | "Do nothing"].!
Bert Freudenberg uploaded a new version of System to project The Inbox:
http://source.squeak.org/inbox/System-bf.997.mcz
==================== Summary ====================
Name: System-bf.997
Author: bf
Time: 25 January 2018, 4:56:35.380251 pm
UUID: 604954ca-0389-43c0-a5c7-4ddc8e613cc9
Ancestors: System-dtl.996
Simplify project dispatch selector detection. No hard-coded list. Almost as good.
=============== Diff against System-dtl.996 ===============
Item was removed:
- ----- Method: Project class>>baseSelectors (in category 'dispatching') -----
- baseSelectors
- "The list of known base selectors that may be dispatched to project specific
- implementations. For example, #OpenLabel:in: will be dispatched to #mvcOpenLabel:in:
- for its MVC specific implementation. Add new base selectors here if additional methods
- are added as targets of the dispatchTo:addPrefixAndSend:withArguments: mechanism."
-
- ^ {
- #StartUpLeftFlush .
- #StartUpWithCaption:icon:at:allowKeyboard: .
- #OpenLabel:in: .
- #Open: .
- #Open .
- #OpenOn:context:label:contents:fullView: .
- #ResumeProcess: .
- #OpenContext:label:contents:
- }
- !
Item was removed:
- ----- Method: Project class>>dispatchSelectors (in category 'dispatching') -----
- dispatchSelectors
- "All known targets of the dispatch mechanism"
-
- "Project dispatchSelectors"
-
- | selectors dispatchPrefixes |
- selectors := OrderedCollection new.
- dispatchPrefixes := Set withAll: (Project allSubclasses collect: [ :e | e basicNew selectorPrefixForDispatch ]).
- self baseSelectors do: [ :base |
- dispatchPrefixes do: [ :prefix |
- selectors add: (prefix, base) asSymbol ] ].
- ^ selectors
-
- !
Item was changed:
----- Method: Project class>>isDispatchSelector: (in category 'dispatching') -----
isDispatchSelector: aSelector
"In support of package modularity, some method selectors are generated based
on project type and dispatched to the appropriate implementation for that project.
For methods with these selectors, let dispatchTo:addPrefixAndSend:withArguments:
be found as a sender."
+ | dispatchPrefixes prefix otherSelector |
+ dispatchPrefixes := Project allSubclasses collect:
+ [:cls | cls basicNew selectorPrefixForDispatch].
+ "If it doesn't start with a recognized prefix, it's not dispatchable"
+ prefix := dispatchPrefixes detect: [:each | aSelector beginsWith: each]
+ ifNone: [^false].
+ "If a similar symbol exists for all other prefixes, it's likely dispatchable"
+ ^(dispatchPrefixes copyWithout: prefix)
+ allSatisfy: [:otherPrefix |
+ otherSelector := otherPrefix, (aSelector allButFirst: prefix size).
+ Symbol hasInterned: otherSelector ifTrue: [:s]]
-
- ^ self dispatchSelectors includes: aSelector.
!
A new version of Kernel was added to project The Inbox:
http://source.squeak.org/inbox/Kernel-tonyg.1149.mcz
==================== Summary ====================
Name: Kernel-tonyg.1149
Author: tonyg
Time: 31 January 2018, 11:45:27.771328 pm
UUID: ab03b520-f8a0-4aa9-87c4-9b7e9dfb0369
Ancestors: Kernel-tonyg.1148
Add an alias for Promise>>#then:, called #>>=, echoing the monadic bind operator.
Use of a binary selector allows for convenient chaining of Promises without lots of nested parentheses.
For example:
(self produceSomePromise)
>>= [:v | self produceAnotherPromiseInvolving: v]
>>= [:v | self makeYetAnotherUsing: v]
instead of the more cumbersome
((self produceSomePromise)
then: [:v | self produceAnotherPromiseInvolving: v])
then: [:v | self makeYetAnotherUsing: v]
Also adds #>>, again named after the analogous monadic operator, which is like #>>= but does not pass the value from the left-hand-side promise to the continuation block.
=============== Diff against Kernel-tonyg.1148 ===============
Item was added:
+ ----- Method: Promise>>>> (in category 'monad') -----
+ >> resolvedBlock
+ "Like >>=, but discards the result of the promise."
+ ^ self then: [:v | resolvedBlock value]!
Item was added:
+ ----- Method: Promise>>>>= (in category 'monad') -----
+ >>= resolvedBlock
+ "Alias for `then:` allowing convenient chaining."
+ ^ self then: resolvedBlock!
A new version of KernelTests was added to project The Inbox:
http://source.squeak.org/inbox/KernelTests-tonyg.331.mcz
==================== Summary ====================
Name: KernelTests-tonyg.331
Author: tonyg
Time: 31 January 2018, 11:38:54.000311 pm
UUID: 76ecc634-5cf0-43e2-8e17-3dcf9ba18408
Ancestors: KernelTests-nice.330
Updated and new tests for Promise, to match Kernel-tonyg.1148
=============== Diff against KernelTests-nice.330 ===============
Item was changed:
----- Method: PromiseTest>>testCannotRejectFulfilledPromise (in category 'testing - monad') -----
testCannotRejectFulfilledPromise
| p |
p := Promise unit: 1.
+ p rejectWith: Error new.
+ self assert: p isResolved.
+ self assert: 1 equals: p value.
+ !
- self should: [p rejectWith: Error new] raise: Error.!
Item was changed:
----- Method: PromiseTest>>testCannotResolveaRejectedPromise (in category 'testing - monad') -----
testCannotResolveaRejectedPromise
+ | p e |
- | p |
p := Promise new.
+ e := Error new.
+ p rejectWith: e.
+ p resolveWith: 1.
+ self assert: p isRejected.
+ self assert: p error == e.
+ !
- p rejectWith: Error new.
- self should: [p resolveWith: 1] raise: Error.!
Item was added:
+ ----- Method: PromiseTest>>testCollapsesChainsOfPromises (in category 'testing - monad') -----
+ testCollapsesChainsOfPromises
+ "The monadic bind operator has signature (m a -> (a -> m b) -> m b): that is, in our setting,
+ the block given to `then:` is expected to return a *Promise* of a value, not a value directly.
+ It is convenient to accept non-promise values and automatically lift them into the monad,
+ but we must also ensure we treat the case where a `then:`-block yields a Promise correctly."
+ | p q r |
+ p := Promise new.
+ q := p then: [:v | Promise unit: v * 2].
+ r := q then: [:v | Promise unit: v + 1].
+ p resolveWith: 4.
+ self assert: 4 * 2 equals: q value.
+ self assert: (4 * 2 + 1) equals: r value.!
Item was added:
+ ----- Method: PromiseTest>>testFirstResolutionWins (in category 'testing - monad') -----
+ testFirstResolutionWins
+ | p |
+ p := Promise new.
+ p resolveWith: 1.
+ p resolveWith: 2.
+ self assert: p isResolved.
+ self assert: p value == 1.
+ !
A new version of KernelTests was added to project The Inbox:
http://source.squeak.org/inbox/KernelTests-tonyg.331.mcz
==================== Summary ====================
Name: KernelTests-tonyg.331
Author: tonyg
Time: 31 January 2018, 11:38:54.000311 pm
UUID: 76ecc634-5cf0-43e2-8e17-3dcf9ba18408
Ancestors: KernelTests-nice.330
Updated and new tests for Promise, to match Kernel-tonyg.1148
=============== Diff against KernelTests-nice.330 ===============
Item was changed:
----- Method: PromiseTest>>testCannotRejectFulfilledPromise (in category 'testing - monad') -----
testCannotRejectFulfilledPromise
| p |
p := Promise unit: 1.
+ p rejectWith: Error new.
+ self assert: p isResolved.
+ self assert: 1 equals: p value.
+ !
- self should: [p rejectWith: Error new] raise: Error.!
Item was changed:
----- Method: PromiseTest>>testCannotResolveaRejectedPromise (in category 'testing - monad') -----
testCannotResolveaRejectedPromise
+ | p e |
- | p |
p := Promise new.
+ e := Error new.
+ p rejectWith: e.
+ p resolveWith: 1.
+ self assert: p isRejected.
+ self assert: p error == e.
+ !
- p rejectWith: Error new.
- self should: [p resolveWith: 1] raise: Error.!
Item was added:
+ ----- Method: PromiseTest>>testCollapsesChainsOfPromises (in category 'testing - monad') -----
+ testCollapsesChainsOfPromises
+ "The monadic bind operator has signature (m a -> (a -> m b) -> m b): that is, in our setting,
+ the block given to `then:` is expected to return a *Promise* of a value, not a value directly.
+ It is convenient to accept non-promise values and automatically lift them into the monad,
+ but we must also ensure we treat the case where a `then:`-block yields a Promise correctly."
+ | p q r |
+ p := Promise new.
+ q := p then: [:v | Promise unit: v * 2].
+ r := q then: [:v | Promise unit: v + 1].
+ p resolveWith: 4.
+ self assert: 4 * 2 equals: q value.
+ self assert: (4 * 2 + 1) equals: r value.!
Item was added:
+ ----- Method: PromiseTest>>testFirstResolutionWins (in category 'testing - monad') -----
+ testFirstResolutionWins
+ | p |
+ p := Promise new.
+ p resolveWith: 1.
+ p resolveWith: 2.
+ self assert: p isResolved.
+ self assert: p value == 1.
+ !
A new version of Multilingual was added to project The Inbox:
http://source.squeak.org/inbox/Multilingual-tonyg.235.mcz
==================== Summary ====================
Name: Multilingual-tonyg.235
Author: tonyg
Time: 31 January 2018, 8:38:16.621047 pm
UUID: 8ca52bc8-a45a-4b10-91dc-a0b4586b459e
Ancestors: Multilingual-tonyg.234
Add
ByteArray>>utf8Decoded
String>>utf8Encoded
per discussion on mailing-list on 28 Jan 2018, http://lists.squeakfoundation.org/pipermail/squeak-dev/2018-January/197082.…
=============== Diff against Multilingual-tonyg.234 ===============
Item was added:
+ ----- Method: ByteArray>>utf8Decoded (in category '*Multilingual-converting') -----
+ utf8Decoded
+ "Interprets the receiver as a UTF8-encoded String. Yields a String, or an InvalidUTF8 exception if the receiver is not valid UTF8."
+ "Equivalent to the Pharo method of the same name."
+ ^ self asString utf8ToSqueak!
Item was added:
+ ----- Method: String>>utf8Encoded (in category '*Multilingual-converting') -----
+ utf8Encoded
+ "Yields a ByteArray containing the UTF8 encoding of the receiver's contents."
+ "Equivalent to the Pharo method of the same name."
+ ^ self squeakToUtf8 asByteArray!
Hi All,
Most versions of the Cryptography package are missing from its repository[1].
Does anyone know what happened to them? Is there a way to restore them?
Levente
[1]http://squeaksource.com/Cryptography.html