opal 0.3.37 → 0.3.38

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 (51) hide show
  1. data/CHANGELOG.md +11 -0
  2. data/Gemfile +0 -8
  3. data/README.md +7 -6
  4. data/bin/opal +18 -10
  5. data/config.ru +8 -21
  6. data/lib/assets/javascripts/opal-parser.js.erb +3 -60
  7. data/lib/assets/javascripts/opal/array.rb +87 -43
  8. data/lib/assets/javascripts/opal/basic_object.rb +4 -0
  9. data/lib/assets/javascripts/opal/boolean.rb +5 -3
  10. data/lib/assets/javascripts/opal/class.rb +19 -4
  11. data/lib/assets/javascripts/opal/comparable.rb +1 -1
  12. data/lib/assets/javascripts/opal/enumerable.rb +32 -0
  13. data/lib/assets/javascripts/opal/error.rb +1 -1
  14. data/lib/assets/javascripts/opal/hash.rb +166 -103
  15. data/lib/assets/javascripts/opal/json.rb +3 -2
  16. data/lib/assets/javascripts/opal/kernel.rb +9 -1
  17. data/lib/assets/javascripts/opal/native.rb +29 -0
  18. data/lib/assets/javascripts/opal/nil_class.rb +9 -1
  19. data/lib/assets/javascripts/opal/numeric.rb +6 -4
  20. data/lib/assets/javascripts/opal/parser.js +57 -0
  21. data/lib/assets/javascripts/opal/proc.rb +5 -5
  22. data/lib/assets/javascripts/opal/regexp.rb +1 -1
  23. data/lib/assets/javascripts/opal/runtime.js +13 -0
  24. data/lib/assets/javascripts/opal/string.rb +14 -3
  25. data/lib/assets/javascripts/opal/time.rb +1 -1
  26. data/lib/opal.rb +1 -1
  27. data/lib/opal/parser.rb +39 -13
  28. data/lib/opal/processor.rb +13 -2
  29. data/lib/opal/version.rb +1 -1
  30. data/opal.gemspec +3 -0
  31. data/spec/core/array/fill_spec.rb +26 -0
  32. data/spec/core/array/try_convert_spec.rb +15 -0
  33. data/spec/core/enumerable/each_slice_spec.rb +24 -0
  34. data/spec/core/enumerable/group_by_spec.rb +16 -0
  35. data/spec/core/module/const_get_spec.rb +34 -0
  36. data/spec/core/module/undef_method_spec.rb +67 -0
  37. data/spec/core/nil/to_h_spec.rb +10 -0
  38. data/spec/core/proc/element_reference_spec.rb +21 -0
  39. data/spec/{core → core_ext}/array/to_json_spec.rb +0 -0
  40. data/spec/core_ext/method_missing_spec.rb +43 -0
  41. data/spec/core_ext/native/fixtures/classes.rb +5 -0
  42. data/spec/core_ext/native/initialize_spec.rb +8 -0
  43. data/spec/core_ext/native/method_missing_spec.rb +7 -0
  44. data/spec/core_ext/native/to_native_spec.rb +7 -0
  45. data/spec/grammar/parser_spec.rb +1 -1
  46. data/spec/language/super_spec.rb +20 -0
  47. data/spec/language/variables_spec.rb +69 -0
  48. data/spec/spec_helper.rb +9 -5
  49. metadata +66 -8
  50. data/lib/assets/javascripts/opal/core.rb +0 -36
  51. data/spec/autorun.rb +0 -3
@@ -38,11 +38,12 @@ module JSON
38
38
  return arr;
39
39
  }
40
40
  else {
41
- var hash = #{ {} }, v, map = hash.map;
41
+ var hash = #{ {} }, v, map = hash.map, keys = hash.keys;
42
42
 
43
43
  for (var k in value) {
44
44
  if (__hasOwn.call(value, k)) {
45
45
  v = to_opal(value[k]);
46
+ keys.push(k);
46
47
  map[k] = v;
47
48
  }
48
49
  }
@@ -52,4 +53,4 @@ module JSON
52
53
  }
53
54
  };
54
55
  }
55
- end
56
+ end
@@ -8,6 +8,10 @@ module Kernel
8
8
  alias :instance_eval :instance_eval
9
9
  alias :instance_exec :instance_exec
10
10
 
11
+ def method_missing(symbol, *args, &block)
12
+ raise NoMethodError, "undefined method `#{symbol}' for #{inspect}"
13
+ end
14
+
11
15
  def =~(obj)
12
16
  false
13
17
  end
@@ -16,6 +20,10 @@ module Kernel
16
20
  `#{self} == other`
17
21
  end
18
22
 
23
+ def as_json
24
+ nil
25
+ end
26
+
19
27
  def method(name)
