Browse Source

Merge branch 'master' into nw-helios-app

Conflicts:
	package.json
Nicolas Petton 10 years ago
parent
commit
030c0d6942
12 changed files with 11522 additions and 380 deletions
  1. 3 1
      Gruntfile.js
  2. 171 29
      cli/src/AmberCli.js
  3. 66 31
      cli/src/AmberCli.st
  4. 11188 119
      cli/support/amber-cli.js
  5. 42 0
      src/Kernel-Infrastructure.js
  6. 10 0
      src/Kernel-Infrastructure.st
  7. 12 12
      src/Kernel-Methods.js
  8. 8 8
      src/Kernel-Methods.st
  9. 18 0
      src/Web.js
  10. 4 0
      src/Web.st
  11. 0 143
      test/Test.js
  12. 0 37
      test/Test.st

+ 3 - 1
Gruntfile.js

@@ -81,7 +81,9 @@ module.exports = function(grunt) {
         src: ['cli/src/AmberCli.st'],
         libraries: [
             'Compiler-Exceptions', 'Compiler-Core', 'Compiler-AST',
-            'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic', 'Compiler-Interpreter', 'parser'
+            'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic', 'Compiler-Interpreter', 'parser',
+            'SUnit', 'Kernel-ImportExport',
+            'Kernel-Tests', 'Compiler-Tests', 'SUnit-Tests'
         ],
         main_class: 'AmberCli',
         output_name: '../support/amber-cli',

+ 171 - 29
cli/src/AmberCli.js

@@ -31,7 +31,7 @@ $1=switches;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"commandLineSwitches",{switches:switches},globals.AmberCli.klass)})},
 args: [],
-source: "commandLineSwitches\x0a\x09\x22Collect all methodnames from the 'commands' protocol of the class\x0a\x09 and select the ones with only one parameter.\x0a\x09 Then remove the ':' at the end of the name.\x0a\x09 Additionally all uppercase letters are made lowercase and preceded by a '-'.\x0a\x09 Example: fallbackPage: becomes --fallback-page.\x0a\x09 Return the Array containing the commandline switches.\x22\x0a\x09| switches |\x0a\x09switches := ((self class methodsInProtocol: 'commands') collect: [ :each | each selector]).\x0a\x09switches := switches select: [ :each | each match: '^[^:]*:$'].\x0a\x09switches :=switches collect: [ :each |\x0a\x09\x09(each allButLast replace: '([A-Z])' with: '-$1') asLowercase].\x0a\x09^switches",
+source: "commandLineSwitches\x0a\x09\x22Collect all methodnames from the 'commands' protocol of the class\x0a\x09 and select the ones with only one parameter.\x0a\x09 Then remove the ':' at the end of the name.\x0a\x09 Additionally all uppercase letters are made lowercase and preceded by a '-'.\x0a\x09 Example: fallbackPage: becomes --fallback-page.\x0a\x09 Return the Array containing the commandline switches.\x22\x0a\x09| switches |\x0a\x09switches := ((self class methodsInProtocol: 'commands') collect: [ :each | each selector]).\x0a\x09switches := switches select: [ :each | each match: '^[^:]*:$'].\x0a\x09switches :=switches collect: [ :each |\x0a\x09\x09(each allButLast replace: '([A-Z])' with: '-$1') asLowercase].\x0a\x09^ switches",
 messageSends: ["collect:", "methodsInProtocol:", "class", "selector", "select:", "match:", "asLowercase", "replace:with:", "allButLast"],
 referencedClasses: []
 }),
@@ -146,7 +146,7 @@ $1=_st(_st($Repl())._new())._createInterface();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"repl:",{args:args},globals.AmberCli.klass)})},
 args: ["args"],
-source: "repl: args\x0a\x09^Repl new createInterface",
+source: "repl: args\x0a\x09^ Repl new createInterface",
 messageSends: ["createInterface", "new"],
 referencedClasses: ["Repl"]
 }),
@@ -176,7 +176,7 @@ $2=selector;
 return $2;
 }, function($ctx1) {$ctx1.fill(self,"selectorForCommandLineSwitch:",{aSwitch:aSwitch,command:command,selector:selector},globals.AmberCli.klass)})},
 args: ["aSwitch"],
-source: "selectorForCommandLineSwitch: aSwitch\x0a\x09\x22Add ':' at the end and replace all occurences of a lowercase letter preceded by a '-' with the Uppercase letter.\x0a\x09 Example: fallback-page becomes fallbackPage:.\x0a\x09 If no correct selector is found return 'help:'\x22\x0a\x09 | command selector |\x0a\x0a\x09 (self commandLineSwitches includes: aSwitch)\x0a\x09 ifTrue: [ selector := (aSwitch replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':']\x0a\x09 ifFalse: [ selector := 'help:' ].\x0a\x09^selector",
+source: "selectorForCommandLineSwitch: aSwitch\x0a\x09\x22Add ':' at the end and replace all occurences of a lowercase letter preceded by a '-' with the Uppercase letter.\x0a\x09 Example: fallback-page becomes fallbackPage:.\x0a\x09 If no correct selector is found return 'help:'\x22\x0a\x09 | command selector |\x0a\x0a\x09 (self commandLineSwitches includes: aSwitch)\x0a\x09 ifTrue: [ selector := (aSwitch replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':']\x0a\x09 ifFalse: [ selector := 'help:' ].\x0a\x09^ selector",
 messageSends: ["ifTrue:ifFalse:", "includes:", "commandLineSwitches", ",", "replace:with:", "asUppercase", "second"],
 referencedClasses: []
 }),
@@ -195,12 +195,31 @@ $1=_st(_st($FileServer())._createServerWithArguments_(args))._start();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"serve:",{args:args},globals.AmberCli.klass)})},
 args: ["args"],
-source: "serve: args\x0a\x09^(FileServer createServerWithArguments: args) start",
+source: "serve: args\x0a\x09^ (FileServer createServerWithArguments: args) start",
 messageSends: ["start", "createServerWithArguments:"],
 referencedClasses: ["FileServer"]
 }),
 globals.AmberCli.klass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tests:",
+protocol: 'commands',
+fn: function (arguments){
+var self=this;
+function $NodeTestRunner(){return globals.NodeTestRunner||(typeof NodeTestRunner=="undefined"?nil:NodeTestRunner)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($NodeTestRunner())._runTestSuite();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"tests:",{arguments:arguments},globals.AmberCli.klass)})},
+args: ["arguments"],
+source: "tests: arguments\x0a\x09^ NodeTestRunner runTestSuite",
+messageSends: ["runTestSuite"],
+referencedClasses: ["NodeTestRunner"]
+}),
+globals.AmberCli.klass);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "version:",
@@ -251,7 +270,7 @@ $1=$2;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"basePath",{},globals.FileServer)})},
 args: [],
-source: "basePath\x0a\x09^basePath ifNil: [self class defaultBasePath]",
+source: "basePath\x0a\x09^ basePath ifNil: [self class defaultBasePath]",
 messageSends: ["ifNil:", "defaultBasePath", "class"],
 referencedClasses: []
 }),
@@ -311,7 +330,7 @@ $1=self["@fallbackPage"];
 return $1;
 },
 args: [],
-source: "fallbackPage\x0a\x09^fallbackPage",
+source: "fallbackPage\x0a\x09^ fallbackPage",
 messageSends: [],
 referencedClasses: []
 }),
@@ -431,7 +450,7 @@ return _st(stream)._end();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"handlePUTRequest:respondTo:",{aRequest:aRequest,aResponse:aResponse,file:file,stream:stream},globals.FileServer)})},
 args: ["aRequest", "aResponse"],
