opal 0.10.0.beta3 → 0.10.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/CHANGELOG.md +9 -1
  4. data/HACKING.md +2 -2
  5. data/docs/compiled_ruby.md +6 -6
  6. data/lib/opal/cli_runners/nodejs.rb +3 -1
  7. data/lib/opal/nodes/args/mlhsarg.rb +1 -3
  8. data/lib/opal/nodes/def.rb +18 -54
  9. data/lib/opal/nodes/helpers.rb +3 -3
  10. data/lib/opal/nodes/iter.rb +32 -3
  11. data/lib/opal/nodes/logic.rb +5 -5
  12. data/lib/opal/nodes/node_with_args.rb +31 -0
  13. data/lib/opal/parser/lexer.rb +9 -7
  14. data/lib/opal/sprockets/processor.rb +2 -2
  15. data/lib/opal/version.rb +1 -1
  16. data/opal/corelib/array.rb +16 -0
  17. data/opal/corelib/basic_object.rb +1 -1
  18. data/opal/corelib/class.rb +15 -0
  19. data/opal/corelib/constants.rb +1 -1
  20. data/opal/corelib/enumerable.rb +32 -62
  21. data/opal/corelib/file.rb +2 -0
  22. data/opal/corelib/helpers.rb +41 -1
  23. data/opal/corelib/module.rb +26 -10
  24. data/opal/corelib/runtime.js +47 -12
  25. data/spec/filters/bugs/date.rb +0 -9
  26. data/spec/filters/bugs/hash.rb +0 -2
  27. data/spec/filters/bugs/kernel.rb +0 -5
  28. data/spec/filters/bugs/language.rb +4 -19
  29. data/spec/filters/bugs/module.rb +0 -30
  30. data/spec/filters/bugs/pathname.rb +5 -0
  31. data/spec/filters/bugs/proc.rb +0 -6
  32. data/spec/filters/unsupported/thread.rb +1 -0
  33. data/spec/lib/compiler_spec.rb +29 -29
  34. data/spec/opal/core/runtime/truthy_spec.rb +26 -0
  35. data/spec/ruby_specs +0 -3
  36. data/stdlib/date.rb +21 -0
  37. data/stdlib/native.rb +1 -1
  38. data/stdlib/nodejs/file.rb +36 -11
  39. data/stdlib/nodejs/io.rb +55 -0
  40. data/stdlib/pathname.rb +43 -0
  41. data/stdlib/promise.rb +1 -1
  42. data/tasks/testing.rake +55 -31
  43. data/test/nodejs/test_file.rb +30 -0
  44. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e7bea1b676089d0921e603acafc794fe81fb671
4
- data.tar.gz: 798d0eef513a0f7a17eb283d810342ffddb64b03
3
+ metadata.gz: 39c814d73a4610d5d13c3d5ce1c8c969cb9fe910
4
+ data.tar.gz: e7e498becdff47976088a5a02bc98451f959d4a5
5
5
  SHA512:
6
- metadata.gz: c349f1c93f09a28b2e0c9285008901d985c4196548171318fadcd416e370e9dc2bcbc4d8b1e184b5e4646206e8c64efee28c58d8a4e11a0939eceb21f929912c
7
- data.tar.gz: 5af01ed324f7c9f0eec062d465d34e051d47bca3e24e33c72e17e6634a7b87cab060f303b3408a5644763e838c3051d29964f8e6d461408f8a18cd2726ceacfa
6
+ metadata.gz: baf8e4f7a5b411c3cfefb5c1da61d1fb3c5ce73fd0c102c8d46a3cb1968f75fd8cb2b421f55c74ba8e317a61980040cd5ca88971465d1ff660e2e98641f2a0e1
7
+ data.tar.gz: cb776c46e913187cc3581029256f8ca1ffca2139315dce2ee0d8e014a6858b7ea19445948a06a3be16bb7ef6e054357723308b6bbb6ca3f13f2da733870b8ed8
data/.travis.yml CHANGED
@@ -26,6 +26,9 @@ matrix:
26
26
  - rvm: 2.3.0
27
27
  env: RUN=mspec_ruby_sprockets_phantomjs
28
28
 
