Browse Source

BlockClosure >> currySelf

Transform plain [ :x :y ... ] block that is to be called
as f(x,y,...) in JS into function that can be used as a JS method,
that it, should be called as x.f(y,...).

Usable with asCompiledMethod.
Herbert Vojčík 11 years ago
parent
commit
2ba42314f3
6 changed files with 103 additions and 0 deletions
  1. 15 0
      js/Kernel-Methods.deploy.js
  2. 20 0
      js/Kernel-Methods.js
  3. 21 0
      js/Kernel-Tests.deploy.js
  4. 26 0
      js/Kernel-Tests.js
  5. 12 0
      st/Kernel-Methods.st
  6. 9 0
      st/Kernel-Tests.st

+ 15 - 0
js/Kernel-Methods.deploy.js

@@ -33,6 +33,21 @@ return self}, function($ctx1) {$ctx1.fill(self,"compiledSource",{}, smalltalk.Bl
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_currySelf",
+smalltalk.method({
+selector: "currySelf",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return function () {
+    	var args = [ this ];
+        args.push.apply(args, arguments);
+        return self.apply(null, args);
+    };
+return self}, function($ctx1) {$ctx1.fill(self,"currySelf",{}, smalltalk.BlockClosure)})}
+}),
+smalltalk.BlockClosure);
+
 smalltalk.addMethod(
 "_ensure_",
 smalltalk.method({

+ 20 - 0
js/Kernel-Methods.js

@@ -49,6 +49,26 @@ referencedClasses: []
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_currySelf",
+smalltalk.method({
+selector: "currySelf",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return function () {
+    	var args = [ this ];
+        args.push.apply(args, arguments);
+        return self.apply(null, args);
+    };
+return self}, function($ctx1) {$ctx1.fill(self,"currySelf",{}, smalltalk.BlockClosure)})},
+args: [],
+source: "currySelf\x0a\x09\x22Transforms [ :selfarg :x :y | stcode ] block\x0a    which represents JS function (selfarg, x, y, ...) {jscode}\x0a    into function (x, y, ...) {jscode} that takes selfarg from 'this'.\x0a    IOW, it is usable as JS method and first arg takes the receiver.\x22\x0a    <return function () {\x0a    \x09var args = [ this ];\x0a        args.push.apply(args, arguments);\x0a        return self.apply(null, args);\x0a    }>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.BlockClosure);
+
 smalltalk.addMethod(
 "_ensure_",
 smalltalk.method({

+ 21 - 0
js/Kernel-Tests.deploy.js

@@ -43,6 +43,27 @@ return self}, function($ctx1) {$ctx1.fill(self,"testCompiledSource",{}, smalltal
 }),
 smalltalk.BlockClosureTest);
 
+smalltalk.addMethod(
+"_testCurrySelf",
+smalltalk.method({
+selector: "testCurrySelf",
+fn: function (){
+var self=this;
+var curriedMethod,array;
+return smalltalk.withContext(function($ctx1) { 
curriedMethod=_st(_st((function(selfarg,x){
+return smalltalk.withContext(function($ctx2) {
return _st(selfarg)._at_(x);
+}, function($ctx2) {$ctx2.fillBlock({selfarg:selfarg,x:x},$ctx1)})}))._currySelf())._asCompiledMethod_("foo:");
+array=[(3), (1), (4)];
+_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(curriedMethod,(smalltalk.Array || Array),"**test helper");
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._assert_equals_((1),_st(array)._foo_((2)));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._ensure_((function(){
+return smalltalk.withContext(function($ctx2) {
return _st((smalltalk.Array || Array))._removeCompiledMethod_(curriedMethod);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"testCurrySelf",{curriedMethod:curriedMethod,array:array}, smalltalk.BlockClosureTest)})}
+}),
+smalltalk.BlockClosureTest);
+
 smalltalk.addMethod(
 "_testEnsure",
 smalltalk.method({

+ 26 - 0
js/Kernel-Tests.js

@@ -58,6 +58,32 @@ referencedClasses: []
 }),
 smalltalk.BlockClosureTest);
 
+smalltalk.addMethod(
+"_testCurrySelf",
+smalltalk.method({
+selector: "testCurrySelf",
+category: 'tests',
+fn: function (){
+var self=this;
+var curriedMethod,array;
+return smalltalk.withContext(function($ctx1) { 
curriedMethod=_st(_st((function(selfarg,x){
+return smalltalk.withContext(function($ctx2) {
return _st(selfarg)._at_(x);
+}, function($ctx2) {$ctx2.fillBlock({selfarg:selfarg,x:x},$ctx1)})}))._currySelf())._asCompiledMethod_("foo:");
+array=[(3), (1), (4)];
+_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(curriedMethod,(smalltalk.Array || Array),"**test helper");
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._assert_equals_((1),_st(array)._foo_((2)));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._ensure_((function(){
+return smalltalk.withContext(function($ctx2) {
return _st((smalltalk.Array || Array))._removeCompiledMethod_(curriedMethod);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"testCurrySelf",{curriedMethod:curriedMethod,array:array}, smalltalk.BlockClosureTest)})},
+args: [],
+source: "testCurrySelf\x0a\x09| curriedMethod array |\x0a    curriedMethod := [ :selfarg :x | selfarg at: x ] currySelf asCompiledMethod: 'foo:'.\x0a    array := #(3 1 4).\x0a    ClassBuilder new installMethod: curriedMethod forClass: Array category: '**test helper'.\x0a    [ self assert: 1 equals: (array foo: 2) ]\x0a    ensure: [ Array removeCompiledMethod: curriedMethod ]",
+messageSends: ["asCompiledMethod:", "currySelf", "at:", "installMethod:forClass:category:", "new", "ensure:", "removeCompiledMethod:", "assert:equals:", "foo:"],
+referencedClasses: ["Array", "ClassBuilder"]
+}),
+smalltalk.BlockClosureTest);
+
 smalltalk.addMethod(
 "_testEnsure",
 smalltalk.method({

+ 12 - 0
st/Kernel-Methods.st

@@ -44,6 +44,18 @@ whileTrue: aBlock
 
 asCompiledMethod: aString
 	<return smalltalk.method({selector:aString, fn:self});>
+!
+
+currySelf
+	"Transforms [ :selfarg :x :y | stcode ] block
+    which represents JS function (selfarg, x, y, ...) {jscode}
+    into function (x, y, ...) {jscode} that takes selfarg from 'this'.
+    IOW, it is usable as JS method and first arg takes the receiver."
+    <return function () {
+    	var args = [ this ];
+        args.push.apply(args, arguments);
+        return self.apply(null, args);
+    }>
 ! !
 
 !BlockClosure methodsFor: 'error handling'!

+ 9 - 0
st/Kernel-Tests.st

@@ -17,6 +17,15 @@ testCompiledSource
 	self assert: ([1+1] compiledSource includesSubString: 'function')
 !
 
+testCurrySelf
+	| curriedMethod array |
+    curriedMethod := [ :selfarg :x | selfarg at: x ] currySelf asCompiledMethod: 'foo:'.
+    array := #(3 1 4).
+    ClassBuilder new installMethod: curriedMethod forClass: Array category: '**test helper'.
+    [ self assert: 1 equals: (array foo: 2) ]
+    ensure: [ Array removeCompiledMethod: curriedMethod ]
+!
+
 testEnsure
 	self assert: 3 equals: ([3] ensure: [4])
 !