opal 0.7.0.beta3 → 0.7.0.rc1

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +4 -0
  3. data/.travis.yml +7 -3
  4. data/.yardopts +6 -0
  5. data/CHANGELOG.md +28 -0
  6. data/Gemfile +1 -1
  7. data/README.md +3 -12
  8. data/Rakefile +4 -150
  9. data/bin/opal-mspec +1 -1
  10. data/docs/compiler_directives.md +127 -0
  11. data/examples/rack/.gitignore +1 -0
  12. data/examples/rack/app/user.rb +1 -0
  13. data/lib/mspec/opal/special_calls.rb +15 -2
  14. data/lib/opal/builder.rb +15 -8
  15. data/lib/opal/compiler.rb +75 -4
  16. data/lib/opal/erb.rb +22 -2
  17. data/lib/opal/fragment.rb +17 -5
  18. data/lib/opal/nodes/def.rb +174 -53
  19. data/lib/opal/nodes/if.rb +14 -0
  20. data/lib/opal/nodes/module.rb +0 -1
  21. data/lib/opal/nodes/rescue.rb +10 -2
  22. data/lib/opal/nodes/scope.rb +0 -17
  23. data/lib/opal/parser.rb +83 -19
  24. data/lib/opal/parser/grammar.rb +2511 -2414
  25. data/lib/opal/parser/grammar.y +71 -9
  26. data/lib/opal/parser/lexer.rb +44 -12
  27. data/lib/opal/parser/parser_scope.rb +3 -0
  28. data/lib/opal/parser/sexp.rb +7 -1
  29. data/lib/opal/paths.rb +5 -5
  30. data/lib/opal/sprockets/environment.rb +2 -10
  31. data/lib/opal/sprockets/path_reader.rb +1 -1
  32. data/lib/opal/sprockets/processor.rb +1 -0
  33. data/lib/opal/sprockets/server.rb +2 -0
  34. data/lib/opal/util.rb +7 -2
  35. data/lib/opal/version.rb +1 -1
  36. data/opal.gemspec +1 -0
  37. data/opal/README.md +1 -1
  38. data/opal/corelib/dir.rb +1 -1
  39. data/opal/corelib/enumerable.rb +3 -1
  40. data/opal/corelib/error.rb +3 -0
  41. data/opal/corelib/file.rb +2 -0
  42. data/opal/corelib/hash.rb +3 -0
  43. data/opal/corelib/io.rb +15 -1
  44. data/opal/corelib/kernel.rb +8 -0
  45. data/opal/corelib/module.rb +42 -17
  46. data/opal/corelib/runtime.js +223 -49
  47. data/opal/corelib/string.rb +1 -1
  48. data/opal/corelib/struct.rb +1 -7
  49. data/spec/README.md +8 -0
  50. data/spec/filters/bugs/language.rb +1 -0
  51. data/spec/filters/bugs/module.rb +4 -0
  52. data/spec/filters/unsupported/frozen.rb +2 -0
  53. data/spec/lib/compiler/pre_processed_conditionals_spec.rb +87 -0
  54. data/spec/lib/compiler_spec.rb +1 -67
  55. data/spec/lib/fixtures/file_with_directives.js +2 -0
  56. data/spec/lib/fixtures/required_file.js +1 -0
  57. data/spec/lib/parser/def_spec.rb +29 -16
  58. data/spec/lib/parser/variables_spec.rb +5 -5
  59. data/spec/lib/sprockets/path_reader_spec.rb +24 -8
  60. data/spec/lib/sprockets/server_spec.rb +10 -3
  61. data/spec/opal/core/date_spec.rb +14 -0
  62. data/spec/opal/core/language/versions/def_2_0_spec.rb +62 -0
  63. data/spec/opal/core/language_spec.rb +23 -0
  64. data/spec/opal/core/runtime/donate_spec.rb +53 -0
  65. data/spec/opal/stdlib/native/native_alias_spec.rb +19 -0
  66. data/spec/opal/stdlib/native/native_class_spec.rb +18 -0
  67. data/spec/opal/stdlib/native/native_module_spec.rb +13 -0
  68. data/spec/rubyspecs +2 -0
  69. data/stdlib/buffer.rb +1 -0
  70. data/stdlib/date.rb +18 -0
  71. data/stdlib/encoding.rb +3 -2
  72. data/stdlib/minitest.rb +780 -0
  73. data/stdlib/minitest/assertions.rb +662 -0
  74. data/stdlib/minitest/autorun.rb +12 -0
  75. data/stdlib/minitest/benchmark.rb +426 -0
  76. data/stdlib/minitest/expectations.rb +281 -0
  77. data/stdlib/minitest/hell.rb +11 -0
  78. data/stdlib/minitest/mock.rb +220 -0
  79. data/stdlib/minitest/parallel.rb +65 -0
  80. data/stdlib/minitest/pride.rb +4 -0
  81. data/stdlib/minitest/pride_plugin.rb +142 -0
  82. data/stdlib/minitest/spec.rb +310 -0
  83. data/stdlib/minitest/test.rb +293 -0
  84. data/stdlib/minitest/unit.rb +45 -0
  85. data/stdlib/native.rb +12 -3
  86. data/stdlib/nodejs/process.rb +16 -2
  87. data/stdlib/promise.rb +99 -0
  88. data/stdlib/test/unit.rb +10 -0
  89. data/stdlib/thread.rb +4 -0
  90. data/tasks/building.rake +58 -0
  91. data/tasks/documentation.rake +38 -0
  92. data/tasks/documenting.rake +37 -0
  93. data/tasks/testing.rake +102 -0
  94. metadata +57 -2
