The Trunk: System-eem.975.mcz

Previous Topic Next Topic
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

The Trunk: System-eem.975.mcz

Eliot Miranda uploaded a new version of System to project The Trunk:

==================== Summary ====================

Name: System-eem.975
Author: eem
Time: 14 November 2017, 11:22:51.118839 am
UUID: d8e00134-ca31-43fb-8558-8bf9a15c7aba
Ancestors: System-tpr.974

Add the ability to set a pragma preference stored in a class or global variable by analysing the getter, obviating the need for a setter.

Improve the class comment for PragmaPreference and mention this feature.

=============== Diff against System-tpr.974 ===============

Item was changed:
  Preference subclass: #PragmaPreference
  instanceVariableNames: 'provider getter setter'
  classVariableNames: ''
  poolDictionaries: ''
  category: 'System-Preferences'!
+ !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:
+ [^false].
+ classVar := getterBytecodes first first arguments first.
+ classVar value: aValue.
+ ^true!

Item was changed:
  ----- Method: PragmaPreference>>rawValue: (in category 'value') -----
  rawValue: aValue
  "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!