Browse Source

Merge branch 'master' into message_send

Conflicts:
	js/boot.js
Nicolas Petton 12 years ago
parent
commit
47c928f5cf

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "examples/googlecharts"]
+	path = examples/googlecharts
+	url = git://github.com/tomrake/googlecharts.git

+ 4 - 3
bin/amberc

@@ -99,8 +99,8 @@ if [ -z $1 ] ; then
 fi
 
 # Define our predefined library combinations
-KERNEL="boot Kernel-Objects Kernel-Classes Kernel-Methods Kernel-Collections Kernel-Exceptions Kernel-Transcript"
-COMPILER="$KERNEL parser Compiler"
+KERNEL="boot Kernel-Objects Kernel-Classes Kernel-Methods Kernel-Collections Kernel-Exceptions Kernel-Transcript Kernel-Announcements"
+COMPILER="$KERNEL parser Compiler Compiler-Exceptions"
 
 # Predefined initializer
 INITIALIZER="$AMBER/js/init.js"
@@ -216,7 +216,8 @@ done
 LIBS="$TOBASE $TOLOAD"
 
 # Get a unique tempdir and make it get auto removed on exit
-TMPDIR=`mktemp -d amberc.XXXXXX`
+TMPDIR=`mktemp -d amberc.XXXXXX 2>>/dev/null` ||\
+    TMPDIR=/tmp/amberc.$$.`date +%s` && mkdir -p $TMPDIR
 trap "rm -rf $TMPDIR" EXIT
 
 

+ 2 - 0
examples/googlecharts/.gitignore

@@ -0,0 +1,2 @@
+# Ignore emacs backup files
+*~

+ 98 - 0
examples/googlecharts/README.md

@@ -0,0 +1,98 @@
+googlecharts
+============
+
+Google Charts API for Amber
+
+Author
+------
+Thomas W Rake
+
+Availability
+------------
+Fork it at https://github.com/tomrake/googlecharts
+
+How to use
+----------
+
+This project is a subproject of https://github.com/tomrake/amber
+If you clone that project you should have this subproject.
+
+
+Version 0.2
+-----------
+
+This API is likely to change in future versions.
+
+A overview of the recipe to create a Pie Chart is have a place in your html dom to place the chart. Create a subclass of ChartApp to control loading of google packages, creation of your charts and bind them to the dom. Ensure your charts have the correct data by subclassing PieChart and add the the makeData and makeOption methods.
+
+Here is the detailed Pie Chart recipe:
+
+1) Create an insertion point div in your html document in my case a my_chart_id div:
+ 
+    <div id="my_chart_div" style="width: 900px;height: 500px;">Loading Google Chart..</div>
+
+2) Create a package for your code MyCode
+
+3) In MyCode package create a subclass of PieChart, as an example MyPieChart, with two instance methods makeData and makeOptions which contain the chart data and options:
+
+     MyPieChart>>makeData
+      "DataTable of example Pie chart slices"
+      ^ self arrayToDataTable: { {'Task'.'Hours per Day'}.
+        		    {'Work' . 11}.
+                            {'Eat'.2}.
+                            {'Commute'.2}.
+                            {'Watch TV'.2}.
+                            {'Snooze'.7}}
+
+
+
+    MyPieChart>>makeOptions
+    	"Return a Dictionary of the options in this case only a title"
+    	^#{'title' -> 'My Daily Activities'}
+
+
+
+4) Determine which Google visualization packages are needed in the PieChart case only 'corechart' is needed. 
+
+5) In package MyCode create a subclass of ChartApp, as an example MyPieApp. In MyPieApp create a class method neededVisualizationPackages to return an Array for the packages needed for the App:
+
+    MyPieApp class>>neededVisualizationPackages
+    "This App only needs a corechart package."
+    	^{'corechart'}
+
+
+
+6) In MyPieApp create an instance method overiding begin, and use it to create, bind and draw MyPieChart. Besure to call super begin:
+
+    begin
+    	"Start the executiong of the MyPieChart by connecting each button/graphic pair"
+        MyPieChart new chartId:'my_chart_div';drawChart.
+        ^super begin
+
+7) Call Amber
+
+    <script src="../../js/amber.js" type="text/javascript"></script>
+    <script type="text/javascript">
+        loadAmber({
+            files: ['GoogleCharts.js','MyCode.js'],
+            prefix: 'examples/googlecharts/js', // path for js files i think
+            ready: function() {
+                $(function() {
+                   smalltalk.MyPieApp._new(); // Start the smalltalk App
+                });
+            }}); 
+    </script>
+
+The purpose of version 0.2 is to show how smalltalk flexibility can drive google charts.
+
+
+
+To Be Done
+----------
+Coordinate information between the Chart API and App API .Each chart has a fixed and known package to be loaded by the JSAPI it would be best if this info was recorded in a fixed place.
+
+Remove the subclasses of GoogleChart in favor of an Abstract Factory.
+
+Be prepaired to split the JSAPI.js ("the loading API") for use with other Google products.
+
+Design smalltalk friendly api for generic charts.

+ 26 - 0
examples/googlecharts/index.html

@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>Google Charts</title>
+    <script src="../../js/amber.js" type="text/javascript"></script>
+    <script type="text/javascript">
+		 loadAmber({
+			files: ['GoogleCharts.js','GoogleChartsExamples'],
+			prefix: 'examples/googlecharts/js', // path for js files i think
+			ready: function() {
+			  $(function() {
+				smalltalk.IndexChartApp._new(); // Start the smalltalk App
+			  });
+		}}); 
+	</script>
+  </head>
+
+  <body>
+    <h1>Google Charts</h1>
+    <button onclick="smalltalk.Browser._open()">class browser</button>
+    <div id="pie_chart_div" style="width: 900px;height: 500px;">Loading Google Chart..</div>
+
+
+    <a href="popcharts.html">Try the Pop Charts!</a> example.
+  </body>
+</html>

+ 392 - 0
examples/googlecharts/js/GoogleCharts.deploy.js