20
28
  %x{
21
29
  var recv = #{self},
@@ -64,7 +72,7 @@ module Kernel
64
72
  end
65
73
 
66
74
  def class
67
- `return #{self}._klass`
75
+ `#{self}._klass`
68
76
  end
69
77
 
70
78
  def define_singleton_method(name, &body)
@@ -0,0 +1,29 @@
1
+ module Native
2
+ def initialize(native)
3
+ %x{
4
+ if (#{native} == null) {
5
+ #{ raise "null or undefined passed to Native" };
6
+ }
7
+ }
8
+
9
+ @native = native
10
+ end
11
+
12
+ def method_missing(symbol, *args, &block)
13
+ native = @native
14
+
15
+ %x{
16
+ var func;
17
+
18
+ if (func = #{native}[#{symbol}]) {
19
+ return func.call(#{native});
20
+ }
21
+ }
22
+
23
+ nil
24
+ end
25
+
26
+ def to_native
27
+ @native
28
+ end
29
+ end
@@ -15,6 +15,10 @@ class NilClass
15
15
  `other === nil`
16
16
  end
17
17
 
18
+ def as_json
19
+ self
20
+ end
21
+
18
22
  def inspect
19
23
  'nil'
20
24
  end
@@ -31,6 +35,10 @@ class NilClass
31
35
  []
32
36
  end
33
37
 
38
+ def to_h
39
+ `__opal.hash()`
40
+ end
41
+
34
42
  def to_i
35
43
  0
36
44
  end
@@ -48,4 +56,4 @@ class NilClass
48
56
  def to_s
49
57
  ''
50
58
  end
51
- end
59
+ end
@@ -1,10 +1,8 @@
1
1
  class Numeric < `Number`
2
- %x{
3
- Numeric.prototype._isNumber = true;
4
- }
5
-
6
2
  include Comparable
7
3
 
4
+ `def._isNumber = true`
5
+
8
6
  def +(other)
9
7
  `#{self} + other`
10
8
  end
@@ -95,6 +93,10 @@ class Numeric < `Number`
95
93
  `Math.abs(#{self})`
96
94
  end
97
95
 
96
+ def as_json
97
+ self
98
+ end
99
+
98
100
  def ceil
99
101
  `Math.ceil(#{self})`
100
102
  end
@@ -0,0 +1,57 @@
1
+ (function() {
2
+ // quick exit if not insde browser
3
+ if (typeof(window) === 'undefined' || typeof(document) === 'undefined') {
4
+ return;
5
+ }
6
+
7
+ function findRubyScripts() {
8
+ var all = document.getElementsByTagName('script');
9
+ for (var i = 0, script; i < all.length; i++) {
10
+ script = all[i];
11
+ if (script.type === 'text/ruby') {
12
+ if (script.src) {
13
+ request(script.src, function(result) {
14
+ runRuby(result);
15
+ });
16
+ }
17
+ else {
18
+ runRuby(script.innerHTML);
19
+ }
20
+ }
21
+ else if (script.type === 'text/erb') {
22
+ runERB(script.innerHTML);
23
+ }
24
+ }
25
+ }
26
+
27
+ function runRuby(source) {
28
+ var js = Opal.Opal.Parser.$new().$parse(source);
29
+ eval('(' + js + ')()');
30
+ }
31
+
32
+ function request(url, callback) {
33
+ var xhr = new (window.ActiveXObject || XMLHttpRequest)('Microsoft.XMLHTTP');
34
+ xhr.open('GET', url, true);
35
+ if ('overrideMimeType' in xhr) {
36
+ xhr.overrideMimeType('text/plain');
37
+ }
38
+ xhr.onreadystatechange = function() {
39
+ if (xhr.readyState === 4) {
40
+ if (xhr.status === 0 || xhr.status === 200) {
41
+ callback(xhr.responseText);
42
+ }
43
+ else {
44
+ throw new Error('Could not load ruby at: ' + url);
45
+ }
46
+ }
47
+ };
48
+ xhr.send(null);
49
+ }
50
+
51
+ if (window.addEventListener) {
52
+ window.addEventListener('DOMContentLoaded', findRubyScripts, false);
53
+ }
54
+ else {
55
+ window.attachEvent('onload', findRubyScripts);
56
+ }
57
+ })();
@@ -1,8 +1,6 @@
1
1
  class Proc < `Function`
2
- %x{
3
- Proc.prototype._isProc = true;
4
- Proc.prototype.is_lambda = true;
5
- }
2
+ `def._isProc = true`
3
+ `def.is_lambda = true`
6
4
 
7
5
  def self.new(&block)
8
6
  `if (block === nil) no_block_given();`
@@ -14,6 +12,8 @@ class Proc < `Function`
14
12
  `#{self}.apply(null, #{args})`
15
13
  end
16
14
 
15
+ alias [] call
16
+
17
17
  def to_proc
18
18
  self
19
19
  end
@@ -25,7 +25,7 @@ class Proc < `Function`
25
25
  end
26
26
 
27
27
  def arity
28
- `this.length - 1`
28
+ `#{self}.length - 1`
29
29
  end
30
30
  end
31
31
 
@@ -69,4 +69,4 @@ class Regexp < `RegExp`
69
69
  end
70
70
 
71
71
  class MatchData
72
- end
72
+ end
@@ -142,6 +142,10 @@
142
142
  constructor._donate = __donate;
143
143
  constructor._sdonate = __sdonate;
144
144
 
145
+ constructor['$==='] = module_eqq;
146
+ constructor.$to_s = module_to_s;
147
+ constructor.toString = module_to_s;
148
+
145
149
  Opal[id] = constructor;
146
150
 
147
151
  return constructor;
@@ -169,6 +173,7 @@
169
173
 
170
174
  constructor['$==='] = module_eqq;
171
175
  constructor.$to_s = module_to_s;
176
+ constructor.toString = module_to_s;
172
177
 
173
178
  var smethods;
174
179
 
@@ -199,6 +204,7 @@
199
204
 
200
205
  constructor['$==='] = module_eqq;
201
206
  constructor.$to_s = module_to_s;
207
+ constructor.toString = module_to_s;
202
208
 
203
209
  var smethods = constructor._smethods = Class._methods.slice();
204
210
  for (var i = 0, length = smethods.length; i < length; i++) {
@@ -221,6 +227,13 @@
221
227
  };
222
228
 
223
229
  Opal.puts = function(a) { console.log(a); };
230
+
231
+ // Method missing dispatcher
232
+ Opal.mm = function(mid) {
233
+ return function() {
234
+ return this.$method_missing.apply(this, [mid].concat(__slice.call(arguments)));
235
+ }
236
+ };
224
237
 
225
238
  // Initialization
226
239
  // --------------
@@ -1,8 +1,8 @@
1
1
  class String < `String`
2
- `String.prototype._isString = true`
3
-
4
2
  include Comparable
5
3
 
4
+ `def._isString = true`
5
+
6
6
  def self.try_convert(what)
7
7
  what.to_str
8
8
  rescue
@@ -131,6 +131,10 @@ class String < `String`
131
131
  }
132
132
  end
133
133
 
134
+ def as_json
135
+ self
136
+ end
137
+
134
138
  def capitalize
135
139
  `#{self}.charAt(0).toUpperCase() + #{self}.substr(1).toLowerCase()`
136
140
  end
@@ -179,7 +183,14 @@ class String < `String`
179
183
  def count(str)
180
184
  `(#{self}.length - #{self}.replace(new RegExp(str,"g"), '').length) / str.length`
181
185
  end
182
-
186
+
187
+ def dasherize
188
+ `#{self}.replace(/[-\\s]+/g, '-')
189
+ .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1-$2')
190
+ .replace(/([a-z\\d])([A-Z])/g, '$1-$2')
191
+ .toLowerCase()`
192
+ end
193
+
183
194
  def demodulize
184
195
  %x{
185
196
  var idx = #{self}.lastIndexOf('::');
@@ -107,4 +107,4 @@ class Time < `Date`
107
107
  end
108
108
 
109
109
  alias_native :year, :getFullYear
110
- end
110
+ end
data/lib/opal.rb CHANGED
@@ -16,7 +16,7 @@ module Opal
16
16
  # @param [String] file the filename to use when parsing
17
17
  # @return [String] the resulting javascript code
18
18
  def self.parse(str, file='(file)')
19
- Parser.new.parse str, file
19
+ Parser.new.parse str, :file => file
20
20
  end
21
21
 
22
22
  def self.core_dir
data/lib/opal/parser.rb CHANGED
@@ -83,10 +83,9 @@ module Opal
83
83
  # @param [String] source the ruby code to parse
84
84
  # @param [String] file the filename representing this code
85
85
  # @return [String] string of javascript code
86
- def parse(source, file = '(file)')
86
+ def parse(source, options = {})
87
87
  @grammar = Grammar.new
88
88
  @requires = []
89
- @file = file
90
89
  @line = 1
91
90
  @indent = ''
92
91
  @unique = 0
@@ -96,7 +95,12 @@ module Opal
96
95
  :slice => true
97
96
  }
98
97
 
99
- top @grammar.parse(source, file)
98
+ # options
99
+ @file = options[:file] || '(file)'
100
+ @method_missing = (options[:method_missing] != false)
101
+ @optimized_operators = (options[:optimized_operators] != false)
102
+
103
+ top @grammar.parse(source, @file)
100
104
  end
101
105
 
102
106
  # This is called when a parsing/processing error occurs. This
@@ -179,17 +183,17 @@ module Opal
179
183
  code = @indent + process(s(:scope, sexp), :stmt)
180
184
  }
