Browse Source

Axolator.

Herbert Vojčík 6 years ago
parent
commit
ff6f7c8a5d
5 changed files with 232 additions and 237 deletions
  1. 13 0
      README.md
  2. 58 175
      src/Axxord-Tests.js
  3. 24 40
      src/Axxord-Tests.st
  4. 123 16
      src/Axxord.js
  5. 14 6
      src/Axxord.st

+ 13 - 0
README.md

@@ -140,3 +140,16 @@ as shown in the following table
 | `#(left (amount))` | enacts | enacts |
 | `#(left (amount) (desc))` | passes | enacts |
 | `#(left (name))` | passes | passes |
+
+Axolator
+----
+
+There is a helper class that allows you to isolate reads/writes done by
+`axes:consume:` and `axes:transform:` from each other. Instead of using
+`model := MyModel new` instance directly, use `model := Axolator on:
+MyModel new` instead. It wraps the instance you pass to `on:` so that
+`axes:consume:` always gets `deepCopy` of the value (so you it can be modified
+but version in the blackboard stays unmodified) and the result written back
+to blackboard by `axes:transform:` is sent `deepCopy` as well
+(so if value passed to `axes:transform:` is saved and modified later,
+it does not alter the blackboard).

+ 58 - 175
src/Axxord-Tests.js