@@ -0,0 +1,392 @@
+smalltalk.addPackage('GoogleCharts', {});
+smalltalk.addClass('ChartApp', smalltalk.Object, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_begin",
+smalltalk.method({
+selector: "begin",
+fn: function (){
+var self=this;
+return self;
+}
+}),
+smalltalk.ChartApp);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_class",[]),"_loadGoogleLoader_",[(function(){
+return smalltalk.send(smalltalk.send(self,"_class",[]),"_loadVisualization_",[(function(){
+return smalltalk.send(self,"_begin",[]);
+})]);
+})]);
+return self}
+}),
+smalltalk.ChartApp);
+
+
+smalltalk.addMethod(
+"_loadGoogleLoader_",
+smalltalk.method({
+selector: "loadGoogleLoader:",
+fn: function (callback){
+var self=this;
+$.ajax({url:"https://www.google.com/jsapi",dataType:"script",success:callback});;
+;
+return self}
+}),
+smalltalk.ChartApp.klass);
+
+smalltalk.addMethod(
+"_loadVisualization_",
+smalltalk.method({
+selector: "loadVisualization:",
+fn: function (callback){
+var self=this;
+var packages;
+packages=smalltalk.send(self,"_neededVisualizationPackages",[]);
+google.load("visualization","1",{"callback" : callback , "packages":packages});;
+;
+return self}
+}),
+smalltalk.ChartApp.klass);
+
+smalltalk.addMethod(
+"_neededVisualizationPackages",
+smalltalk.method({
+selector: "neededVisualizationPackages",
+fn: function (){
+var self=this;
+var $1;
+$1=[];
+return $1;
+}
+}),
+smalltalk.ChartApp.klass);
+
+
+smalltalk.addClass('ChartButton', smalltalk.Object, ['element', 'clickBlock'], 'GoogleCharts');
+smalltalk.addMethod(
+"_activate",
+smalltalk.method({
+selector: "activate",
+fn: function (){
+var self=this;
+var button;
+button=smalltalk.send(smalltalk.send(self,"_element",[]),"_asJQuery",[]);
+smalltalk.send(button,"_click_",[(function(){
+return smalltalk.send(smalltalk.send(self,"_clickBlock",[]),"_value",[]);
+})]);
+return self}
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_clickBlock",
+smalltalk.method({
+selector: "clickBlock",
+fn: function (){
+var self=this;
+return self["@clickBlock"];
+}
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_clickBlock_",
+smalltalk.method({
+selector: "clickBlock:",
+fn: function (aBlock){
+var self=this;
+self["@clickBlock"]=aBlock;
+return self}
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_element",
+smalltalk.method({
+selector: "element",
+fn: function (){
+var self=this;
+return self["@element"];
+}
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_element_",
+smalltalk.method({
+selector: "element:",
+fn: function (aSymbol){
+var self=this;
+self["@element"]=aSymbol;
+return self}
+}),
+smalltalk.ChartButton);
+
+
+smalltalk.addMethod(
+"_element_clickBlock_",
+smalltalk.method({
+selector: "element:clickBlock:",
+fn: function (elementSymbol,clickBlock){
+var self=this;
+var $2,$3,$1;
+$2=smalltalk.send(self,"_new",[]);
+smalltalk.send($2,"_element_",[elementSymbol]);
+smalltalk.send($2,"_clickBlock_",[clickBlock]);
+smalltalk.send($2,"_activate",[]);
+$3=smalltalk.send($2,"_yourself",[]);
+$1=$3;
+return $1;
+}
+}),
+smalltalk.ChartButton.klass);
+
+smalltalk.addMethod(
+"_popUpChart_atDom_",
+smalltalk.method({
+selector: "popUpChart:atDom:",
+fn: function (chart,element){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_element_clickBlock_",[element,(function(){
+return smalltalk.send(chart,"_drawChart",[]);
+})]);
+return $1;
+}
+}),
+smalltalk.ChartButton.klass);
+
+
+smalltalk.addClass('GoogleChart', smalltalk.Object, ['chartId', 'chartType'], 'GoogleCharts');
+smalltalk.addMethod(
+"_arrayToDataTable_",
+smalltalk.method({
+selector: "arrayToDataTable:",
+fn: function (array){
+var self=this;
+var $1;
+$1=google.visualization.arrayToDataTable(array);
+;
+return $1;
+}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartId",
+smalltalk.method({
+selector: "chartId",
+fn: function (){
+var self=this;
+return self["@chartId"];
+}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartId_",
+smalltalk.method({
+selector: "chartId:",
+fn: function (aString){
+var self=this;
+self["@chartId"]=aString;
+return self}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartType",
+smalltalk.method({
+selector: "chartType",
+fn: function (){
+var self=this;
+return self["@chartType"];
+}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartType_",
+smalltalk.method({
+selector: "chartType:",
+fn: function (aString){
+var self=this;
+self["@chartType"]=aString;
+return self}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_drawChart",
+smalltalk.method({
+selector: "drawChart",
+fn: function (){
+var self=this;
+var chart;
+var data;
+var options;
+data=smalltalk.send(self,"_makeData",[]);
+chart=smalltalk.send(self,"_makeChart_",[smalltalk.send(self,"_chartId",[])]);
+options=smalltalk.send(self,"_makeOptions",[]);
+chart.draw(data,options);
+;
+return self}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_getElementById_",
+smalltalk.method({
+selector: "getElementById:",
+fn: function (id){
+var self=this;
+var $1;
+$1=document.getElementById(id);
+;
+return $1;
+}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+return self;
+}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_makeChart_",
+smalltalk.method({
+selector: "makeChart:",
+fn: function (id){
+var self=this;
+var $1;
+var e;
+var t;
+e=smalltalk.send(self,"_getElementById_",[id]);
+t=smalltalk.send(self,"_chartType",[]);
+$1=new google.visualization[t](e);
+;
+return $1;
+}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_subclassresponsibility",[]);
+return $1;
+}
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_subclassresponsibility",[]);
+return $1;
+}
+}),
+smalltalk.GoogleChart);
+
+
+smalltalk.addMethod(
+"_chartId_",
+smalltalk.method({
+selector: "chartId:",
+fn: function (aString){
+var self=this;
+var $2,$3,$1;
+$2=smalltalk.send(self,"_new",[]);
+smalltalk.send($2,"_chartId_",[aString]);
+$3=smalltalk.send($2,"_yourself",[]);
+$1=$3;
+return $1;
+}
+}),
+smalltalk.GoogleChart.klass);
+
+
+smalltalk.addClass('GaugeChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["Gauge"]);
+return self;
+}
+}),
+smalltalk.GaugeChart);
+
+
+
+smalltalk.addClass('GeoChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["GeoChart"]);
+return self;
+}
+}),
+smalltalk.GeoChart);
+
+
+
+smalltalk.addClass('PieChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["PieChart"]);
+return self;
+}
+}),
+smalltalk.PieChart);
+
+
+
+smalltalk.addClass('ScatterChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["ScatterChart"]);
+return self;
+}
+}),
+smalltalk.ScatterChart);
+
+
+

+ 533 - 0
examples/googlecharts/js/GoogleCharts.js

@@ -0,0 +1,533 @@
+smalltalk.addPackage('GoogleCharts', {});
+smalltalk.addClass('ChartApp', smalltalk.Object, [], 'GoogleCharts');
+smalltalk.ChartApp.comment="A chart app is an example App which loads the google JSAPI and visualization API."
+smalltalk.addMethod(
+"_begin",
+smalltalk.method({
+selector: "begin",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+return self;
+},
+args: [],
+source: "begin\x0a\x09\x22Start the executiong of the ChartApp\x22\x0a\x09^self",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChartApp);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+smalltalk.send(smalltalk.send(self,"_class",[]),"_loadGoogleLoader_",[(function(){
+return smalltalk.send(smalltalk.send(self,"_class",[]),"_loadVisualization_",[(function(){
+return smalltalk.send(self,"_begin",[]);
+})]);
+})]);
+return self},
+args: [],
+source: "initialize\x0a\x09\x22Load my external JS\x22\x0a    self class loadGoogleLoader:[self class loadVisualization:[self begin]]\x0a  ",
+messageSends: ["loadGoogleLoader:", "loadVisualization:", "begin", "class"],
+referencedClasses: []
+}),
+smalltalk.ChartApp);
+
+
+smalltalk.addMethod(
+"_loadGoogleLoader_",
+smalltalk.method({
+selector: "loadGoogleLoader:",
+category: 'not yet classified',
+fn: function (callback){
+var self=this;
+$.ajax({url:"https://www.google.com/jsapi",dataType:"script",success:callback});;
+;
+return self},
+args: ["callback"],
+source: "loadGoogleLoader: callback\x0a\x09\x22Load the Google JSAPI - Use JQuery.ajax() since that is available\x22\x0a\x09<$.ajax({url:\x22https://www.google.com/jsapi\x22,dataType:\x22script\x22,success:callback});>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChartApp.klass);
+
+smalltalk.addMethod(
+"_loadVisualization_",
+smalltalk.method({
+selector: "loadVisualization:",
+category: 'not yet classified',
+fn: function (callback){
+var self=this;
+var packages;
+packages=smalltalk.send(self,"_neededVisualizationPackages",[]);
+google.load("visualization","1",{"callback" : callback , "packages":packages});;
+;
+return self},
+args: ["callback"],
+source: "loadVisualization: callback\x0a\x09\x22Use google.load() to load visualization and load the needed packages\x22\x0a    |packages|\x0a    packages := self neededVisualizationPackages.\x0a    <google.load(\x22visualization\x22,\x221\x22,{\x22callback\x22 : callback , \x22packages\x22:packages});>",
+messageSends: ["neededVisualizationPackages"],
+referencedClasses: []
+}),
+smalltalk.ChartApp.klass);
+
+smalltalk.addMethod(
+"_neededVisualizationPackages",
+smalltalk.method({
+selector: "neededVisualizationPackages",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=[];
+return $1;
+},
+args: [],
+source: "neededVisualizationPackages\x0a\x22This is a hook for subclasses to define which visualization packages to load.\x22\x0a\x09^{}",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChartApp.klass);
+
+
+smalltalk.addClass('ChartButton', smalltalk.Object, ['element', 'clickBlock'], 'GoogleCharts');
+smalltalk.addMethod(
+"_activate",
+smalltalk.method({
+selector: "activate",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var button;
+button=smalltalk.send(smalltalk.send(self,"_element",[]),"_asJQuery",[]);
+smalltalk.send(button,"_click_",[(function(){
+return smalltalk.send(smalltalk.send(self,"_clickBlock",[]),"_value",[]);
+})]);
+return self},
+args: [],
+source: "activate\x0a\x09|button|\x0a\x09button := self element asJQuery.\x0a    button click:[self clickBlock value]",
+messageSends: ["asJQuery", "element", "click:", "value", "clickBlock"],
+referencedClasses: []
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_clickBlock",
+smalltalk.method({
+selector: "clickBlock",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+return self["@clickBlock"];
+},
+args: [],
+source: "clickBlock\x0a\x09^clickBlock",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_clickBlock_",
+smalltalk.method({
+selector: "clickBlock:",
+category: 'not yet classified',
+fn: function (aBlock){
+var self=this;
+self["@clickBlock"]=aBlock;
+return self},
+args: ["aBlock"],
+source: "clickBlock: aBlock\x0a\x09clickBlock := aBlock",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_element",
+smalltalk.method({
+selector: "element",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+return self["@element"];
+},
+args: [],
+source: "element\x0a\x09^element",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChartButton);
+
+smalltalk.addMethod(
+"_element_",
+smalltalk.method({
+selector: "element:",
+category: 'not yet classified',
+fn: function (aSymbol){
+var self=this;
+self["@element"]=aSymbol;
+return self},
+args: ["aSymbol"],
+source: "element: aSymbol\x0a\x09element := aSymbol",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChartButton);
+
+
+smalltalk.addMethod(
+"_element_clickBlock_",
+smalltalk.method({
+selector: "element:clickBlock:",
+category: 'not yet classified',
+fn: function (elementSymbol,clickBlock){
+var self=this;
+var $2,$3,$1;
+$2=smalltalk.send(self,"_new",[]);
+smalltalk.send($2,"_element_",[elementSymbol]);
+smalltalk.send($2,"_clickBlock_",[clickBlock]);
+smalltalk.send($2,"_activate",[]);
+$3=smalltalk.send($2,"_yourself",[]);
+$1=$3;
+return $1;
+},
+args: ["elementSymbol", "clickBlock"],
+source: "element: elementSymbol clickBlock: clickBlock\x0a\x09^self new element: elementSymbol; clickBlock: clickBlock; activate;yourself",
+messageSends: ["element:", "new", "clickBlock:", "activate", "yourself"],
+referencedClasses: []
+}),
+smalltalk.ChartButton.klass);
+
+smalltalk.addMethod(
+"_popUpChart_atDom_",
+smalltalk.method({
+selector: "popUpChart:atDom:",
+category: 'not yet classified',
+fn: function (chart,element){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_element_clickBlock_",[element,(function(){
+return smalltalk.send(chart,"_drawChart",[]);
+})]);
+return $1;
+},
+args: ["chart", "element"],
+source: "popUpChart: chart atDom: element\x0a\x09\x22Make the chart popup on click of an element\x22\x0a    ^self element: element clickBlock:[chart drawChart]\x0a\x09",
+messageSends: ["element:clickBlock:", "drawChart"],
+referencedClasses: []
+}),
+smalltalk.ChartButton.klass);
+
+
+smalltalk.addClass('GoogleChart', smalltalk.Object, ['chartId', 'chartType'], 'GoogleCharts');
+smalltalk.addMethod(
+"_arrayToDataTable_",
+smalltalk.method({
+selector: "arrayToDataTable:",
+category: 'data table',
+fn: function (array){
+var self=this;
+var $1;
+$1=google.visualization.arrayToDataTable(array);
+;
+return $1;
+},
+args: ["array"],
+source: "arrayToDataTable: array\x0a\x0a\x09^ <google.visualization.arrayToDataTable(array)>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartId",
+smalltalk.method({
+selector: "chartId",
+category: 'accessor',
+fn: function (){
+var self=this;
+return self["@chartId"];
+},
+args: [],
+source: "chartId\x0a\x09^chartId",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartId_",
+smalltalk.method({
+selector: "chartId:",
+category: 'accessor',
+fn: function (aString){
+var self=this;
+self["@chartId"]=aString;
+return self},
+args: ["aString"],
+source: "chartId: aString\x0a\x09chartId := aString",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartType",
+smalltalk.method({
+selector: "chartType",
+category: 'accessor',
+fn: function (){
+var self=this;
+return self["@chartType"];
+},
+args: [],
+source: "chartType\x0a\x09^ chartType",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_chartType_",
+smalltalk.method({
+selector: "chartType:",
+category: 'accessor',
+fn: function (aString){
+var self=this;
+self["@chartType"]=aString;
+return self},
+args: ["aString"],
+source: "chartType: aString\x0a\x09chartType := aString",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_drawChart",
+smalltalk.method({
+selector: "drawChart",
+category: 'chart',
+fn: function (){
+var self=this;
+var chart;
+var data;
+var options;
+data=smalltalk.send(self,"_makeData",[]);
+chart=smalltalk.send(self,"_makeChart_",[smalltalk.send(self,"_chartId",[])]);
+options=smalltalk.send(self,"_makeOptions",[]);
+chart.draw(data,options);
+;
+return self},
+args: [],
+source: "drawChart\x0a    |  chart data options|\x0a     data := self makeData.\x0a     chart :=self makeChart:self chartId.\x0a     options :=self makeOptions.\x0a     <chart.draw(data,options)>\x0a",
+messageSends: ["makeData", "makeChart:", "chartId", "makeOptions"],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_getElementById_",
+smalltalk.method({
+selector: "getElementById:",
+category: 'DOM',
+fn: function (id){
+var self=this;
+var $1;
+$1=document.getElementById(id);
+;
+return $1;
+},
+args: ["id"],
+source: "getElementById: id\x0a\x09\x22Find element by the id in the DOM\x22\x0a\x09^ <document.getElementById(id)>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'init',
+fn: function (){
+var self=this;
+return self;
+},
+args: [],
+source: "initialize\x0a\x09^self",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_makeChart_",
+smalltalk.method({
+selector: "makeChart:",
+category: 'chart',
+fn: function (id){
+var self=this;
+var $1;
+var e;
+var t;
+e=smalltalk.send(self,"_getElementById_",[id]);
+t=smalltalk.send(self,"_chartType",[]);
+$1=new google.visualization[t](e);
+;
+return $1;
+},
+args: ["id"],
+source: "makeChart: id\x0a\x22build a chart at specific element id in the DOM and return\x22\x0a\x09|e t|\x0a    e := self getElementById:id.\x0a    t := self chartType.\x0a    ^ <new google.visualization[t](e)>",
+messageSends: ["getElementById:", "chartType"],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+category: 'abstraction',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_subclassresponsibility",[]);
+return $1;
+},
+args: [],
+source: "makeData\x0a\x09\x22abstraction - return the data for a google chart\x22\x0a  \x09 ^self subclassresponsibility",
+messageSends: ["subclassresponsibility"],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+category: 'abstraction',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_subclassresponsibility",[]);
+return $1;
+},
+args: [],
+source: "makeOptions\x0a\x09\x22Abstract method - return options for a Google Chart\x22\x0a   ^\x09 self subclassresponsibility",
+messageSends: ["subclassresponsibility"],
+referencedClasses: []
+}),
+smalltalk.GoogleChart);
+
+
+smalltalk.addMethod(
+"_chartId_",
+smalltalk.method({
+selector: "chartId:",
+category: 'not yet classified',
+fn: function (aString){
+var self=this;
+var $2,$3,$1;
+$2=smalltalk.send(self,"_new",[]);
+smalltalk.send($2,"_chartId_",[aString]);
+$3=smalltalk.send($2,"_yourself",[]);
+$1=$3;
+return $1;
+},
+args: ["aString"],
+source: "chartId: aString\x0a\x09^self new chartId:aString;yourself",
+messageSends: ["chartId:", "new", "yourself"],
+referencedClasses: []
+}),
+smalltalk.GoogleChart.klass);
+
+
+smalltalk.addClass('GaugeChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["Gauge"]);
+return self;
+},
+args: [],
+source: "initialize\x0a\x09\x22 Create a Guage with the chartId that identifies the chart graphic placement and the chartType to be created at that id.\x22\x0a    super initialize.\x0a    self chartType:'Gauge'.\x0a\x09^self",
+messageSends: ["initialize", "chartType:"],
+referencedClasses: []
+}),
+smalltalk.GaugeChart);
+
+
+
+smalltalk.addClass('GeoChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["GeoChart"]);
+return self;
+},
+args: [],
+source: "initialize\x0a\x09\x22 Create a Geo Chart\x22\x0a    super initialize.\x0a    self chartType:'GeoChart'.\x0a\x09^self",
+messageSends: ["initialize", "chartType:"],
+referencedClasses: []
+}),
+smalltalk.GeoChart);
+
+
+
+smalltalk.addClass('PieChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["PieChart"]);
+return self;
+},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a    self chartType:'PieChart'.\x0a\x09^self",
+messageSends: ["initialize", "chartType:"],
+referencedClasses: []
+}),
+smalltalk.PieChart);
+
+
+
+smalltalk.addClass('ScatterChart', smalltalk.GoogleChart, [], 'GoogleCharts');
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.GoogleChart);
+smalltalk.send(self,"_chartType_",["ScatterChart"]);
+return self;
+},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a    self chartType:'ScatterChart'.\x0a\x09^self",
+messageSends: ["initialize", "chartType:"],
+referencedClasses: []
+}),
+smalltalk.ScatterChart);
+
+
+

+ 197 - 0
examples/googlecharts/js/GoogleChartsExamples.deploy.js

@@ -0,0 +1,197 @@
+smalltalk.addPackage('GoogleChartsExamples', {});
+smalltalk.addClass('GaugeChartExample', smalltalk.GaugeChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["Label","Value"],["Memory",(80)],["CPU",(55)],["Network",(68)]]]);
+return $1;
+}
+}),
+smalltalk.GaugeChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+fn: function (){
+var self=this;
+var $1;
+$1={width:400, heigth:120,
+   redFrom:90,redTo:100,
+   yellowFrom:75,yellowTo:90,
+   minorTicks:5};
+;
+return $1;
+}
+}),
+smalltalk.GaugeChartExample);
+
+
+
+smalltalk.addClass('GeoChartExample', smalltalk.GeoChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["City","Population","Area"],["Rome",(2761477),(1285.31)],["Milan",(1324110),(181.76)],["Naples",(959574),(117.27)],["Turin",(907563),(130.17)],["Palermo",(655875),(158.9)],["Genoa",(607906),(243.6)],["Bologna",(380181),(140.7)],["Florence",(371282),(102.41)],["Fiumicino",(67370),(213.44)],["Anzio",(52192),(43.43)],["Ciampino",(38262),(11)]]]);
+return $1;
+}
+}),
+smalltalk.GeoChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+fn: function (){
+var self=this;
+var $1;
+$1={
+        region: 'IT',
+        displayMode: 'markers',
+        colorAxis: {colors: ['green', 'blue']}
+      };
+;
+return $1;
+}
+}),
+smalltalk.GeoChartExample);
+
+
+
+smalltalk.addClass('IndexChartApp', smalltalk.ChartApp, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_begin",
+smalltalk.method({
+selector: "begin",
+fn: function (){
+var self=this;
+var $1,$2,$3;
+$1=smalltalk.send((smalltalk.PieChartExample || PieChartExample),"_new",[]);
+smalltalk.send($1,"_chartId_",["pie_chart_div"]);
+$2=smalltalk.send($1,"_drawChart",[]);
+$3=smalltalk.send(self,"_begin",[],smalltalk.ChartApp);
+return $3;
+}
+}),
+smalltalk.IndexChartApp);
+
+
+smalltalk.addMethod(
+"_neededVisualizationPackages",
+smalltalk.method({
+selector: "neededVisualizationPackages",
+fn: function (){
+var self=this;
+var $1;
+$1=["corechart"];
+return $1;
+}
+}),
+smalltalk.IndexChartApp.klass);
+
+
+smalltalk.addClass('PieChartExample', smalltalk.PieChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["Task","Hours per Day"],["Work",(11)],["Eat",(2)],["Commute",(2)],["Watch TV",(2)],["Snooze",(7)]]]);
+return $1;
+}
+}),
+smalltalk.PieChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.HashedCollection._fromPairs_([smalltalk.send("title","__minus_gt",["My Daily Activities"])]);
+return $1;
+}
+}),
+smalltalk.PieChartExample);
+
+
+
+smalltalk.addClass('PopupChartApp', smalltalk.ChartApp, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_begin",
+smalltalk.method({
+selector: "begin",
+fn: function (){
+var self=this;
+var $1;
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.PieChartExample || PieChartExample),"_chartId_",["pie_chart_div"]),"#popPieChart"]);
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.ScatterChartExample || ScatterChartExample),"_chartId_",["scatter_chart_div"]),"#popScatterChart"]);
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.GaugeChartExample || GaugeChartExample),"_chartId_",["gauge_chart_div"]),"#popGaugeChart"]);
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.GeoChartExample || GeoChartExample),"_chartId_",["geo_markers_chart_div"]),"#popGeoMarkersChart"]);
+$1=smalltalk.send(self,"_begin",[],smalltalk.ChartApp);
+return $1;
+}
+}),
+smalltalk.PopupChartApp);
+
+
+smalltalk.addMethod(
+"_neededVisualizationPackages",
+smalltalk.method({
+selector: "neededVisualizationPackages",
+fn: function (){
+var self=this;
+var $1;
+$1=["corechart","gauge","geochart"];
+return $1;
+}
+}),
+smalltalk.PopupChartApp.klass);
+
+
+smalltalk.addClass('ScatterChartExample', smalltalk.ScatterChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["Age","Weight"],[(8),(11)],[(4),(5.5)],[(11),(14)],[(4),(5)],[(3),(3)],[(6.5),(7)]]]);
+return $1;
+}
+}),
+smalltalk.ScatterChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+fn: function (){
+var self=this;
+var $1;
+$1={
+          title: 'Age vs. Weight comparison',
+          hAxis: {title: 'Age', minValue: 0, maxValue: 15},
+          vAxis: {title: 'Weight', minValue: 0, maxValue: 15},
+          legend: 'none'
+        };
+;
+return $1;
+}
+}),
+smalltalk.ScatterChartExample);
+
+
+