181
185
 
182
- @scope.add_temp "__opal = Opal"
183
186
  @scope.add_temp "self = __opal.top"
184
187
  @scope.add_temp "__scope = __opal"
185
188
  @scope.add_temp "nil = __opal.nil"
189
+ @scope.add_temp "$mm = __opal.mm"
186
190
  @scope.add_temp "def = #{current_self}._klass.prototype" if @scope.defines_defn
187
191
  @helpers.keys.each { |h| @scope.add_temp "__#{h} = __opal.#{h}" }
188
192
 
189
193
  code = INDENT + @scope.to_vars + "\n" + code
190
194
  end
191
195
 
192
- "(function() {\n#{ code }\n})();\n"
196
+ "(function(__opal) {\n#{ code }\n})(Opal);\n"
193
197
  end
194
198
 
195
199
  # Every time the parser enters a new scope, this is called with
@@ -497,7 +501,7 @@ module Opal
497
501
  meth, recv, arg = sexp
498
502
  mid = mid_to_jsid meth.to_s
499
503
 
500
- if @parser_uses_optimized_operators
504
+ if @optimized_operators
501
505
  with_temp do |a|
502
506
  with_temp do |b|
503
507
  l = process recv, :expr
@@ -507,9 +511,9 @@ module Opal
507
511
  [a, l, b, r, a, a, meth.to_s, b, a, mid, b]