@@ -1,4 +1,4 @@
-define(["amber/boot", "amber_core/SUnit", "axxord/Axxord"], function($boot){"use strict";
+define(["amber/boot", "amber_core/SUnit", "axxord/Axxord-Axon"], function($boot){"use strict";
 if(!$boot.nilAsReceiver)$boot.nilAsReceiver=$boot.nil;
 if(!("nilAsValue" in $boot))$boot.nilAsValue=$boot.nilAsReceiver;
 var $core=$boot.api,nil=$boot.nilAsValue,$nil=$boot.nilAsReceiver,$recv=$boot.asReceiver,$globals=$boot.globals;
@@ -8,93 +8,19 @@ $core.packages["Axxord-Tests"].innerEval = function (expr) { return eval(expr);
 $core.packages["Axxord-Tests"].transport = {"type":"amd","amdNamespace":"axxord"};
 
 $core.addClass("AxolatorTest", $globals.TestCase, ["rootModel"], "Axxord-Tests");
-$core.addMethod(
-$core.method({
-selector: "setUp",
-protocol: "running",
-fn: function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-$1=$recv($globals.EavModel)._new();
-$recv($1)._getBlock_((function(x){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv(x)._root();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-$self["@rootModel"]=$recv($1)._putBlock_((function(x,y){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv(x)._root_(y);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({x:x,y:y},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"setUp",{},$globals.AxolatorTest)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "setUp\x0a\x0arootModel := EavModel new\x0a\x09getBlock: [:x | x root];\x0a    putBlock: [:x :y | x root: y].",
-referencedClasses: ["EavModel"],
-//>>excludeEnd("ide");
-messageSends: ["getBlock:", "new", "root", "putBlock:", "root:"]
-}),
-$globals.AxolatorTest);
-
 $core.addMethod(
 $core.method({
 selector: "testNontrivialModelGetsAppropriateValueForModification",
 protocol: "tests",
 fn: function (){
 var self=this,$self=this;
-var isolator,model,result;
+var isolator,result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$3,$2;
 result=nil;
 isolator=$recv($globals.Axolator)._on_($globals.HashedCollection._newFromPairs_(["foo",["bar", [(1), [(2), (5)]], "baz"],"moo","zoo"]));
-$1=$recv($globals.EavModel)._new();
-$recv($1)._getBlock_((function(x){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-$3=$recv(x)._root();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["root"]=1;
-//>>excludeEnd("ctx");
-$2=$recv($3)._at_("foo");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["at:"]=2;
-//>>excludeEnd("ctx");
-return $recv($2)._at_((2));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["at:"]=1;
-//>>excludeEnd("ctx");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-model=$recv($1)._putBlock_((function(x,y){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($recv($recv(x)._root())._at_("foo"))._at_put_((2),y);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({x:x,y:y},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-$recv(isolator)._model_modify_(model,(function(r){
+$recv(isolator)._axes_transform_(["foo", (2)],(function(r){
 result=r;
 return result;
 
@@ -102,15 +28,15 @@ return result;
 $self._assert_equals_([(1), [(2), (5)]],result);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"testNontrivialModelGetsAppropriateValueForModification",{isolator:isolator,model:model,result:result},$globals.AxolatorTest)});
+}, function($ctx1) {$ctx1.fill(self,"testNontrivialModelGetsAppropriateValueForModification",{isolator:isolator,result:result},$globals.AxolatorTest)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testNontrivialModelGetsAppropriateValueForModification\x0a| isolator model result |\x0aresult := nil.\x0aisolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 5)) 'baz'). 'moo' -> 'zoo' }.\x0amodel := EavModel new\x0a\x09getBlock: [ :x | (x root at: 'foo') at: 2 ];\x0a\x09putBlock: [ :x :y | (x root at: 'foo') at: 2 put: y].\x0aisolator model: model modify: [:r|result := r].\x0aself assert: #(1 #(2 5)) equals: result",
-referencedClasses: ["Axolator", "EavModel"],
+source: "testNontrivialModelGetsAppropriateValueForModification\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 5)) 'baz'). 'moo' -> 'zoo' }.\x0aisolator axes: #(foo 2) transform: [:r|result := r].\x0aself assert: #(1 #(2 5)) equals: result",
+referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "getBlock:", "new", "at:", "root", "putBlock:", "at:put:", "model:modify:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -120,60 +46,29 @@ selector: "testNontrivialModelModifiesAppropriateValue",
 protocol: "tests",
 fn: function (){
 var self=this,$self=this;
-var isolator,model,result;
+var isolator,result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$3,$2;
 result=nil;
 isolator=$recv($globals.Axolator)._on_($globals.HashedCollection._newFromPairs_(["foo",["bar", [(1), [(2), (3)]], "baz"],"moo","zoo"]));
-$1=$recv($globals.EavModel)._new();
-$recv($1)._getBlock_((function(x){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-$3=$recv(x)._root();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["root"]=1;
-//>>excludeEnd("ctx");
-$2=$recv($3)._at_("foo");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["at:"]=2;
-//>>excludeEnd("ctx");
-return $recv($2)._at_((2));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["at:"]=1;
-//>>excludeEnd("ctx");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-model=$recv($1)._putBlock_((function(x,y){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($recv($recv(x)._root())._at_("foo"))._at_put_((2),y);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({x:x,y:y},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-$recv(isolator)._model_modify_(model,(function(r){
+$recv(isolator)._axes_transform_(["foo", (2)],(function(r){
 return "new";
 
 }));
-$recv(isolator)._model_read_(model,(function(r){
+$recv(isolator)._axes_consume_(["foo", (2)],(function(r){
 result=r;
 return result;
 
 }));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["model:read:"]=1;
+$ctx1.sendIdx["axes:consume:"]=1;
 //>>excludeEnd("ctx");
 $self._assert_equals_("new",result);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["assert:equals:"]=1;
 //>>excludeEnd("ctx");
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -181,15 +76,15 @@ return result;
 $self._assert_equals_($globals.HashedCollection._newFromPairs_(["foo",["bar", "new", "baz"],"moo","zoo"]),result);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"testNontrivialModelModifiesAppropriateValue",{isolator:isolator,model:model,result:result},$globals.AxolatorTest)});
+}, function($ctx1) {$ctx1.fill(self,"testNontrivialModelModifiesAppropriateValue",{isolator:isolator,result:result},$globals.AxolatorTest)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testNontrivialModelModifiesAppropriateValue\x0a| isolator model result |\x0aresult := nil.\x0aisolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 3)) 'baz'). 'moo' -> 'zoo' }.\x0amodel := EavModel new\x0a\x09getBlock: [ :x | (x root at: 'foo') at: 2 ];\x0a\x09putBlock: [ :x :y | (x root at: 'foo') at: 2 put: y].\x0aisolator model: model modify: [:r|#new].\x0aisolator model: model read: [:r|result := r].\x0aself assert: #new equals: result.\x0aisolator model: rootModel read: [:r|result := r].\x0aself assert: #{ 'foo' -> #('bar' #new 'baz'). 'moo' -> 'zoo' } equals: result",
-referencedClasses: ["Axolator", "EavModel"],
+source: "testNontrivialModelModifiesAppropriateValue\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 3)) 'baz'). 'moo' -> 'zoo' }.\x0aisolator axes: #(foo 2) transform: [:r|#new].\x0aisolator axes: #(foo 2) consume: [:r|result := r].\x0aself assert: #new equals: result.\x0aisolator axes: #() consume: [:r|result := r].\x0aself assert: #{ 'foo' -> #('bar' #new 'baz'). 'moo' -> 'zoo' } equals: result",
+referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "getBlock:", "new", "at:", "root", "putBlock:", "at:put:", "model:modify:", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -199,25 +94,13 @@ selector: "testNontrivialModelReturnsAppropriateValue",
 protocol: "tests",
 fn: function (){
 var self=this,$self=this;
-var isolator,model,result;
+var isolator,result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 result=nil;
 isolator=$recv($globals.Axolator)._on_($globals.HashedCollection._newFromPairs_(["foo",["bar", [(1), [(2), (3)]], "baz"],"moo","zoo"]));
-model=$recv($recv($globals.EavModel)._new())._getBlock_((function(x){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($recv($recv(x)._root())._at_("foo"))._at_((2));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["at:"]=1;
-//>>excludeEnd("ctx");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({x:x},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-$recv(isolator)._model_read_(model,(function(r){
+$recv(isolator)._axes_consume_(["foo", (2)],(function(r){
 result=r;
 return result;
 
@@ -225,15 +108,15 @@ return result;
 $self._assert_equals_([(1), [(2), (3)]],result);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"testNontrivialModelReturnsAppropriateValue",{isolator:isolator,model:model,result:result},$globals.AxolatorTest)});
+}, function($ctx1) {$ctx1.fill(self,"testNontrivialModelReturnsAppropriateValue",{isolator:isolator,result:result},$globals.AxolatorTest)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testNontrivialModelReturnsAppropriateValue\x0a| isolator model result |\x0aresult := nil.\x0aisolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 3)) 'baz'). 'moo' -> 'zoo' }.\x0amodel := EavModel new getBlock: [ :x | (x root at: 'foo') at: 2 ].\x0aisolator model: model read: [:r|result := r].\x0aself assert: #(1 #(2 3)) equals: result",
-referencedClasses: ["Axolator", "EavModel"],
+source: "testNontrivialModelReturnsAppropriateValue\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 3)) 'baz'). 'moo' -> 'zoo' }.\x0aisolator axes: #(foo 2) consume: [:r|result := r].\x0aself assert: #(1 #(2 3)) equals: result",
+referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "getBlock:", "new", "at:", "root", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -249,7 +132,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (3)]]);
-$recv(isolator)._model_modify_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_transform_([],(function(r){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -258,7 +141,7 @@ return $recv(r)._second();
 }, function($ctx2) {$ctx2.fillBlock({r:r},$ctx1,1)});
 //>>excludeEnd("ctx");
 }));
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -271,10 +154,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelExaminesThenModifiesRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator model: rootModel modify: [:r|r second].\x0aisolator model: rootModel read: [:r|result := r].\x0aself assert: #(2 3) equals: result",
+source: "testRootModelExaminesThenModifiesRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator axes: #() transform: [:r|r second].\x0aisolator axes: #() consume: [:r|result := r].\x0aself assert: #(2 3) equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:modify:", "second", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "second", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -290,7 +173,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(2), [(1), (0)]]);
-$recv(isolator)._model_modify_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_transform_([],(function(r){
 result=r;
 return result;
 
@@ -303,10 +186,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelGetsRootForModification\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(2 #(1 0)).\x0aisolator model: rootModel modify: [:r|result := r].\x0aself assert: #(2 #(1 0)) equals: result",
+source: "testRootModelGetsRootForModification\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(2 #(1 0)).\x0aisolator axes: #() transform: [:r|result := r].\x0aself assert: #(2 #(1 0)) equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:modify:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -323,7 +206,7 @@ return $core.withContext(function($ctx1) {
 result=nil;
 newValue=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (3)]]);
-$recv(isolator)._model_modify_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_transform_([],(function(r){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -342,7 +225,7 @@ $recv(newValue)._at_put_((2),"bar");
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["at:put:"]=2;
 //>>excludeEnd("ctx");
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -356,10 +239,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelModifiesAndDeeplyIsolatesInPlaceModifiedRoot\x0a| isolator result newValue |\x0aresult := nil. newValue := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator model: rootModel modify: [:r|newValue := r. r at: 1 put: 4. r].\x0anewValue at: 2 put: 'bar'.\x0aisolator model: rootModel read: [:r|result := r].\x0anewValue at: 2 put: 'baz'.\x0aself assert: #(4 #(2 3)) equals: result",
+source: "testRootModelModifiesAndDeeplyIsolatesInPlaceModifiedRoot\x0a| isolator result newValue |\x0aresult := nil. newValue := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator axes: #() transform: [:r|newValue := r. r at: 1 put: 4. r].\x0anewValue at: 2 put: 'bar'.\x0aisolator axes: #() consume: [:r|result := r].\x0anewValue at: 2 put: 'baz'.\x0aself assert: #(4 #(2 3)) equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:modify:", "at:put:", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "at:put:", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -377,7 +260,7 @@ var $1;
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (3)]]);
 newValue=$globals.HashedCollection._newFromPairs_(["foo",[(4), (5), (6)]]);
-$recv(isolator)._model_modify_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_transform_([],(function(r){
 return newValue;
 
 }));
@@ -389,7 +272,7 @@ $recv($1)._at_put_((1),"bar");
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["at:put:"]=1;
 //>>excludeEnd("ctx");
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -403,10 +286,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelModifiesAndDeeplyIsolatesRoot\x0a| isolator result newValue |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0anewValue := #{'foo'->#(4 5 6)}.\x0aisolator model: rootModel modify: [:r|newValue].\x0a(newValue at: 'foo') at: 1 put: 'bar'.\x0aisolator model: rootModel read: [:r|result := r].\x0a(newValue at: 'foo') at: 3 put: 'baz'.\x0aself assert: #{'foo'->#(4 5 6)} equals: result",
+source: "testRootModelModifiesAndDeeplyIsolatesRoot\x0a| isolator result newValue |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0anewValue := #{'foo'->#(4 5 6)}.\x0aisolator axes: #() transform: [:r|newValue].\x0a(newValue at: 'foo') at: 1 put: 'bar'.\x0aisolator axes: #() consume: [:r|result := r].\x0a(newValue at: 'foo') at: 3 put: 'baz'.\x0aself assert: #{'foo'->#(4 5 6)} equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:modify:", "at:put:", "at:", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "at:put:", "at:", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -423,7 +306,7 @@ return $core.withContext(function($ctx1) {
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (3)]]);
 newValue=$globals.HashedCollection._newFromPairs_(["foo",[(4), (5), (6)]]);
-$recv(isolator)._model_modify_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_transform_([],(function(r){
 return newValue;
 
 }));
@@ -431,7 +314,7 @@ $recv(newValue)._at_put_("foo","bar");
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["at:put:"]=1;
 //>>excludeEnd("ctx");
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -445,10 +328,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelModifiesAndIsolatesRoot\x0a| isolator result newValue |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0anewValue := #{'foo'->#(4 5 6)}.\x0aisolator model: rootModel modify: [:r|newValue].\x0anewValue at: 'foo' put: 'bar'.\x0aisolator model: rootModel read: [:r|result := r].\x0anewValue at: 'foo' put: 'baz'.\x0aself assert: #{'foo'->#(4 5 6)} equals: result",
+source: "testRootModelModifiesAndIsolatesRoot\x0a| isolator result newValue |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0anewValue := #{'foo'->#(4 5 6)}.\x0aisolator axes: #() transform: [:r|newValue].\x0anewValue at: 'foo' put: 'bar'.\x0aisolator axes: #() consume: [:r|result := r].\x0anewValue at: 'foo' put: 'baz'.\x0aself assert: #{'foo'->#(4 5 6)} equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:modify:", "at:put:", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "at:put:", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -464,11 +347,11 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (3)]]);
-$recv(isolator)._model_modify_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_transform_([],(function(r){
 return $globals.HashedCollection._newFromPairs_(["foo",[(4), (5), (6)]]);
 
 }));
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -481,10 +364,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelModifiesRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator model: rootModel modify: [:r|#{'foo'->#(4 5 6)}].\x0aisolator model: rootModel read: [:r|result := r].\x0aself assert: #{'foo'->#(4 5 6)} equals: result",
+source: "testRootModelModifiesRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator axes: #() transform: [:r|#{'foo'->#(4 5 6)}].\x0aisolator axes: #() consume: [:r|result := r].\x0aself assert: #{'foo'->#(4 5 6)} equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:modify:", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:transform:", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -500,7 +383,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (3)]]);
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -510,9 +393,9 @@ return $recv($recv(r)._at_((2)))._at_put_((1),(0));
 //>>excludeEnd("ctx");
 }));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["model:read:"]=1;
+$ctx1.sendIdx["axes:consume:"]=1;
 //>>excludeEnd("ctx");
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -525,10 +408,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelReturnsDeeplyIsolatedRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator model: rootModel read: [:r|(r at: 2) at: 1 put: 0].\x0aisolator model: rootModel read: [:r|result := r].\x0aself assert: #(1 #(2 3)) equals: result",
+source: "testRootModelReturnsDeeplyIsolatedRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator axes: #() consume: [:r|(r at: 2) at: 1 put: 0].\x0aisolator axes: #() consume: [:r|result := r].\x0aself assert: #(1 #(2 3)) equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:read:", "at:put:", "at:", "assert:equals:"]
+messageSends: ["on:", "axes:consume:", "at:put:", "at:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -544,7 +427,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (4)]]);
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
@@ -554,9 +437,9 @@ return $recv(r)._at_put_((2),nil);
 //>>excludeEnd("ctx");
 }));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["model:read:"]=1;