-source: "handlePUTRequest: aRequest respondTo: aResponse\x0a\x09| file stream |\x0a\x09(self isAuthenticated: aRequest)\x0a\x09\x09ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^nil].\x0a\x0a\x09file := '.', aRequest url.\x0a\x09stream := fs createWriteStream: file.\x0a\x0a\x09stream on: 'error' do: [:error |\x0a\x09\x09console warn: 'Error creating WriteStream for file ', file.\x0a\x09\x09console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.\x0a\x09\x09console warn: '    The exact error is: ', error.\x0a\x09\x09self respondNotCreatedTo: aResponse].\x0a\x0a\x09stream on: 'close' do: [\x0a\x09\x09self respondCreatedTo: aResponse].\x0a\x0a\x09aRequest setEncoding: 'utf8'.\x0a\x09aRequest on: 'data' do: [:data |\x0a\x09\x09stream write: data].\x0a\x0a\x09aRequest on: 'end' do: [\x0a\x09\x09stream writable ifTrue: [stream end]]",
+source: "handlePUTRequest: aRequest respondTo: aResponse\x0a\x09| file stream |\x0a\x09(self isAuthenticated: aRequest)\x0a\x09\x09ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^ nil].\x0a\x0a\x09file := '.', aRequest url.\x0a\x09stream := fs createWriteStream: file.\x0a\x0a\x09stream on: 'error' do: [:error |\x0a\x09\x09console warn: 'Error creating WriteStream for file ', file.\x0a\x09\x09console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.\x0a\x09\x09console warn: '    The exact error is: ', error.\x0a\x09\x09self respondNotCreatedTo: aResponse].\x0a\x0a\x09stream on: 'close' do: [\x0a\x09\x09self respondCreatedTo: aResponse].\x0a\x0a\x09aRequest setEncoding: 'utf8'.\x0a\x09aRequest on: 'data' do: [:data |\x0a\x09\x09stream write: data].\x0a\x0a\x09aRequest on: 'end' do: [\x0a\x09\x09stream writable ifTrue: [stream end]]",
 messageSends: ["ifFalse:", "isAuthenticated:", "respondAuthenticationRequiredTo:", ",", "url", "createWriteStream:", "on:do:", "warn:", "respondNotCreatedTo:", "respondCreatedTo:", "setEncoding:", "write:", "ifTrue:", "writable", "end"],
 referencedClasses: []
 }),
@@ -482,7 +501,7 @@ $1=self["@host"];
 return $1;
 },
 args: [],
-source: "host\x0a\x09^host",
+source: "host\x0a\x09^ host",
 messageSends: [],
 referencedClasses: []
 }),
@@ -597,7 +616,7 @@ return false;
 };
 return self}, function($ctx1) {$ctx1.fill(self,"isAuthenticated:",{aRequest:aRequest,header:header,token:token,auth:auth,parts:parts},globals.FileServer)})},
 args: ["aRequest"],
-source: "isAuthenticated: aRequest\x0a\x09\x22Basic HTTP Auth: http://stackoverflow.com/a/5957629/293175\x0a\x09 and https://gist.github.com/1686663\x22\x0a\x09| header token auth parts|\x0a\x0a\x09(username isNil and: [password isNil]) ifTrue: [^true].\x0a\x0a\x09\x22get authentication header\x22\x0a\x09header := (aRequest headers at: 'authorization') ifNil:[''].\x0a\x09(header isEmpty)\x0a\x09ifTrue: [^false]\x0a\x09ifFalse: [\x0a\x09\x09\x22get authentication token\x22\x0a\x09\x09token := (header tokenize: ' ') ifNil:[''].\x0a\x09\x09\x22convert back from base64\x22\x0a\x09\x09auth := self base64Decode: (token at: 2).\x0a\x09\x09\x22split token at colon\x22\x0a\x09\x09parts := auth tokenize: ':'.\x0a\x0a\x09\x09((username = (parts at: 1)) and: [password = (parts at: 2)])\x0a\x09\x09\x09ifTrue: [^true]\x0a\x09\x09\x09ifFalse: [^false]\x0a\x09].",
+source: "isAuthenticated: aRequest\x0a\x09\x22Basic HTTP Auth: http://stackoverflow.com/a/5957629/293175\x0a\x09 and https://gist.github.com/1686663\x22\x0a\x09| header token auth parts|\x0a\x0a\x09(username isNil and: [password isNil]) ifTrue: [^ true].\x0a\x0a\x09\x22get authentication header\x22\x0a\x09header := (aRequest headers at: 'authorization') ifNil:[''].\x0a\x09(header isEmpty)\x0a\x09ifTrue: [^ false]\x0a\x09ifFalse: [\x0a\x09\x09\x22get authentication token\x22\x0a\x09\x09token := (header tokenize: ' ') ifNil:[''].\x0a\x09\x09\x22convert back from base64\x22\x0a\x09\x09auth := self base64Decode: (token at: 2).\x0a\x09\x09\x22split token at colon\x22\x0a\x09\x09parts := auth tokenize: ':'.\x0a\x0a\x09\x09((username = (parts at: 1)) and: [password = (parts at: 2)])\x0a\x09\x09\x09ifTrue: [^ true]\x0a\x09\x09\x09ifFalse: [^ false]\x0a\x09].",
 messageSends: ["ifTrue:", "and:", "isNil", "ifNil:", "at:", "headers", "ifTrue:ifFalse:", "isEmpty", "tokenize:", "base64Decode:", "="],
 referencedClasses: []
 }),
@@ -629,7 +648,7 @@ $1=self["@port"];
 return $1;
 },
 args: [],
-source: "port\x0a\x09^port",
+source: "port\x0a\x09^ port",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1022,7 +1041,7 @@ $1=_st(self["@path"])._join_with_(self._basePath(),aBaseRelativePath);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"withBasePath:",{aBaseRelativePath:aBaseRelativePath},globals.FileServer)})},
 args: ["aBaseRelativePath"],
-source: "withBasePath: aBaseRelativePath\x0a\x09\x22return a file path which is relative to the basePath.\x22\x0a\x09^\x09path join: self basePath with: aBaseRelativePath",
+source: "withBasePath: aBaseRelativePath\x0a\x09\x22return a file path which is relative to the basePath.\x22\x0a\x09^ path join: self basePath with: aBaseRelativePath",
 messageSends: ["join:with:", "basePath"],
 referencedClasses: []
 }),
@@ -1073,7 +1092,7 @@ $1=switches;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"commandLineSwitches",{switches:switches},globals.FileServer.klass)})},
 args: [],
-source: "commandLineSwitches\x0a\x09\x22Collect all methodnames from the 'accessing' protocol\x0a\x09 and select the ones with only one parameter.\x0a\x09 Then remove the ':' at the end of the name\x0a\x09 and add a '--' at the beginning.\x0a\x09 Additionally all uppercase letters are made lowercase and preceded by a '-'.\x0a\x09 Example: fallbackPage: becomes --fallback-page.\x0a\x09 Return the Array containing the commandline switches.\x22\x0a\x09| switches |\x0a\x09switches := ((self methodsInProtocol: 'accessing') collect: [ :each | each selector]).\x0a\x09switches := switches select: [ :each | each match: '^[^:]*:$'].\x0a\x09switches :=switches collect: [ :each |\x0a\x09\x09(each allButLast replace: '([A-Z])' with: '-$1') asLowercase replace: '^([a-z])' with: '--$1' ].\x0a\x09^switches",
+source: "commandLineSwitches\x0a\x09\x22Collect all methodnames from the 'accessing' protocol\x0a\x09 and select the ones with only one parameter.\x0a\x09 Then remove the ':' at the end of the name\x0a\x09 and add a '--' at the beginning.\x0a\x09 Additionally all uppercase letters are made lowercase and preceded by a '-'.\x0a\x09 Example: fallbackPage: becomes --fallback-page.\x0a\x09 Return the Array containing the commandline switches.\x22\x0a\x09| switches |\x0a\x09switches := ((self methodsInProtocol: 'accessing') collect: [ :each | each selector]).\x0a\x09switches := switches select: [ :each | each match: '^[^:]*:$'].\x0a\x09switches :=switches collect: [ :each |\x0a\x09\x09(each allButLast replace: '([A-Z])' with: '-$1') asLowercase replace: '^([a-z])' with: '--$1' ].\x0a\x09^ switches",
 messageSends: ["collect:", "methodsInProtocol:", "selector", "select:", "match:", "replace:with:", "asLowercase", "allButLast"],
 referencedClasses: []
 }),