@@ -0,0 +1,293 @@
1
+ require "minitest" unless defined? Minitest::Runnable
2
+
3
+ module Minitest
4
+ ##
5
+ # Subclass Test to create your own tests. Typically you'll want a
6
+ # Test subclass per implementation class.
7
+ #
8
+ # See Minitest::Assertions
9
+
10
+ class Test < Runnable
11
+ require "minitest/assertions"
12
+ include Minitest::Assertions
13
+
14
+ PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, # :nodoc:
15
+ Interrupt, SystemExit]
16
+
17
+ class << self; attr_accessor :io_lock; end # :nodoc:
18
+ self.io_lock = Mutex.new
19
+
20
+ ##
21
+ # Call this at the top of your tests when you absolutely
22
+ # positively need to have ordered tests. In doing so, you're
23
+ # admitting that you suck and your tests are weak.
24
+
25
+ def self.i_suck_and_my_tests_are_order_dependent!
26
+ class << self
27
+ undef_method :test_order if method_defined? :test_order
28
+ define_method :test_order do :alpha end
29
+ end
30
+ end
31
+
32
+ ##
33
+ # Make diffs for this Test use #pretty_inspect so that diff
34
+ # in assert_equal can have more details. NOTE: this is much slower
35
+ # than the regular inspect but much more usable for complex
36
+ # objects.
37
+
38
+ def self.make_my_diffs_pretty!
39
+ require "pp"
40
+
41
+ define_method :mu_pp do |o|
42
+ o.pretty_inspect
43
+ end
44
+ end
45
+
46
+ ##
47
+ # Call this at the top of your tests when you want to run your
48
+ # tests in parallel. In doing so, you're admitting that you rule
49
+ # and your tests are awesome.
50
+
51
+ def self.parallelize_me!
52
+ include Minitest::Parallel::Test
53
+ extend Minitest::Parallel::Test::ClassMethods
54
+ end
55
+
56
+ ##
57
+ # Returns all instance methods starting with "test_". Based on
58
+ # #test_order, the methods are either sorted, randomized
59
+ # (default), or run in parallel.
60
+
61
+ def self.runnable_methods
62
+ methods = methods_matching(/^test_/)
63
+
64
+ case self.test_order
65
+ when :random, :parallel then
66
+ max = methods.size
67
+ methods.sort.sort_by { rand max }
68
+ when :alpha, :sorted then
69
+ methods.sort
70
+ else
71
+ raise "Unknown test_order: #{self.test_order.inspect}"
72
+ end
73
+ end
74
+
75
+ ##
76
+ # Defines the order to run tests (:random by default). Override
77
+ # this or use a convenience method to change it for your tests.
78
+
79
+ def self.test_order
80
+ :random
81
+ end
82
+
83
+ ##
84
+ # The time it took to run this test.
85
+
86
+ attr_accessor :time
87
+
88
+ def marshal_dump # :nodoc:
89
+ super << self.time
90
+ end
91
+
92
+ def marshal_load ary # :nodoc:
93
+ self.time = ary.pop
94
+ super
95
+ end
96
+
97
+ TEARDOWN_METHODS = %w{ before_teardown teardown after_teardown } # :nodoc:
98
+
99
+ ##
100
+ # Runs a single test with setup/teardown hooks.
101
+
102
+ def run
103
+ with_info_handler do
104
+ time_it do
105
+ capture_exceptions do
106
+ before_setup; setup; after_setup
107
+
108
+ self.send self.name
109
+ end
110
+
111
+ TEARDOWN_METHODS.each do |hook|
112
+ capture_exceptions do
113
+ self.send hook
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ self # per contract
120
+ end
121
+
122
+ ##
123
+ # Provides before/after hooks for setup and teardown. These are
124
+ # meant for library writers, NOT for regular test authors. See
125
+ # #before_setup for an example.
126
+
127
+ module LifecycleHooks
128
+
129
+ ##
130
+ # Runs before every test, before setup. This hook is meant for
131
+ # libraries to extend minitest. It is not meant to be used by
132
+ # test developers.
133
+ #
134
+ # As a simplistic example:
135
+ #
136
+ # module MyMinitestPlugin
137
+ # def before_setup
138
+ # super
139
+ # # ... stuff to do before setup is run
140
+ # end
141
+ #
142
+ # def after_setup
143
+ # # ... stuff to do after setup is run
144
+ # super
145
+ # end
146
+ #
147
+ # def before_teardown
148
+ # super
149
+ # # ... stuff to do before teardown is run
150
+ # end
151
+ #
152
+ # def after_teardown
153
+ # # ... stuff to do after teardown is run
154
+ # super
155
+ # end
156
+ # end
157
+ #
158
+ # class MiniTest::Test
159
+ # include MyMinitestPlugin
160
+ # end
161
+
162
+ def before_setup; end
163
+
164
+ ##
165
+ # Runs before every test. Use this to set up before each test
166
+ # run.
167
+
168
+ def setup; end
169
+
170
+ ##
171
+ # Runs before every test, after setup. This hook is meant for
172
+ # libraries to extend minitest. It is not meant to be used by
173
+ # test developers.
174
+ #
175
+ # See #before_setup for an example.
176
+
177
+ def after_setup; end
178
+
179
+ ##
180
+ # Runs after every test, before teardown. This hook is meant for
181
+ # libraries to extend minitest. It is not meant to be used by
182
+ # test developers.
183
+ #
184
+ # See #before_setup for an example.
185
+
186
+ def before_teardown; end
187
+
188
+ ##
189
+ # Runs after every test. Use this to clean up after each test
190
+ # run.
191
+
192
+ def teardown; end
193
+
194
+ ##
195
+ # Runs after every test, after teardown. This hook is meant for
196
+ # libraries to extend minitest. It is not meant to be used by
197
+ # test developers.
198
+ #
199
+ # See #before_setup for an example.
200
+
201
+ def after_teardown; end
202
+ end # LifecycleHooks
203
+
204
+ def capture_exceptions # :nodoc:
205
+ begin
206
+ yield
207
+ # rescue *PASSTHROUGH_EXCEPTIONS
208
+ # raise
209
+ # rescue Assertion => e
210
+ # self.failures << e
211
+ # rescue Exception => e
212
+ # self.failures << UnexpectedError.new(e)
213
+ rescue => e
214
+ case e
215
+ when *PASSTHROUGH_EXCEPTIONS
216
+ when Assertion then self.failures << e
217
+ when Exception then self.failures << UnexpectedError.new(e)
218
+ end
219
+ end
220
+ end
221
+
222
+ ##
223
+ # Did this run error?
224
+
225
+ def error?
226
+ self.failures.any? { |f| UnexpectedError === f }
227
+ end
228
+
229
+ ##
230
+ # The location identifier of this test.
231
+
232
+ def location
233
+ loc = " [#{self.failure.location}]" unless passed? or error?
234
+ "#{self.class}##{self.name}#{loc}"
235
+ end
236
+
237
+ ##
238
+ # Did this run pass?
239
+ #
240
+ # Note: skipped runs are not considered passing, but they don't
241
+ # cause the process to exit non-zero.
242
+
243
+ def passed?
244
+ not self.failure
245
+ end
246
+
247
+ ##
248
+ # Returns ".", "F", or "E" based on the result of the run.
249
+
250
+ def result_code
251
+ self.failure and self.failure.result_code or "."
252
+ end
253
+
254
+ ##
255
+ # Was this run skipped?
256
+
257
+ def skipped?
258
+ self.failure and Skip === self.failure
259
+ end
260
+
261
+ def time_it # :nodoc:
262
+ t0 = Time.now
263
+
264
+ yield
265
+ ensure
266
+ self.time = Time.now - t0
267
+ end
268
+
269
+ def to_s # :nodoc:
270
+ return location if passed? and not skipped?
271
+
272
+ failures.map { |failure|
273
+ "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
274
+ }.join "\n"
275
+ end
276
+
277
+ def with_info_handler &block # :nodoc:
278
+ t0 = Time.now
279
+
280
+ handler = lambda do
281
+ warn "\nCurrent: %s#%s %.2fs" % [self.class, self.name, Time.now - t0]
282
+ end
283
+
284
+ self.class.on_signal "INFO", handler, &block
285
+ end
286
+
287
+ include LifecycleHooks
288
+ include Guard
289
+ extend Guard
290
+ end # Test
291
+ end
292
+
293
+ require "minitest/unit" unless defined?(MiniTest) # compatibility layer only
@@ -0,0 +1,45 @@
1
+ # :stopdoc:
2
+
3
+ unless defined?(Minitest) then
4
+ # all of this crap is just to avoid circular requires and is only
5
+ # needed if a user requires "minitest/unit" directly instead of
6
+ # "minitest/autorun", so we also warn
7
+
8
+ from = caller.reject { |s| s =~ /rubygems/ }.join("\n ")
9
+ warn "Warning: you should require 'minitest/autorun' instead."
10
+ warn %(Warning: or add 'gem "minitest"' before 'require "minitest/autorun"')
11
+ warn "From:\n #{from}"
12
+
13
+ module Minitest; end
14
+ MiniTest = Minitest # prevents minitest.rb from requiring back to us
15
+ require "minitest"
16
+ end
17
+
18
+ MiniTest = Minitest unless defined?(MiniTest)
19
+
20
+ module Minitest
21
+ class Unit
22
+ VERSION = Minitest::VERSION
23
+ class TestCase < Minitest::Test
24
+ def self.inherited klass # :nodoc:
25
+ from = caller.first
26
+ warn "MiniTest::Unit::TestCase is now Minitest::Test. From #{from}"
27
+ super
28
+ end
29
+ end
30
+
31
+ def self.autorun # :nodoc:
32
+ from = caller.first
33
+ warn "MiniTest::Unit.autorun is now Minitest.autorun. From #{from}"
34
+ Minitest.autorun
35
+ end
36
+
37
+ def self.after_tests(&b)
38
+ from = caller.first
39
+ warn "MiniTest::Unit.after_tests is now Minitest.after_run. From #{from}"
40
+ Minitest.after_run(&b)
41
+ end
42
+ end
43
+ end
44
+
45
+ # :startdoc:
data/stdlib/native.rb CHANGED
@@ -538,11 +538,20 @@ class Module
538
538
  end
