opal 0.3.19 → 0.3.20
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -1
- data/Gemfile +3 -2
- data/README.md +304 -48
- data/Rakefile +1 -2
- data/core/alpha.rb +2 -1
- data/core/array.rb +92 -96
- data/core/basic_object.rb +1 -10
- data/core/boolean.rb +6 -18
- data/core/class.rb +9 -10
- data/core/comparable.rb +1 -1
- data/core/enumerable.rb +11 -11
- data/core/enumerator.rb +2 -10
- data/core/error.rb +16 -31
- data/core/hash.rb +32 -36
- data/core/json.rb +50 -0
- data/core/kernel.rb +48 -57
- data/core/load_order +3 -5
- data/core/module.rb +37 -35
- data/core/nil_class.rb +4 -0
- data/core/numeric.rb +10 -30
- data/core/proc.rb +1 -1
- data/core/range.rb +3 -4
- data/core/regexp.rb +21 -6
- data/core/runtime.js +278 -370
- data/core/string.rb +21 -37
- data/core/struct.rb +11 -3
- data/core/time.rb +44 -37
- data/lib/opal.rb +3 -3
- data/lib/opal/builder.rb +48 -27
- data/lib/opal/builder_task.rb +3 -20
- data/lib/opal/grammar.rb +18 -13
- data/lib/opal/grammar.y +7 -4
- data/lib/opal/parser.rb +290 -199
- data/lib/opal/scope.rb +187 -176
- data/lib/opal/version.rb +1 -1
- data/test/core/kernel/define_singleton_method_spec.rb +21 -0
- data/test/core/time/at_spec.rb +7 -0
- data/test/core/time/day_spec.rb +5 -0
- data/test/core/time/friday_spec.rb +9 -0
- data/test/core/time/hour_spec.rb +5 -0
- data/test/core/time/min_spec.rb +5 -0
- data/test/core/time/monday_spec.rb +9 -0
- data/test/core/time/month_spec.rb +5 -0
- data/test/core/time/now_spec.rb +5 -0
- data/test/core/time/saturday_spec.rb +9 -0
- data/test/index.html +2 -1
- data/test/language/singleton_class_spec.rb +0 -16
- data/test/opal/array/to_json_spec.rb +7 -0
- data/test/opal/boolean/singleton_class_spec.rb +9 -0
- data/test/opal/boolean/to_json_spec.rb +9 -0
- data/test/opal/hash/to_json_spec.rb +9 -0
- data/test/opal/json/parse_spec.rb +31 -0
- data/test/opal/kernel/to_json_spec.rb +5 -0
- data/test/opal/nil/to_json_spec.rb +5 -0
- data/test/opal/numeric/to_json_spec.rb +6 -0
- data/test/opal/runtime/call_spec.rb +16 -0
- data/test/opal/runtime/defined_spec.rb +11 -0
- data/test/opal/runtime/super_spec.rb +16 -0
- data/test/opal/string/to_json_spec.rb +6 -0
- data/test/spec_helper.rb +1 -3
- metadata +48 -15
- data/core/dir.rb +0 -89
- data/core/file.rb +0 -85
- data/core/match_data.rb +0 -35
- data/core/rational.rb +0 -16
- data/test/core/file/expand_path_spec.rb +0 -20
data/core/string.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
class String < `String`
|
2
2
|
%x{
|
3
|
-
|
4
|
-
var string_class = this;
|
3
|
+
String_prototype._isString = true;
|
5
4
|
}
|
6
5
|
|
7
6
|
include Comparable
|
@@ -80,7 +79,7 @@ class String < `String`
|
|
80
79
|
def =~(other)
|
81
80
|
%x{
|
82
81
|
if (typeof other === 'string') {
|
83
|
-
|
82
|
+
#{ raise 'string given' };
|
84
83
|
}
|
85
84
|
|
86
85
|
return #{other =~ self};
|
@@ -88,8 +87,7 @@ class String < `String`
|
|
88
87
|
end
|
89
88
|
|
90
89
|
# TODO: implement range based accessors
|
91
|
-
|
92
|
-
def [](index, length = undefined)
|
90
|
+
def [](index, length)
|
93
91
|
%x{
|
94
92
|
if (length == null) {
|
95
93
|
if (index < 0) {
|
@@ -162,9 +160,7 @@ class String < `String`
|
|
162
160
|
`this.charAt(0)`
|
163
161
|
end
|
164
162
|
|
165
|
-
|
166
|
-
`this.toLowerCase()`
|
167
|
-
end
|
163
|
+
alias_native :downcase, :toLowerCase
|
168
164
|
|
169
165
|
alias each_char chars
|
170
166
|
|
@@ -204,12 +200,10 @@ class String < `String`
|
|
204
200
|
`this.toString() === val.toString()`
|
205
201
|
end
|
206
202
|
|
207
|
-
|
208
|
-
`this.charCodeAt(index)`
|
209
|
-
end
|
203
|
+
alias_native :getbyte, :charCodeAt
|
210
204
|
|
211
|
-
def gsub(pattern, replace
|
212
|
-
return enum_for :gsub, pattern, replace if !block && `pattern
|
205
|
+
def gsub(pattern, replace, &block)
|
206
|
+
return enum_for :gsub, pattern, replace if !block && `pattern == null`
|
213
207
|
|
214
208
|
if pattern.is_a?(String)
|
215
209
|
pattern = /#{Regexp.escape(pattern)}/
|
@@ -224,9 +218,7 @@ class String < `String`
|
|
224
218
|
}
|
225
219
|
end
|
226
220
|
|
227
|
-
|
228
|
-
`this.toString()`
|
229
|
-
end
|
221
|
+
alias_native :hash, :toString
|
230
222
|
|
231
223
|
def hex
|
232
224
|
to_i 16
|
@@ -236,7 +228,7 @@ class String < `String`
|
|
236
228
|
`this.indexOf(other) !== -1`
|
237
229
|
end
|
238
230
|
|
239
|
-
def index(what, offset
|
231
|
+
def index(what, offset)
|
240
232
|
unless String === what || Regexp === what
|
241
233
|
raise TypeError, "type mismatch: #{what.class} given"
|
242
234
|
end
|
@@ -244,7 +236,7 @@ class String < `String`
|
|
244
236
|
%x{
|
245
237
|
var result = -1;
|
246
238
|
|
247
|
-
if (offset
|
239
|
+
if (offset != null) {
|
248
240
|
if (offset < 0) {
|
249
241
|
offset = this.length - offset;
|
250
242
|
}
|
@@ -315,7 +307,7 @@ class String < `String`
|
|
315
307
|
`this.replace(/^\\s*/, '')`
|
316
308
|
end
|
317
309
|
|
318
|
-
def match(pattern, pos
|
310
|
+
def match(pattern, pos, &block)
|
319
311
|
(pattern.is_a?(Regexp) ? pattern : /#{Regexp.escape(pattern)}/).match(self, pos, &block)
|
320
312
|
end
|
321
313
|
|
@@ -377,15 +369,13 @@ class String < `String`
|
|
377
369
|
`this.replace(/^\\s*/, '').replace(/\\s*$/, '')`
|
378
370
|
end
|
379
371
|
|
380
|
-
def sub(pattern, replace
|
372
|
+
def sub(pattern, replace, &block)
|
381
373
|
%x{
|
382
374
|
if (typeof(replace) === 'string') {
|
383
375
|
return this.replace(pattern, replace);
|
384
376
|
}
|
385
377
|
if (block !== nil) {
|
386
378
|
return this.replace(pattern, function(str) {
|
387
|
-
//$opal.match_data = arguments
|
388
|
-
|
389
379
|
return block.call(__context, str);
|
390
380
|
});
|
391
381
|
}
|
@@ -394,13 +384,13 @@ class String < `String`
|
|
394
384
|
return this.replace(pattern, function(str) {
|
395
385
|
var value = #{replace[str]};
|
396
386
|
|
397
|
-
return (value
|
387
|
+
return (value == null) ? nil : #{value.to_s};
|
398
388
|
});
|
399
389
|
}
|
400
390
|
else {
|
401
391
|
replace = #{String.try_convert(replace)};
|
402
392
|
|
403
|
-
if (replace
|
393
|
+
if (replace == null) {
|
404
394
|
#{raise TypeError, "can't convert #{replace.class} into String"};
|
405
395
|
}
|
406
396
|
|
@@ -433,7 +423,7 @@ class String < `String`
|
|
433
423
|
return $1 ? $0.toUpperCase() : $0.toLowerCase();
|
434
424
|
});
|
435
425
|
|
436
|
-
if (this._klass ===
|
426
|
+
if (this._klass === String) {
|
437
427
|
return str;
|
438
428
|
}
|
439
429
|
|
@@ -455,11 +445,7 @@ class String < `String`
|
|
455
445
|
%x{
|
456
446
|
var result = parseFloat(this);
|
457
447
|
|
458
|
-
|
459
|
-
return 0;
|
460
|
-
}
|
461
|
-
|
462
|
-
return result;
|
448
|
+
return isNaN(result) ? 0 : result;
|
463
449
|
}
|
464
450
|
end
|
465
451
|
|
@@ -475,6 +461,8 @@ class String < `String`
|
|
475
461
|
}
|
476
462
|
end
|
477
463
|
|
464
|
+
alias to_json inspect
|
465
|
+
|
478
466
|
def to_proc
|
479
467
|
%x{
|
480
468
|
var self = this, jsid = mid_to_jsid(self);
|
@@ -483,17 +471,13 @@ class String < `String`
|
|
483
471
|
}
|
484
472
|
end
|
485
473
|
|
486
|
-
|
487
|
-
`this.toString()`
|
488
|
-
end
|
474
|
+
alias_native :to_s, :toString
|
489
475
|
|
490
476
|
alias to_str to_s
|
491
477
|
|
492
478
|
alias to_sym intern
|
493
479
|
|
494
|
-
|
495
|
-
`this.toUpperCase()`
|
496
|
-
end
|
480
|
+
alias_native :upcase, :toUpperCase
|
497
481
|
end
|
498
482
|
|
499
|
-
Symbol = String
|
483
|
+
Symbol = String
|
data/core/struct.rb
CHANGED
@@ -2,7 +2,7 @@ class Struct
|
|
2
2
|
def self.new(name, *args)
|
3
3
|
return super unless self == Struct
|
4
4
|
|
5
|
-
if name.
|
5
|
+
if name[0] == name[0].upcase
|
6
6
|
Struct.const_set(name, new(*args))
|
7
7
|
else
|
8
8
|
args.unshift name
|
@@ -14,6 +14,10 @@ class Struct
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.define_struct_attribute(name)
|
17
|
+
if self == Struct
|
18
|
+
raise ArgumentError, 'you cannot define attributes to the Struct class'
|
19
|
+
end
|
20
|
+
|
17
21
|
members << name
|
18
22
|
|
19
23
|
define_method name do
|
@@ -26,6 +30,10 @@ class Struct
|
|
26
30
|
end
|
27
31
|
|
28
32
|
def self.members
|
33
|
+
if self == Struct
|
34
|
+
raise ArgumentError, 'the Struct class has no members'
|
35
|
+
end
|
36
|
+
|
29
37
|
@members ||= []
|
30
38
|
end
|
31
39
|
|
@@ -42,7 +50,7 @@ class Struct
|
|
42
50
|
end
|
43
51
|
|
44
52
|
def [](name)
|
45
|
-
if name
|
53
|
+
if Integer === name
|
46
54
|
raise IndexError, "offset #{name} too large for struct(size:#{members.size})" if name >= members.size
|
47
55
|
|
48
56
|
name = members[name]
|
@@ -54,7 +62,7 @@ class Struct
|
|
54
62
|
end
|
55
63
|
|
56
64
|
def []=(name, value)
|
57
|
-
if name
|
65
|
+
if Integer === name
|
58
66
|
raise IndexError, "offset #{name} too large for struct(size:#{members.size})" if name >= members.size
|
59
67
|
|
60
68
|
name = members[name]
|
data/core/time.rb
CHANGED
@@ -1,36 +1,43 @@
|
|
1
|
-
class Time
|
1
|
+
class Time < `Date`
|
2
2
|
include Comparable
|
3
3
|
|
4
4
|
def self.at(seconds, frac = 0)
|
5
|
-
|
6
|
-
`result.time = new Date(seconds * 1000 + frac)`
|
7
|
-
result
|
5
|
+
allocate `seconds * 1000 + frac`
|
8
6
|
end
|
9
7
|
|
10
|
-
def self.
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
def self.new(year, month, day, hour, minute, second, millisecond)
|
9
|
+
%x{
|
10
|
+
switch (arguments.length) {
|
11
|
+
case 1:
|
12
|
+
return new Date(year);
|
13
|
+
case 2:
|
14
|
+
return new Date(year, month - 1);
|
15
|
+
case 3:
|
16
|
+
return new Date(year, month - 1, day);
|
17
|
+
case 4:
|
18
|
+
return new Date(year, month - 1, day, hour);
|
19
|
+
case 5:
|
20
|
+
return new Date(year, month - 1, day, hour, minute);
|
21
|
+
case 6:
|
22
|
+
return new Date(year, month - 1, day, hour, minute, second);
|
23
|
+
case 7:
|
24
|
+
return new Date(year, month - 1, day, hour, minute, second, millisecond);
|
25
|
+
default:
|
26
|
+
return new Date();
|
27
|
+
}
|
28
|
+
}
|
14
29
|
end
|
15
30
|
|
16
|
-
def
|
17
|
-
|
31
|
+
def self.now
|
32
|
+
allocate
|
18
33
|
end
|
19
34
|
|
20
35
|
def +(other)
|
21
|
-
|
22
|
-
var res = #{Time.allocate};
|
23
|
-
res.time = new Date(#{to_f + other.to_f});
|
24
|
-
return res;
|
25
|
-
}
|
36
|
+
Time.allocate(self.to_f + other.to_f)
|
26
37
|
end
|
27
38
|
|
28
39
|
def -(other)
|
29
|
-
|
30
|
-
var res = #{Time.allocate};
|
31
|
-
res.time = new Date(#{to_f - other.to_f});
|
32
|
-
return res;
|
33
|
-
}
|
40
|
+
Time.allocate(self.to_f - other.to_f)
|
34
41
|
end
|
35
42
|
|
36
43
|
def <=>(other)
|
@@ -38,7 +45,7 @@ class Time
|
|
38
45
|
end
|
39
46
|
|
40
47
|
def day
|
41
|
-
`this.
|
48
|
+
`this.getDate()`
|
42
49
|
end
|
43
50
|
|
44
51
|
def eql?(other)
|
@@ -46,66 +53,66 @@ class Time
|
|
46
53
|
end
|
47
54
|
|
48
55
|
def friday?
|
49
|
-
`this.
|
56
|
+
`this.getDay() === 5`
|
50
57
|
end
|
51
58
|
|
52
59
|
def hour
|
53
|
-
`this.
|
60
|
+
`this.getHours()`
|
54
61
|
end
|
55
62
|
|
56
63
|
alias mday day
|
57
64
|
|
58
65
|
def min
|
59
|
-
`this.
|
66
|
+
`this.getMinutes()`
|
60
67
|
end
|
61
68
|
|
62
69
|
def mon
|
63
|
-
`this.
|
70
|
+
`this.getMonth() + 1`
|
64
71
|
end
|
65
72
|
|
66
73
|
def monday?
|
67
|
-
`this.
|
74
|
+
`this.getDay() === 1`
|
68
75
|
end
|
69
76
|
|
70
77
|
alias month mon
|
71
78
|
|
72
79
|
def saturday?
|
73
|
-
`this.
|
80
|
+
`this.getDay() === 6`
|
74
81
|
end
|
75
82
|
|
76
83
|
def sec
|
77
|
-
`this.
|
84
|
+
`this.getSeconds()`
|
78
85
|
end
|
79
86
|
|
80
87
|
def sunday?
|
81
|
-
`this.
|
88
|
+
`this.getDay() === 0`
|
82
89
|
end
|
83
90
|
|
84
91
|
def thursday?
|
85
|
-
`this.
|
92
|
+
`this.getDay() === 4`
|
86
93
|
end
|
87
94
|
|
88
95
|
def to_f
|
89
|
-
`this.
|
96
|
+
`this.getTime() / 1000`
|
90
97
|
end
|
91
98
|
|
92
99
|
def to_i
|
93
|
-
`parseInt(this.
|
100
|
+
`parseInt(this.getTime() / 1000)`
|
94
101
|
end
|
95
102
|
|
96
103
|
def tuesday?
|
97
|
-
`this.
|
104
|
+
`this.getDay() === 2`
|
98
105
|
end
|
99
106
|
|
100
107
|
def wday
|
101
|
-
`this.
|
108
|
+
`this.getDay()`
|
102
109
|
end
|
103
110
|
|
104
111
|
def wednesday?
|
105
|
-
`this.
|
112
|
+
`this.getDay() === 3`
|
106
113
|
end
|
107
114
|
|
108
115
|
def year
|
109
|
-
`this.
|
116
|
+
`this.getFullYear()`
|
110
117
|
end
|
111
|
-
end
|
118
|
+
end
|
data/lib/opal.rb
CHANGED
@@ -5,9 +5,9 @@ require 'opal/version'
|
|
5
5
|
|
6
6
|
module Opal
|
7
7
|
# Parse given string of ruby into javascript
|
8
|
-
def self.parse(str)
|
9
|
-
js = Parser.new.parse str
|
10
|
-
"(#{js})
|
8
|
+
def self.parse(str, file='(file)')
|
9
|
+
js = Parser.new.parse str, file
|
10
|
+
"(#{js})();"
|
11
11
|
end
|
12
12
|
|
13
13
|
# Returns opal runtime js code (string)
|
data/lib/opal/builder.rb
CHANGED
@@ -12,23 +12,17 @@ module Opal
|
|
12
12
|
|
13
13
|
methods = Parser::METHOD_NAMES.map { |f, t| "'#{f}': '$#{t}$'" }
|
14
14
|
runtime = File.read(File.join core_dir, 'runtime.js')
|
15
|
-
corelib = Opal.parse corelib.join("\n")
|
15
|
+
corelib = Opal.parse corelib.join("\n"), '(corelib)'
|
16
16
|
|
17
17
|
[
|
18
|
-
"
|
19
|
-
"
|
20
|
-
"
|
21
|
-
"
|
22
|
-
" * Copyright 2012, Adam Beynon",
|
23
|
-
" * Released under the MIT License",
|
24
|
-
" */",
|
18
|
+
"// Opal v#{Opal::VERSION}",
|
19
|
+
"// http://opalrb.org",
|
20
|
+
"// Copyright 2012, Adam Beynon",
|
21
|
+
"// Released under the MIT License",
|
25
22
|
"(function(undefined) {",
|
26
23
|
runtime,
|
27
|
-
"var method_names = {#{ methods.join ', ' }}
|
28
|
-
"
|
29
|
-
"for (var id in method_names) {",
|
30
|
-
"reverse_method_names[method_names[id]] = id;",
|
31
|
-
"}",
|
24
|
+
"var method_names = {#{ methods.join ', ' }};",
|
25
|
+
"Opal.version = #{ Opal::VERSION.inspect };",
|
32
26
|
corelib,
|
33
27
|
"}).call(this);"
|
34
28
|
].join("\n")
|
@@ -41,7 +35,6 @@ module Opal
|
|
41
35
|
def initialize(options = {})
|
42
36
|
@sources = Array(options[:files])
|
43
37
|
@options = options
|
44
|
-
@debug = !!options[:debug]
|
45
38
|
end
|
46
39
|
|
47
40
|
def build
|
@@ -50,11 +43,13 @@ module Opal
|
|
50
43
|
end
|
51
44
|
|
52
45
|
@dir = File.expand_path(@options[:dir] || Dir.getwd)
|
53
|
-
@main = @options[:main]
|
54
46
|
|
55
47
|
files = files_for @sources
|
56
48
|
FileUtils.mkdir_p File.dirname(out)
|
57
49
|
|
50
|
+
@files = {}
|
51
|
+
@requires = {}
|
52
|
+
|
58
53
|
build_to files, out
|
59
54
|
end
|
60
55
|
|
@@ -70,36 +65,62 @@ module Opal
|
|
70
65
|
end
|
71
66
|
end
|
72
67
|
|
73
|
-
files.map! { |f| File.expand_path f }
|
74
|
-
|
75
68
|
files
|
76
69
|
end
|
77
70
|
|
78
71
|
def build_to(files, out)
|
79
|
-
@parser = Parser.new
|
72
|
+
@parser = Parser.new
|
80
73
|
|
81
74
|
files.each { |file| build_file(file) }
|
82
75
|
|
83
76
|
File.open(out, 'w+') do |o|
|
84
|
-
|
85
|
-
|
86
|
-
o.puts js
|
77
|
+
build_order(@requires).each do |f|
|
78
|
+
o.puts @files[f]
|
87
79
|
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param [Hash<Array<String>>] files hash of dependencies
|
84
|
+
def build_order(files)
|
85
|
+
all = files.keys
|
86
|
+
result = []
|
87
|
+
handled = {}
|
88
|
+
|
89
|
+
all.each { |r| _find_build_order r, files, handled, result }
|
90
|
+
result
|
91
|
+
end
|
88
92
|
|
89
|
-
|
93
|
+
def _find_build_order(file, files, handled, result)
|
94
|
+
if handled[file] or !files[file]
|
95
|
+
return
|
90
96
|
end
|
97
|
+
|
98
|
+
handled[file] = true
|
99
|
+
|
100
|
+
files[file].each do |r|
|
101
|
+
_find_build_order r, files, handled, result
|
102
|
+
end
|
103
|
+
|
104
|
+
result << file
|
91
105
|
end
|
92
106
|
|
93
107
|
def build_file(file)
|
94
|
-
lib_name
|
108
|
+
lib_name = lib_name_for file
|
109
|
+
parser_name = parser_name_for file
|
95
110
|
|
96
|
-
|
97
|
-
@parser.parse File.read(file),
|
111
|
+
if File.extname(file) == '.rb'
|
112
|
+
code = @parser.parse File.read(file), parser_name
|
113
|
+
@requires[lib_name] = @parser.requires
|
114
|
+
code = "(#{code})();"
|
98
115
|
else
|
99
|
-
File.read file
|
116
|
+
code = File.read file
|
100
117
|
end
|
101
118
|
|
102
|
-
"
|
119
|
+
@files[lib_name] = "// file #{ parser_name }\n#{ code }"
|
120
|
+
end
|
121
|
+
|
122
|
+
def parser_name_for(file)
|
123
|
+
file.sub /^#{@dir}\//, ''
|
103
124
|
end
|
104
125
|
|
105
126
|
def lib_name_for(file)
|