@@ -1151,7 +1170,7 @@ return $11;
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"createServerWithArguments:",{options:options,server:server,popFront:popFront,front:front,optionName:optionName,optionValue:optionValue,switches:switches},globals.FileServer.klass)})},
 args: ["options"],
-source: "createServerWithArguments: options\x0a\x09\x22If options are empty return a default FileServer instance.\x0a\x09 If options are given loop through them and set the passed in values\x0a\x09 on the FileServer instance.\x0a\x09 \x0a\x09 Commanline options map directly to methods in the 'accessing' protocol\x0a\x09 taking one parameter.\x0a\x09 Adding a method to this protocol makes it directly settable through\x0a\x09 command line options.\x0a\x09 \x22\x0a\x09| server popFront front optionName optionValue switches |\x0a\x0a\x09switches := self commandLineSwitches.\x0a\x0a\x09server := self new.\x0a\x0a\x09options ifEmpty: [^server].\x0a\x0a\x09(options size even) ifFalse: [\x0a\x09\x09console log: 'Using default parameters.'.\x0a\x09\x09console log: 'Wrong commandline options or not enough arguments for: ' , options.\x0a\x09\x09console log: 'Use any of the following ones: ', switches.\x0a\x09\x09^server].\x0a\x0a\x09popFront := [:args |\x0a\x09\x09front := args first.\x0a\x09\x09args remove: front.\x0a\x09\x09front].\x0a\x0a\x09[options notEmpty] whileTrue: [\x0a\x09\x09optionName  := popFront value: options.\x0a\x09\x09optionValue := popFront value: options.\x0a\x0a\x09\x09(switches includes: optionName) ifTrue: [\x0a\x09\x09\x09optionName := self selectorForCommandLineSwitch: optionName.\x0a\x09\x09\x09server perform: optionName withArguments: (Array with: optionValue)]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09console log: optionName, ' is not a valid commandline option'.\x0a\x09\x09\x09\x09console log: 'Use any of the following ones: ', switches ]].\x0a\x09^server.",
+source: "createServerWithArguments: options\x0a\x09\x22If options are empty return a default FileServer instance.\x0a\x09 If options are given loop through them and set the passed in values\x0a\x09 on the FileServer instance.\x0a\x09 \x0a\x09 Commanline options map directly to methods in the 'accessing' protocol\x0a\x09 taking one parameter.\x0a\x09 Adding a method to this protocol makes it directly settable through\x0a\x09 command line options.\x0a\x09 \x22\x0a\x09| server popFront front optionName optionValue switches |\x0a\x0a\x09switches := self commandLineSwitches.\x0a\x0a\x09server := self new.\x0a\x0a\x09options ifEmpty: [^server].\x0a\x0a\x09(options size even) ifFalse: [\x0a\x09\x09console log: 'Using default parameters.'.\x0a\x09\x09console log: 'Wrong commandline options or not enough arguments for: ' , options.\x0a\x09\x09console log: 'Use any of the following ones: ', switches.\x0a\x09\x09^server].\x0a\x0a\x09popFront := [:args |\x0a\x09\x09front := args first.\x0a\x09\x09args remove: front.\x0a\x09\x09front].\x0a\x0a\x09[options notEmpty] whileTrue: [\x0a\x09\x09optionName  := popFront value: options.\x0a\x09\x09optionValue := popFront value: options.\x0a\x0a\x09\x09(switches includes: optionName) ifTrue: [\x0a\x09\x09\x09optionName := self selectorForCommandLineSwitch: optionName.\x0a\x09\x09\x09server perform: optionName withArguments: (Array with: optionValue)]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09console log: optionName, ' is not a valid commandline option'.\x0a\x09\x09\x09\x09console log: 'Use any of the following ones: ', switches ]].\x0a\x09^ server.",
 messageSends: ["commandLineSwitches", "new", "ifEmpty:", "ifFalse:", "even", "size", "log:", ",", "first", "remove:", "whileTrue:", "notEmpty", "value:", "ifTrue:ifFalse:", "includes:", "selectorForCommandLineSwitch:", "perform:withArguments:", "with:"],
 referencedClasses: ["Array"]
 }),
@@ -1181,7 +1200,7 @@ var self=this;
 return "127.0.0.1";
 },
 args: [],
-source: "defaultHost\x0a\x09^'127.0.0.1'",
+source: "defaultHost\x0a\x09^ '127.0.0.1'",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1213,7 +1232,7 @@ var self=this;
 return (4000);
 },
 args: [],
-source: "defaultPort\x0a\x09^4000",
+source: "defaultPort\x0a\x09^ 4000",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1250,7 +1269,7 @@ return self}
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"main",{fileServer:fileServer,args:args},globals.FileServer.klass)})},
 args: [],
-source: "main\x0a\x09\x22Main entry point for Amber applications.\x0a\x09 Creates and starts a FileServer instance.\x22\x0a\x09| fileServer args |\x0a\x09args := process argv.\x0a\x09\x22Remove the first args which contain the path to the node executable and the script file.\x22\x0a\x09args removeFrom: 1 to: 3.\x0a\x0a\x09args detect: [ :each |\x0a\x09\x09(each = '--help') ifTrue: [FileServer printHelp]]\x0a\x09ifNone: [\x0a\x09\x09fileServer := FileServer createServerWithArguments: args.\x0a\x09\x09^fileServer start]",
+source: "main\x0a\x09\x22Main entry point for Amber applications.\x0a\x09 Creates and starts a FileServer instance.\x22\x0a\x09| fileServer args |\x0a\x09args := process argv.\x0a\x09\x22Remove the first args which contain the path to the node executable and the script file.\x22\x0a\x09args removeFrom: 1 to: 3.\x0a\x0a\x09args detect: [ :each |\x0a\x09\x09(each = '--help') ifTrue: [FileServer printHelp]]\x0a\x09ifNone: [\x0a\x09\x09fileServer := FileServer createServerWithArguments: args.\x0a\x09\x09^ fileServer start]",
 messageSends: ["argv", "removeFrom:to:", "detect:ifNone:", "ifTrue:", "=", "printHelp", "createServerWithArguments:", "start"],
 referencedClasses: ["FileServer"]
 }),
@@ -1270,7 +1289,7 @@ return "text/plain";
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"mimeTypeFor:",{aString:aString},globals.FileServer.klass)})},
 args: ["aString"],
-source: "mimeTypeFor: aString\x0a\x09^self mimeTypes at: (aString replace: '.*[\x5c.]' with: '') ifAbsent: ['text/plain']",
+source: "mimeTypeFor: aString\x0a\x09^ self mimeTypes at: (aString replace: '.*[\x5c.]' with: '') ifAbsent: ['text/plain']",
 messageSends: ["at:ifAbsent:", "mimeTypes", "replace:with:"],
 referencedClasses: []
 }),
@@ -1294,7 +1313,7 @@ $1=$2;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"mimeTypes",{},globals.FileServer.klass)})},
 args: [],