+ 257 - 0
examples/googlecharts/js/GoogleChartsExamples.js

@@ -0,0 +1,257 @@
+smalltalk.addPackage('GoogleChartsExamples', {});
+smalltalk.addClass('GaugeChartExample', smalltalk.GaugeChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["Label","Value"],["Memory",(80)],["CPU",(55)],["Network",(68)]]]);
+return $1;
+},
+args: [],
+source: "makeData\x0a\x22Example Gauge Data\x22\x0a  ^ self arrayToDataTable: { {'Label'.'Value'}.\x0a    \x09\x09\x09\x09\x09{'Memory' . 80}.\x0a                        {'CPU' . 55}.\x0a                        {'Network' . 68}}",
+messageSends: ["arrayToDataTable:"],
+referencedClasses: []
+}),
+smalltalk.GaugeChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1={width:400, heigth:120,
+   redFrom:90,redTo:100,
+   yellowFrom:75,yellowTo:90,
+   minorTicks:5};
+;
+return $1;
+},
+args: [],
+source: "makeOptions\x0a\x22Example Gauge options\x22\x0a   ^<{width:400, heigth:120,\x0a   redFrom:90,redTo:100,\x0a   yellowFrom:75,yellowTo:90,\x0a   minorTicks:5}>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GaugeChartExample);
+
+
+
+smalltalk.addClass('GeoChartExample', smalltalk.GeoChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["City","Population","Area"],["Rome",(2761477),(1285.31)],["Milan",(1324110),(181.76)],["Naples",(959574),(117.27)],["Turin",(907563),(130.17)],["Palermo",(655875),(158.9)],["Genoa",(607906),(243.6)],["Bologna",(380181),(140.7)],["Florence",(371282),(102.41)],["Fiumicino",(67370),(213.44)],["Anzio",(52192),(43.43)],["Ciampino",(38262),(11)]]]);
+return $1;
+},
+args: [],
+source: "makeData\x0a\x22Example Geo Data\x22\x0a  ^ self arrayToDataTable: {\x0a{'City'.   'Population' . 'Area'}.\x0a        {'Rome'.      2761477 .    1285.31}.\x0a        {'Milan'.     1324110 .    181.76}.\x0a        {'Naples'.    959574 .    117.27}.\x0a        {'Turin'.     907563 .     130.17}.\x0a        {'Palermo'.   655875 .     158.9}.\x0a        {'Genoa'.     607906 .   243.60}.\x0a        {'Bologna'.   380181 .     140.7}.\x0a        {'Florence'.  371282 .    102.41}.\x0a        {'Fiumicino'. 67370 .      213.44}.\x0a        {'Anzio'.     52192 .      43.43}.\x0a        {'Ciampino'.  38262 .      11} \x0a        }",
+messageSends: ["arrayToDataTable:"],
+referencedClasses: []
+}),
+smalltalk.GeoChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1={
+        region: 'IT',
+        displayMode: 'markers',
+        colorAxis: {colors: ['green', 'blue']}
+      };
+;
+return $1;
+},
+args: [],
+source: "makeOptions\x0a\x22Example Geo Options\x22\x0a\x0a   ^<{\x0a        region: 'IT',\x0a        displayMode: 'markers',\x0a        colorAxis: {colors: ['green', 'blue']}\x0a      }>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.GeoChartExample);
+
+
+
+smalltalk.addClass('IndexChartApp', smalltalk.ChartApp, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_begin",
+smalltalk.method({
+selector: "begin",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1,$2,$3;
+$1=smalltalk.send((smalltalk.PieChartExample || PieChartExample),"_new",[]);
+smalltalk.send($1,"_chartId_",["pie_chart_div"]);
+$2=smalltalk.send($1,"_drawChart",[]);
+$3=smalltalk.send(self,"_begin",[],smalltalk.ChartApp);
+return $3;
+},
+args: [],
+source: "begin\x0a\x09\x22Start the executiong of the ExampleChartApp by connecting each button/graphic pair\x22\x0a    PieChartExample new chartId:'pie_chart_div';drawChart.\x0a    ^super begin",
+messageSends: ["chartId:", "new", "drawChart", "begin"],
+referencedClasses: ["PieChartExample"]
+}),
+smalltalk.IndexChartApp);
+
+
+smalltalk.addMethod(
+"_neededVisualizationPackages",
+smalltalk.method({
+selector: "neededVisualizationPackages",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=["corechart"];
+return $1;
+},
+args: [],
+source: "neededVisualizationPackages\x0a\x22This App only needs a corechart package.\x22\x0a\x09^{'corechart'}",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.IndexChartApp.klass);
+
+
+smalltalk.addClass('PieChartExample', smalltalk.PieChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["Task","Hours per Day"],["Work",(11)],["Eat",(2)],["Commute",(2)],["Watch TV",(2)],["Snooze",(7)]]]);
+return $1;
+},
+args: [],
+source: "makeData\x0a\x09\x22return a DataTable of example Pie Chart data\x22\x0a\x0a  ^ self arrayToDataTable: { {'Task'.'Hours per Day'}.\x0a    \x09\x09\x09\x09\x09{'Work' . 11}.\x0a                        {'Eat'.2}.\x0a                        {'Commute'.2}.\x0a                        {'Watch TV'.2}.\x0a                        {'Snooze'.7}}",
+messageSends: ["arrayToDataTable:"],
+referencedClasses: []
+}),
+smalltalk.PieChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.HashedCollection._fromPairs_([smalltalk.send("title","__minus_gt",["My Daily Activities"])]);
+return $1;
+},
+args: [],
+source: "makeOptions\x0a\x09\x22Return a Dictionary of the options in this case only a title\x22\x0a\x09^#{'title' -> 'My Daily Activities'}\x0a",
+messageSends: ["->"],
+referencedClasses: []
+}),
+smalltalk.PieChartExample);
+
+
+
+smalltalk.addClass('PopupChartApp', smalltalk.ChartApp, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_begin",
+smalltalk.method({
+selector: "begin",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.PieChartExample || PieChartExample),"_chartId_",["pie_chart_div"]),"#popPieChart"]);
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.ScatterChartExample || ScatterChartExample),"_chartId_",["scatter_chart_div"]),"#popScatterChart"]);
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.GaugeChartExample || GaugeChartExample),"_chartId_",["gauge_chart_div"]),"#popGaugeChart"]);
+smalltalk.send((smalltalk.ChartButton || ChartButton),"_popUpChart_atDom_",[smalltalk.send((smalltalk.GeoChartExample || GeoChartExample),"_chartId_",["geo_markers_chart_div"]),"#popGeoMarkersChart"]);
+$1=smalltalk.send(self,"_begin",[],smalltalk.ChartApp);
+return $1;
+},
+args: [],
+source: "begin\x0a\x09\x22Start the executiong of the ExampleChartApp by connecting each button/graphic pair\x22\x0a    ChartButton popUpChart:(PieChartExample chartId:'pie_chart_div') atDom:'#popPieChart' .\x0a    ChartButton popUpChart:(ScatterChartExample chartId:'scatter_chart_div') atDom:'#popScatterChart'.\x0a    ChartButton popUpChart:(GaugeChartExample chartId:'gauge_chart_div') atDom:'#popGaugeChart'.\x0a    ChartButton popUpChart:(GeoChartExample chartId:'geo_markers_chart_div') atDom: '#popGeoMarkersChart'.\x0a    ^super begin",
+messageSends: ["popUpChart:atDom:", "chartId:", "begin"],
+referencedClasses: ["PieChartExample", "ChartButton", "ScatterChartExample", "GaugeChartExample", "GeoChartExample"]
+}),
+smalltalk.PopupChartApp);
+
+
+smalltalk.addMethod(
+"_neededVisualizationPackages",
+smalltalk.method({
+selector: "neededVisualizationPackages",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=["corechart","gauge","geochart"];
+return $1;
+},
+args: [],
+source: "neededVisualizationPackages\x0a\x22This is a hook for subclasses to define which visualization packages to load.\x22\x0a\x09^{'corechart'.'gauge'.'geochart'}",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.PopupChartApp.klass);
+
+
+smalltalk.addClass('ScatterChartExample', smalltalk.ScatterChart, [], 'GoogleChartsExamples');
+smalltalk.addMethod(
+"_makeData",
+smalltalk.method({
+selector: "makeData",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1=smalltalk.send(self,"_arrayToDataTable_",[[["Age","Weight"],[(8),(11)],[(4),(5.5)],[(11),(14)],[(4),(5)],[(3),(3)],[(6.5),(7)]]]);
+return $1;
+},
+args: [],
+source: "makeData\x0a  \x22Return the example dataset\x22\x0a  ^ self arrayToDataTable: { \x0a  \x09\x09\x09\x09\x09\x09\x09{'Age'.'Weight'}.\x0a                            {8 . 11} . \x0a                            { 4 . 5.5} . \x0a                            { 11 . 14 } . \x0a                            { 4 . 5}. \x0a                            {3 . 3} . \x0a                            {6.5 . 7}}\x0a     ",
+messageSends: ["arrayToDataTable:"],
+referencedClasses: []
+}),
+smalltalk.ScatterChartExample);
+
+smalltalk.addMethod(
+"_makeOptions",
+smalltalk.method({
+selector: "makeOptions",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var $1;
+$1={
+          title: 'Age vs. Weight comparison',
+          hAxis: {title: 'Age', minValue: 0, maxValue: 15},
+          vAxis: {title: 'Weight', minValue: 0, maxValue: 15},
+          legend: 'none'
+        };
+;
+return $1;
+},
+args: [],
+source: "makeOptions\x0a\x22options for example dataset\x22\x0a   ^<{\x0a          title: 'Age vs. Weight comparison',\x0a          hAxis: {title: 'Age', minValue: 0, maxValue: 15},\x0a          vAxis: {title: 'Weight', minValue: 0, maxValue: 15},\x0a          legend: 'none'\x0a        }>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ScatterChartExample);
+
+
+

+ 30 - 0
examples/googlecharts/popcharts.html

@@ -0,0 +1,30 @@
+<html>
+  <head>
+    <script src="../../js/amber.js" type="text/javascript"></script>
+    <script type="text/javascript">
+		 loadAmber({
+			files: ['GoogleCharts.js','GoogleChartsExamples'],
+			prefix: 'examples/googlecharts/js', // path for js files i think
+			ready: function() {
+			  $(function() {
+				smalltalk.PopupChartApp._new(); // Start the smalltalk App
+			  });
+		}}); 
+	</script>
+  </head>
+  <body>
+       <h1>My First Google Chart Project</h1>
+	   
+       <button onclick="smalltalk.Browser._open()">class browser</button>
+	   <button id="popPieChart">pop pie chart</button>
+	   <div id="pie_chart_div"></div>
+	   <button id="popScatterChart">pop scatter chart</button>
+	   <div id="scatter_chart_div"></div>
+           <button id="popGaugeChart">pop gauge chart</button>
+	   <div id="gauge_chart_div"></div>
+           <button id="popGeoMarkersChart">pop Geo Markers Chart</button>
+           <div id="geo_markers_chart_div"></div>
+    
+
+  </body>
+</html>

+ 205 - 0
examples/googlecharts/st/GoogleCharts.st

@@ -0,0 +1,205 @@
+Smalltalk current createPackage: 'GoogleCharts' properties: #{}!
+Object subclass: #ChartApp
+	instanceVariableNames: ''
+	package: 'GoogleCharts'!
+!ChartApp commentStamp!
+A chart app is an example App which loads the google JSAPI and visualization API.!
+
+!ChartApp methodsFor: 'not yet classified'!
+
+begin
+	"Start the executiong of the ChartApp"
+	^self
+!
+
+initialize
+	"Load my external JS"
+    self class loadGoogleLoader:[self class loadVisualization:[self begin]]
+! !
+
+!ChartApp class methodsFor: 'not yet classified'!
+
+loadGoogleLoader: callback
+	"Load the Google JSAPI - Use JQuery.ajax() since that is available"
+	<$.ajax({url:"https://www.google.com/jsapi",dataType:"script",success:callback});>
+!
+
+loadVisualization: callback
+	"Use google.load() to load visualization and load the needed packages"
+    |packages|
+    packages := self neededVisualizationPackages.
+    <google.load("visualization","1",{"callback" : callback , "packages":packages});>
+!
+
+neededVisualizationPackages
+"This is a hook for subclasses to define which visualization packages to load."
+	^{}
+! !
+
+Object subclass: #ChartButton
+	instanceVariableNames: 'element clickBlock'
+	package: 'GoogleCharts'!
+
+!ChartButton methodsFor: 'not yet classified'!
+
+activate
+	|button|
+	button := self element asJQuery.
+    button click:[self clickBlock value]
+!
+
+clickBlock
+	^clickBlock
+!
+
+clickBlock: aBlock
+	clickBlock := aBlock
+!
+
+element
+	^element
+!
+
+element: aSymbol
+	element := aSymbol
+! !
+
+!ChartButton class methodsFor: 'not yet classified'!
+
+element: elementSymbol clickBlock: clickBlock
+	^self new element: elementSymbol; clickBlock: clickBlock; activate;yourself
+!
+
+popUpChart: chart atDom: element
+	"Make the chart popup on click of an element"
+    ^self element: element clickBlock:[chart drawChart]
+! !
+
+Object subclass: #GoogleChart
+	instanceVariableNames: 'chartId chartType'
+	package: 'GoogleCharts'!
+
+!GoogleChart methodsFor: 'DOM'!
+
+getElementById: id
+	"Find element by the id in the DOM"
+	^ <document.getElementById(id)>
+! !
+
+!GoogleChart methodsFor: 'abstraction'!
+
+makeData
+	"abstraction - return the data for a google chart"
+  	 ^self subclassresponsibility
+!
+
+makeOptions
+	"Abstract method - return options for a Google Chart"
+   ^	 self subclassresponsibility
+! !
+
+!GoogleChart methodsFor: 'accessor'!
+
+chartId
+	^chartId
+!
+
+chartId: aString
+	chartId := aString
+!
+
+chartType
+	^ chartType
+!
+
+chartType: aString
+	chartType := aString
+! !
+
+!GoogleChart methodsFor: 'chart'!
+
+drawChart
+    |  chart data options|
+     data := self makeData.
+     chart :=self makeChart:self chartId.
+     options :=self makeOptions.
+     <chart.draw(data,options)>
+!
+
+makeChart: id
+"build a chart at specific element id in the DOM and return"
+	|e t|
+    e := self getElementById:id.
+    t := self chartType.
+    ^ <new google.visualization[t](e)>
+! !
+
+!GoogleChart methodsFor: 'data table'!
+
+arrayToDataTable: array
+
+	^ <google.visualization.arrayToDataTable(array)>
+! !
+
+!GoogleChart methodsFor: 'init'!
+
+initialize
+	^self
+! !
+
+!GoogleChart class methodsFor: 'not yet classified'!
+
+chartId: aString
+	^self new chartId:aString;yourself
+! !
+
+GoogleChart subclass: #GaugeChart
+	instanceVariableNames: ''
+	package: 'GoogleCharts'!
+
+!GaugeChart methodsFor: 'not yet classified'!
+
+initialize
+	" Create a Guage with the chartId that identifies the chart graphic placement and the chartType to be created at that id."
+    super initialize.
+    self chartType:'Gauge'.
+	^self
+! !
+
+GoogleChart subclass: #GeoChart
+	instanceVariableNames: ''
+	package: 'GoogleCharts'!
+
+!GeoChart methodsFor: 'not yet classified'!
+
+initialize
+	" Create a Geo Chart"
+    super initialize.
+    self chartType:'GeoChart'.
+	^self
+! !
+
+GoogleChart subclass: #PieChart
+	instanceVariableNames: ''
+	package: 'GoogleCharts'!
+
+!PieChart methodsFor: 'not yet classified'!
+
+initialize
+	super initialize.
+    self chartType:'PieChart'.
+	^self
+! !
+
+GoogleChart subclass: #ScatterChart
+	instanceVariableNames: ''
+	package: 'GoogleCharts'!
+
+!ScatterChart methodsFor: 'not yet classified'!
+
+initialize
+	super initialize.
+    self chartType:'ScatterChart'.
+	^self
+! !
+

+ 148 - 0
examples/googlecharts/st/GoogleChartsExamples.st

@@ -0,0 +1,148 @@
+Smalltalk current createPackage: 'GoogleChartsExamples' properties: #{}!
+GaugeChart subclass: #GaugeChartExample
+	instanceVariableNames: ''
+	package: 'GoogleChartsExamples'!
+
+!GaugeChartExample methodsFor: 'not yet classified'!
+
+makeData
+"Example Gauge Data"
+  ^ self arrayToDataTable: { {'Label'.'Value'}.
+    					{'Memory' . 80}.
+                        {'CPU' . 55}.
+                        {'Network' . 68}}
+!
+
+makeOptions
+"Example Gauge options"
+   ^<{width:400, heigth:120,
+   redFrom:90,redTo:100,
+   yellowFrom:75,yellowTo:90,
+   minorTicks:5}>
+! !
+
+GeoChart subclass: #GeoChartExample
+	instanceVariableNames: ''
+	package: 'GoogleChartsExamples'!
+
+!GeoChartExample methodsFor: 'not yet classified'!
+
+makeData
+"Example Geo Data"
+  ^ self arrayToDataTable: {
+{'City'.   'Population' . 'Area'}.
+        {'Rome'.      2761477 .    1285.31}.
+        {'Milan'.     1324110 .    181.76}.
+        {'Naples'.    959574 .    117.27}.
+        {'Turin'.     907563 .     130.17}.
+        {'Palermo'.   655875 .     158.9}.
+        {'Genoa'.     607906 .   243.60}.
+        {'Bologna'.   380181 .     140.7}.
+        {'Florence'.  371282 .    102.41}.
+        {'Fiumicino'. 67370 .      213.44}.
+        {'Anzio'.     52192 .      43.43}.
+        {'Ciampino'.  38262 .      11} 
+        }
+!
+
+makeOptions
+"Example Geo Options"
+
+   ^<{
+        region: 'IT',
+        displayMode: 'markers',
+        colorAxis: {colors: ['green', 'blue']}
+      }>
+! !
+
+ChartApp subclass: #IndexChartApp
+	instanceVariableNames: ''
+	package: 'GoogleChartsExamples'!
+
+!IndexChartApp methodsFor: 'not yet classified'!
+
+begin
+	"Start the executiong of the ExampleChartApp by connecting each button/graphic pair"
+    PieChartExample new chartId:'pie_chart_div';drawChart.
+    ^super begin
+! !
+
+!IndexChartApp class methodsFor: 'not yet classified'!
+
+neededVisualizationPackages
+"This App only needs a corechart package."
+	^{'corechart'}
+! !
+
+PieChart subclass: #PieChartExample
+	instanceVariableNames: ''
+	package: 'GoogleChartsExamples'!
+
+!PieChartExample methodsFor: 'not yet classified'!
+
+makeData
+	"return a DataTable of example Pie Chart data"
+
+  ^ self arrayToDataTable: { {'Task'.'Hours per Day'}.
+    					{'Work' . 11}.
+                        {'Eat'.2}.
+                        {'Commute'.2}.
+                        {'Watch TV'.2}.
+                        {'Snooze'.7}}
+!
+
+makeOptions
+	"Return a Dictionary of the options in this case only a title"
+	^#{'title' -> 'My Daily Activities'}
+! !
+
+ChartApp subclass: #PopupChartApp
+	instanceVariableNames: ''
+	package: 'GoogleChartsExamples'!
+
+!PopupChartApp methodsFor: 'not yet classified'!
+
+begin
+	"Start the executiong of the ExampleChartApp by connecting each button/graphic pair"
+    ChartButton popUpChart:(PieChartExample chartId:'pie_chart_div') atDom:'#popPieChart' .
+    ChartButton popUpChart:(ScatterChartExample chartId:'scatter_chart_div') atDom:'#popScatterChart'.
+    ChartButton popUpChart:(GaugeChartExample chartId:'gauge_chart_div') atDom:'#popGaugeChart'.
+    ChartButton popUpChart:(GeoChartExample chartId:'geo_markers_chart_div') atDom: '#popGeoMarkersChart'.
+    ^super begin
+! !
+
+!PopupChartApp class methodsFor: 'not yet classified'!
+
+neededVisualizationPackages
+"This is a hook for subclasses to define which visualization packages to load."
+	^{'corechart'.'gauge'.'geochart'}
+! !
+
+ScatterChart subclass: #ScatterChartExample
+	instanceVariableNames: ''
+	package: 'GoogleChartsExamples'!
+
+!ScatterChartExample methodsFor: 'not yet classified'!
+
+makeData
+  "Return the example dataset"
+  ^ self arrayToDataTable: { 
+  							{'Age'.'Weight'}.
+                            {8 . 11} . 
+                            { 4 . 5.5} . 
+                            { 11 . 14 } . 
+                            { 4 . 5}. 
+                            {3 . 3} . 
+                            {6.5 . 7}}
+!
+
+makeOptions
+"options for example dataset"
+   ^<{
+          title: 'Age vs. Weight comparison',
+          hAxis: {title: 'Age', minValue: 0, maxValue: 15},
+          vAxis: {title: 'Weight', minValue: 0, maxValue: 15},
+          legend: 'none'
+        }>
+! !
+

+ 1 - 1
index.html

@@ -12,7 +12,7 @@
   </head> 
   <body> 
     
-    <a href="http://github.com/NicolasPetton/amber"><img style="position: absolute; top: 0; left: 0; border: 0;" src="https://assets.github.com/img/bec6c51521dcc8148146135149fe06a9cc737577?repo=&url=http%3A%2F%2Fs3.amazonaws.com%2Fgithub%2Fribbons%2Fforkme_left_darkblue_121621.png&path=" alt="Fork me on GitHub"></a> 
+    <a href="http://github.com/NicolasPetton/amber"><img style="position: absolute; top: 0; left: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_left_orange_ff7600.png" alt="Fork me on GitHub"></a>
     
     <div id="wrapper"> 
       

File diff suppressed because it is too large
+ 0 - 6
js/IDE.deploy.js


File diff suppressed because it is too large
+ 0 - 6
js/IDE.js


+ 18 - 14
js/Kernel-Methods.deploy.js

@@ -298,20 +298,24 @@ smalltalk.addMethod(
 "_category_",
 smalltalk.method({
 selector: "category:",
-fn: function (aString) {
-    var self = this;
-    var $1;
-    var oldCategory;
-    oldCategory = smalltalk.send(self, "_category", []);
-    smalltalk.send(self, "_basicAt_put_", ["category", aString]);
-    $1 = smalltalk.send(self, "_methodClass", []);
-    if (($receiver = $1) == nil || $receiver == undefined) {
-    } else {
-        smalltalk.send(smalltalk.send(smalltalk.send(self, "_methodClass", []), "_organizer", []), "_addElement_", [aString]);
-        smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_methodClass", []), "_methods", []), "_select_", [function (each) {return smalltalk.send(smalltalk.send(each, "_category", []), "__eq", [oldCategory]);}]), "_ifEmpty_", [function () {return smalltalk.send(smalltalk.send(smalltalk.send(self, "_methodClass", []), "_organizer", []), "_removeElement_", [oldCategory]);}]);
-    }
-    return self;
-}
+fn: function (aString){
+var self=this;
+var $1;
+var oldCategory;
+oldCategory=smalltalk.send(self,"_category",[]);
+smalltalk.send(self,"_basicAt_put_",["category",aString]);
+$1=smalltalk.send(self,"_methodClass",[]);
+if(($receiver = $1) == nil || $receiver == undefined){
+$1;
+} else {
+smalltalk.send(smalltalk.send(smalltalk.send(self,"_methodClass",[]),"_organization",[]),"_addElement_",[aString]);
+smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self,"_methodClass",[]),"_methods",[]),"_select_",[(function(each){
+return smalltalk.send(smalltalk.send(each,"_category",[]),"__eq",[oldCategory]);
+})]),"_ifEmpty_",[(function(){
+return smalltalk.send(smalltalk.send(smalltalk.send(self,"_methodClass",[]),"_organization",[]),"_removeElement_",[oldCategory]);
+})]);
+};
+return self}
 }),
 smalltalk.CompiledMethod);
 