+$ctx1.sendIdx["axes:consume:"]=1;
 //>>excludeEnd("ctx");
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -569,10 +452,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelReturnsIsolatedRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 4)).\x0aisolator model: rootModel read: [:r|r at: 2 put: nil].\x0aisolator model: rootModel read: [:r|result := r].\x0aself assert: #(1 #(2 4)) equals: result",
+source: "testRootModelReturnsIsolatedRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 4)).\x0aisolator axes: #() consume: [:r|r at: 2 put: nil].\x0aisolator axes: #() consume: [:r|result := r].\x0aself assert: #(1 #(2 4)) equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:read:", "at:put:", "assert:equals:"]
+messageSends: ["on:", "axes:consume:", "at:put:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 
@@ -588,7 +471,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 result=nil;
 isolator=$recv($globals.Axolator)._on_([(1), [(2), (3)]]);
-$recv(isolator)._model_read_($self["@rootModel"],(function(r){
+$recv(isolator)._axes_consume_([],(function(r){
 result=r;
 return result;
 
@@ -601,10 +484,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testRootModelReturnsRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator model: rootModel read: [:r|result := r].\x0aself assert: #(1 #(2 3)) equals: result",
+source: "testRootModelReturnsRoot\x0a| isolator result |\x0aresult := nil.\x0aisolator := Axolator on: #(1 #(2 3)).\x0aisolator axes: #() consume: [:r|result := r].\x0aself assert: #(1 #(2 3)) equals: result",
 referencedClasses: ["Axolator"],
 //>>excludeEnd("ide");
-messageSends: ["on:", "model:read:", "assert:equals:"]
+messageSends: ["on:", "axes:consume:", "assert:equals:"]
 }),
 $globals.AxolatorTest);
 

+ 24 - 40
src/Axxord-Tests.st

@@ -3,48 +3,32 @@ TestCase subclass: #AxolatorTest
 	instanceVariableNames: 'rootModel'
 	package: 'Axxord-Tests'!
 
-!AxolatorTest methodsFor: 'running'!
-
-setUp
-
-rootModel := EavModel new
-	getBlock: [:x | x root];
-    putBlock: [:x :y | x root: y].
-! !
-
 !AxolatorTest methodsFor: 'tests'!
 
 testNontrivialModelGetsAppropriateValueForModification
-| isolator model result |
+| isolator result |
 result := nil.
 isolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 5)) 'baz'). 'moo' -> 'zoo' }.