-source: "mimeTypes\x0a\x09^mimeTypes ifNil: [mimeTypes := self defaultMimeTypes]",
+source: "mimeTypes\x0a\x09^ mimeTypes ifNil: [mimeTypes := self defaultMimeTypes]",
 messageSends: ["ifNil:", "defaultMimeTypes"],
 referencedClasses: []
 }),
@@ -1340,13 +1359,136 @@ $1=_st($2).__comma(":");
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"selectorForCommandLineSwitch:",{aSwitch:aSwitch},globals.FileServer.klass)})},
 args: ["aSwitch"],
-source: "selectorForCommandLineSwitch: aSwitch\x0a\x09\x22Remove the trailing '--', add ':' at the end\x0a\x09 and replace all occurences of a lowercase letter preceded by a '-' with\x0a\x09 the Uppercase letter.\x0a\x09 Example: --fallback-page becomes fallbackPage:\x22\x0a\x09^((aSwitch replace: '^--' with: '')\x0a\x09\x09replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':'",
+source: "selectorForCommandLineSwitch: aSwitch\x0a\x09\x22Remove the trailing '--', add ':' at the end\x0a\x09 and replace all occurences of a lowercase letter preceded by a '-' with\x0a\x09 the Uppercase letter.\x0a\x09 Example: --fallback-page becomes fallbackPage:\x22\x0a\x09^ ((aSwitch replace: '^--' with: '')\x0a\x09\x09replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':'",
 messageSends: [",", "replace:with:", "asUppercase", "second"],
 referencedClasses: []
 }),
 globals.FileServer.klass);
 
 
+smalltalk.addClass('NodeTestRunner', globals.Object, [], 'AmberCli');
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "runTestSuite",
+protocol: 'not yet classified',
+fn: function (){
+var self=this;
+var suite,worker;
+function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
+function $TestCase(){return globals.TestCase||(typeof TestCase=="undefined"?nil:TestCase)}
+function $TestSuiteRunner(){return globals.TestSuiteRunner||(typeof TestSuiteRunner=="undefined"?nil:TestSuiteRunner)}
+function $ResultAnnouncement(){return globals.ResultAnnouncement||(typeof ResultAnnouncement=="undefined"?nil:ResultAnnouncement)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3,$9,$8,$12,$11,$10,$7,$6,$15,$14,$13,$5,$4,$17,$16,$19,$18,$26,$25,$24,$23,$22,$28,$27,$21,$20,$30,$29,$32,$31,$39,$38,$37,$36,$35,$34,$33;
+suite=_st($OrderedCollection())._new();
+_st(_st(_st($TestCase())._allSubclasses())._select_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(each)._isAbstract())._not();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})})))._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(suite)._addAll_(_st(each)._buildSuite());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
+worker=_st($TestSuiteRunner())._on_(suite);
+_st(_st(worker)._announcer())._on_do_($ResultAnnouncement(),(function(ann){
+var result;
+return smalltalk.withContext(function($ctx2) {
+result=_st(ann)._result();
+result;
+$2=_st(result)._runs();
+$ctx2.sendIdx["runs"]=1;
+$1=_st($2).__eq(_st(result)._total());
+if(smalltalk.assert($1)){
+$3=console;
+$9=_st(_st(result)._runs())._asString();
+$ctx2.sendIdx["asString"]=1;
+$8=_st($9).__comma(" tests run, ");
+$ctx2.sendIdx[","]=5;
+$12=_st(result)._failures();
+$ctx2.sendIdx["failures"]=1;
+$11=_st($12)._size();
+$ctx2.sendIdx["size"]=1;
+$10=_st($11)._asString();
+$ctx2.sendIdx["asString"]=2;
+$7=_st($8).__comma($10);
+$ctx2.sendIdx[","]=4;
+$6=_st($7).__comma(" failures, ");
+$ctx2.sendIdx[","]=3;
+$15=_st(result)._errors();
+$ctx2.sendIdx["errors"]=1;
+$14=_st($15)._size();
+$13=_st($14)._asString();
+$5=_st($6).__comma($13);
+$ctx2.sendIdx[","]=2;
+$4=_st($5).__comma(" errors.");
+$ctx2.sendIdx[","]=1;
+_st($3)._log_($4);
+$17=_st(result)._failures();
+$ctx2.sendIdx["failures"]=2;
+$16=_st($17)._isEmpty();
+$ctx2.sendIdx["isEmpty"]=1;
+if(! smalltalk.assert($16)){
+$19=_st(result)._failures();
+$ctx2.sendIdx["failures"]=3;
+$18=_st($19)._first();
+$ctx2.sendIdx["first"]=1;
+_st($18)._runCase();
+$ctx2.sendIdx["runCase"]=1;
+$26=_st(result)._failures();
+$ctx2.sendIdx["failures"]=4;
+$25=_st($26)._first();
+$ctx2.sendIdx["first"]=2;
+$24=_st($25)._class();
+$ctx2.sendIdx["class"]=1;
+$23=_st($24)._name();
+$ctx2.sendIdx["name"]=1;
+$22=_st($23).__comma(" >> ");
+$ctx2.sendIdx[","]=8;
+$28=_st(_st(result)._failures())._first();
+$ctx2.sendIdx["first"]=3;
+$27=_st($28)._selector();
+$ctx2.sendIdx["selector"]=1;
+$21=_st($22).__comma($27);
+$ctx2.sendIdx[","]=7;
+$20=_st($21).__comma(" is failing!!");
+$ctx2.sendIdx[","]=6;
+self._throw_($20);
+$ctx2.sendIdx["throw:"]=1;
+};
+$30=_st(result)._errors();
+$ctx2.sendIdx["errors"]=2;
+$29=_st($30)._isEmpty();
+if(! smalltalk.assert($29)){
+$32=_st(result)._errors();
+$ctx2.sendIdx["errors"]=3;
+$31=_st($32)._first();
+$ctx2.sendIdx["first"]=4;
+_st($31)._runCase();
+$39=_st(result)._errors();
+$ctx2.sendIdx["errors"]=4;
+$38=_st($39)._first();
+$ctx2.sendIdx["first"]=5;
+$37=_st($38)._class();
+$36=_st($37)._name();
+$35=_st($36).__comma(" >> ");
+$34=_st($35).__comma(_st(_st(_st(result)._errors())._first())._selector());
+$ctx2.sendIdx[","]=10;
+$33=_st($34).__comma(" has errors!!");
+$ctx2.sendIdx[","]=9;
+return self._throw_($33);
+};
+};
+}, function($ctx2) {$ctx2.fillBlock({ann:ann,result:result},$ctx1,3)})}));
+_st(worker)._run();
+return self}, function($ctx1) {$ctx1.fill(self,"runTestSuite",{suite:suite,worker:worker},globals.NodeTestRunner.klass)})},
+args: [],
+source: "runTestSuite\x0a\x09| suite worker |\x0a\x0a\x09suite := OrderedCollection new.\x0a\x09(TestCase allSubclasses select: [ :each | each isAbstract not ])\x0a\x09\x09do: [ :each | suite addAll: each buildSuite ].\x0a\x0a\x09worker := TestSuiteRunner on: suite.\x0a\x09worker announcer on: ResultAnnouncement do:\x0a\x09\x09[ :ann | | result |\x0a\x09\x09\x09result := ann result.\x0a\x09\x09\x09result runs = result total ifTrue: [\x0a\x09\x09\x09\x09console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.\x0a\x0a\x09\x09\x09\x09result failures isEmpty ifFalse: [\x0a\x09\x09\x09\x09\x09result failures first runCase.\x0a\x09\x09\x09\x09\x09\x22the line above should throw, normally, but just in case I leave the line below\x22\x0a\x09\x09\x09\x09\x09self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!' ].\x0a\x09\x09\x09\x09result errors isEmpty ifFalse: [\x0a\x09\x09\x09\x09\x09result errors first runCase.\x0a\x09\x09\x09\x09\x09\x22the line above should throw, normally, but just in case I leave the line below\x22\x0a\x09\x09\x09\x09\x09self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!' ].\x0a\x09]].\x0a\x09worker run",
+messageSends: ["new", "do:", "select:", "allSubclasses", "not", "isAbstract", "addAll:", "buildSuite", "on:", "on:do:", "announcer", "result", "ifTrue:", "=", "runs", "total", "log:", ",", "asString", "size", "failures", "errors", "ifFalse:", "isEmpty", "runCase", "first", "throw:", "name", "class", "selector", "run"],
+referencedClasses: ["OrderedCollection", "TestCase", "TestSuiteRunner", "ResultAnnouncement"]
+}),
+globals.NodeTestRunner.klass);
+
+
 smalltalk.addClass('Repl', globals.Object, ['readline', 'interface', 'util', 'session', 'resultCount', 'commands'], 'AmberCli');
 globals.Repl.comment="I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.\x0aOn the prompt you can type Amber statements which will be evaluated after pressing <Enter>.\x0aThe evaluation is comparable with executing a 'DoIt' in a workspace.\x0a\x0aMy runtime requirement is a functional Node.js executable with working Readline support.";
 smalltalk.addMethod(
@@ -1528,16 +1670,16 @@ $3=_st($4).__comma(aString);
 $ctx1.sendIdx[","]=2;
 $2=_st($3).__comma(" := anObject");
 $ctx1.sendIdx[","]=1;
-_st($1)._install_forClass_category_($2,aClass,"session");
-$ctx1.sendIdx["install:forClass:category:"]=1;
+_st($1)._install_forClass_protocol_($2,aClass,"session");
+$ctx1.sendIdx["install:forClass:protocol:"]=1;
 $5=compiler;
 $6=_st(_st(aString).__comma(" ^ ")).__comma(aString);
 $ctx1.sendIdx[","]=4;
-_st($5)._install_forClass_category_($6,aClass,"session");
+_st($5)._install_forClass_protocol_($6,aClass,"session");
 return self}, function($ctx1) {$ctx1.fill(self,"encapsulateVariable:withValue:in:",{aString:aString,anObject:anObject,aClass:aClass,compiler:compiler},globals.Repl)})},
 args: ["aString", "anObject", "aClass"],
