opal 0.7.0.beta3 → 0.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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)