opal 0.3.37 → 0.3.38
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +11 -0
- data/Gemfile +0 -8
- data/README.md +7 -6
- data/bin/opal +18 -10
- data/config.ru +8 -21
- data/lib/assets/javascripts/opal-parser.js.erb +3 -60
- data/lib/assets/javascripts/opal/array.rb +87 -43
- data/lib/assets/javascripts/opal/basic_object.rb +4 -0
- data/lib/assets/javascripts/opal/boolean.rb +5 -3
- data/lib/assets/javascripts/opal/class.rb +19 -4
- data/lib/assets/javascripts/opal/comparable.rb +1 -1
- data/lib/assets/javascripts/opal/enumerable.rb +32 -0
- data/lib/assets/javascripts/opal/error.rb +1 -1
- data/lib/assets/javascripts/opal/hash.rb +166 -103
- data/lib/assets/javascripts/opal/json.rb +3 -2
- data/lib/assets/javascripts/opal/kernel.rb +9 -1
- data/lib/assets/javascripts/opal/native.rb +29 -0
- data/lib/assets/javascripts/opal/nil_class.rb +9 -1
- data/lib/assets/javascripts/opal/numeric.rb +6 -4
- data/lib/assets/javascripts/opal/parser.js +57 -0
- data/lib/assets/javascripts/opal/proc.rb +5 -5
- data/lib/assets/javascripts/opal/regexp.rb +1 -1
- data/lib/assets/javascripts/opal/runtime.js +13 -0
- data/lib/assets/javascripts/opal/string.rb +14 -3
- data/lib/assets/javascripts/opal/time.rb +1 -1
- data/lib/opal.rb +1 -1
- data/lib/opal/parser.rb +39 -13
- data/lib/opal/processor.rb +13 -2
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +3 -0
- data/spec/core/array/fill_spec.rb +26 -0
- data/spec/core/array/try_convert_spec.rb +15 -0
- data/spec/core/enumerable/each_slice_spec.rb +24 -0
- data/spec/core/enumerable/group_by_spec.rb +16 -0
- data/spec/core/module/const_get_spec.rb +34 -0
- data/spec/core/module/undef_method_spec.rb +67 -0
- data/spec/core/nil/to_h_spec.rb +10 -0
- data/spec/core/proc/element_reference_spec.rb +21 -0
- data/spec/{core → core_ext}/array/to_json_spec.rb +0 -0
- data/spec/core_ext/method_missing_spec.rb +43 -0
- data/spec/core_ext/native/fixtures/classes.rb +5 -0
- data/spec/core_ext/native/initialize_spec.rb +8 -0
- data/spec/core_ext/native/method_missing_spec.rb +7 -0
- data/spec/core_ext/native/to_native_spec.rb +7 -0
- data/spec/grammar/parser_spec.rb +1 -1
- data/spec/language/super_spec.rb +20 -0
- data/spec/language/variables_spec.rb +69 -0
- data/spec/spec_helper.rb +9 -5
- metadata +66 -8
- data/lib/assets/javascripts/opal/core.rb +0 -36
- 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
|
-
|
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
|
-
|
3
|
-
|
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
|
-
|
28
|
+
`#{self}.length - 1`
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -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('::');
|
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,
|
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
|
-
|
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 @
|
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
|
-
|
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
|
-
|
819
|
-
|
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 "
|
1837
|
+
js_super "__slice.call(arguments)"
|
1812
1838
|
end
|
1813
1839
|
|
1814
1840
|
def js_super args
|