539
539
 
540
540
  class Class
541
- def native_alias(jsid, mid)
542
- `#{self}.$$proto[#{jsid}] = #{self}.$$proto['$' + #{mid}]`
541
+ def native_alias(new_jsid, existing_mid)
542
+ %x{
543
+ var aliased = #{self}.$$proto['$' + #{existing_mid}];
544
+ if (!aliased) {
545
+ #{raise NameError, "undefined method `#{existing_mid}' for class `#{inspect}'"};
546
+ }
547
+ #{self}.$$proto[#{new_jsid}] = aliased;
548
+ }
543
549
  end
544
550
 
545
- alias native_class native_module
551
+ def native_class
552
+ native_module
553
+ `self.new = self.$new;`
554
+ end
546
555
  end
547
556
 
548
557
  # native global
@@ -1,6 +1,20 @@
1
1
  module Kernel
2
- def exit(status)
3
- `process.exit(status)`
2
+ def exit(status = true)
3
+ $__at_exit__.reverse.each(&:call) if $__at_exit__
4
+ `process.exit(status === true ? 0 : status)`
5
+ end
6
+
7
+ def caller
8
+ %x{
9
+ var stack;
10
+ try {
11
+ var err = Error("my error");
12
+ throw err;
13
+ } catch(e) {
14
+ stack = e.stack;
15
+ }
16
+ return stack.$split("\n").slice(3);
17
+ }
4
18
  end