-model := EavModel new
-	getBlock: [ :x | (x root at: 'foo') at: 2 ];
-	putBlock: [ :x :y | (x root at: 'foo') at: 2 put: y].
-isolator model: model modify: [:r|result := r].
+isolator axes: #(foo 2) transform: [:r|result := r].
 self assert: #(1 #(2 5)) equals: result
 !
 
 testNontrivialModelModifiesAppropriateValue
-| isolator model result |
+| isolator result |
 result := nil.
 isolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 3)) 'baz'). 'moo' -> 'zoo' }.
-model := EavModel new
-	getBlock: [ :x | (x root at: 'foo') at: 2 ];
-	putBlock: [ :x :y | (x root at: 'foo') at: 2 put: y].
-isolator model: model modify: [:r|#new].
-isolator model: model read: [:r|result := r].
+isolator axes: #(foo 2) transform: [:r|#new].
+isolator axes: #(foo 2) consume: [:r|result := r].
 self assert: #new equals: result.
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() consume: [:r|result := r].
 self assert: #{ 'foo' -> #('bar' #new 'baz'). 'moo' -> 'zoo' } equals: result
 !
 
 testNontrivialModelReturnsAppropriateValue
-| isolator model result |
+| isolator result |
 result := nil.
 isolator := Axolator on: #{ 'foo' -> #('bar' #(1 #(2 3)) 'baz'). 'moo' -> 'zoo' }.
-model := EavModel new getBlock: [ :x | (x root at: 'foo') at: 2 ].
-isolator model: model read: [:r|result := r].
+isolator axes: #(foo 2) consume: [:r|result := r].
 self assert: #(1 #(2 3)) equals: result
 !
 
@@ -52,8 +36,8 @@ testRootModelExaminesThenModifiesRoot
 | isolator result |
 result := nil.
 isolator := Axolator on: #(1 #(2 3)).
-isolator model: rootModel modify: [:r|r second].
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() transform: [:r|r second].
+isolator axes: #() consume: [:r|result := r].
 self assert: #(2 3) equals: result
 !
 
@@ -61,7 +45,7 @@ testRootModelGetsRootForModification
 | isolator result |
 result := nil.
 isolator := Axolator on: #(2 #(1 0)).
-isolator model: rootModel modify: [:r|result := r].
+isolator axes: #() transform: [:r|result := r].
 self assert: #(2 #(1 0)) equals: result
 !
 
@@ -69,9 +53,9 @@ testRootModelModifiesAndDeeplyIsolatesInPlaceModifiedRoot
 | isolator result newValue |
 result := nil. newValue := nil.
 isolator := Axolator on: #(1 #(2 3)).
-isolator model: rootModel modify: [:r|newValue := r. r at: 1 put: 4. r].
+isolator axes: #() transform: [:r|newValue := r. r at: 1 put: 4. r].
 newValue at: 2 put: 'bar'.
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() consume: [:r|result := r].
 newValue at: 2 put: 'baz'.
 self assert: #(4 #(2 3)) equals: result
 !
@@ -81,9 +65,9 @@ testRootModelModifiesAndDeeplyIsolatesRoot
 result := nil.
 isolator := Axolator on: #(1 #(2 3)).
 newValue := #{'foo'->#(4 5 6)}.
-isolator model: rootModel modify: [:r|newValue].
+isolator axes: #() transform: [:r|newValue].
 (newValue at: 'foo') at: 1 put: 'bar'.
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() consume: [:r|result := r].
 (newValue at: 'foo') at: 3 put: 'baz'.
 self assert: #{'foo'->#(4 5 6)} equals: result
 !
@@ -93,9 +77,9 @@ testRootModelModifiesAndIsolatesRoot
 result := nil.
 isolator := Axolator on: #(1 #(2 3)).
 newValue := #{'foo'->#(4 5 6)}.
-isolator model: rootModel modify: [:r|newValue].
+isolator axes: #() transform: [:r|newValue].
 newValue at: 'foo' put: 'bar'.
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() consume: [:r|result := r].
 newValue at: 'foo' put: 'baz'.
 self assert: #{'foo'->#(4 5 6)} equals: result
 !
@@ -104,8 +88,8 @@ testRootModelModifiesRoot
 | isolator result |
 result := nil.
 isolator := Axolator on: #(1 #(2 3)).
-isolator model: rootModel modify: [:r|#{'foo'->#(4 5 6)}].
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() transform: [:r|#{'foo'->#(4 5 6)}].
+isolator axes: #() consume: [:r|result := r].
 self assert: #{'foo'->#(4 5 6)} equals: result
 !
 
@@ -113,8 +97,8 @@ testRootModelReturnsDeeplyIsolatedRoot
 | isolator result |
 result := nil.
 isolator := Axolator on: #(1 #(2 3)).
-isolator model: rootModel read: [:r|(r at: 2) at: 1 put: 0].
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() consume: [:r|(r at: 2) at: 1 put: 0].
+isolator axes: #() consume: [:r|result := r].
 self assert: #(1 #(2 3)) equals: result
 !
 
@@ -122,8 +106,8 @@ testRootModelReturnsIsolatedRoot
 | isolator result |
 result := nil.
 isolator := Axolator on: #(1 #(2 4)).
-isolator model: rootModel read: [:r|r at: 2 put: nil].
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() consume: [:r|r at: 2 put: nil].
+isolator axes: #() consume: [:r|result := r].
 self assert: #(1 #(2 4)) equals: result
 !
 
@@ -131,7 +115,7 @@ testRootModelReturnsRoot
 | isolator result |
 result := nil.
 isolator := Axolator on: #(1 #(2 3)).
-isolator model: rootModel read: [:r|result := r].
+isolator axes: #() consume: [:r|result := r].
 self assert: #(1 #(2 3)) equals: result
 ! !
 

+ 123 - 16
src/Axxord.js

@@ -474,51 +474,158 @@ $globals.Axes.a$cls);
 $core.addClass("Axolator", $globals.Object, ["root"], "Axxord");
 $core.addMethod(
 $core.method({
-selector: "model:modify:",
+selector: "atAxes:ifAbsent:",
+protocol: "action",
+fn: function (aCollection,aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($self["@root"])._atAxes_ifAbsent_(aCollection,aBlock);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"atAxes:ifAbsent:",{aCollection:aCollection,aBlock:aBlock},$globals.Axolator)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection", "aBlock"],
+source: "atAxes: aCollection ifAbsent: aBlock\x0a\x09^ root atAxes: aCollection ifAbsent: aBlock",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["atAxes:ifAbsent:"]
+}),
+$globals.Axolator);
+
+$core.addMethod(
+$core.method({
+selector: "atAxes:ifAbsent:put:",
+protocol: "action",
+fn: function (aCollection,aBlock,value){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($self["@root"])._atAxes_ifAbsent_put_(aCollection,aBlock,value);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"atAxes:ifAbsent:put:",{aCollection:aCollection,aBlock:aBlock,value:value},$globals.Axolator)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection", "aBlock", "value"],
+source: "atAxes: aCollection ifAbsent: aBlock put: value\x0a\x09^ root atAxes: aCollection ifAbsent: aBlock put: value",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["atAxes:ifAbsent:put:"]
+}),
+$globals.Axolator);
+
+$core.addMethod(
+$core.method({
+selector: "axes:consume:",
 protocol: "action",
-fn: function (anEavModel,aBlock){
+fn: function (aCollection,aBlock){
 var self=this,$self=this;
-var newValue;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-newValue=$recv(aBlock)._value_($recv(anEavModel)._on_(self));
-$recv(anEavModel)._on_put_(self,$recv(newValue)._deepCopy());
+(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = true,
+//>>excludeEnd("ctx");
+($globals.Axolator.superclass||$boot.nilAsClass).fn.prototype._axes_consume_.apply($self, [aCollection,(function(value){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(aBlock)._value_($recv(value)._deepCopy());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1,1)});
+//>>excludeEnd("ctx");
+})]));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = false;
+//>>excludeEnd("ctx");;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"model:modify:",{anEavModel:anEavModel,aBlock:aBlock,newValue:newValue},$globals.Axolator)});
+}, function($ctx1) {$ctx1.fill(self,"axes:consume:",{aCollection:aCollection,aBlock:aBlock},$globals.Axolator)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anEavModel", "aBlock"],
-source: "model: anEavModel modify: aBlock\x0a\x0a| newValue |\x0anewValue := aBlock value: (anEavModel on: self).\x0aanEavModel on: self put: newValue deepCopy",
+args: ["aCollection", "aBlock"],
+source: "axes: aCollection consume: aBlock\x0a\x0asuper axes: aCollection consume: [:value | aBlock value: value deepCopy]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["value:", "on:", "on:put:", "deepCopy"]
+messageSends: ["axes:consume:", "value:", "deepCopy"]
 }),
 $globals.Axolator);
 
 $core.addMethod(
 $core.method({
-selector: "model:read:",
+selector: "axes:transform:",
 protocol: "action",
-fn: function (anEavModel,aBlock){
+fn: function (aCollection,aBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-$recv(aBlock)._value_($recv($recv(anEavModel)._on_(self))._deepCopy());
+var $2,$1,$3,$receiver;
+$recv(aCollection)._ifEmpty_ifNotEmpty_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$2=$recv(aBlock)._value_($self._root());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["value:"]=1;
+//>>excludeEnd("ctx");
+$1=$recv($2)._deepCopy();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["deepCopy"]=1;
+//>>excludeEnd("ctx");
+$self._root_($1);
+$3=$self._axxord();
+if(($receiver = $3) == null || $receiver.a$nil){
+return $3;
+} else {
+var axxord;
+axxord=$receiver;
+return $recv(axxord)._changed_(aCollection);
+}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}),(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return (
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.supercall = true,
+//>>excludeEnd("ctx");
+($globals.Axolator.superclass||$boot.nilAsClass).fn.prototype._axes_transform_.apply($self, [aCollection,(function(value){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($recv(aBlock)._value_(value))._deepCopy();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({value:value},$ctx2,4)});
+//>>excludeEnd("ctx");
+})]));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.supercall = false;
+//>>excludeEnd("ctx");;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)});
+//>>excludeEnd("ctx");
+}));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"model:read:",{anEavModel:anEavModel,aBlock:aBlock},$globals.Axolator)});
+}, function($ctx1) {$ctx1.fill(self,"axes:transform:",{aCollection:aCollection,aBlock:aBlock},$globals.Axolator)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anEavModel", "aBlock"],
-source: "model: anEavModel read: aBlock\x0a\x0aaBlock value: (anEavModel on: self) deepCopy",
+args: ["aCollection", "aBlock"],
+source: "axes: aCollection transform: aBlock\x0a\x0aaCollection\x0a\x09ifEmpty: [ self root: (aBlock value: self root) deepCopy. self axxord ifNotNil: [ :axxord | axxord changed: aCollection ] ]\x0a\x09ifNotEmpty: [ super axes: aCollection transform: [:value | (aBlock value: value) deepCopy] ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["value:", "deepCopy", "on:"]
+messageSends: ["ifEmpty:ifNotEmpty:", "root:", "deepCopy", "value:", "root", "ifNotNil:", "axxord", "changed:", "axes:transform:"]
 }),
 $globals.Axolator);
 

+ 14 - 6
src/Axxord.st

@@ -87,16 +87,24 @@ root := anObject
 
 !Axolator methodsFor: 'action'!
 
-model: anEavModel modify: aBlock
+atAxes: aCollection ifAbsent: aBlock
+	^ root atAxes: aCollection ifAbsent: aBlock
+!
+
+atAxes: aCollection ifAbsent: aBlock put: value
+	^ root atAxes: aCollection ifAbsent: aBlock put: value
+!
+
+axes: aCollection consume: aBlock
 
-| newValue |
-newValue := aBlock value: (anEavModel on: self).
-anEavModel on: self put: newValue deepCopy
+super axes: aCollection consume: [:value | aBlock value: value deepCopy]
 !
 
-model: anEavModel read: aBlock
+axes: aCollection transform: aBlock
 
-aBlock value: (anEavModel on: self) deepCopy
+aCollection
+	ifEmpty: [ self root: (aBlock value: self root) deepCopy. self axxord ifNotNil: [ :axxord | axxord changed: aCollection ] ]
+	ifNotEmpty: [ super axes: aCollection transform: [:value | (aBlock value: value) deepCopy] ]
 ! !
 
 !Axolator class methodsFor: 'instance creation'!