-source: "encapsulateVariable: aString withValue: anObject in: aClass\x0a\x09\x22Add getter and setter for given variable to session.\x22\x0a\x09| compiler |\x0a\x09compiler := Compiler new.\x0a\x09compiler install: aString, ': anObject ^ ', aString, ' := anObject' forClass: aClass category: 'session'.\x0a\x09compiler install: aString, ' ^ ', aString forClass: aClass category: 'session'.",
-messageSends: ["new", "install:forClass:category:", ","],
+source: "encapsulateVariable: aString withValue: anObject in: aClass\x0a\x09\x22Add getter and setter for given variable to session.\x22\x0a\x09| compiler |\x0a\x09compiler := Compiler new.\x0a\x09compiler install: aString, ': anObject ^ ', aString, ' := anObject' forClass: aClass protocol: 'session'.\x0a\x09compiler install: aString, ' ^ ', aString forClass: aClass protocol: 'session'.",
+messageSends: ["new", "install:forClass:protocol:", ","],
 referencedClasses: ["Compiler"]
 }),
 globals.Repl);
@@ -1573,11 +1715,11 @@ return smalltalk.withContext(function($ctx1) {
 var $1,$2,$3;
 $1=_st(buffer)._isEmpty();
 if(! smalltalk.assert($1)){
-self._try_catch_((function(){
+_st((function(){
 return smalltalk.withContext(function($ctx2) {
 result=_st(_st($Compiler())._new())._evaluateExpression_on_(buffer,anObject);
 return result;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}),(function(e){
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}))._tryCatch_((function(e){
 return smalltalk.withContext(function($ctx2) {
 $2=_st(e)._isSmalltalkError();
 if(smalltalk.assert($2)){
@@ -1591,8 +1733,8 @@ $3=result;
 return $3;
 }, function($ctx1) {$ctx1.fill(self,"eval:on:",{buffer:buffer,anObject:anObject,result:result},globals.Repl)})},
 args: ["buffer", "anObject"],
-source: "eval: buffer on: anObject\x0a\x09| result |\x0a\x09buffer isEmpty ifFalse: [\x0a\x09\x09self try: [\x0a\x09\x09\x09result := Compiler new evaluateExpression: buffer on: anObject]\x0a\x09\x09catch: [:e |\x0a\x09\x09\x09e isSmalltalkError\x0a\x09\x09\x09    ifTrue: [ e resignal ]\x0a\x09\x09\x09    ifFalse: [ process stdout write: e jsStack ]]].\x0a\x09^ result",
-messageSends: ["ifFalse:", "isEmpty", "try:catch:", "evaluateExpression:on:", "new", "ifTrue:ifFalse:", "isSmalltalkError", "resignal", "write:", "stdout", "jsStack"],
+source: "eval: buffer on: anObject\x0a\x09| result |\x0a\x09buffer isEmpty ifFalse: [\x0a\x09\x09[result := Compiler new evaluateExpression: buffer on: anObject]\x0a\x09\x09\x09tryCatch: [:e |\x0a\x09\x09\x09\x09e isSmalltalkError\x0a\x09\x09\x09\x09    ifTrue: [ e resignal ]\x0a\x09\x09\x09 \x09   ifFalse: [ process stdout write: e jsStack ]]].\x0a\x09^ result",
+messageSends: ["ifFalse:", "isEmpty", "tryCatch:", "evaluateExpression:on:", "new", "ifTrue:ifFalse:", "isSmalltalkError", "resignal", "write:", "stdout", "jsStack"],
 referencedClasses: ["Compiler"]
 }),
 globals.Repl);
@@ -1875,7 +2017,7 @@ var self=this;
 return "amber >> ";
 },
 args: [],
-source: "prompt\x0a\x09^'amber >> '",
+source: "prompt\x0a\x09^ 'amber >> '",
 messageSends: [],
 referencedClasses: []
 }),

+ 66 - 31
cli/src/AmberCli.st

@@ -30,7 +30,7 @@ commandLineSwitches
 	switches := switches select: [ :each | each match: '^[^:]*:$'].
 	switches :=switches collect: [ :each |
 		(each allButLast replace: '([A-Z])' with: '-$1') asLowercase].
-	^switches
+	^ switches
 !
 
 handleArguments: args
@@ -50,7 +50,7 @@ selectorForCommandLineSwitch: aSwitch
 	 (self commandLineSwitches includes: aSwitch)
 	 ifTrue: [ selector := (aSwitch replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':']
 	 ifFalse: [ selector := 'help:' ].
-	^selector
+	^ selector
 ! !
 
 !AmberCli class methodsFor: 'commands'!
@@ -61,11 +61,15 @@ help: args
 !
 
 repl: args
-	^Repl new createInterface
+	^ Repl new createInterface
 !
 
 serve: args
-	^(FileServer createServerWithArguments: args) start
+	^ (FileServer createServerWithArguments: args) start
+!
+
+tests: arguments
+	^ NodeTestRunner runTestSuite
 !
 
 version: arguments
@@ -131,7 +135,7 @@ Adding new commandline parameters to `FileServer` is as easy as adding a new sin
 !FileServer methodsFor: 'accessing'!
 
 basePath
-	^basePath ifNil: [self class defaultBasePath]
+	^ basePath ifNil: [self class defaultBasePath]
 !
 
 basePath: aString
@@ -140,7 +144,7 @@ basePath: aString
 !
 
 fallbackPage
-	^fallbackPage
+	^ fallbackPage
 !
 
 fallbackPage: aString
@@ -148,7 +152,7 @@ fallbackPage: aString
 !
 
 host
-	^host
+	^ host
 !
 
 host: hostname
@@ -160,7 +164,7 @@ password: aPassword
 !
 
 port
-	^port
+	^ port
 !
 
 port: aNumber
@@ -206,12 +210,12 @@ isAuthenticated: aRequest
 	 and https://gist.github.com/1686663"
 	| header token auth parts|
 
-	(username isNil and: [password isNil]) ifTrue: [^true].
+	(username isNil and: [password isNil]) ifTrue: [^ true].
 
 	"get authentication header"
 	header := (aRequest headers at: 'authorization') ifNil:[''].
 	(header isEmpty)
-	ifTrue: [^false]
+	ifTrue: [^ false]
 	ifFalse: [
 		"get authentication token"
 		token := (header tokenize: ' ') ifNil:[''].
@@ -221,8 +225,8 @@ isAuthenticated: aRequest
 		parts := auth tokenize: ':'.
 
 		((username = (parts at: 1)) and: [password = (parts at: 2)])
-			ifTrue: [^true]
-			ifFalse: [^false]
+			ifTrue: [^ true]
+			ifFalse: [^ false]
 	].
 !
 
@@ -240,7 +244,7 @@ validateBasePath
 
 withBasePath: aBaseRelativePath
 	"return a file path which is relative to the basePath."
-	^	path join: self basePath with: aBaseRelativePath
+	^ path join: self basePath with: aBaseRelativePath
 !
 
 writeData: data toFileNamed: aFilename
@@ -273,7 +277,7 @@ handleOPTIONSRequest: aRequest respondTo: aResponse
 handlePUTRequest: aRequest respondTo: aResponse
 	| file stream |
 	(self isAuthenticated: aRequest)
-		ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^nil].
+		ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^ nil].
 
 	file := '.', aRequest url.
 	stream := fs createWriteStream: file.
@@ -417,7 +421,7 @@ commandLineSwitches
 	switches := switches select: [ :each | each match: '^[^:]*:$'].
 	switches :=switches collect: [ :each |
 		(each allButLast replace: '([A-Z])' with: '-$1') asLowercase replace: '^([a-z])' with: '--$1' ].
-	^switches
+	^ switches
 !
 
 defaultBasePath
@@ -425,7 +429,7 @@ defaultBasePath
 !
 
 defaultHost
-	^'127.0.0.1'
+	^ '127.0.0.1'
 !
 
 defaultMimeTypes
@@ -843,15 +847,15 @@ defaultMimeTypes
 !
 
 defaultPort
-	^4000
+	^ 4000
 !
 
 mimeTypeFor: aString
-	^self mimeTypes at: (aString replace: '.*[\.]' with: '') ifAbsent: ['text/plain']
+	^ self mimeTypes at: (aString replace: '.*[\.]' with: '') ifAbsent: ['text/plain']
 !
 
 mimeTypes
-	^mimeTypes ifNil: [mimeTypes := self defaultMimeTypes]
+	^ mimeTypes ifNil: [mimeTypes := self defaultMimeTypes]
 !
 
 printHelp
@@ -866,7 +870,7 @@ selectorForCommandLineSwitch: aSwitch
 	 and replace all occurences of a lowercase letter preceded by a '-' with
 	 the Uppercase letter.
 	 Example: --fallback-page becomes fallbackPage:"
-	^((aSwitch replace: '^--' with: '')
+	^ ((aSwitch replace: '^--' with: '')
 		replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':'
 ! !
 
@@ -911,7 +915,7 @@ createServerWithArguments: options
 			ifFalse: [
 				console log: optionName, ' is not a valid commandline option'.
 				console log: 'Use any of the following ones: ', switches ]].
-	^server.
+	^ server.
 !
 
 main
@@ -926,7 +930,39 @@ main
 		(each = '--help') ifTrue: [FileServer printHelp]]
 	ifNone: [
 		fileServer := FileServer createServerWithArguments: args.
-		^fileServer start]
+		^ fileServer start]
+! !
+
+Object subclass: #NodeTestRunner
+	instanceVariableNames: ''
+	package: 'AmberCli'!
+
+!NodeTestRunner class methodsFor: 'not yet classified'!
+
+runTestSuite
+	| suite worker |
+
+	suite := OrderedCollection new.
+	(TestCase allSubclasses select: [ :each | each isAbstract not ])
+		do: [ :each | suite addAll: each buildSuite ].
+
+	worker := TestSuiteRunner on: suite.
+	worker announcer on: ResultAnnouncement do:
+		[ :ann | | result |
+			result := ann result.
+			result runs = result total ifTrue: [
+				console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.
+
+				result failures isEmpty ifFalse: [
+					result failures first runCase.
+					"the line above should throw, normally, but just in case I leave the line below"
+					self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!!!' ].
+				result errors isEmpty ifFalse: [
+					result errors first runCase.
+					"the line above should throw, normally, but just in case I leave the line below"
+					self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!!!' ].
+	]].
+	worker run
 ! !
 
 Object subclass: #Repl
@@ -946,7 +982,7 @@ commands
 !
 
 prompt
-	^'amber >> '
+	^ 'amber >> '
 ! !
 
 !Repl methodsFor: 'actions'!
@@ -978,12 +1014,11 @@ eval: buffer
 eval: buffer on: anObject
 	| result |
 	buffer isEmpty ifFalse: [
-		self try: [
-			result := Compiler new evaluateExpression: buffer on: anObject]
-		catch: [:e |
-			e isSmalltalkError
-			    ifTrue: [ e resignal ]
-			    ifFalse: [ process stdout write: e jsStack ]]].
+		[result := Compiler new evaluateExpression: buffer on: anObject]
+			tryCatch: [:e |
+				e isSmalltalkError
+				    ifTrue: [ e resignal ]
+			 	   ifFalse: [ process stdout write: e jsStack ]]].
 	^ result
 !
 
@@ -1043,8 +1078,8 @@ encapsulateVariable: aString withValue: anObject in: aClass
 	"Add getter and setter for given variable to session."
 	| compiler |
 	compiler := Compiler new.
-	compiler install: aString, ': anObject ^ ', aString, ' := anObject' forClass: aClass category: 'session'.
-	compiler install: aString, ' ^ ', aString forClass: aClass category: 'session'.
+	compiler install: aString, ': anObject ^ ', aString, ' := anObject' forClass: aClass protocol: 'session'.
+	compiler install: aString, ' ^ ', aString forClass: aClass protocol: 'session'.
 !
 
 executeCommand: aString

File diff suppressed because it is too large
+ 11188 - 119
cli/support/amber-cli.js


+ 42 - 0
src/Kernel-Infrastructure.js

@@ -209,6 +209,25 @@ referencedClasses: ["PlatformInterface"]
 }),
 globals.InterfacingObject);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "prompt:default:",
+protocol: 'actions',
+fn: function (aString,defaultString){
+var self=this;
+function $PlatformInterface(){return globals.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($PlatformInterface())._prompt_default_(aString,defaultString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"prompt:default:",{aString:aString,defaultString:defaultString},globals.InterfacingObject)})},
+args: ["aString", "defaultString"],
+source: "prompt: aString default: defaultString\x0a\x09^ PlatformInterface prompt: aString default: defaultString",
+messageSends: ["prompt:default:"],
+referencedClasses: ["PlatformInterface"]
+}),
+globals.InterfacingObject);
+
 
 
 smalltalk.addClass('Environment', globals.InterfacingObject, [], 'Kernel-Infrastructure');