+ 20 - 16
js/Kernel-Methods.js

@@ -416,23 +416,27 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "category:",
 category: 'accessing',
-fn: function (aString) {
-    var self = this;
-    var $1;
-    var oldCategory;
-    oldCategory = smalltalk.send(self, "_category", []);
-    smalltalk.send(self, "_basicAt_put_", ["category", aString]);
-    $1 = smalltalk.send(self, "_methodClass", []);
-    if (($receiver = $1) == nil || $receiver == undefined) {
-    } else {
-        smalltalk.send(smalltalk.send(smalltalk.send(self, "_methodClass", []), "_organizer", []), "_addElement_", [aString]);
-        smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_methodClass", []), "_methods", []), "_select_", [function (each) {return smalltalk.send(smalltalk.send(each, "_category", []), "__eq", [oldCategory]);}]), "_ifEmpty_", [function () {return smalltalk.send(smalltalk.send(smalltalk.send(self, "_methodClass", []), "_organizer", []), "_removeElement_", [oldCategory]);}]);
-    }
-    return self;
-},
+fn: function (aString){
+var self=this;
+var $1;
+var oldCategory;
+oldCategory=smalltalk.send(self,"_category",[]);
+smalltalk.send(self,"_basicAt_put_",["category",aString]);
+$1=smalltalk.send(self,"_methodClass",[]);
+if(($receiver = $1) == nil || $receiver == undefined){
+$1;
+} else {
+smalltalk.send(smalltalk.send(smalltalk.send(self,"_methodClass",[]),"_organization",[]),"_addElement_",[aString]);
+smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self,"_methodClass",[]),"_methods",[]),"_select_",[(function(each){
+return smalltalk.send(smalltalk.send(each,"_category",[]),"__eq",[oldCategory]);
+})]),"_ifEmpty_",[(function(){
+return smalltalk.send(smalltalk.send(smalltalk.send(self,"_methodClass",[]),"_organization",[]),"_removeElement_",[oldCategory]);
+})]);
+};
+return self},
 args: ["aString"],
