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.
- 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
|