opal 0.3.19 → 0.3.20
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/.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)
|