js2 0.3.4 → 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
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