Browse Source

Merge pull request #827 from herby/newvalue-refactor

Newvalue refactor
Nicolas Petton 11 years ago
parent
commit
eb39ee65bd
4 changed files with 19 additions and 37 deletions
  1. 2 4
      js/Kernel-Methods.js
  2. 8 9
      js/Kernel-Tests.js
  3. 2 16
      st/Kernel-Methods.st
  4. 7 8
      st/Kernel-Tests.st

+ 2 - 4
js/Kernel-Methods.js

@@ -185,15 +185,13 @@ fn: function (aCollection){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-		var constructor = function() {};
-		constructor.prototype = self.prototype;
-		var object = new constructor;
+		var object = Object.create(self.prototype);
 		var result = self.apply(object, aCollection);
 		return typeof result === "object" ? result : object;
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"newWithValues:",{aCollection:aCollection},globals.BlockClosure)})},
 args: ["aCollection"],
-source: "newWithValues: aCollection\x0a\x09\x22Use the receiver as a JavaScript constructor with a variable number of arguments.\x0a\x09Answer the object created using the operator `new`.\x0a\x0a\x09This algorithm was inspired by http://stackoverflow.com/a/6069331.\x0a\x0a\x09Here's a general breakdown of what's going on:\x0a\x091) Create a new, empty constructor function.\x0a\x092) Set it's prototype to the receiver's prototype. Because the receiver is a `BlockClosure`, it is also a JavaScript function.\x0a\x093) Instantiate a new object using the constructor function just created. \x0a\x09\x09This forces the interpreter to set the internal [[prototype]] property to what was set on the function before. \x0a   \x09\x09This has to be done, as we have no access to the [[prototype]] property externally.\x0a\x094) Apply `self` to the object I just instantiated.\x22\x0a\x0a\x09<\x0a\x09\x09var constructor = function() {};\x0a\x09\x09constructor.prototype = self.prototype;\x0a\x09\x09var object = new constructor;\x0a\x09\x09var result = self.apply(object, aCollection);\x0a\x09\x09return typeof result === \x22object\x22 ? result : object;\x0a\x09>",
+source: "newWithValues: aCollection\x0a\x09\x22Simulates JS new operator by combination of Object.create and .apply\x22\x0a\x09<\x0a\x09\x09var object = Object.create(self.prototype);\x0a\x09\x09var result = self.apply(object, aCollection);\x0a\x09\x09return typeof result === \x22object\x22 ? result : object;\x0a\x09>",
 messageSends: [],
 referencedClasses: []
 }),

+ 8 - 9
js/Kernel-Tests.js

@@ -299,20 +299,19 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-	function theTestPrototype() {this.name = "theTestPrototype";}
-	function theTestConstructor(arg1, arg2, arg3) {}
-	theTestConstructor.prototype = new theTestPrototype;
+	function TestConstructor(arg1, arg2, arg3) {}
+	TestConstructor.prototype.name = 'theTestPrototype';
 
-	var theWrappedConstructor = _st(theTestConstructor);
-	var theResult = theWrappedConstructor._newWithValues_([1, 2, 3 ]);
-	self._assert_equals_(Object.getPrototypeOf(theResult).name, 'theTestPrototype');
+	var wrappedConstructor = _st(TestConstructor);
+	var result = wrappedConstructor._newWithValues_([1, 2, 3 ]);
+	self._assert_(result instanceof TestConstructor);
+	self._assert_equals_(result.name, 'theTestPrototype');
 
 	"newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made."
-	function constructionShouldFail() {var anotherResult = theWrappedConstructor._newWithValues_('This is so wrong');}
-	self._should_raise_(_st(constructionShouldFail), globals.Error);;
+	self._should_raise_(function () {wrappedConstructor._newWithValues_('single argument');}, globals.Error);;
 return self}, function($ctx1) {$ctx1.fill(self,"testNewWithValues",{},globals.BlockClosureTest)})},
 args: [],
