opal 0.10.0.beta3 → 0.10.0.beta4
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/CHANGELOG.md +9 -1
- data/HACKING.md +2 -2
- data/docs/compiled_ruby.md +6 -6
- data/lib/opal/cli_runners/nodejs.rb +3 -1
- data/lib/opal/nodes/args/mlhsarg.rb +1 -3
- data/lib/opal/nodes/def.rb +18 -54
- data/lib/opal/nodes/helpers.rb +3 -3
- data/lib/opal/nodes/iter.rb +32 -3
- data/lib/opal/nodes/logic.rb +5 -5
- data/lib/opal/nodes/node_with_args.rb +31 -0
- data/lib/opal/parser/lexer.rb +9 -7
- data/lib/opal/sprockets/processor.rb +2 -2
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array.rb +16 -0
- data/opal/corelib/basic_object.rb +1 -1
- data/opal/corelib/class.rb +15 -0
- data/opal/corelib/constants.rb +1 -1
- data/opal/corelib/enumerable.rb +32 -62
- data/opal/corelib/file.rb +2 -0
- data/opal/corelib/helpers.rb +41 -1
- data/opal/corelib/module.rb +26 -10
- data/opal/corelib/runtime.js +47 -12
- data/spec/filters/bugs/date.rb +0 -9
- data/spec/filters/bugs/hash.rb +0 -2
- data/spec/filters/bugs/kernel.rb +0 -5
- data/spec/filters/bugs/language.rb +4 -19
- data/spec/filters/bugs/module.rb +0 -30
- data/spec/filters/bugs/pathname.rb +5 -0
- data/spec/filters/bugs/proc.rb +0 -6
- data/spec/filters/unsupported/thread.rb +1 -0
- data/spec/lib/compiler_spec.rb +29 -29
- data/spec/opal/core/runtime/truthy_spec.rb +26 -0
- data/spec/ruby_specs +0 -3
- data/stdlib/date.rb +21 -0
- data/stdlib/native.rb +1 -1
- data/stdlib/nodejs/file.rb +36 -11
- data/stdlib/nodejs/io.rb +55 -0
- data/stdlib/pathname.rb +43 -0
- data/stdlib/promise.rb +1 -1
- data/tasks/testing.rake +55 -31
- data/test/nodejs/test_file.rb +30 -0
- metadata +6 -2
@@ -34,4 +34,30 @@ describe "Opal truthyness" do
|
|
34
34
|
|
35
35
|
is_falsey.should be_true
|
36
36
|
end
|
37
|
+
|
38
|
+
it "should consider false, nil, null, and undefined as not truthy" do
|
39
|
+
called = nil
|
40
|
+
[`false`, `nil`, `null`, `undefined`].each do |v|
|
41
|
+
if v
|
42
|
+
called = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
called.should be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should true as truthy" do
|
50
|
+
if `true`
|
51
|
+
called = true
|
52
|
+
end
|
53
|
+
|
54
|
+
called.should be_true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should handle logic operators correctly for false, nil, null, and undefined" do
|
58
|
+
(`false` || `nil` || `null` || `undefined` || 1).should == 1
|
59
|
+
[`false`, `nil`, `null`, `undefined`].each do |v|
|
60
|
+
`#{1 && v} === #{v}`.should == true
|
61
|
+
end
|
62
|
+
end
|
37
63
|
end
|
data/spec/ruby_specs
CHANGED
@@ -100,9 +100,6 @@ ruby/core/unboundmethod
|
|
100
100
|
ruby/language
|
101
101
|
!ruby/language/constants_spec
|
102
102
|
!ruby/language/execution_spec
|
103
|
-
!ruby/language/next_spec
|
104
|
-
!ruby/language/return_spec
|
105
|
-
!ruby/language/yield_spec
|
106
103
|
|
107
104
|
ruby/library/base64
|
108
105
|
ruby/library/bigdecimal
|
data/stdlib/date.rb
CHANGED
@@ -338,6 +338,10 @@ class Date
|
|
338
338
|
def today
|
339
339
|
wrap `new Date()`
|
340
340
|
end
|
341
|
+
|
342
|
+
def gregorian_leap?(year)
|
343
|
+
`(new Date(#{year}, 1, 29).getMonth()-1) === 0`
|
344
|
+
end
|
341
345
|
end
|
342
346
|
|
343
347
|
def initialize(year = -4712, month = 1, day = 1, start = ITALY)
|
@@ -411,6 +415,10 @@ class Date
|
|
411
415
|
|
412
416
|
def <=>(other)
|
413
417
|
%x{
|
418
|
+
if (other.$$is_number) {
|
419
|
+
return #{self.jd <=> other}
|
420
|
+
}
|
421
|
+
|
414
422
|
var a = #@date, b = #{other}.date;
|
415
423
|
a.setHours(0, 0, 0, 0);
|
416
424
|
b.setHours(0, 0, 0, 0);
|
@@ -601,6 +609,19 @@ class Date
|
|
601
609
|
`#@date.getFullYear()`
|
602
610
|
end
|
603
611
|
|
612
|
+
def cwday
|
613
|
+
`#@date.getDay() || 7;`
|
614
|
+
end
|
615
|
+
|
616
|
+
def cweek
|
617
|
+
%x{
|
618
|
+
var d = new Date(#@date);
|
619
|
+
d.setHours(0,0,0);
|
620
|
+
d.setDate(d.getDate()+4-(d.getDay()||7));
|
621
|
+
return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
|
622
|
+
}
|
623
|
+
end
|
624
|
+
|
604
625
|
%x{
|
605
626
|
function days_in_month(year, month) {
|
606
627
|
var leap = ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
|
data/stdlib/native.rb
CHANGED
@@ -59,7 +59,7 @@ module Native
|
|
59
59
|
if (prop instanceof Function) {
|
60
60
|
var converted = new Array(args.length);
|
61
61
|
|
62
|
-
for (var i = 0,
|
62
|
+
for (var i = 0, l = args.length; i < l; i++) {
|
63
63
|
var item = args[i],
|
64
64
|
conv = #{try_convert(`item`)};
|
65
65
|
|
data/stdlib/nodejs/file.rb
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
%x{
|
2
|
+
var warnings = {};
|
3
|
+
function handle_unsupported_feature(message) {
|
4
|
+
switch (Opal.config.unsupported_features_severity) {
|
5
|
+
case 'error':
|
6
|
+
#{Kernel.raise NotImplementedError, `message`}
|
7
|
+
break;
|
8
|
+
case 'warning':
|
9
|
+
warn(message)
|
10
|
+
break;
|
11
|
+
default: // ignore
|
12
|
+
// noop
|
13
|
+
}
|
14
|
+
}
|
15
|
+
function warn(string) {
|
16
|
+
if (warnings[string]) {
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
warnings[string] = true;
|
20
|
+
#{warn(`string`)};
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
1
24
|
class File < IO
|
2
25
|
include ::IO::Writable
|
3
26
|
include ::IO::Readable
|
@@ -35,14 +58,6 @@ class File < IO
|
|
35
58
|
end
|
36
59
|
end
|
37
60
|
|
38
|
-
def self.basename(path, ext = undefined)
|
39
|
-
`__path__.basename(#{path}, #{ext})`
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.dirname(path)
|
43
|
-
`__path__.dirname(#{path})`
|
44
|
-
end
|
45
|
-
|
46
61
|
def self.join(*paths)
|
47
62
|
`__path__.join.apply(__path__, #{paths})`
|
48
63
|
end
|
@@ -80,16 +95,20 @@ class File < IO
|
|
80
95
|
File::Stat.new(path)
|
81
96
|
end
|
82
97
|
|
98
|
+
def self.mtime path
|
99
|
+
`__fs__.statSync(#{path}).mtime`
|
100
|
+
end
|
101
|
+
|
83
102
|
# Instance Methods
|
84
103
|
|
85
104
|
def initialize(path, flags)
|
86
105
|
binary_flag_regexp = /b/
|
87
106
|
encoding_flag_regexp = /:(.*)/
|
88
107
|
# binary flag is unsupported
|
89
|
-
|
108
|
+
`handle_unsupported_feature("Binary flag (b) is unsupported by Node.js openSync method, removing flag.")` if flags.match(binary_flag_regexp)
|
90
109
|
flags = flags.gsub(binary_flag_regexp, '')
|
91
110
|
# encoding flag is unsupported
|
92
|
-
|
111
|
+
`handle_unsupported_feature("Encoding flag (:encoding) is unsupported by Node.js openSync method, removing flag.")` if flags.match(encoding_flag_regexp)
|
93
112
|
flags = flags.gsub(encoding_flag_regexp, '')
|
94
113
|
@path = path
|
95
114
|
@flags = flags
|
@@ -109,6 +128,10 @@ class File < IO
|
|
109
128
|
def close
|
110
129
|
`__fs__.closeSync(#{@fd})`
|
111
130
|
end
|
131
|
+
|
132
|
+
def mtime
|
133
|
+
`__fs__.statSync(#{@path}).mtime`
|
134
|
+
end
|
112
135
|
end
|
113
136
|
|
114
137
|
class File::Stat
|
@@ -120,9 +143,11 @@ class File::Stat
|
|
120
143
|
@path = path
|
121
144
|
end
|
122
145
|
|
123
|
-
|
124
146
|
def file?
|
125
147
|
`__fs__.statSync(#{@path}).isFile()`
|
126
148
|
end
|
127
149
|
|
150
|
+
def mtime
|
151
|
+
`__fs__.statSync(#{@path}).mtime`
|
152
|
+
end
|
128
153
|
end
|
data/stdlib/nodejs/io.rb
CHANGED
@@ -1,3 +1,58 @@
|
|
1
|
+
class IO
|
2
|
+
|
3
|
+
@__fs__ = node_require :fs
|
4
|
+
`var __fs__ = #{@__fs__}`
|
5
|
+
|
6
|
+
attr_reader :eof
|
7
|
+
attr_reader :lineno
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@eof = false
|
11
|
+
@lineno = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def read
|
15
|
+
if @eof
|
16
|
+
''
|
17
|
+
else
|
18
|
+
res = `__fs__.readFileSync(#{@path}).toString()`
|
19
|
+
@eof = true
|
20
|
+
@lineno = res.size
|
21
|
+
res
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def each_line(separator = $/, &block)
|
26
|
+
if @eof
|
27
|
+
return block_given? ? self : [].to_enum
|
28
|
+
end
|
29
|
+
|
30
|
+
if block_given?
|
31
|
+
lines = File.read(@path)
|
32
|
+
%x{
|
33
|
+
self.eof = false;
|
34
|
+
self.lineno = 0;
|
35
|
+
var chomped = #{lines.chomp},
|
36
|
+
trailing = lines.length != chomped.length,
|
37
|
+
splitted = chomped.split(separator);
|
38
|
+
for (var i = 0, length = splitted.length; i < length; i++) {
|
39
|
+
self.lineno += 1;
|
40
|
+
if (i < length - 1 || trailing) {
|
41
|
+
#{yield `splitted[i] + separator`};
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
#{yield `splitted[i]`};
|
45
|
+
}
|
46
|
+
}
|
47
|
+
self.eof = true;
|
48
|
+
}
|
49
|
+
self
|
50
|
+
else
|
51
|
+
read.each_line
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
1
56
|
STDOUT.write_proc = -> (string) {`process.stdout.write(string)`}
|
2
57
|
STDERR.write_proc = -> (string) {`process.stderr.write(string)`}
|
3
58
|
|
data/stdlib/pathname.rb
CHANGED
@@ -166,6 +166,49 @@ class Pathname
|
|
166
166
|
|
167
167
|
alias :to_str :to_path
|
168
168
|
alias :to_s :to_path
|
169
|
+
|
170
|
+
SAME_PATHS = if File::FNM_SYSCASE.nonzero?
|
171
|
+
# Avoid #zero? here because #casecmp can return nil.
|
172
|
+
proc {|a, b| a.casecmp(b) == 0}
|
173
|
+
else
|
174
|
+
proc {|a, b| a == b}
|
175
|
+
end
|
176
|
+
|
177
|
+
def relative_path_from(base_directory)
|
178
|
+
dest_directory = self.cleanpath.to_s
|
179
|
+
base_directory = base_directory.cleanpath.to_s
|
180
|
+
dest_prefix = dest_directory
|
181
|
+
dest_names = []
|
182
|
+
while r = chop_basename(dest_prefix)
|
183
|
+
dest_prefix, basename = r
|
184
|
+
dest_names.unshift basename if basename != '.'
|
185
|
+
end
|
186
|
+
base_prefix = base_directory
|
187
|
+
base_names = []
|
188
|
+
while r = chop_basename(base_prefix)
|
189
|
+
base_prefix, basename = r
|
190
|
+
base_names.unshift basename if basename != '.'
|
191
|
+
end
|
192
|
+
unless SAME_PATHS[dest_prefix, base_prefix]
|
193
|
+
raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
|
194
|
+
end
|
195
|
+
while !dest_names.empty? &&
|
196
|
+
!base_names.empty? &&
|
197
|
+
SAME_PATHS[dest_names.first, base_names.first]
|
198
|
+
dest_names.shift
|
199
|
+
base_names.shift
|
200
|
+
end
|
201
|
+
if base_names.include? '..'
|
202
|
+
raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
|
203
|
+
end
|
204
|
+
base_names.fill('..')
|
205
|
+
relpath_names = base_names + dest_names
|
206
|
+
if relpath_names.empty?
|
207
|
+
Pathname.new('.')
|
208
|
+
else
|
209
|
+
Pathname.new(File.join(*relpath_names))
|
210
|
+
end
|
211
|
+
end
|
169
212
|
end
|
170
213
|
|
171
214
|
module Kernel
|
data/stdlib/promise.rb
CHANGED
data/tasks/testing.rake
CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:rspec) do |t|
|
|
8
8
|
t.pattern = 'spec/lib/**/*_spec.rb'
|
9
9
|
end
|
10
10
|
|
11
|
-
module
|
11
|
+
module MSpecSuite
|
12
12
|
extend self
|
13
13
|
|
14
14
|
def stubs
|
@@ -125,9 +125,9 @@ DESC
|
|
125
125
|
url = "http://localhost:#{port}/"
|
126
126
|
|
127
127
|
mkdir_p File.dirname(filename)
|
128
|
-
|
128
|
+
MSpecSuite.write_file filename, MSpecSuite.specs(ENV.to_hash.merge 'SUITE' => suite)
|
129
129
|
|
130
|
-
|
130
|
+
MSpecSuite.stubs.each {|s| ::Opal::Config.stubbed_files << s }
|
131
131
|
|
132
132
|
Opal::Config.arity_check_enabled = true
|
133
133
|
Opal::Config.freezing_stubs_enabled = true
|
@@ -157,10 +157,10 @@ DESC
|
|
157
157
|
|
158
158
|
filename = "tmp/mspec_#{platform}.rb"
|
159
159
|
mkdir_p File.dirname(filename)
|
160
|
-
bm_filepath =
|
161
|
-
|
160
|
+
bm_filepath = MSpecSuite.bm_filepath if ENV['BM']
|
161
|
+
MSpecSuite.write_file filename, MSpecSuite.specs(ENV.to_hash.merge 'SUITE' => suite), bm_filepath
|
162
162
|
|
163
|
-
stubs =
|
163
|
+
stubs = MSpecSuite.stubs.map{|s| "-s#{s}"}.join(' ')
|
164
164
|
|
165
165
|
sh "ruby -rbundler/setup -r#{__dir__}/testing/mspec_special_calls "\
|
166
166
|
"bin/opal -gmspec #{include_paths} #{stubs} -R#{platform} -Dwarning -A #{filename}"
|
@@ -199,47 +199,71 @@ task :jshint do
|
|
199
199
|
end
|
200
200
|
end
|
201
201
|
|
202
|
+
|
203
|
+
module MinitestSuite
|
204
|
+
extend self
|
205
|
+
|
206
|
+
def build_js_command(files, options = {})
|
207
|
+
includes = options.fetch(:includes, [])
|
208
|
+
js_filename = options.fetch(:js_filename, [])
|
209
|
+
|
210
|
+
includes << 'vendored-minitest'
|
211
|
+
include_paths = includes.map {|i| " -I#{i}"}.join
|
212
|
+
|
213
|
+
requires = files.map{|f| "require '#{f}'"}
|
214
|
+
rb_filename = js_filename.sub(/\.js$/, '.rb')
|
215
|
+
mkdir_p File.dirname(rb_filename)
|
216
|
+
File.write rb_filename, requires.join("\n")
|
217
|
+
|
218
|
+
stubs = "-soptparse -sio/console -stimeout -smutex_m -srubygems -stempfile -smonitor"
|
219
|
+
|
220
|
+
"ruby -rbundler/setup bin/opal #{include_paths} #{stubs} -Dwarning -A #{rb_filename} -c > #{js_filename}"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
202
224
|
task :cruby_tests do
|
203
225
|
if ENV.key? 'FILES'
|
204
|
-
files = Dir[ENV['FILES']
|
205
|
-
|
226
|
+
files = Dir[ENV['FILES']]
|
227
|
+
includes = %w[test . tmp lib]
|
206
228
|
else
|
207
|
-
|
208
|
-
test_dir = Pathname("#{__dir__}/../test/cruby/test")
|
229
|
+
includes = %w[test test/cruby/test]
|
209
230
|
files = %w[
|
210
231
|
benchmark/test_benchmark.rb
|
211
232
|
ruby/test_call.rb
|
212
233
|
opal/test_keyword.rb
|
213
234
|
base64/test_base64.rb
|
214
235
|
opal/unsupported_and_bugs.rb
|
215
|
-
]
|
216
|
-
if path.end_with?('.rb')
|
217
|
-
path
|
218
|
-
else
|
219
|
-
glob = test_dir.join(path+"/test_*.rb").to_s
|
220
|
-
size = test_dir.to_s.size
|
221
|
-
Dir[glob].map { |file| file[size+1..-1] }
|
222
|
-
end
|
223
|
-
end
|
236
|
+
]
|
224
237
|
end
|
225
|
-
include_paths << ' -Ivendored-minitest'
|
226
238
|
|
227
|
-
requires = files.map{|f| "require '#{f}'"}
|
228
|
-
filename = 'tmp/cruby_tests.rb'
|
229
239
|
js_filename = 'tmp/cruby_tests.js'
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
240
|
+
build_js_command = MinitestSuite.build_js_command(
|
241
|
+
%w[
|
242
|
+
opal/platform
|
243
|
+
opal-parser
|
244
|
+
] + files,
|
245
|
+
includes: includes,
|
246
|
+
js_filename: js_filename,
|
247
|
+
)
|
248
|
+
sh build_js_command
|
249
|
+
sh "NODE_PATH=stdlib/nodejs/node_modules node #{js_filename}"
|
250
|
+
end
|
236
251
|
|
237
|
-
|
238
|
-
|
252
|
+
task :test_nodejs do
|
253
|
+
js_filename = 'tmp/test_nodejs.js'
|
254
|
+
build_js_command = MinitestSuite.build_js_command(
|
255
|
+
%w[
|
256
|
+
opal-parser.rb
|
257
|
+
test_file.rb
|
258
|
+
],
|
259
|
+
includes: %w[test/nodejs],
|
260
|
+
js_filename: js_filename,
|
261
|
+
)
|
262
|
+
sh build_js_command
|
239
263
|
sh "NODE_PATH=stdlib/nodejs/node_modules node #{js_filename}"
|
240
264
|
end
|
241
265
|
|
242
266
|
task :mspec => [:mspec_phantomjs, :mspec_nodejs, :mspec_sprockets_phantomjs]
|
243
|
-
task :minitest => [:cruby_tests]
|
267
|
+
task :minitest => [:cruby_tests, :test_nodejs]
|
244
268
|
task :test_all => [:rspec, :mspec, :minitest]
|
245
269
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copied from cruby and modified to skip unsupported syntaxes
|
2
|
+
require 'test/unit'
|
3
|
+
require 'nodejs'
|
4
|
+
require 'nodejs/file'
|
5
|
+
|
6
|
+
class TestNodejsFile < Test::Unit::TestCase
|
7
|
+
def test_write_read
|
8
|
+
path = '/tmp/testing_nodejs_file_implementation'
|
9
|
+
contents = 'foobar'
|
10
|
+
assert !File.exist?(path)
|
11
|
+
File.write path, contents
|
12
|
+
|
13
|
+
assert_equal(contents, File.read(path))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_read_file
|
17
|
+
File.write('tmp/foo', 'bar')
|
18
|
+
assert_equal("bar", File.read('tmp/foo'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_read_each_line
|
22
|
+
File.write('tmp/bar', "one\ntwo")
|
23
|
+
file = File.new('tmp/bar', 'r')
|
24
|
+
lines = []
|
25
|
+
file.each_line do |line|
|
26
|
+
lines << line
|
27
|
+
end
|
28
|
+
assert_equal(lines.length, 2)
|
29
|
+
end
|
30
|
+
end
|