-source: "category: aString\x0a\x09| oldCategory |\x0a    oldCategory := self category.\x0a\x09self basicAt: 'category' put: aString.\x0a    \x0a    self methodClass ifNotNil: [\x0a    \x09self methodClass organizer addElement: aString.\x0a    \x0a\x09\x09(self methodClass methods \x0a    \x09\x09select: [ :each | each category = oldCategory ])\x0a        \x09ifEmpty: [ self methodClass organizer removeElement: oldCategory ] ]",
-messageSends: ["category", "basicAt:put:", "ifNotNil:", "addElement:", "organizer", "methodClass", "ifEmpty:", "removeElement:", "select:", "=", "methods"],
+source: "category: aString\x0a\x09| oldCategory |\x0a    oldCategory := self category.\x0a\x09self basicAt: 'category' put: aString.\x0a    \x0a    self methodClass ifNotNil: [\x0a    \x09self methodClass organization addElement: aString.\x0a    \x0a\x09\x09(self methodClass methods \x0a    \x09\x09select: [ :each | each category = oldCategory ])\x0a        \x09ifEmpty: [ self methodClass organization removeElement: oldCategory ] ]",
+messageSends: ["category", "basicAt:put:", "ifNotNil:", "addElement:", "organization", "methodClass", "ifEmpty:", "removeElement:", "select:", "=", "methods"],
 referencedClasses: []
 }),
 smalltalk.CompiledMethod);

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

@@ -322,6 +322,24 @@ return self}
 }),
 smalltalk.BooleanTest);
 
+smalltalk.addMethod(
+"_testNonBooleanError",
+smalltalk.method({
+selector: "testNonBooleanError",
+fn: function (){
+var self=this;
+var b;
+b= '' ;
+;
+smalltalk.send(self,"_should_raise_",[(function(){
+if(smalltalk.assert(self["@nonBoolean"])){
+} else {
+};
+}),(smalltalk.NonBooleanReceiver || NonBooleanReceiver)]);
+return self}
+}),
+smalltalk.BooleanTest);
+
 
 
 smalltalk.addClass('ClassBuilderTest', smalltalk.TestCase, ['builder', 'theClass'], 'Kernel-Tests');

+ 23 - 0
js/Kernel-Tests.js

@@ -387,6 +387,29 @@ referencedClasses: []
 }),
 smalltalk.BooleanTest);
 
+smalltalk.addMethod(
+"_testNonBooleanError",
+smalltalk.method({
+selector: "testNonBooleanError",
+category: 'tests',
+fn: function (){
+var self=this;
+var b;
+b= '' ;
+;
+smalltalk.send(self,"_should_raise_",[(function(){
+if(smalltalk.assert(self["@nonBoolean"])){
+} else {
+};
+}),(smalltalk.NonBooleanReceiver || NonBooleanReceiver)]);
+return self},
+args: [],
+source: "testNonBooleanError\x0a\x09|b|\x0a    b := < '' >.\x0a    self should: [nonBoolean ifTrue: [] ifFalse: []] raise: NonBooleanReceiver",
+messageSends: ["should:raise:", "ifTrue:ifFalse:"],
+referencedClasses: ["NonBooleanReceiver"]
+}),
+smalltalk.BooleanTest);
+
 
 
 smalltalk.addClass('ClassBuilderTest', smalltalk.TestCase, ['builder', 'theClass'], 'Kernel-Tests');

+ 177 - 17
js/SUnit.deploy.js

@@ -1,4 +1,29 @@
 smalltalk.addPackage('SUnit', {});
+smalltalk.addClass('ResultAnnouncement', smalltalk.Object, ['result'], 'SUnit');
+smalltalk.addMethod(
+"_result",
+smalltalk.method({
+selector: "result",
+fn: function (){
+var self=this;
+return self["@result"];
+}
+}),
+smalltalk.ResultAnnouncement);
+
+smalltalk.addMethod(
+"_result_",
+smalltalk.method({
+selector: "result:",
+fn: function (aTestResult){
+var self=this;
+self["@result"]=aTestResult;
+return self}
+}),
+smalltalk.ResultAnnouncement);
+
+
+
 smalltalk.addClass('TestCase', smalltalk.Object, ['testSelector'], 'SUnit');
 smalltalk.addMethod(
 "_assert_",
@@ -52,29 +77,29 @@ fn: function (aBoolean) {
 smalltalk.TestCase);
 
 smalltalk.addMethod(
-"_performTestFor_",
+"_performTest",
 smalltalk.method({
-selector: "performTestFor:",
-fn: function (aResult) {
-    var self = this;
-    smalltalk.send(function () {return smalltalk.send(function () {return smalltalk.send(self, "_perform_", [smalltalk.send(self, "_selector", [])]);}, "_on_do_", [smalltalk.TestFailure || TestFailure, function (ex) {return smalltalk.send(aResult, "_addFailure_", [self]);}]);}, "_on_do_", [smalltalk.Error || Error, function (ex) {return smalltalk.send(aResult, "_addError_", [self]);}]);
-    return self;
-}
+selector: "performTest",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_perform_",[smalltalk.send(self,"_selector",[])]);
+return self}
 }),
 smalltalk.TestCase);
 
 smalltalk.addMethod(
-"_runCaseFor_",
+"_runCase",
 smalltalk.method({
-selector: "runCaseFor:",
-fn: function (aTestResult) {
-    var self = this;
-    smalltalk.send(self, "_setUp", []);
-    smalltalk.send(aTestResult, "_increaseRuns", []);
-    smalltalk.send(self, "_performTestFor_", [aTestResult]);
-    smalltalk.send(self, "_tearDown", []);
-    return self;
-}
+selector: "runCase",
+fn: function (){
+var self=this;
+smalltalk.send((function(){
+smalltalk.send(self,"_setUp",[]);
+return smalltalk.send(self,"_performTest",[]);
+}),"_ensure_",[(function(){
+return smalltalk.send(self,"_tearDown",[]);
+})]);
+return self}
 }),
 smalltalk.TestCase);
 
@@ -352,6 +377,42 @@ fn: function () {
 }),
 smalltalk.TestResult);
 