@@ -2328,6 +2347,29 @@ referencedClasses: []
 }),
 globals.PlatformInterface.klass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "prompt:default:",
+protocol: 'actions',
+fn: function (aString,defaultString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$receiver;
+$2=self["@worker"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=self._error_("prompt: not available");
+} else {
+$1=_st(self["@worker"])._prompt_default_(aString,defaultString);
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"prompt:default:",{aString:aString,defaultString:defaultString},globals.PlatformInterface.klass)})},
+args: ["aString", "defaultString"],
+source: "prompt: aString default: defaultString\x0a\x09^ worker\x0a\x09\x09ifNotNil: [ worker prompt: aString default: defaultString ]\x0a\x09\x09ifNil: [ self error: 'prompt: not available' ]",
+messageSends: ["ifNotNil:ifNil:", "prompt:default:", "error:"],
+referencedClasses: []
+}),
+globals.PlatformInterface.klass);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "setWorker:",

+ 10 - 0
src/Kernel-Infrastructure.st

@@ -74,6 +74,10 @@ confirm: aString
 
 prompt: aString
 	^ PlatformInterface prompt: aString
+!
+
+prompt: aString default: defaultString
+	^ PlatformInterface prompt: aString default: defaultString
 ! !
 
 InterfacingObject subclass: #Environment