508
512
  end
509
513
  end
514
+ else
515
+ "#{process recv, :recv}#{mid}(#{process arg, :expr})"
510
516
  end
511
-
512
- "#{process recv, :recv}#{mid}(#{process arg, :expr})"
513
517
  end
514
518
 
515
519
  def js_block_given(sexp, level)
@@ -807,16 +811,38 @@ module Opal
807
811
  tmprecv = @scope.new_temp
808
812
  elsif splat and recv != [:self] and recv[0] != :lvar
809
813
  tmprecv = @scope.new_temp
814
+ else # method_missing
815
+ tmprecv = @scope.new_temp
810
816
  end
811
817
 
812
818
  args = ""
813
819
 
814
820
  recv_code = process recv, :recv
815
821
 
816
- args = process arglist, :expr
822
+ if @method_missing
823
+ call_recv = s(:js_tmp, tmprecv || recv_code)
824
+ arglist.insert 1, call_recv unless splat
825
+ args = process arglist, :expr
826
+
827
+ dispatch = if tmprecv
828
+ "((#{tmprecv} = #{recv_code})#{mid} || $mm('#{ meth.to_s }'))"
829
+ else
830
+ "(#{recv_code}#{mid} || $mm('#{ meth.to_s }'))"
831
+ end
832
+
833
+ result = if splat
834
+ "#{dispatch}.apply(#{process call_recv, :expr}, #{args})"
835
+ else
836
+ "#{dispatch}.call(#{args})"
837
+ end
838
+ else
839
+ args = process arglist, :expr
840
+ dispatch = tmprecv ? "(#{tmprecv} = #{recv_code})#{mid}" : "#{recv_code}#{mid}"
841
+ result = splat ? "#{dispatch}.apply(#{tmprecv || recv_code}, #{args})" : "#{dispatch}(#{args})"
842
+ end
817
843
 
818
- dispatch = tmprecv ? "(#{tmprecv} = #{recv_code})#{mid}" : "#{recv_code}#{mid}"
819
- splat ? "#{dispatch}.apply(#{tmprecv || recv_code}, #{args})" : "#{dispatch}(#{args})"
844
+ @scope.queue_temp tmprecv if tmprecv
845
+ result
820
846
  end
821
847
 
822
848
  # s(:arglist, [arg [, arg ..]])
@@ -1256,7 +1282,7 @@ module Opal
1256
1282
  map = hash_keys.map { |k| "#{k}: #{hash_obj[k]}"}
1257
1283
 
1258
1284
  @helpers[:hash2] = true
1259
- "__hash2({#{map.join(', ')}})"
1285
+ "__hash2([#{hash_keys.join ', '}], {#{map.join(', ')}})"
1260
1286
  else
1261
1287
  @helpers[:hash] = true
1262
1288
  "__hash(#{sexp.map { |p| process p, :expr }.join ', '})"
@@ -1808,7 +1834,7 @@ module Opal
1808
1834
  #
1809
1835
  # s(:zsuper)
1810
1836
  def process_zsuper(exp, level)
1811
- js_super "[self].concat(__slice.call(arguments))"
1837
+ js_super "__slice.call(arguments)"
1812
1838
  end
1813
1839
 
1814
1840
  def js_super args