+ !PragmaPreference commentStamp: 'eem 11/14/2017 11:20' prior: 0!
+ Differs from superclass by redirecting all queries to a preference provider that defines its preference via a class-side preference method marked with a pragma. For example, evaluate
+ self systemNavigation browseAllCallsOn: #preference:categoryList:description:type:
+ Each preference method getter can be accompanied by a setter that assigns to the preference whose value the getter answers. If the getter is of the form
+ ^SomeGlobalOrClassVar ifNil: [...]
+ then the framework is smart enough to figure out the SomeGlobalOrClassVar from the getter and no setter method is required.!
- !PragmaPreference commentStamp: 'ar 3/9/2009 21:27' prior: 0!
- Differs from superclass by redirecting all queries to preference provider.!
Item was added:
+ ----- Method: PragmaPreference>>attemptToSetValueFromGetter: (in category 'value') -----
+ attemptToSetValueFromGetter: aValue
+ "Attempt to set the value of the preference from the getter method, answering if the attempt was successful.
+ Do so by seeing if the method is of the form
+ ^ClassVar ifNil: [...]
+ by analysing its bytecode, and if so, extracting the class (or global) var and setting its value."
+ | getterMethod getterBytecodes getterBytecodeNames
+ constant comparison branchTuple distance followingpc
+ classVar |
+ getterMethod := provider class compiledMethodAt: getter ifAbsent: [^false].
+ getterBytecodes := getterMethod abstractBytecodeMessagesAndPCs.
+ getterBytecodeNames := getterBytecodes collect: [:tuple| tuple first selector].
+ ((getterBytecodeNames beginsWith: #(pushLiteralVariable: doDup #pushConstant: send:super:numArgs: jump:if:))
+ and: [getterBytecodeNames last == #methodReturnTop
+ and: [(constant := getterBytecodes third first) arguments first == nil
+ and: [(comparison := getterBytecodes fourth first) arguments first == #==
+ and: [branchTuple := getterBytecodes fifth.
+ followingpc := getterBytecodes sixth last.
+ distance := branchTuple first arguments first.
+ "i.e. does the branch jump to the return?"
+ distance + followingpc = getterBytecodes last second]]]]) ifFalse:
+ classVar := getterBytecodes first first arguments first.
+ classVar value: aValue.
Item was changed:
----- Method: PragmaPreference>>rawValue: (in category 'value') -----
"set the value as indicated, with no side effects"
+ [provider perform: setter with: aValue]
+ on: MessageNotUnderstood
+ do: [:ex|
+ (self attemptToSetValueFromGetter: aValue) ifFalse:
+ [ex pass]]!
- provider perform: setter with: aValue!