5
19
  end
6
20
 
data/stdlib/promise.rb CHANGED
@@ -1,3 +1,102 @@
1
+ # {Promise} is used to help structure asynchronous code.
2
+ #
3
+ # It is available in the Opal standard library, and can be required in any Opal
4
+ # application:
5
+ #
6
+ # require 'promise'
7
+ #
8
+ # ## Basic Usage
9
+ #
10
+ # Promises are created and returned as objects with the assumption that they
11
+ # will eventually be resolved or rejected, but never both. A {Promise} has
12
+ # a {#then} and {#fail} method (or one of their aliases) that can be used to
13
+ # register a block that gets called once resolved or rejected.
14
+ #
15
+ # promise = Promise.new
16
+ #
17
+ # promise.then {
18
+ # puts "resolved!"
19
+ # }.fail {
20
+ # puts "rejected!"
21
+ # }
22
+ #
23
+ # # some time later
24
+ # promise.resolve
25
+ #
26
+ # # => "resolved!"
27
+ #
28
+ # It is important to remember that a promise can only be resolved or rejected
29
+ # once, so the block will only ever be called once (or not at all).
30
+ #
31
+ # ## Resolving Promises
32
+ #
33
+ # To resolve a promise, means to inform the {Promise} that it has succeeded
34
+ # or evaluated to a useful value. {#resolve} can be passed a value which is
35
+ # then passed into the block handler:
36
+ #
37
+ # def get_json
38
+ # promise = Promise.new
39
+ #
40
+ # HTTP.get("some_url") do |req|
41
+ # promise.resolve req.json
42
+ # end
43
+ #
44
+ # promise
45
+ # end
46
+ #
47
+ # get_json.then do |json|
48
+ # puts "got some JSON from server"
49
+ # end
50
+ #
51
+ # ## Rejecting Promises
52
+ #
53
+ # Promises are also designed to handle error cases, or situations where an
54
+ # outcome is not as expected. Taking the previous example, we can also pass
55
+ # a value to a {#reject} call, which passes that object to the registered
56
+ # {#fail} handler:
57
+ #
58
+ # def get_json
59
+ # promise = Promise.new
60
+ #
61
+ # HTTP.get("some_url") do |req|
62
+ # if req.ok?
63
+ # promise.resolve req.json
64
+ # else
65
+ # promise.reject req
66
+ # end
67
+ #
68
+ # promise
69
+ # end
70
+ #
71
+ # get_json.then {
72
+ # # ...
73
+ # }.fail { |req|
74
+ # puts "it went wrong: #{req.message}"
75
+ # }
76
+ #
77
+ # ## Chaining Promises
78
+ #
79
+ # Promises become even more useful when chained together. Each {#then} or
80
+ # {#fail} call returns a new {Promise} which can be used to chain more and more
81
+ # handlers together.
82
+ #
83
+ # promise.then { wait_for_something }.then { do_something_else }
84
+ #
85
+ # Rejections are propagated through the entire chain, so a "catch all" handler
86
+ # can be attached at the end of the tail:
87
+ #
88
+ # promise.then { ... }.then { ... }.fail { ... }
89
+ #
90
+ # ## Composing Promises
91
+ #
92
+ # {Promise.when} can be used to wait for more than one promise to resolve (or
93
+ # reject). Using the previous example, we could request two different json
94
+ # requests and wait for both to finish:
95
+ #
96
+ # Promise.when(get_json, get_json2).then |first, second|
97
+ # puts "got two json payloads: #{first}, #{second}"
98
+ # end
99
+ #
1
100
  class Promise
2
101
  def self.value(value)
3
102
  new.resolve(value)