@@ -858,6 +862,12 @@ prompt: aString
 	^ worker
 		ifNotNil: [ worker prompt: aString ]
 		ifNil: [ self error: 'prompt: not available' ]
+!
+
+prompt: aString default: defaultString
+	^ worker
+		ifNotNil: [ worker prompt: aString default: defaultString ]
+		ifNil: [ self error: 'prompt: not available' ]
 ! !
 
 !PlatformInterface class methodsFor: 'initialization'!

+ 12 - 12
src/Kernel-Methods.js

@@ -1899,12 +1899,12 @@ fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-		var native=eval(aString);
-		return new native();
+		var nativeFunc=eval(aString);
+		return new nativeFunc();
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"constructor:",{aString:aString},globals.NativeFunction.klass)})},
 args: ["aString"],
-source: "constructor: aString\x0a\x09<\x0a\x09\x09var native=eval(aString);\x0a\x09\x09return new native();\x0a\x09>",
+source: "constructor: aString\x0a\x09<\x0a\x09\x09var nativeFunc=eval(aString);\x0a\x09\x09return new nativeFunc();\x0a\x09>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1918,12 +1918,12 @@ fn: function (aString,anObject){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-		var native=eval(aString);
-		return new native(anObject);
+		var nativeFunc=eval(aString);
+		return new nativeFunc(anObject);
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:",{aString:aString,anObject:anObject},globals.NativeFunction.klass)})},
 args: ["aString", "anObject"],
-source: "constructor: aString value:anObject\x0a\x09<\x0a\x09\x09var native=eval(aString);\x0a\x09\x09return new native(anObject);\x0a\x09>",
+source: "constructor: aString value:anObject\x0a\x09<\x0a\x09\x09var nativeFunc=eval(aString);\x0a\x09\x09return new nativeFunc(anObject);\x0a\x09>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1937,12 +1937,12 @@ fn: function (aString,anObject,anObject2){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-		var native=eval(aString);
-		return new native(anObject,anObject2);
+		var nativeFunc=eval(aString);
+		return new nativeFunc(anObject,anObject2);
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:value:",{aString:aString,anObject:anObject,anObject2:anObject2},globals.NativeFunction.klass)})},
 args: ["aString", "anObject", "anObject2"],
-source: "constructor: aString value:anObject value: anObject2\x0a\x09<\x0a\x09\x09var native=eval(aString);\x0a\x09\x09return new native(anObject,anObject2);\x0a\x09>",
+source: "constructor: aString value:anObject value: anObject2\x0a\x09<\x0a\x09\x09var nativeFunc=eval(aString);\x0a\x09\x09return new nativeFunc(anObject,anObject2);\x0a\x09>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1956,12 +1956,12 @@ fn: function (aString,anObject,anObject2,anObject3){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-		var native=eval(aString);
-		return new native(anObject,anObject2, anObject3);
+		var nativeFunc=eval(aString);
+		return new nativeFunc(anObject,anObject2, anObject3);
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:value:value:",{aString:aString,anObject:anObject,anObject2:anObject2,anObject3:anObject3},globals.NativeFunction.klass)})},
 args: ["aString", "anObject", "anObject2", "anObject3"],
-source: "constructor: aString value:anObject value: anObject2 value:anObject3\x0a\x09<\x0a\x09\x09var native=eval(aString);\x0a\x09\x09return new native(anObject,anObject2, anObject3);\x0a\x09>",
+source: "constructor: aString value:anObject value: anObject2 value:anObject3\x0a\x09<\x0a\x09\x09var nativeFunc=eval(aString);\x0a\x09\x09return new nativeFunc(anObject,anObject2, anObject3);\x0a\x09>",
 messageSends: [],
 referencedClasses: []
 }),

+ 8 - 8
src/Kernel-Methods.st

@@ -697,29 +697,29 @@ Created instances will most probably be instance of `JSObjectProxy`.
 
 constructor: aString
 	<
-		var native=eval(aString);
-		return new native();
+		var nativeFunc=eval(aString);
+		return new nativeFunc();
 	>
 !
 
 constructor: aString value:anObject
 	<
-		var native=eval(aString);
-		return new native(anObject);
+		var nativeFunc=eval(aString);
+		return new nativeFunc(anObject);
 	>
 !
 
 constructor: aString value:anObject value: anObject2
 	<
-		var native=eval(aString);
-		return new native(anObject,anObject2);
+		var nativeFunc=eval(aString);
+		return new nativeFunc(anObject,anObject2);
 	>
 !
 
 constructor: aString value:anObject value: anObject2 value:anObject3
 	<
-		var native=eval(aString);
-		return new native(anObject,anObject2, anObject3);
+		var nativeFunc=eval(aString);
+		return new nativeFunc(anObject,anObject2, anObject3);
 	>
 ! !
 

+ 18 - 0
src/Web.js

@@ -92,6 +92,24 @@ referencedClasses: []
 }),
 globals.BrowserInterface);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "prompt:default:",
+protocol: 'actions',
+fn: function (aString,defaultString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(window)._prompt_default_(aString,defaultString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"prompt:default:",{aString:aString,defaultString:defaultString},globals.BrowserInterface)})},
+args: ["aString", "defaultString"],
+source: "prompt: aString default: defaultString\x0a\x09^ window prompt: aString default: defaultString",
+messageSends: ["prompt:default:"],
+referencedClasses: []
+}),
+globals.BrowserInterface);
+
 
 
 smalltalk.addClass('HTMLCanvas', globals.Object, ['root'], 'Web');

+ 4 - 0
src/Web.st

@@ -33,6 +33,10 @@ confirm: aString
 
 prompt: aString
 	^ window prompt: aString
+!
+
+prompt: aString default: defaultString
+	^ window prompt: aString default: defaultString
 ! !
 
 !BrowserInterface methodsFor: 'testing'!

+ 0 - 143
test/Test.js

