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