29
+ - rvm: 2.3.0
30
+ env: RUN=minitest
31
+
29
32
  - rvm: 2.3.0
30
33
  env: RUN=rspec RACK_VERSION='2.0.0.alpha' CHECK_COVERAGE=true
31
34
 
data/CHANGELOG.md CHANGED
@@ -26,6 +26,7 @@ Whitespace conventions:
26
26
 
27
27
  ### Added
28
28
 
29
+ - Pathname#relative_path_from
29
30
  - Source maps now include method names
30
31
  - `Module#included_modules` works
31
32
  - Internal runtime cleanup (#1241)
@@ -40,18 +41,22 @@ Whitespace conventions:
40
41
  * `Enumerable#max`
41
42
  * `Enumerable#each_entry` (#1303)
42
43
  * `Module#const_set`
44
+ * `Module#module_eval` with a string
43
45
  - Add `-L` / `--library` option to compile only the code of the library (#1281)
44
46
  - Implement `Kernel.open` method (#1218)
45
47
  - Generate meaningful names for functions representing Ruby methods
46
48
  - Implement `Pathname#join` and `Pathname#+` methods (#1301)
47
49
  - Added support for `begin;rescue;else;end`.
48
50
  - Implement `File.extname` method (#1219)
49
- - Implement File.extname method (#1219)
50
51
  - Added support for keyword arguments as lambda parameters.
51
52
  - Super works with define_method blocks
52
53
  - Added support for kwsplats.
53
54
  - Added support for squiggly heredoc.
54
55
  - Implement `Method#parameters` and `Proc#parameters`.
56
+ - Implement `File.new("path").mtime`, `File.mtime("path")`, `File.stat("path").mtime`.
57
+ - if-conditions now support `null` and `undefined` as falsy values (#867)
58
+ - Implement IO.read method for Node.js (#1332)
59
+ - Implement IO.each_line method for Node.js (#1221)
55
60
 
56
61
 
57
62
  ### Changed
@@ -78,6 +83,8 @@ Whitespace conventions:
78
83
 
79
84
  ### Fixed
80
85
 
86
+ - `Module#ancestors` and shared code like `====` and `is_a?` deal with singleton class modules better (#1449)
87
+ - `Class#to_s` now shows correct names for singleton classes
81
88
  - `Pathname#absolute?` and `Pathname#relative?` now work properly
82
89
  - `File::dirname` and `File::basename` are now Rubyspec compliant
83
90
  - `SourceMap::VLQ` patch (#1075)
@@ -114,6 +121,7 @@ Whitespace conventions:
114
121
  - Fixed Base64 and enabled specs
115
122
  - Fixed method definition in method body.
116
123
  - Partially implemented `Marshal.load`/`Marshal.dump`. In order to use it require `opal/full`.
124
+ - Fixed docs for Compiled Ruby - Native section. Rename opal variable to win since window was causing error
117
125
 
118
126
 
119
127
  ### Removed
data/HACKING.md CHANGED
@@ -51,7 +51,7 @@ $ bundle exec rake mspec_ruby_nodejs PATTERN=spec/ruby/core/string/sub_spec.rb
51
51
  This will make sure that only `spec/ruby/core/string/sub_spec.rb` is run, and no other specs are executed. Globs can be used too:
52
52
 
53
53
  ```
54
- $ bundle exec rake mspec_ruby_nodejs PATTERN=spec/ruby/core/string/*_spec.rb
54
+ $ bundle exec rake mspec_ruby_nodejs PATTERN="spec/ruby/core/string/*_spec.rb"
55
55
  ```
56
56
 
57
57
  Another way to quickly validate ideas and play with your changes is to use `opal-repl`, a tool similar to `irb`. Running `opal-repl` drops you into an interactive environment with your current version of Opal loaded, including any changes you have made.
@@ -82,7 +82,7 @@ Comment out any of the `fail` lines in any of the files in the `spec/filters/bug
82
82
  Core classes use each other and your changes may fix other bugs in `spec/filters/bugs`. If you think it's possible, run an inverted test suite by providing environment variable `INVERT_RUNNING_MODE=true`:
83
83
 
84
84
  ```
85
- $ env INVERT_RUNNING_MODE=true RUBYSPECS=true PATTERN=spec/ruby/core/string/*_spec.rb rake mspec_ruby_nodejs
85
+ $ env INVERT_RUNNING_MODE=true RUBYSPECS=true PATTERN="spec/ruby/core/string/*_spec.rb" rake mspec_ruby_nodejs
86
86
  ```
87
87
 
88
88
  This command will execute tests marked as "bugs" from every file in the `spec/ruby/core/string` directory. After running it you will get a list of specs that in fact are passing. Feel free to remove them from `spec/filters/bugs`.
@@ -275,26 +275,26 @@ Let's see how it works and wrap `window`:
275
275
  ```ruby
276
276
  require 'native'
277
277
 
278
- window = Native(`window`) # equivalent to Native::Object.new(`window`)
278
+ win = Native(`window`) # equivalent to Native::Object.new(`window`)
279
279
  ```
280
280
 
281
281
  Now what if we want to access one of its properties?
282
282
 
283
283
  ```ruby
284
- window[:location][:href] # => "http://dev.mikamai.com/"
285
- window[:location][:href] = "http://mikamai.com/" # will bring you to mikamai.com
284
+ win[:location][:href] # => "http://dev.mikamai.com/"
285
+ win[:location][:href] = "http://mikamai.com/" # will bring you to mikamai.com
286
286
  ```
287
287
 
288
288
  And what about methods?
289
289
 
290
290
  ```ruby
291
- window.alert('hey there!')
291
+ win.alert('hey there!')
292
292
  ```
293
293
 
294
294
  So let’s do something more interesting:
295
295
 
296
296
  ```ruby
297
- class << window
297
+ class << win
298
298
  # A cross-browser window close method (works in IE!)
299
299
  def close!
300
300
  %x{
@@ -314,7 +314,7 @@ end
314
314
  That’s all for now, bye!
315
315
 
316
316
  ```ruby
317
- window.close!
317
+ win.close!
318
318
  ```
319
319
 
320
320
  ### Calling JavaScript Methods
@@ -4,6 +4,8 @@ require 'opal/paths'
4
4
  module Opal
5
5
  module CliRunners
6
6
  class Nodejs
7
+ NODE_PATH = File.expand_path('../stdlib/nodejs/node_modules', ::Opal.gem_dir)
8
+
7
9
  def initialize(options)
8
10
  @output = options.fetch(:output, $stdout)
9
11
  end
@@ -14,7 +16,7 @@ module Opal
14
16
  end
15
17
 
16
18
  def node_modules
17
- File.expand_path('../stdlib/nodejs/node_modules', ::Opal.gem_dir)
19
+ NODE_PATH
18
20
  end
19
21
 
20
22
  def run(code, argv)
@@ -39,9 +39,7 @@ module Opal
39
39
  line " #{var_name} = nil;"
40
40
  line "}"
41
41
 
42
- line "if (!#{var_name}.$$is_array) {"
43
- line " #{var_name} = [#{var_name}];"
44
- line "}"
42
+ line "#{var_name} = Opal.to_ary(#{var_name});"
45
43
 
46
44
  scope.with_inline_args([]) do
47
45
  scope.in_mlhs do
@@ -48,16 +48,13 @@ module Opal
48
48
  compile_post_args
49
49
 
50
50
  scope.identify!
51
-
52
- if compiler.arity_check?
53
- arity_code = arity_check(mid)
54
- end
55
-
56
51
  scope_name = scope.identity
57
52
 
58
53
  compile_block_arg
59
54
 
60
- line arity_code if arity_code
55
+ if compiler.arity_check?
56
+ compile_arity_check
57
+ end
61
58
 
62
59
  if scope.uses_zuper
63
60
  add_local '$zuper'
@@ -97,60 +94,27 @@ module Opal
97
94
  push ", #{scope_name}.$$parameters = #{parameters_code}"
98
95
  end
99
96
 
100
- if recvr
101
- unshift 'Opal.defs(', recv(recvr), ", '$#{mid}', "
102
- push ')'
103
- elsif scope.iter?
104
- wrap "Opal.def(self, '$#{mid}', ", ')'
105
- elsif scope.module? || scope.class?
106
- wrap "Opal.defn(self, '$#{mid}', ", ')'
107
- elsif scope.sclass?
108
- if scope.defs
109
- unshift "Opal.defs(self, '$#{mid}', "
110
- else
111
- unshift "Opal.defn(self, '$#{mid}', "
112
- end
113
- push ')'
114
- elsif compiler.eval?
115
- unshift "Opal.def(self, '$#{mid}', "
116
- push ')'
117
- elsif scope.top?
118
- unshift "Opal.defn(Opal.Object, '$#{mid}', "
119
- push ')'
120
- elsif scope.def?
121
- wrap "Opal.def(self, '$#{mid}', ", ')'
122
- else
123
- raise "Unsupported use of `def`; please file a bug at https://github.com/opal/opal reporting this message."
97
+ if recvr then unshift 'Opal.defs(', recv(recvr), ", '$#{mid}', "
98
+ elsif scope.iter? then unshift "Opal.def(self, '$#{mid}', "
99
+ elsif scope.module? || scope.class? then unshift "Opal.defn(self, '$#{mid}', "
100
+ elsif scope.sclass? && scope.defs then unshift "Opal.defs(self, '$#{mid}', "
101
+ elsif scope.sclass? then unshift "Opal.defn(self, '$#{mid}', "
102
+ elsif compiler.eval? then unshift "Opal.def(self, '$#{mid}', "
103
+ elsif scope.top? then unshift "Opal.defn(Opal.Object, '$#{mid}', "
104
+ elsif scope.def? then unshift "Opal.def(self, '$#{mid}', "
105
+ else raise "Unsupported use of `def`; please file a bug at https://github.com/opal/opal/issues/new reporting this message."
124
106
  end
107
+ push ')'
125
108
 
126
109
  wrap '(', ", nil) && '#{mid}'" if expr?
127
110
  end
128
111
 
129
112
  # Returns code used in debug mode to check arity of method call
130
- def arity_check(mid)
131
- meth = mid.to_s.inspect
132
-
133
- arity = args.size - 1
134
- arity -= (opt_args.size)
135
-
136
- arity -= 1 if rest_arg
137
-
138
- arity -= (keyword_args.size)
139
-
140
- arity = -arity - 1 if !opt_args.empty? or !keyword_args.empty? or rest_arg
141
-
142
- # $arity will point to our received arguments count
143
- aritycode = "var $arity = arguments.length;"
144
-
145
- if arity < 0 # splat or opt args
146
- min_arity = -(arity + 1)
147
- max_arity = args.size - 1
148
- checks = []
149
- checks << "$arity < #{min_arity}" if min_arity > 0
150
- checks << "$arity > #{max_arity}" if max_arity and not(rest_arg)
151
- aritycode + "if (#{checks.join(' || ')}) { Opal.ac($arity, #{arity}, this, #{meth}); }" if checks.size > 0
152
- else
153
- aritycode + "if ($arity !== #{arity}) { Opal.ac($arity, #{arity}, this, #{meth}); }"
113
+ def compile_arity_check
114
+ if arity_checks.size > 0
115
+ meth = scope.mid.to_s.inspect
116
+ line "var $arity = arguments.length;"
117
+ push " if (#{arity_checks.join(' || ')}) { Opal.ac($arity, #{arity}, this, #{meth}); }"
154
118
  end
155
119
  end
156
120
  end
@@ -95,7 +95,7 @@ module Opal
95
95
  end
96
96
 
97
97
  with_temp do |tmp|
98
- [fragment("((#{tmp} = "), expr(sexp), fragment(") !== nil && (!#{tmp}.$$is_boolean || #{tmp} == true))")]
98
+ [fragment("((#{tmp} = "), expr(sexp), fragment(") !== nil && #{tmp} != null && (!#{tmp}.$$is_boolean || #{tmp} == true))")]
99
99
  end
100
100
  end
101
101
 
@@ -109,7 +109,7 @@ module Opal
109
109
  end
110
110
 
111
111
  with_temp do |tmp|
112
- [fragment("((#{tmp} = "), expr(sexp), fragment(") === nil || (#{tmp}.$$is_boolean && #{tmp} == false))")]
112
+ [fragment("((#{tmp} = "), expr(sexp), fragment(") === nil || #{tmp} == null || (#{tmp}.$$is_boolean && #{tmp} == false))")]
113
113
  end
114
114
  end
115
115
 
@@ -131,7 +131,7 @@ module Opal
131
131
  expr(sexp)
132
132
  end
133
133
  elsif [:lvar, :self].include? sexp.type
134
- [expr(sexp.dup), fragment(" !== false && "), expr(sexp.dup), fragment(" !== nil")]
134
+ [expr(sexp.dup), fragment(" !== false && "), expr(sexp.dup), fragment(" !== nil && "), expr(sexp.dup), fragment(" != null")]
135
135
  end
136
136
  end
137
137
  end
@@ -23,14 +23,16 @@ module Opal
23
23
  identity = scope.identify!
24
24
  add_temp "self = #{identity}.$$s || this"
25
25
 
26
+ compile_block_arg
26
27
  compile_shadow_args
27
-
28
28
  compile_inline_args
29
29
  compile_post_args
30
-
31
- compile_block_arg
32
30
  compile_norm_args
33
31
 
32
+ if compiler.arity_check?
33
+ compile_arity_check
34
+ end
35
+
34
36
  body_code = stmt(body)
35
37
  to_vars = scope.to_vars
36
38
  end
@@ -150,6 +152,33 @@ module Opal
150
152
  def has_trailing_comma_in_args?
151
153
  args.meta[:has_trailing_comma]
152
154
  end
155
+
156
+ # Returns code used in debug mode to check arity of method call
157
+ def compile_arity_check
158
+ if arity_checks.size > 0
159
+ parent_scope = scope
160
+ while !(parent_scope.top? || parent_scope.def? || parent_scope.class_scope?)
161
+ parent_scope = parent_scope.parent
162
+ end
163
+
164
+ context = if parent_scope.top?
165
+ "'<main>'"
166
+ elsif parent_scope.def?
167
+ "'#{parent_scope.mid}'"
168
+ elsif parent_scope.class?
169
+ "'<class:#{parent_scope.name}>'"
170
+ elsif parent_scope.module?
171
+ "'<module:#{parent_scope.name}>'"
172
+ end
173
+
174
+ identity = scope.identity
175
+
176
+ line "if (#{identity}.$$is_lambda || #{identity}.$$define_meth) {"
177
+ line " var $arity = arguments.length;"
178
+ line " if (#{arity_checks.join(' || ')}) { Opal.block_ac($arity, #{arity}, #{context}); }"
179
+ line "}"
180
+ end
181
+ end
153
182
  end
154
183
  end
155
184
  end
@@ -86,7 +86,7 @@ module Opal
86
86
  def compile
87
87
  with_temp do |tmp|
88
88
  push expr(value)
89
- wrap "(#{tmp} = ", ", (#{tmp} === nil || #{tmp} === false))"
89
+ wrap "(#{tmp} = ", ", (#{tmp} === nil || #{tmp} === false || #{tmp} == null))"
90
90
  end
91
91
  end
92
92
  end
@@ -138,7 +138,7 @@ module Opal
138
138
  with_temp do |tmp|
139
139
  push "(((#{tmp} = "
140
140
  push expr(lhs)
141
- push ") !== false && #{tmp} !== nil) ? #{tmp} : "
141
+ push ") !== false && #{tmp} !== nil && #{tmp} != null) ? #{tmp} : "
142
142
  push expr(rhs)
143
143
  push ")"
144
144
  end
@@ -146,7 +146,7 @@ module Opal
146
146
 
147
147
  def compile_if
148
148
  with_temp do |tmp|
149
- push "if (#{tmp} = ", expr(lhs), ", #{tmp} !== false && #{tmp} !== nil) {"
149
+ push "if (#{tmp} = ", expr(lhs), ", #{tmp} !== false && #{tmp} !== nil && #{tmp} != null) {"
150
150
  indent do
151
151
  line tmp
152
152
  end
@@ -176,7 +176,7 @@ module Opal
176
176
  else
177
177
  push "(#{tmp} = "
178
178
  push expr(lhs)
179
- push ", #{tmp} !== false && #{tmp} !== nil ?"
179
+ push ", #{tmp} !== false && #{tmp} !== nil && #{tmp} != null ?"
180
180
  push expr(rhs)
181
181
  push " : #{tmp})"
182
182
  end
@@ -188,7 +188,7 @@ module Opal
188
188
  if truthy_opt = js_truthy_optimize(lhs)
189
189
  push "if (#{tmp} = ", truthy_opt, ") {"
190
190
  else
191
- push "if (#{tmp} = ", expr(lhs), ", #{tmp} !== false && #{tmp} !== nil) {"
191
+ push "if (#{tmp} = ", expr(lhs), ", #{tmp} !== false && #{tmp} !== nil && #{tmp} != null) {"
192
192
  end
193
193
  indent do
194
194
  line expr(rhs)
@@ -208,6 +208,37 @@ module Opal
208
208
 
209
209
  "[#{stringified_parameters.join(', ')}]"
210
210
  end
211
+
212
+ # Returns an array of JS conditions for raising and argument
213
+ # error caused by arity check
214
+ def arity_checks
215
+ return @arity_checks if @arity_checks
216
+
217
+ arity = args.size - 1
218
+ arity -= (opt_args.size)
219
+
220
+ arity -= 1 if rest_arg
221
+
222
+ arity -= (keyword_args.size)
223
+
224
+ arity = -arity - 1 if !opt_args.empty? or !keyword_args.empty? or rest_arg
225
+
226
+ # $arity will point to our received arguments count
227
+ aritycode = "var $arity = arguments.length;"
228
+
229
+ @arity_checks = []
230
+
231
+ if arity < 0 # splat or opt args
232
+ min_arity = -(arity + 1)
233
+ max_arity = args.size - 1
234
+ @arity_checks << "$arity < #{min_arity}" if min_arity > 0
235
+ @arity_checks << "$arity > #{max_arity}" if max_arity and not(rest_arg)
236
+ else
237
+ @arity_checks << "$arity !== #{arity}"
238
+ end
239
+
240
+ @arity_checks
241
+ end
211
242
  end
212
243
  end
213
244
  end
@@ -70,7 +70,8 @@ module Opal
70
70
  @scanner_stack = [@scanner]
71
71
 
72
72
  @case_stmt = nil
73
- @start_of_lambda = nil
73
+ @paren_nest = 0
74
+ @lambda_stack = []
74
75
  end
75
76
 
76
77
  # Returns next token from source input stream.
@@ -643,8 +644,8 @@ module Opal
643
644
  return :tIDENTIFIER
644
645
  end
645
646
 
646
- if @start_of_lambda
647
- @start_of_lambda = false
647
+ if @lambda_stack.last == @paren_nest
648
+ @lambda_stack.pop
648
649
  @lex_state = :expr_beg
649
650
  return :kDO_LAMBDA
650
651
  elsif cond?
@@ -1010,12 +1011,14 @@ module Opal
1010
1011
  @lex_state = :expr_beg
1011
1012
  cond_push 0
1012
1013
  cmdarg_push 0
1014
+ @paren_nest += 1
1013
1015
 
1014
1016
  return result
1015
1017
 
1016
1018
  elsif scan(/\)/)
1017
1019
  cond_lexpop
1018
1020
  cmdarg_lexpop
1021
+ @paren_nest -= 1
1019
1022
  @lex_state = :expr_end
1020
1023
  @lparen_arg_seen = false
1021
1024
  return :tRPAREN
@@ -1176,9 +1179,8 @@ module Opal
1176
1179
  end
1177
1180
 
1178
1181
  elsif scan(/->/)
1179
- # FIXME: # should be :expr_arg, but '(' breaks it...
1180
1182
  @lex_state = :expr_end
1181
- @start_of_lambda = true
1183
+ @lambda_stack.push(@paren_nest)
1182
1184
  return :tLAMBDA
1183
1185
 
1184
1186
  elsif scan(/[+-]/)
@@ -1289,8 +1291,8 @@ module Opal
1289
1291
  return :tCOMMA
1290
1292
 
1291
1293
  elsif scan(/\{/)
1292
- if @start_of_lambda
1293
- @start_of_lambda = false
1294
+ if @lambda_stack.last == @paren_nest
1295
+ @lambda_stack.pop
1294
1296
  @lex_state = :expr_beg
1295
1297
  cond_push 0
1296
1298
  cmdarg_push 0