+smalltalk.addMethod(
+"_nextRunDo_",
+smalltalk.method({
+selector: "nextRunDo:",
+fn: function (aBlock){
+var self=this;
+var $2,$1;
+$2=smalltalk.send(smalltalk.send(self,"_runs",[]),"__eq_eq",[smalltalk.send(self,"_total",[])]);
+if(! smalltalk.assert($2)){
+$1=smalltalk.send(aBlock,"_value_",[smalltalk.send(smalltalk.send(self,"_runs",[]),"__plus",[(1)])]);
+};
+return $1;
+}
+}),
+smalltalk.TestResult);
+
+smalltalk.addMethod(
+"_runCase_",
+smalltalk.method({
+selector: "runCase:",
+fn: function (aTestCase){
+var self=this;
+smalltalk.send((function(){
+return smalltalk.send((function(){
+smalltalk.send(self,"_increaseRuns",[]);
+return smalltalk.send(aTestCase,"_runCase",[]);
+}),"_on_do_",[(smalltalk.TestFailure || TestFailure),(function(ex){
+return smalltalk.send(self,"_addFailure_",[aTestCase]);
+})]);
+}),"_on_do_",[(smalltalk.Error || Error),(function(ex){
+return smalltalk.send(self,"_addError_",[aTestCase]);
+})]);
+return self}
+}),
+smalltalk.TestResult);
+
 smalltalk.addMethod(
 "_runs",
 smalltalk.method({
@@ -422,3 +483,102 @@ smalltalk.TestResult);
 
 
 
+smalltalk.addClass('TestSuiteRunner', smalltalk.Object, ['suite', 'result', 'announcer'], 'SUnit');
+smalltalk.addMethod(
+"_announcer",
+smalltalk.method({
+selector: "announcer",
+fn: function (){
+var self=this;
+return self["@announcer"];
+}
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.Object);
+self["@announcer"]=smalltalk.send((smalltalk.Announcer || Announcer),"_new",[]);
+self["@result"]=smalltalk.send((smalltalk.TestResult || TestResult),"_new",[]);
+return self}
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_result",
+smalltalk.method({
+selector: "result",
+fn: function (){
+var self=this;
+return self["@result"];
+}
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_run",
+smalltalk.method({
+selector: "run",
+fn: function (){
+var self=this;
+var worker;
+smalltalk.send(self["@result"],"_total_",[smalltalk.send(self["@suite"],"_size",[])]);
+smalltalk.send(self["@announcer"],"_announce_",[smalltalk.send(smalltalk.send((smalltalk.ResultAnnouncement || ResultAnnouncement),"_new",[]),"_result_",[self["@result"]])]);
+worker=(function(){
+return smalltalk.send(self["@result"],"_nextRunDo_",[(function(index){
+return smalltalk.send((function(){
+return smalltalk.send(self["@result"],"_runCase_",[smalltalk.send(self["@suite"],"_at_",[index])]);
+}),"_ensure_",[(function(){
+smalltalk.send(worker,"_valueWithTimeout_",[(0)]);
+return smalltalk.send(self["@announcer"],"_announce_",[smalltalk.send(smalltalk.send((smalltalk.ResultAnnouncement || ResultAnnouncement),"_new",[]),"_result_",[self["@result"]])]);
+})]);
+})]);
+});
+smalltalk.send(smalltalk.send(smalltalk.send(self["@suite"],"_size",[]),"_min_",[(25)]),"_timesRepeat_",[(function(){
+return smalltalk.send(worker,"_valueWithTimeout_",[(0)]);
+})]);
+return self}
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_suite_",
+smalltalk.method({
+selector: "suite:",
+fn: function (aCollection){
+var self=this;
+self["@suite"]=aCollection;
+return self}
+}),
+smalltalk.TestSuiteRunner);
+
+
+smalltalk.addMethod(
+"_new",
+smalltalk.method({
+selector: "new",
+fn: function (){
+var self=this;
+smalltalk.send(self,"_shouldNotImplement",[]);
+return self}
+}),
+smalltalk.TestSuiteRunner.klass);
+
+smalltalk.addMethod(
+"_on_",
+smalltalk.method({
+selector: "on:",
+fn: function (aCollection){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(self,"_new",[],smalltalk.Object.klass),"_suite_",[aCollection]);
+return $1;
+}
+}),
+smalltalk.TestSuiteRunner.klass);
+
+

+ 239 - 24
js/SUnit.js

@@ -1,4 +1,39 @@
 smalltalk.addPackage('SUnit', {});
+smalltalk.addClass('ResultAnnouncement', smalltalk.Object, ['result'], 'SUnit');
+smalltalk.addMethod(
+"_result",
+smalltalk.method({
+selector: "result",
+category: 'accessing',
+fn: function (){
+var self=this;
+return self["@result"];
+},
+args: [],
+source: "result\x0a\x09^result",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ResultAnnouncement);
+
+smalltalk.addMethod(
+"_result_",
+smalltalk.method({
+selector: "result:",
+category: 'accessing',
+fn: function (aTestResult){
+var self=this;
+self["@result"]=aTestResult;
+return self},
+args: ["aTestResult"],
+source: "result: aTestResult\x0a\x09result := aTestResult",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ResultAnnouncement);
+
+
+
 smalltalk.addClass('TestCase', smalltalk.Object, ['testSelector'], 'SUnit');
 smalltalk.addMethod(
 "_assert_",
@@ -72,38 +107,38 @@ referencedClasses: []
 smalltalk.TestCase);
 
 smalltalk.addMethod(
-"_performTestFor_",
+"_performTest",
 smalltalk.method({
-selector: "performTestFor:",
+selector: "performTest",
 category: 'running',
-fn: function (aResult) {
-    var self = this;
-    smalltalk.send(function () {return smalltalk.send(function () {return smalltalk.send(self, "_perform_", [smalltalk.send(self, "_selector", [])]);}, "_on_do_", [smalltalk.TestFailure || TestFailure, function (ex) {return smalltalk.send(aResult, "_addFailure_", [self]);}]);}, "_on_do_", [smalltalk.Error || Error, function (ex) {return smalltalk.send(aResult, "_addError_", [self]);}]);
-    return self;
-},
-args: ["aResult"],
-source: "performTestFor: aResult\x0a\x09[[self perform: self selector]\x0a\x09\x09on: TestFailure do: [:ex | aResult addFailure: self]]\x0a\x09\x09on: Error do: [:ex | aResult addError: self]",
-messageSends: ["on:do:", "addError:", "addFailure:", "perform:", "selector"],
-referencedClasses: ["Error", "TestFailure"]
+fn: function (){
+var self=this;
+smalltalk.send(self,"_perform_",[smalltalk.send(self,"_selector",[])]);
+return self},
+args: [],
+source: "performTest\x0a\x09self perform: self selector\x0a",
+messageSends: ["perform:", "selector"],
+referencedClasses: []
 }),
 smalltalk.TestCase);
 
 smalltalk.addMethod(
-"_runCaseFor_",
+"_runCase",
 smalltalk.method({
-selector: "runCaseFor:",
+selector: "runCase",
 category: 'running',
-fn: function (aTestResult) {
-    var self = this;
-    smalltalk.send(self, "_setUp", []);
-    smalltalk.send(aTestResult, "_increaseRuns", []);
-    smalltalk.send(self, "_performTestFor_", [aTestResult]);
-    smalltalk.send(self, "_tearDown", []);
-    return self;
-},
-args: ["aTestResult"],
-source: "runCaseFor: aTestResult\x0a\x09self setUp.\x0a\x09aTestResult increaseRuns.\x0a\x09self performTestFor: aTestResult.\x0a\x09self tearDown",
-messageSends: ["setUp", "increaseRuns", "performTestFor:", "tearDown"],
+fn: function (){
+var self=this;
+smalltalk.send((function(){
+smalltalk.send(self,"_setUp",[]);
+return smalltalk.send(self,"_performTest",[]);
+}),"_ensure_",[(function(){
+return smalltalk.send(self,"_tearDown",[]);
+})]);
+return self},
+args: [],
+source: "runCase\x0a\x09[\x09self setUp.\x0a\x09\x09self performTest ] ensure: [\x0a\x09\x09self tearDown.\x0a\x09\x09\x22self cleanUpInstanceVariables\x22 ]\x0a",
+messageSends: ["ensure:", "tearDown", "setUp", "performTest"],
 referencedClasses: []
 }),
 smalltalk.TestCase);
@@ -487,6 +522,52 @@ referencedClasses: ["Date", "Array"]
 }),
 smalltalk.TestResult);
 
+smalltalk.addMethod(
+"_nextRunDo_",
+smalltalk.method({
+selector: "nextRunDo:",
+category: 'running',
+fn: function (aBlock){
+var self=this;
+var $2,$1;
+$2=smalltalk.send(smalltalk.send(self,"_runs",[]),"__eq_eq",[smalltalk.send(self,"_total",[])]);
+if(! smalltalk.assert($2)){
+$1=smalltalk.send(aBlock,"_value_",[smalltalk.send(smalltalk.send(self,"_runs",[]),"__plus",[(1)])]);
+};
+return $1;
+},
+args: ["aBlock"],
+source: "nextRunDo: aBlock\x0a\x22Runs aBlock with index of next run\x0aor does nothing if no more runs\x22\x0a^self runs == self total\x0a\x09ifFalse: [ aBlock value: self runs + 1 ]",
+messageSends: ["ifFalse:", "value:", "+", "runs", "==", "total"],
+referencedClasses: []
+}),
+smalltalk.TestResult);
+
+smalltalk.addMethod(
+"_runCase_",
+smalltalk.method({
+selector: "runCase:",
+category: 'running',
+fn: function (aTestCase){
+var self=this;
+smalltalk.send((function(){
+return smalltalk.send((function(){
+smalltalk.send(self,"_increaseRuns",[]);
+return smalltalk.send(aTestCase,"_runCase",[]);
+}),"_on_do_",[(smalltalk.TestFailure || TestFailure),(function(ex){
+return smalltalk.send(self,"_addFailure_",[aTestCase]);
+})]);
+}),"_on_do_",[(smalltalk.Error || Error),(function(ex){
+return smalltalk.send(self,"_addError_",[aTestCase]);
+})]);
+return self},
+args: ["aTestCase"],
+source: "runCase: aTestCase\x0a\x09[[\x09self increaseRuns.\x0a    \x09aTestCase runCase]\x0a\x09on: TestFailure do: [:ex | self addFailure: aTestCase]]\x0a\x09on: Error do: [:ex | self addError: aTestCase]\x0a",
+messageSends: ["on:do:", "addError:", "addFailure:", "increaseRuns", "runCase"],
+referencedClasses: ["Error", "TestFailure"]
+}),
+smalltalk.TestResult);
+
 smalltalk.addMethod(
 "_runs",
 smalltalk.method({
@@ -582,3 +663,137 @@ smalltalk.TestResult);
 
 
 
+smalltalk.addClass('TestSuiteRunner', smalltalk.Object, ['suite', 'result', 'announcer'], 'SUnit');
+smalltalk.addMethod(
+"_announcer",
+smalltalk.method({
+selector: "announcer",
+category: 'accessing',
+fn: function (){
+var self=this;
+return self["@announcer"];
+},
+args: [],
+source: "announcer\x0a\x09^announcer",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'initialization',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_initialize",[],smalltalk.Object);
+self["@announcer"]=smalltalk.send((smalltalk.Announcer || Announcer),"_new",[]);
+self["@result"]=smalltalk.send((smalltalk.TestResult || TestResult),"_new",[]);
+return self},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a\x09announcer := Announcer new.\x0a    result := TestResult new",
+messageSends: ["initialize", "new"],
+referencedClasses: ["Announcer", "TestResult"]
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_result",
+smalltalk.method({
+selector: "result",
+category: 'accessing',
+fn: function (){
+var self=this;
+return self["@result"];
+},
+args: [],
+source: "result\x0a\x09^result",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_run",
+smalltalk.method({
+selector: "run",
+category: 'actions',
+fn: function (){
+var self=this;
+var worker;
+smalltalk.send(self["@result"],"_total_",[smalltalk.send(self["@suite"],"_size",[])]);
+smalltalk.send(self["@announcer"],"_announce_",[smalltalk.send(smalltalk.send((smalltalk.ResultAnnouncement || ResultAnnouncement),"_new",[]),"_result_",[self["@result"]])]);
+worker=(function(){
+return smalltalk.send(self["@result"],"_nextRunDo_",[(function(index){
+return smalltalk.send((function(){
+return smalltalk.send(self["@result"],"_runCase_",[smalltalk.send(self["@suite"],"_at_",[index])]);
+}),"_ensure_",[(function(){
+smalltalk.send(worker,"_valueWithTimeout_",[(0)]);
+return smalltalk.send(self["@announcer"],"_announce_",[smalltalk.send(smalltalk.send((smalltalk.ResultAnnouncement || ResultAnnouncement),"_new",[]),"_result_",[self["@result"]])]);
+})]);
+})]);
+});
+smalltalk.send(smalltalk.send(smalltalk.send(self["@suite"],"_size",[]),"_min_",[(25)]),"_timesRepeat_",[(function(){
+return smalltalk.send(worker,"_valueWithTimeout_",[(0)]);
+})]);
+return self},
+args: [],
+source: "run\x0a\x09| worker |\x0a\x09result total: suite size.\x0a    announcer announce: (ResultAnnouncement new result: result).\x0a    worker := [ result nextRunDo: [ :index |\x0a\x09\x09[ result runCase: (suite at: index) ]\x0a\x09\x09ensure: [ worker valueWithTimeout: 0.\x0a        \x09announcer announce: (ResultAnnouncement new result: result) ]]].\x0a\x09(suite size min: 25) timesRepeat: [ worker valueWithTimeout: 0 ]",
+messageSends: ["total:", "size", "announce:", "result:", "new", "nextRunDo:", "ensure:", "valueWithTimeout:", "runCase:", "at:", "timesRepeat:", "min:"],
+referencedClasses: ["ResultAnnouncement"]
+}),
+smalltalk.TestSuiteRunner);
+
+smalltalk.addMethod(
+"_suite_",
+smalltalk.method({
+selector: "suite:",
+category: 'accessing',
+fn: function (aCollection){
+var self=this;
+self["@suite"]=aCollection;
+return self},
+args: ["aCollection"],
+source: "suite: aCollection\x0a\x09suite := aCollection",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TestSuiteRunner);
+
+
+smalltalk.addMethod(
+"_new",
+smalltalk.method({
+selector: "new",
+category: 'instance creation',
+fn: function (){
+var self=this;
+smalltalk.send(self,"_shouldNotImplement",[]);
+return self},
+args: [],
+source: "new\x0a\x09self shouldNotImplement",
+messageSends: ["shouldNotImplement"],
+referencedClasses: []
+}),
+smalltalk.TestSuiteRunner.klass);
+
+smalltalk.addMethod(
+"_on_",
+smalltalk.method({
+selector: "on:",
+category: 'instance creation',
+fn: function (aCollection){
+var self=this;
+var $1;
+$1=smalltalk.send(smalltalk.send(self,"_new",[],smalltalk.Object.klass),"_suite_",[aCollection]);
+return $1;
+},
+args: ["aCollection"],
+source: "on: aCollection\x0a\x09^super new suite: aCollection",
+messageSends: ["suite:", "new"],
+referencedClasses: []
+}),
+smalltalk.TestSuiteRunner.klass);
+
+

+ 30 - 29
js/boot.js

@@ -214,8 +214,8 @@ function Smalltalk() {
 			that.fn = function() {},
 			spec.superclass ? spec.superclass.klass.fn : SmalltalkClass
 		);
-		setupClass(that);
 		that.instanceClass = new that.fn();
+        setupClass(that);
 		return that;
 	}
 
@@ -479,21 +479,24 @@ function Smalltalk() {
 
     st.removeMethod = function(method) {
         var protocol = method.category;
-        var shouldDeleteProtocol;
         var klass = method.methodClass;
 
         delete klass.fn.prototype[st.selector(method.selector)];
 	    delete klass.methods[method.selector];
 
-        for(var i=0; i<klass.methods; i++) {
-            if(klass.methods[i].category == protocol) {
-                shouldDeleteProtocol = true;
-			}
-		}
-		if(shouldDeleteProtocol) {
-            klass.organization.elements.removeElement(protocol);
-		}
-	};
+		var selectors = Object.keys(klass.methods);
+		var shouldDeleteProtocol = true;
+
+		for(var i = 0, l = selectors.length; i<l; i++) {
+            if(klass.methods[selectors[i]].category === protocol) {
+                shouldDeleteProtocol = false;
+				break;
+            };
+        };
+        if(shouldDeleteProtocol) {
+            klass.organization.elements.removeElement(protocol)
+        };
+    };
 
 	/* Handles unhandled errors during message sends */
 
@@ -723,13 +726,12 @@ function Smalltalk() {
     /* Boolean assertion */
 
     st.assert = function(boolean) {
-		if(boolean.klass === st.Boolean) {
-			return boolean;
-		} else {
-			st.NonBooleanReceiver._new()._object_(boolean)._signal();
-			//TODO return sane value
-		}
-	};
+        if ((undefined !== boolean) && (boolean.klass === smalltalk.Boolean)) {
+            return boolean;
+        } else {
+            st.NonBooleanReceiver._new()._object_(boolean)._signal();
+        }
+    };
 
     /* Smalltalk initialization. Called on page load */
 
@@ -754,13 +756,6 @@ function SmalltalkMethodContext(receiver, selector, temps, home) {
     this.selector    = selector;
 	this.temps       = temps || {};
 	this.homeContext = home;
-
-    // TODO: adapt.
-    // this.resume = function() {
-    //     //Brutally set the receiver as thisContext, then re-enter the function
-    //     smalltalk.thisContext = this;
-    //     return this.method.apply(receiver, temps);
-    // };
 }
 
 inherits(SmalltalkMethodContext, SmalltalkObject);
@@ -776,15 +771,21 @@ SmalltalkMethodContext.prototype.copy = function() {
 	);
 };
 
+SmalltalkMethodContext.prototype.resume = function() {
+    //Brutally set the receiver as thisContext, then re-enter the function
+    smalltalk.thisContext = this;
+    return this.method.apply(receiver, temps);
+};
+
+/* Global Smalltalk objects. */
+
+var nil = new SmalltalkNil();
+var smalltalk = new Smalltalk();
 
 if(this.jQuery) {
 	this.jQuery.allowJavaScriptCalls = true;
 }
 
-
-var nil       = new SmalltalkNil();
-var smalltalk = new Smalltalk();
-
 /*
  * Answer the smalltalk representation of o.
  * Used in message sends

+ 38 - 6
server/FileServer.st

@@ -25,6 +25,15 @@ initialize
 	fs := self require: 'fs'.
 	util := self require: 'util'.
 	url := self require: 'url'
+!
+
+checkDirectoryLayout
+	(path existsSync: self basePath, 'index.html') ifFalse: [
+		console warn: 'Warning: project directory does not contain index.html'].
+	(path existsSync: self basePath, 'st') ifFalse: [
+		console warn: 'Warning: project directory is missing an "st" directory'].
+	(path existsSync: self basePath, 'js') ifFalse: [
+		console warn: 'Warning: roject directory is missing a "js" directory'].
 ! !
 
 !FileServer methodsFor: 'private'!
@@ -69,8 +78,17 @@ handleGETRequest: aRequest respondTo: aResponse
 !
 
 handlePUTRequest: aRequest respondTo: aResponse
-	|stream |
-	stream := fs createWriteStream: '.' , aRequest url.
+	| file stream |
+	file := '.', aRequest url.
+	stream := fs createWriteStream: file.
+	stream on: 'error' do: [:error |
+		"TODO: notify Amber about the error, otherwise the user might not notice and lose his work."
+		console warn: 'Error creating WriteStream for file ', file.
+		console warn: '    Did you forget to create the necessary js/ or st/ directory in your project?'.
+		console warn: '    The exact error is: ', error].
+	stream writable ifFalse: [
+		console log: 'Could not write to ', file.
+		^nil].
         aRequest setEncoding: 'utf8'.
         aRequest on: 'data' do: [:data | stream write: data].
 
@@ -98,7 +116,9 @@ respondFileNamed: aFilename to: aResponse
 
 	fs readFile: filename do: [:ex :file |
 		ex notNil 
-			ifTrue: [self respondInternalErrorTo: aResponse]
+			ifTrue: [
+				console log: filename, ' does not exist'.
+				self respondInternalErrorTo: aResponse]
 			ifFalse: [
 				type := self class mimeTypeFor: filename.
 				type = 'application/javascript'
@@ -132,8 +152,10 @@ startOn: aPort
 
 start
 	(http createServer: [:request :response |
-	 	self handleRequest: request respondTo: response]) listen: self port.
-	console log: 'Starting file server on port ', self port asString
+	      self handleRequest: request respondTo: response])
+	      on: 'error' do: [:error | console log: 'Error starting server: ', error];
+	      on: 'listening' do: [console log: 'Starting file server on port ', self port asString];
+	      listen: self port.
 ! !
 
 FileServer class instanceVariableNames: 'port mimeTypes'!
@@ -573,6 +595,16 @@ mimeTypeFor: aString
 !FileServer class methodsFor: 'initialization'!
 
 main
-	^self new startOn: self port
+	| fileServer arguments portOption port|
+	fileServer := self new.
+	fileServer checkDirectoryLayout.
+
+	arguments := process argv.
+	portOption := arguments at: 3 ifAbsent: [nil].
+	port := arguments at: 4 ifAbsent: [nil].
+	('-p' = portOption and: [port notNil]) ifTrue: [
+		fileServer port: port.
+	].
+	^fileServer start
 ! !
 

File diff suppressed because it is too large
+ 353 - 232
server/server.js


+ 14 - 13
st/IDE.st

@@ -1226,7 +1226,8 @@ updateSourceAndButtons
 				with: [ |option|
 					html option
 						with: 'References';
-						at: 'disabled' put: 'disabled'.
+						at: 'disabled' put: 'disabled';
+                        at: 'selected' put: 'selected'.
 					html option
 						class: 'important';
 						with: selectedMethod selector.
@@ -2058,17 +2059,17 @@ performFailure: aTestCase
 !
 
 run: aCollection
-	result := TestResult new.
-	self 
-		updateStatusDiv;
-		updateMethodsList.
-	self progressBar updatePercent: 0.
-	result total: aCollection size.
-	aCollection do: [:each | 
-		[each runCaseFor: result.
-		self progressBar updatePercent: result runs / result total * 100.
-		self updateStatusDiv.
-		self updateMethodsList] valueWithTimeout: 100].
+| worker |
+	worker := TestSuiteRunner on: aCollection.
+	result := worker result.
+    worker announcer on: ResultAnnouncement do: [:ann |
+    	ann result == result ifTrue: [
+			self progressBar updatePercent: result runs / result total * 100.
+			self updateStatusDiv.
+			self updateMethodsList
+  		]
+	].
+	worker run
 !
 
 selectAllCategories
@@ -2124,7 +2125,7 @@ printFailures
 !
 
 printPasses
-	^(self result total - self result errors size - self result failures size) asString , ' passes, '
+	^(self result runs - self result errors size - self result failures size) asString , ' passes, '
 !
 
 printTotal

+ 2 - 2
st/Kernel-Methods.st

@@ -167,11 +167,11 @@ category: aString
 	self basicAt: 'category' put: aString.
     
     self methodClass ifNotNil: [
-    	self methodClass organizer addElement: aString.
+    	self methodClass organization addElement: aString.
     
 		(self methodClass methods 
     		select: [ :each | each category = oldCategory ])
-        	ifEmpty: [ self methodClass organizer removeElement: oldCategory ] ]
+        	ifEmpty: [ self methodClass organization removeElement: oldCategory ] ]
 !
 
 fn

+ 6 - 0
st/Kernel-Tests.st

@@ -150,6 +150,12 @@ testLogicKeywords
 		assert: (false or: [ 1 > 0 ]); 
 		assert: ((1 > 0) or: [ false ]); 
 		assert: ((1 > 0) or: [ 1 > 2 ])
+!
+
+testNonBooleanError
+	|b|
+    b := < '' >.
+    self should: [nonBoolean ifTrue: [] ifFalse: []] raise: NonBooleanReceiver
 ! !
 
 TestCase subclass: #ClassBuilderTest

+ 86 - 9
st/SUnit.st

@@ -1,4 +1,18 @@
 Smalltalk current createPackage: 'SUnit' properties: #{}!
+Object subclass: #ResultAnnouncement
+	instanceVariableNames: 'result'
+	package: 'SUnit'!
+
+!ResultAnnouncement methodsFor: 'accessing'!
+
+result
+	^result
+!
+
+result: aTestResult
+	result := aTestResult
+! !
+
 Object subclass: #TestCase
 	instanceVariableNames: 'testSelector'
 	package: 'SUnit'!
@@ -23,17 +37,15 @@ signalFailure: aString
 
 !TestCase methodsFor: 'running'!
 
-performTestFor: aResult
-	[[self perform: self selector]
-		on: TestFailure do: [:ex | aResult addFailure: self]]
-		on: Error do: [:ex | aResult addError: self]
+performTest
+	self perform: self selector
 !
 
-runCaseFor: aTestResult
-	self setUp.
-	aTestResult increaseRuns.
-	self performTestFor: aTestResult.
-	self tearDown
+runCase
+	[	self setUp.
+		self performTest ] ensure: [
+		self tearDown.
+		"self cleanUpInstanceVariables" ]
 !
 
 setUp
@@ -180,3 +192,68 @@ initialize
 	total := 0
 ! !
 
+!TestResult methodsFor: 'running'!
+
+nextRunDo: aBlock
+"Runs aBlock with index of next run
+or does nothing if no more runs"
+^self runs == self total
+	ifFalse: [ aBlock value: self runs + 1 ]
+!
+
+runCase: aTestCase
+	[[	self increaseRuns.
+    	aTestCase runCase]
+	on: TestFailure do: [:ex | self addFailure: aTestCase]]
+	on: Error do: [:ex | self addError: aTestCase]
+! !
+
+Object subclass: #TestSuiteRunner
+	instanceVariableNames: 'suite result announcer'
+	package: 'SUnit'!
+
+!TestSuiteRunner methodsFor: 'accessing'!
+
+announcer
+	^announcer
+!
+
+result
+	^result
+!
+
+suite: aCollection
+	suite := aCollection
+! !
+
+!TestSuiteRunner methodsFor: 'actions'!
+
+run
+	| worker |
+	result total: suite size.
+    announcer announce: (ResultAnnouncement new result: result).
+    worker := [ result nextRunDo: [ :index |
+		[ result runCase: (suite at: index) ]
+		ensure: [ worker valueWithTimeout: 0.
+        	announcer announce: (ResultAnnouncement new result: result) ]]].
+	(suite size min: 25) timesRepeat: [ worker valueWithTimeout: 0 ]
+! !
+
+!TestSuiteRunner methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	announcer := Announcer new.
+    result := TestResult new
+! !
+
+!TestSuiteRunner class methodsFor: 'instance creation'!
+
+new
+	self shouldNotImplement
+!
+
+on: aCollection
+	^super new suite: aCollection
+! !
+

+ 35 - 22
test/Test.deploy.js

@@ -5,11 +5,10 @@ smalltalk.addMethod(
 "_initialize",
 smalltalk.method({
 selector: "initialize",
-fn: function () {
-    var self = this;
-    smalltalk.send(self, "_runTestSuite", []);
-    return self;
-}
+fn: function (){
+var self=this;
+smalltalk.send(self, "_runTestSuite", []);
+return self;}
 }),
 smalltalk.NodeTestRunner.klass);
 
@@ -17,23 +16,37 @@ smalltalk.addMethod(
 "_runTestSuite",
 smalltalk.method({
 selector: "runTestSuite",
-fn: function () {
-    var self = this;
-    var $1, $2;
-    var result;
-    result = smalltalk.send(smalltalk.TestResult || TestResult, "_new", []);
-    smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.TestCase || TestCase, "_allSubclasses", []), "_select_", [function (each) {return smalltalk.send(smalltalk.send(each, "_isAbstract", []), "_not", []);}]), "_do_", [function (each) {return smalltalk.send(smalltalk.send(each, "_buildSuite", []), "_do_", [function (suite) {return smalltalk.send(suite, "_runCaseFor_", [result]);}]);}]);
-    smalltalk.send(console, "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result, "_runs", []), "_asString", []), "__comma", [" tests run, "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_failures", []), "_size", []), "_asString", [])]), "__comma", [" failures, "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_errors", []), "_size", []), "_asString", [])]), "__comma", [" errors."])]);
-    $1 = smalltalk.send(smalltalk.send(result, "_failures", []), "_isEmpty", []);
-    if (!smalltalk.assert($1)) {
-        smalltalk.send(self, "_throw_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result, "_failures", []), "_first", []), "_class", []), "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_failures", []), "_first", []), "_selector", [])]), "__comma", [" is failing!"])]);
-    }
-    $2 = smalltalk.send(smalltalk.send(result, "_errors", []), "_isEmpty", []);
-    if (!smalltalk.assert($2)) {
-        smalltalk.send(self, "_throw_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result, "_errors", []), "_first", []), "_class", []), "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_errors", []), "_first", []), "_selector", [])]), "__comma", [" has errors!"])]);
-    }
-    return self;
-}
+fn: function (){
+var self=this;
+var $1,$2,$3;
+var suite;
+var worker;
+suite=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection),"_new",[]);
+smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.TestCase || TestCase),"_allSubclasses",[]),"_select_",[(function(each){
+return smalltalk.send(smalltalk.send(each,"_isAbstract",[]),"_not",[]);
+})]),"_do_",[(function(each){
+return smalltalk.send(suite,"_addAll_",[smalltalk.send(each,"_buildSuite",[])]);
+})]);
+worker=smalltalk.send((smalltalk.TestSuiteRunner || TestSuiteRunner),"_on_",[suite]);
+smalltalk.send(smalltalk.send(worker,"_announcer",[]),"_on_do_",[(smalltalk.ResultAnnouncement || ResultAnnouncement),(function(ann){
+var result;
+result=smalltalk.send(ann,"_result",[]);
+result;
+$1=smalltalk.send(smalltalk.send(result,"_runs",[]),"__eq",[smalltalk.send(result,"_total",[])]);
+if(smalltalk.assert($1)){
+smalltalk.send(console,"_log_",[smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result,"_runs",[]),"_asString",[]),"__comma",[" tests run, "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_failures",[]),"_size",[]),"_asString",[])]),"__comma",[" failures, "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_errors",[]),"_size",[]),"_asString",[])]),"__comma",[" errors."])]);
+$2=smalltalk.send(smalltalk.send(result,"_failures",[]),"_isEmpty",[]);
+if(! smalltalk.assert($2)){
+smalltalk.send(self,"_throw_",[smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result,"_failures",[]),"_first",[]),"_class",[]),"_name",[]),"__comma",[" >> "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_failures",[]),"_first",[]),"_selector",[])]),"__comma",[" is failing!"])]);
+};
+$3=smalltalk.send(smalltalk.send(result,"_errors",[]),"_isEmpty",[]);
+if(! smalltalk.assert($3)){
+return smalltalk.send(self,"_throw_",[smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result,"_errors",[]),"_first",[]),"_class",[]),"_name",[]),"__comma",[" >> "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_errors",[]),"_first",[]),"_selector",[])]),"__comma",[" has errors!"])]);
+};
+};
+})]);
+smalltalk.send(worker,"_run",[]);
+return self}
 }),
 smalltalk.NodeTestRunner.klass);
 

+ 39 - 26
test/Test.js

@@ -6,13 +6,12 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "initialize",
 category: 'not yet classified',
-fn: function () {
-    var self = this;
-    smalltalk.send(self, "_runTestSuite", []);
-    return self;
-},
+fn: function (){
+var self=this;
+smalltalk.send(self, "_runTestSuite", []);
+return self;},
 args: [],
-source: "initialize\x0a\x09self runTestSuite",
+source: "initialize\x0d\x0a\x09self runTestSuite",
 messageSends: ["runTestSuite"],
 referencedClasses: []
 }),
@@ -23,27 +22,41 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "runTestSuite",
 category: 'not yet classified',
-fn: function () {
-    var self = this;
-    var $1, $2;
-    var result;
-    result = smalltalk.send(smalltalk.TestResult || TestResult, "_new", []);
-    smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.TestCase || TestCase, "_allSubclasses", []), "_select_", [function (each) {return smalltalk.send(smalltalk.send(each, "_isAbstract", []), "_not", []);}]), "_do_", [function (each) {return smalltalk.send(smalltalk.send(each, "_buildSuite", []), "_do_", [function (suite) {return smalltalk.send(suite, "_runCaseFor_", [result]);}]);}]);
-    smalltalk.send(console, "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result, "_runs", []), "_asString", []), "__comma", [" tests run, "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_failures", []), "_size", []), "_asString", [])]), "__comma", [" failures, "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_errors", []), "_size", []), "_asString", [])]), "__comma", [" errors."])]);
-    $1 = smalltalk.send(smalltalk.send(result, "_failures", []), "_isEmpty", []);
-    if (!smalltalk.assert($1)) {
-        smalltalk.send(self, "_throw_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result, "_failures", []), "_first", []), "_class", []), "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_failures", []), "_first", []), "_selector", [])]), "__comma", [" is failing!"])]);
-    }
-    $2 = smalltalk.send(smalltalk.send(result, "_errors", []), "_isEmpty", []);
-    if (!smalltalk.assert($2)) {
-        smalltalk.send(self, "_throw_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result, "_errors", []), "_first", []), "_class", []), "_name", []), "__comma", [" >> "]), "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(result, "_errors", []), "_first", []), "_selector", [])]), "__comma", [" has errors!"])]);
-    }
-    return self;
-},
+fn: function (){
+var self=this;
+var $1,$2,$3;
+var suite;
+var worker;
+suite=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection),"_new",[]);
+smalltalk.send(smalltalk.send(smalltalk.send((smalltalk.TestCase || TestCase),"_allSubclasses",[]),"_select_",[(function(each){
+return smalltalk.send(smalltalk.send(each,"_isAbstract",[]),"_not",[]);
+})]),"_do_",[(function(each){
+return smalltalk.send(suite,"_addAll_",[smalltalk.send(each,"_buildSuite",[])]);
+})]);
+worker=smalltalk.send((smalltalk.TestSuiteRunner || TestSuiteRunner),"_on_",[suite]);
+smalltalk.send(smalltalk.send(worker,"_announcer",[]),"_on_do_",[(smalltalk.ResultAnnouncement || ResultAnnouncement),(function(ann){
+var result;
+result=smalltalk.send(ann,"_result",[]);
+result;
+$1=smalltalk.send(smalltalk.send(result,"_runs",[]),"__eq",[smalltalk.send(result,"_total",[])]);
+if(smalltalk.assert($1)){
+smalltalk.send(console,"_log_",[smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result,"_runs",[]),"_asString",[]),"__comma",[" tests run, "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_failures",[]),"_size",[]),"_asString",[])]),"__comma",[" failures, "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_errors",[]),"_size",[]),"_asString",[])]),"__comma",[" errors."])]);
+$2=smalltalk.send(smalltalk.send(result,"_failures",[]),"_isEmpty",[]);
+if(! smalltalk.assert($2)){
+smalltalk.send(self,"_throw_",[smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result,"_failures",[]),"_first",[]),"_class",[]),"_name",[]),"__comma",[" >> "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_failures",[]),"_first",[]),"_selector",[])]),"__comma",[" is failing!"])]);
+};
+$3=smalltalk.send(smalltalk.send(result,"_errors",[]),"_isEmpty",[]);
+if(! smalltalk.assert($3)){
+return smalltalk.send(self,"_throw_",[smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(result,"_errors",[]),"_first",[]),"_class",[]),"_name",[]),"__comma",[" >> "]),"__comma",[smalltalk.send(smalltalk.send(smalltalk.send(result,"_errors",[]),"_first",[]),"_selector",[])]),"__comma",[" has errors!"])]);
+};
+};
+})]);
+smalltalk.send(worker,"_run",[]);
+return self},
 args: [],
-source: "runTestSuite\x0a\x09| result |\x0a\x09result := TestResult new.\x0a\x0a\x09((TestCase allSubclasses\x0a\x09\x09select: [ :each | each isAbstract not ])\x0a\x09\x09do: [ :each | each buildSuite do: [ :suite | suite runCaseFor: result ] ]).\x0a\x0a\x09console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.\x0a\x0a\x09result failures isEmpty ifFalse: [ \x0a\x09\x09self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!' ].\x0a\x09result errors isEmpty ifFalse: [\x0a\x09\x09self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!' ].",
-messageSends: ["new", "do:", "runCaseFor:", "buildSuite", "select:", "not", "isAbstract", "allSubclasses", "log:", ",", "asString", "size", "errors", "failures", "runs", "ifFalse:", "throw:", "selector", "first", "name", "class", "isEmpty"],
-referencedClasses: ["TestResult", "TestCase"]
+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                self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!' ].\x0a            result errors isEmpty ifFalse: [\x0a                self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!' ].\x0a    ]].\x0a    worker run",
+messageSends: ["new", "do:", "addAll:", "buildSuite", "select:", "not", "isAbstract", "allSubclasses", "on:", "on:do:", "result", "ifTrue:", "log:", ",", "asString", "size", "errors", "failures", "runs", "ifFalse:", "throw:", "selector", "first", "name", "class", "isEmpty", "=", "total", "announcer", "run"],
+referencedClasses: ["OrderedCollection", "TestCase", "TestSuiteRunner", "ResultAnnouncement"]
 }),
 smalltalk.NodeTestRunner.klass);
 

+ 16 - 10
test/Test.st

@@ -10,18 +10,24 @@ initialize
 !
 
 runTestSuite
-	| result |
-	result := TestResult new.
+	| suite worker |
 
-	((TestCase allSubclasses
-		select: [ :each | each isAbstract not ])
-		do: [ :each | each buildSuite do: [ :suite | suite runCaseFor: result ] ]).
+	suite := OrderedCollection new.
+    (TestCase allSubclasses select: [ :each | each isAbstract not ])
+	do: [ :each | suite addAll: each buildSuite ].
 
-	console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.
+	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: [ 
-		self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!' ].
-	result errors isEmpty ifFalse: [
-		self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!' ].
+            result failures isEmpty ifFalse: [
+                self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!' ].
+            result errors isEmpty ifFalse: [
+                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