js2 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/CHANGELOG +12 -2
  2. data/lib/js2/js2.js +135 -22
  3. metadata +17 -7
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ 0.3.5
2
+ * Added scope and binding support to shorthand functions
3
+ * Added support for modules
4
+
5
+ 0.3.4
6
+ * coded reduce to clojure spec
7
+ * fixed collect and some other iterators
8
+
1
9
  0.3.3
2
- - using closure for classes instead of hashes
3
- - adding static methods
10
+ * using closure for classes instead of hashes
11
+ * adding static methods
12
+
13
+
data/lib/js2/js2.js CHANGED
@@ -14,6 +14,7 @@ function mainFunction (arg) {
14
14
 
15
15
  var JS2 = root.JS2 = mainFunction;
16
16
  var js2 = root.js2 = JS2;
17
+ js2.VERSION = "0.3.5";
17
18
 
18
19
  JS2.ROOT = JS2;
19
20
 
@@ -24,22 +25,39 @@ function mainFunction (arg) {
24
25
  this.klass = klass;
25
26
  this.par = par;
26
27
 
27
- this['static'] = {
28
- methods: {},
29
- members: {},
30
- };
31
-
32
- this.methods = {};
33
- this.members = {};
28
+ this.members = {};
29
+ this.staticMembers = {};
34
30
  this.children = [];
31
+ this.included = [];
35
32
 
36
- if (this.par) this.par.oo.children.push(klass);
33
+ if (this.par) this.par.OO.children.push(klass);
37
34
  };
38
35
 
39
36
  OO.prototype = {
40
37
  forbiddenMembers: {
41
38
  'prototype': undefined,
42
- 'oo': undefined
39
+ 'OO': undefined
40
+ },
41
+
42
+ include: function(module) {
43
+ this.included.push(module);
44
+ var members = module.OO.members;
45
+ for (var name in members) {
46
+ if (members.hasOwnProperty(name)) {
47
+ this.addMember(name, members[name]);
48
+ }
49
+ }
50
+
51
+ var staticMembers = module.OO.staticMembers;
52
+ for (var name in staticMembers) {
53
+ if (staticMembers.hasOwnProperty(name)) {
54
+ this.addStaticMember(name, staticMembers[name]);
55
+ }
56
+ }
57
+
58
+ if (typeof staticMembers['included'] == 'function') {
59
+ staticMembers['included'](this.klass);
60
+ }
43
61
  },
44
62
 
45
63
  createNamespace: function(name) {
@@ -74,6 +92,7 @@ function mainFunction (arg) {
74
92
  }
75
93
 
76
94
  proto[name] = member;
95
+ this.members[name] = member;
77
96
  },
78
97
 
79
98
  addStaticMember: function(name, member) {
@@ -86,14 +105,15 @@ function mainFunction (arg) {
86
105
  }
87
106
 
88
107
  this.klass[name] = member;
108
+ this.staticMembers[name] = member;
89
109
  }
90
110
  };
91
111
 
92
112
  JS2.Class = function() { this.initialize.apply(this, arguments); };
93
- JS2.Class.oo = new OO(JS2.Class);
113
+ JS2.Class.OO = new OO(JS2.Class);
94
114
  JS2.Class.prototype = {
95
115
  initialize: function () {},
96
- oo: JS2.Class.oo
116
+ oo: JS2.Class.OO
97
117
  };
98
118
 
99
119
  var namedClasses = {};
@@ -104,13 +124,13 @@ function mainFunction (arg) {
104
124
  var noInit = false;
105
125
  JS2.Class.extend = function(name, klassDef) {
106
126
  var klass = function() { if (!noInit) this.initialize.apply(this, arguments); };
107
- klass.oo = new OO(klass, this);
127
+ klass.OO = new OO(klass, this);
108
128
 
109
129
  if (typeof name != 'string') {
110
130
  klassDef = name;
111
131
  } else {
112
132
  namedClasses[name] = klass;
113
- var namespace = this.oo.createNamespace(name);
133
+ var namespace = this.OO.createNamespace(name);
114
134
  namespace[0][namespace[1]] = klass;
115
135
  }
116
136
 
@@ -120,8 +140,8 @@ function mainFunction (arg) {
120
140
  noInit = false;
121
141
 
122
142
  klass.prototype = proto;
123
- var oo = klass.oo;
124
- proto.oo = oo;
143
+ var oo = klass.OO;
144
+ proto.OO = oo;
125
145
 
126
146
  for (var name in this) {
127
147
  oo.addStaticMember(name, this[name]);
@@ -138,6 +158,8 @@ function mainFunction (arg) {
138
158
  return klass;
139
159
  };
140
160
 
161
+ JS2.Module = JS2.Class;
162
+
141
163
  var assert = {
142
164
  'eq': function(expected, actual) { if (expected != actual) console.log("Expected "+expected+", but got "+actual+".") },
143
165
  'isFalse': function(val) { if (val) console.log("Expected false, but got "+val+".") },
@@ -159,7 +181,9 @@ function mainFunction (arg) {
159
181
  [ 'SPACE', "\\s+" ],
160
182
  [ 'REGEX', "\\/" ],
161
183
  [ 'CLASS', "class" ],
184
+ [ 'MODULE', "module" ],
162
185
  [ 'STATIC', "static" ],
186
+ [ 'include', "include" ],
163
187
  [ 'SHORT_FUNCT', "#\\{|#\\(" ],
164
188
  [ 'FOREACH', "foreach" ],
165
189
  [ 'CURRY', "curry" ],
@@ -437,6 +461,7 @@ function mainFunction (arg) {
437
461
  this.index = 0;
438
462
  this.str = str;
439
463
  this.orig = str;
464
+ this.before = [];
440
465
  },
441
466
 
442
467
  toArray: function() {
@@ -478,7 +503,9 @@ function mainFunction (arg) {
478
503
  },
479
504
 
480
505
  pop: function() {
481
- return this.tokens.pop();
506
+ var ret = this.tokens.pop();
507
+ this.before.push(ret);
508
+ return ret;
482
509
  },
483
510
 
484
511
  peek: function() {
@@ -494,6 +521,7 @@ function mainFunction (arg) {
494
521
  case '(': this.braceCount++; break;
495
522
  case ')': this.braceCount--; break;
496
523
  }
524
+ this.before.unshift(token);
497
525
  return token;
498
526
  },
499
527
 
@@ -539,7 +567,7 @@ function mainFunction (arg) {
539
567
  }
540
568
  };
541
569
 
542
- var KEYWORDS = { 'var': null, 'class': null, 'function': null, 'in': null, 'with': null, 'curry': null, 'static': null };
570
+ var KEYWORDS = { 'var': null, 'class': null, 'function': null, 'in': null, 'with': null, 'curry': null, 'static': null, 'module':null };
543
571
  var IDS = JS2.Lexer.IDS;
544
572
  IDS['NODE'] = -1;
545
573
 
@@ -655,6 +683,7 @@ function mainFunction (arg) {
655
683
  handOff: function(token) {
656
684
  switch (token[1]) {
657
685
  case IDS.CLASS: return Klass;
686
+ case IDS.MODULE: return Module;
658
687
  case IDS.FOREACH: return Foreach;
659
688
  case IDS.SHORT_FUNCT: return ShortFunct;
660
689
  case IDS.CURRY: return Curry;
@@ -692,6 +721,23 @@ function mainFunction (arg) {
692
721
  }
693
722
  });
694
723
 
724
+ var Module = Klass.extend({
725
+ name: 'Module',
726
+ toString: function() {
727
+ var v = this.validate(/(module)(\s+)/);
728
+ var last = v.last;
729
+ var m = last.match(/^([\w$]+(\.[\w$]+)*)/);
730
+ if (m) {
731
+ var name = m[1];
732
+ var source = last.substr(name.length);
733
+ return JS2.DECORATOR.createModule(name, source);
734
+ } else {
735
+ // raise error
736
+ }
737
+ }
738
+ });
739
+
740
+
695
741
  var Block = Content.extend({
696
742
  name: 'Block',
697
743
  handleToken: function(token) {
@@ -708,6 +754,7 @@ function mainFunction (arg) {
708
754
  case 'var': return Member;
709
755
  case 'function': return Method;
710
756
  case 'static': return StaticMember;
757
+ case 'include': return Include;
711
758
  }
712
759
  },
713
760
 
@@ -719,10 +766,23 @@ function mainFunction (arg) {
719
766
 
720
767
  toString: function() {
721
768
  var str = this.$super();
722
- return str.replace(/^{/, 'function(KLASS, OO){').replace(/}$/, "}");
769
+ return str.replace(/^{/, 'function(KLASS, OO){');
723
770
  }
724
771
  });
725
772
 
773
+ var Include = Content.extend({
774
+ name: 'Include',
775
+ handleToken: function(token) {
776
+ if (token[0] == ';') this.closed = true;
777
+ },
778
+
779
+ toString: function() {
780
+ var v = this.validate(/^(include)(\s+)/);
781
+ return "OO.include(" + v.last.replace(/;$/, ');');
782
+ }
783
+
784
+ });
785
+
726
786
  var StaticMember = Content.extend({
727
787
  name: 'StaticMember',
728
788
  handOff: function(token) {
@@ -829,9 +889,8 @@ function mainFunction (arg) {
829
889
  handOff: function(token) {
830
890
  if (this.started) {
831
891
  this.closed = true;
832
- var foo = (new Validator(this.tokens.toArray())).getString(2);
833
892
  this.semi = (new Validator(this.tokens.toArray())).validate(/^(\s*)([^\s\w$])/, 2) ? '' : ';';
834
- }
893
+ }
835
894
 
836
895
  switch (token[0]) {
837
896
  case '(': return Braces;
@@ -839,9 +898,50 @@ function mainFunction (arg) {
839
898
  }
840
899
  },
841
900
 
901
+ parseArgs: function(str) {
902
+ // (arg1, arg2 with scope1, scope2 binds bindingVar)
903
+ var m = str.match(/^\((\s*([\w\$]+)(\s*,\s*[\w\$]+)*)?(\s*with\s+(([\w\$]+)(\s*,\s*[\w\$]+)*))?(\s*binds\s+(.+))?\)/);
904
+ if (!m) {} // raise error
905
+
906
+ return {
907
+ braces: '(' + (m[1] || '') + ')',
908
+ scope: m[5],
909
+ binds: m[9]
910
+ };
911
+ },
912
+
842
913
  toString: function() {
843
- var v = this.validate(/(#)(Braces)?(\s*)(Block)/);
844
- return "function" + (v[2] ? v[2] : "($1,$2,$3)") + v[4] + this.semi;
914
+ var scopes = null;
915
+ var inScopes = null;
916
+
917
+ var v = this.validate(/(#)(Braces)?(\s*)(Block)/);
918
+ var args = this.parseArgs(v[2] ? v[2].toString() : '($1,$2,$3)');
919
+ var body = v[4];
920
+
921
+ // we need a function within a function
922
+ if (args.binds || args.scope) {
923
+ var scope = args.scope || '';
924
+ var inScope = scope;
925
+
926
+ // need to pass in __self and bind to __self
927
+ if (args.binds) {
928
+ var comma = scope == '' ? '' : ',';
929
+ inScope = scope.replace(/^/, '__self' + comma);
930
+ scope = scope.replace(/^/, args.binds + comma);
931
+
932
+ return '(function(' + inScope + '){' + 'var f = function' + args.braces + body + ';' + ' return function() { return f.apply(__self, arguments)};})(' + scope + ')' + this.semi;
933
+ }
934
+
935
+ // no binding, just use scoping
936
+ else {
937
+ return '(function(' + inScope + '){' + 'return function' + args.braces + body + ';' + '})(' + scope + ')' + this.semi;
938
+ }
939
+ }
940
+
941
+ // just a normal function
942
+ else {
943
+ return "function" + args.braces + body + this.semi;
944
+ }
845
945
  }
846
946
  });
847
947
 
@@ -1208,6 +1308,7 @@ JS2.Class.extend('Config', function(KLASS, OO){
1208
1308
 
1209
1309
  JS2.Class.extend('Commander', function(KLASS, OO){
1210
1310
  OO.addMember("BANNER","js2 <command> [options] <arguments>\n" +
1311
+ "VERSION: " + js2.VERSION + "\n" +
1211
1312
  "Commands:\n" +
1212
1313
  " * run <file> -- Executes file\n" +
1213
1314
  " * render <file> -- Shows JS2 compiled output\n" +
@@ -1297,6 +1398,10 @@ JS2.Class.extend('BrowserDecorator', function(KLASS, OO){
1297
1398
  OO.addMember("klass",function (name, par, source) {
1298
1399
  return par+".extend('"+name+"',"+source+");";
1299
1400
  });
1401
+
1402
+ OO.addMember("createModule",function (name, source) {
1403
+ return "JS2.Module.extend('"+name+"',"+source+");";
1404
+ });
1300
1405
  });
1301
1406
 
1302
1407
  JS2.Class.extend('NodeDecorator', function(KLASS, OO){
@@ -1307,6 +1412,10 @@ JS2.Class.extend('NodeDecorator', function(KLASS, OO){
1307
1412
  OO.addMember("klass",function (name, par, source) {
1308
1413
  return "var "+name+"=exports['"+name+"']="+par+".extend("+source+");";
1309
1414
  });
1415
+
1416
+ OO.addMember("createModule",function (name, source) {
1417
+ return "var "+name+"=exports['"+name+"']=JS2.Module.extend("+source+");";
1418
+ });
1310
1419
  });
1311
1420
 
1312
1421
  JS2.Class.extend('RingoDecorator', function(KLASS, OO){
@@ -1317,6 +1426,10 @@ JS2.Class.extend('RingoDecorator', function(KLASS, OO){
1317
1426
  OO.addMember("klass",function (name, par, source) {
1318
1427
  return "var "+name+"=exports['"+name+"']="+par+".extend("+source+");";
1319
1428
  });
1429
+
1430
+ OO.addMember("createModule",function (name, source) {
1431
+ return "var "+name+"=exports['"+name+"']=JS2.Module.extend("+source+");";
1432
+ });
1320
1433
  });
1321
1434
 
1322
1435
  JS2.DECORATOR = JS2.DECORATOR || new JS2.BrowserDecorator();
metadata CHANGED
@@ -1,8 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: js2
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.3.4
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 5
9
+ version: 0.3.5
6
10
  platform: ruby
7
11
  authors:
8
12
  - Jeff Su
@@ -10,7 +14,7 @@ autorequire:
10
14
  bindir: bin
11
15
  cert_chain: []
12
16
 
13
- date: 2011-03-10 00:00:00 +08:00
17
+ date: 2011-03-14 00:00:00 -07:00
14
18
  default_executable:
15
19
  dependencies:
16
20
  - !ruby/object:Gem::Dependency
@@ -21,6 +25,8 @@ dependencies:
21
25
  requirements:
22
26
  - - ">="
23
27
  - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
24
30
  version: "0"
25
31
  type: :runtime
26
32
  version_requirements: *id001
@@ -36,11 +42,11 @@ extra_rdoc_files: []
36
42
  files:
37
43
  - bin/js2
38
44
  - bin/js2-ruby
39
- - lib/js2.rb
40
- - lib/js2/context.rb
41
- - lib/js2/rack.rb
42
45
  - lib/js2/command.rb
46
+ - lib/js2/context.rb
43
47
  - lib/js2/fs.rb
48
+ - lib/js2/rack.rb
49
+ - lib/js2.rb
44
50
  - lib/js2/js2.js
45
51
  - CHANGELOG
46
52
  has_rdoc: true
@@ -57,17 +63,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
63
  requirements:
58
64
  - - ">="
59
65
  - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
60
68
  version: "0"
61
69
  required_rubygems_version: !ruby/object:Gem::Requirement
62
70
  none: false
63
71
  requirements:
64
72
  - - ">="
65
73
  - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
66
76
  version: "0"
67
77
  requirements: []
68
78
 
69
79
  rubyforge_project:
70
- rubygems_version: 1.5.2
80
+ rubygems_version: 1.3.7
71
81
  signing_key:
72
82
  specification_version: 3
73
83
  summary: Javascript Syntactic Sugar