-source: "testNewWithValues\x0a<\x0a\x09function theTestPrototype() {this.name = \x22theTestPrototype\x22;}\x0a\x09function theTestConstructor(arg1, arg2, arg3) {}\x0a\x09theTestConstructor.prototype = new theTestPrototype;\x0a\x0a\x09var theWrappedConstructor = _st(theTestConstructor);\x0a\x09var theResult = theWrappedConstructor._newWithValues_([1, 2, 3 ]);\x0a\x09self._assert_equals_(Object.getPrototypeOf(theResult).name, 'theTestPrototype');\x0a\x0a\x09\x22newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made.\x22\x0a\x09function constructionShouldFail() {var anotherResult = theWrappedConstructor._newWithValues_('This is so wrong');}\x0a\x09self._should_raise_(_st(constructionShouldFail), globals.Error);\x0a>",
+source: "testNewWithValues\x0a<\x0a\x09function TestConstructor(arg1, arg2, arg3) {}\x0a\x09TestConstructor.prototype.name = 'theTestPrototype';\x0a\x0a\x09var wrappedConstructor = _st(TestConstructor);\x0a\x09var result = wrappedConstructor._newWithValues_([1, 2, 3 ]);\x0a\x09self._assert_(result instanceof TestConstructor);\x0a\x09self._assert_equals_(result.name, 'theTestPrototype');\x0a\x0a\x09\x22newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made.\x22\x0a\x09self._should_raise_(function () {wrappedConstructor._newWithValues_('single argument');}, globals.Error);\x0a>",
 messageSends: [],
 referencedClasses: []
 }),

+ 2 - 16
st/Kernel-Methods.st

@@ -121,23 +121,9 @@ newValue: anObject value: anObject2 value: anObject3
 !
 
 newWithValues: aCollection
-	"Use the receiver as a JavaScript constructor with a variable number of arguments.
-	Answer the object created using the operator `new`.
-
-	This algorithm was inspired by http://stackoverflow.com/a/6069331.
-
-	Here's a general breakdown of what's going on:
-	1) Create a new, empty constructor function.
-	2) Set it's prototype to the receiver's prototype. Because the receiver is a `BlockClosure`, it is also a JavaScript function.
-	3) Instantiate a new object using the constructor function just created. 
-		This forces the interpreter to set the internal [[prototype]] property to what was set on the function before. 
-   		This has to be done, as we have no access to the [[prototype]] property externally.
-	4) Apply `self` to the object I just instantiated."
-
+	"Simulates JS new operator by combination of Object.create and .apply"
 	<
-		var constructor = function() {};
-		constructor.prototype = self.prototype;
-		var object = new constructor;
+		var object = Object.create(self.prototype);
 		var result = self.apply(object, aCollection);
 		return typeof result === "object" ? result : object;
 	>

+ 7 - 8
st/Kernel-Tests.st

@@ -108,17 +108,16 @@ testExceptionSemantics
 
 testNewWithValues
 <
-	function theTestPrototype() {this.name = "theTestPrototype";}
-	function theTestConstructor(arg1, arg2, arg3) {}
-	theTestConstructor.prototype = new theTestPrototype;
+	function TestConstructor(arg1, arg2, arg3) {}
+	TestConstructor.prototype.name = 'theTestPrototype';
 
-	var theWrappedConstructor = _st(theTestConstructor);
-	var theResult = theWrappedConstructor._newWithValues_([1, 2, 3 ]);
-	self._assert_equals_(Object.getPrototypeOf(theResult).name, 'theTestPrototype');
+	var wrappedConstructor = _st(TestConstructor);
+	var result = wrappedConstructor._newWithValues_([1, 2, 3 ]);
+	self._assert_(result instanceof TestConstructor);
+	self._assert_equals_(result.name, 'theTestPrototype');
 
 	"newWithValues: cannot help if the argument list is wrong, and should warn that a mistake was made."
-	function constructionShouldFail() {var anotherResult = theWrappedConstructor._newWithValues_('This is so wrong');}
-	self._should_raise_(_st(constructionShouldFail), globals.Error);
+	self._should_raise_(function () {wrappedConstructor._newWithValues_('single argument');}, globals.Error);
 >
 !