@@ -1,143 +0,0 @@
-define("amber_core/Test", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
-smalltalk.addPackage('Test');
-smalltalk.packages["Test"].transport = {"type":"amd","amdNamespace":"amber_core"};
-
-smalltalk.addClass('NodeTestRunner', globals.Object, [], 'Test');
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "main",
-protocol: 'not yet classified',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self._runTestSuite();
-return self}, function($ctx1) {$ctx1.fill(self,"main",{},globals.NodeTestRunner.klass)})},
-args: [],
-source: "main\x0a\x09self runTestSuite",
-messageSends: ["runTestSuite"],
-referencedClasses: []
-}),
-globals.NodeTestRunner.klass);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "runTestSuite",
-protocol: 'not yet classified',
-fn: function (){
-var self=this;
-var suite,worker;
-function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
-function $TestCase(){return globals.TestCase||(typeof TestCase=="undefined"?nil:TestCase)}
-function $TestSuiteRunner(){return globals.TestSuiteRunner||(typeof TestSuiteRunner=="undefined"?nil:TestSuiteRunner)}
-function $ResultAnnouncement(){return globals.ResultAnnouncement||(typeof ResultAnnouncement=="undefined"?nil:ResultAnnouncement)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1,$3,$9,$8,$12,$11,$10,$7,$6,$15,$14,$13,$5,$4,$17,$16,$19,$18,$26,$25,$24,$23,$22,$28,$27,$21,$20,$30,$29,$32,$31,$39,$38,$37,$36,$35,$34,$33;
-suite=_st($OrderedCollection())._new();
-_st(_st(_st($TestCase())._allSubclasses())._select_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(_st(each)._isAbstract())._not();
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})})))._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(suite)._addAll_(_st(each)._buildSuite());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
-worker=_st($TestSuiteRunner())._on_(suite);
-_st(_st(worker)._announcer())._on_do_($ResultAnnouncement(),(function(ann){
-var result;
-return smalltalk.withContext(function($ctx2) {
-result=_st(ann)._result();
-result;
-$2=_st(result)._runs();
-$ctx2.sendIdx["runs"]=1;
-$1=_st($2).__eq(_st(result)._total());
-if(smalltalk.assert($1)){
-$3=console;
-$9=_st(_st(result)._runs())._asString();
-$ctx2.sendIdx["asString"]=1;
-$8=_st($9).__comma(" tests run, ");
-$ctx2.sendIdx[","]=5;
-$12=_st(result)._failures();
-$ctx2.sendIdx["failures"]=1;
-$11=_st($12)._size();
-$ctx2.sendIdx["size"]=1;
-$10=_st($11)._asString();
-$ctx2.sendIdx["asString"]=2;
-$7=_st($8).__comma($10);
-$ctx2.sendIdx[","]=4;
-$6=_st($7).__comma(" failures, ");
-$ctx2.sendIdx[","]=3;
-$15=_st(result)._errors();
-$ctx2.sendIdx["errors"]=1;
-$14=_st($15)._size();
-$13=_st($14)._asString();
-$5=_st($6).__comma($13);
-$ctx2.sendIdx[","]=2;
-$4=_st($5).__comma(" errors.");
-$ctx2.sendIdx[","]=1;
-_st($3)._log_($4);
-$17=_st(result)._failures();
-$ctx2.sendIdx["failures"]=2;
-$16=_st($17)._isEmpty();
-$ctx2.sendIdx["isEmpty"]=1;
-if(! smalltalk.assert($16)){
-$19=_st(result)._failures();
-$ctx2.sendIdx["failures"]=3;
-$18=_st($19)._first();
-$ctx2.sendIdx["first"]=1;
-_st($18)._runCase();
-$ctx2.sendIdx["runCase"]=1;
-$26=_st(result)._failures();
-$ctx2.sendIdx["failures"]=4;
-$25=_st($26)._first();
-$ctx2.sendIdx["first"]=2;
-$24=_st($25)._class();
-$ctx2.sendIdx["class"]=1;
-$23=_st($24)._name();
-$ctx2.sendIdx["name"]=1;
-$22=_st($23).__comma(" >> ");
-$ctx2.sendIdx[","]=8;
-$28=_st(_st(result)._failures())._first();
-$ctx2.sendIdx["first"]=3;
-$27=_st($28)._selector();
-$ctx2.sendIdx["selector"]=1;
-$21=_st($22).__comma($27);
-$ctx2.sendIdx[","]=7;
-$20=_st($21).__comma(" is failing!");
-$ctx2.sendIdx[","]=6;
-self._throw_($20);
-$ctx2.sendIdx["throw:"]=1;
-};
-$30=_st(result)._errors();
-$ctx2.sendIdx["errors"]=2;
-$29=_st($30)._isEmpty();
-if(! smalltalk.assert($29)){
-$32=_st(result)._errors();
-$ctx2.sendIdx["errors"]=3;
-$31=_st($32)._first();
-$ctx2.sendIdx["first"]=4;
-_st($31)._runCase();
-$39=_st(result)._errors();
-$ctx2.sendIdx["errors"]=4;
-$38=_st($39)._first();
-$ctx2.sendIdx["first"]=5;
-$37=_st($38)._class();
-$36=_st($37)._name();
-$35=_st($36).__comma(" >> ");
-$34=_st($35).__comma(_st(_st(_st(result)._errors())._first())._selector());
-$ctx2.sendIdx[","]=10;
-$33=_st($34).__comma(" has errors!");
-$ctx2.sendIdx[","]=9;
-return self._throw_($33);
-};
-};
-}, function($ctx2) {$ctx2.fillBlock({ann:ann,result:result},$ctx1,3)})}));
-_st(worker)._run();
-return self}, function($ctx1) {$ctx1.fill(self,"runTestSuite",{suite:suite,worker:worker},globals.NodeTestRunner.klass)})},
-args: [],
-source: "runTestSuite\x0a\x09| suite worker |\x0a\x0a\x09suite := OrderedCollection new.\x0a    (TestCase allSubclasses select: [ :each | each isAbstract not ])\x0a\x09do: [ :each | suite addAll: each buildSuite ].\x0a\x0a\x09worker := TestSuiteRunner on: suite.\x0a\x09worker announcer on: ResultAnnouncement do:\x0a\x09[ :ann | | result |\x0a    \x09result := ann result.\x0a        result runs = result total ifTrue: [\x0a\x09        console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.\x0a\x0a            result failures isEmpty ifFalse: [\x0a                result failures first runCase.\x0a                \x22the line above should throw, normally, but just in case I leave the line below\x22\x0a                self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!' ].\x0a            result errors isEmpty ifFalse: [\x0a                result errors first runCase.\x0a                \x22the line above should throw, normally, but just in case I leave the line below\x22\x0a                self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!' ].\x0a    ]].\x0a    worker run",
-messageSends: ["new", "do:", "select:", "allSubclasses", "not", "isAbstract", "addAll:", "buildSuite", "on:", "on:do:", "announcer", "result", "ifTrue:", "=", "runs", "total", "log:", ",", "asString", "size", "failures", "errors", "ifFalse:", "isEmpty", "runCase", "first", "throw:", "name", "class", "selector", "run"],
-referencedClasses: ["OrderedCollection", "TestCase", "TestSuiteRunner", "ResultAnnouncement"]
-}),
-globals.NodeTestRunner.klass);
-
-});

+ 0 - 37
test/Test.st

@@ -1,37 +0,0 @@
-Smalltalk createPackage: 'Test'!
-Object subclass: #NodeTestRunner
-	instanceVariableNames: ''
-	package: 'Test'!
-
-!NodeTestRunner class methodsFor: 'not yet classified'!
-
-main
-	self runTestSuite
-!
-
-runTestSuite
-	| suite worker |
-
-	suite := OrderedCollection new.
-    (TestCase allSubclasses select: [ :each | each isAbstract not ])
-	do: [ :each | suite addAll: each buildSuite ].
-
-	worker := TestSuiteRunner on: suite.
-	worker announcer on: ResultAnnouncement do:
-	[ :ann | | result |
-    	result := ann result.
-        result runs = result total ifTrue: [
-	        console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.
-
-            result failures isEmpty ifFalse: [
-                result failures first runCase.
-                "the line above should throw, normally, but just in case I leave the line below"
-                self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!' ].
-            result errors isEmpty ifFalse: [
-                result errors first runCase.
-                "the line above should throw, normally, but just in case I leave the line below"
-                self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!' ].
-    ]].
-    worker run
-! !
-

Some files were not shown because too many files changed in this diff