opal 0.6.3 → 0.7.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.spectator +2 -0
  4. data/.spectator-mspec +3 -0
  5. data/.travis.yml +8 -11
  6. data/CHANGELOG.md +33 -0
  7. data/CONTRIBUTING.md +8 -43
  8. data/Gemfile +15 -4
  9. data/Guardfile +77 -0
  10. data/README.md +15 -9
  11. data/Rakefile +36 -12
  12. data/benchmarks/operators.rb +11 -0
  13. data/bin/opal +10 -13
  14. data/bin/opal-build +4 -4
  15. data/bin/opal-mspec +10 -0
  16. data/bin/opal-repl +4 -3
  17. data/examples/sinatra/Gemfile +1 -1
  18. data/examples/sinatra/config.ru +3 -3
  19. data/lib/mspec/opal/main.rb.erb +2 -2
  20. data/lib/mspec/opal/rake_task.rb +31 -24
  21. data/lib/mspec/opal/runner.rb +18 -1
  22. data/lib/mspec/opal/sprockets.js +17 -0
  23. data/lib/opal.rb +1 -34
  24. data/lib/opal/builder.rb +92 -58
  25. data/lib/opal/builder_processors.rb +165 -0
  26. data/lib/opal/cli.rb +85 -144
  27. data/lib/opal/cli_options.rb +136 -90
  28. data/lib/opal/cli_runners.rb +10 -0
  29. data/lib/opal/cli_runners/nodejs.rb +56 -0
  30. data/lib/opal/cli_runners/phantom.js +35 -0
  31. data/lib/opal/cli_runners/phantomjs.rb +28 -0
  32. data/lib/opal/cli_runners/server.rb +54 -0
  33. data/lib/opal/compiler.rb +35 -16
  34. data/lib/opal/erb.rb +29 -15
  35. data/lib/opal/hike_path_finder.rb +18 -0
  36. data/lib/opal/nodes.rb +1 -0
  37. data/lib/opal/nodes/call.rb +107 -26
  38. data/lib/opal/nodes/call_special.rb +31 -6
  39. data/lib/opal/nodes/class.rb +2 -2
  40. data/lib/opal/nodes/constants.rb +5 -20
  41. data/lib/opal/nodes/def.rb +4 -4
  42. data/lib/opal/nodes/defined.rb +3 -3
  43. data/lib/opal/nodes/definitions.rb +1 -1
  44. data/lib/opal/nodes/for.rb +35 -0
  45. data/lib/opal/nodes/helpers.rb +2 -2
  46. data/lib/opal/nodes/iter.rb +3 -3
  47. data/lib/opal/nodes/literal.rb +10 -2
  48. data/lib/opal/nodes/masgn.rb +2 -2
  49. data/lib/opal/nodes/module.rb +2 -2
  50. data/lib/opal/nodes/scope.rb +1 -0
  51. data/lib/opal/nodes/singleton_class.rb +2 -2
  52. data/lib/opal/nodes/super.rb +2 -2
  53. data/lib/opal/nodes/top.rb +30 -3
  54. data/lib/opal/parser.rb +15 -1
  55. data/lib/opal/parser/grammar.rb +2571 -2452
  56. data/lib/opal/parser/grammar.y +37 -5
  57. data/lib/opal/parser/keywords.rb +2 -0
  58. data/lib/opal/parser/lexer.rb +21 -11
  59. data/lib/opal/path_reader.rb +28 -0
  60. data/lib/opal/paths.rb +38 -0
  61. data/lib/opal/source_map.rb +32 -15
  62. data/lib/opal/sprockets/environment.rb +9 -2
  63. data/lib/opal/sprockets/erb.rb +1 -2
  64. data/lib/opal/sprockets/path_reader.rb +34 -0
  65. data/lib/opal/sprockets/processor.rb +40 -39
  66. data/lib/opal/sprockets/server.rb +47 -33
  67. data/lib/opal/version.rb +1 -1
  68. data/opal.gemspec +10 -5
  69. data/opal/README.md +6 -0
  70. data/opal/corelib/array.rb +36 -4
  71. data/opal/corelib/array/inheritance.rb +6 -6
  72. data/opal/corelib/basic_object.rb +9 -9
  73. data/opal/corelib/boolean.rb +1 -1
  74. data/opal/corelib/class.rb +12 -12
  75. data/opal/corelib/dir.rb +20 -0
  76. data/opal/corelib/enumerable.rb +42 -42
  77. data/opal/corelib/enumerator.rb +1 -1
  78. data/opal/corelib/error.rb +2 -2
  79. data/opal/corelib/file.rb +56 -0
  80. data/opal/corelib/hash.rb +5 -5
  81. data/opal/corelib/helpers.rb +3 -3
  82. data/opal/corelib/io.rb +13 -10
  83. data/opal/corelib/kernel.rb +44 -68
  84. data/opal/corelib/method.rb +1 -1
  85. data/opal/corelib/module.rb +89 -114
  86. data/opal/corelib/nil_class.rb +1 -1
  87. data/opal/corelib/numeric.rb +27 -23
  88. data/opal/corelib/proc.rb +5 -5
  89. data/opal/corelib/range.rb +8 -4
  90. data/opal/corelib/regexp.rb +5 -5
  91. data/opal/corelib/runtime.js +589 -272
  92. data/opal/corelib/string.rb +52 -37
  93. data/opal/corelib/string/inheritance.rb +5 -5
  94. data/opal/corelib/time.rb +102 -52
  95. data/opal/corelib/variables.rb +3 -3
  96. data/opal/opal.rb +2 -0
  97. data/package.json +9 -0
  98. data/spec/filters/bugs/array.rb +0 -6
  99. data/spec/filters/bugs/language.rb +4 -0
  100. data/spec/filters/bugs/numeric.rb +7 -6
  101. data/spec/filters/bugs/opal.rb +2 -0
  102. data/spec/filters/bugs/regexp.rb +4 -0
  103. data/spec/filters/bugs/string.rb +0 -7
  104. data/spec/filters/bugs/stringscanner.rb +4 -1
  105. data/spec/filters/unsupported/private_methods.rb +2 -0
  106. data/spec/lib/builder_processors_spec.rb +27 -0
  107. data/spec/lib/builder_spec.rb +66 -0
  108. data/spec/{cli → lib}/cli_spec.rb +60 -5
  109. data/spec/{cli → lib}/compiler_spec.rb +66 -5
  110. data/spec/{cli → lib}/dependency_resolver_spec.rb +1 -1
  111. data/spec/lib/fixtures/no_requires.rb +1 -0
  112. data/spec/{cli → lib}/fixtures/opal_file.rb +0 -0
  113. data/spec/lib/fixtures/require_tree_test.rb +3 -0
  114. data/spec/lib/fixtures/required_tree_test/required_file1.rb +1 -0
  115. data/spec/lib/fixtures/required_tree_test/required_file2.rb +1 -0
  116. data/spec/lib/fixtures/requires.rb +7 -0
  117. data/spec/{cli → lib}/fixtures/sprockets_file.js.rb +0 -0
  118. data/spec/lib/fixtures/sprockets_require_tree_test.rb +3 -0
  119. data/spec/lib/hike_path_finder_spec.rb +23 -0
  120. data/spec/{cli → lib}/lexer_spec.rb +1 -1
  121. data/spec/{cli → lib}/parser/alias_spec.rb +1 -1
  122. data/spec/{cli → lib}/parser/and_spec.rb +1 -1
  123. data/spec/{cli → lib}/parser/attrasgn_spec.rb +1 -1
  124. data/spec/{cli → lib}/parser/begin_spec.rb +1 -1
  125. data/spec/{cli → lib}/parser/block_spec.rb +1 -1
  126. data/spec/{cli → lib}/parser/break_spec.rb +1 -1
  127. data/spec/{cli → lib}/parser/call_spec.rb +1 -1
  128. data/spec/{cli → lib}/parser/class_spec.rb +1 -1
  129. data/spec/{cli → lib}/parser/comments_spec.rb +1 -1
  130. data/spec/{cli → lib}/parser/def_spec.rb +1 -1
  131. data/spec/{cli → lib}/parser/if_spec.rb +1 -1
  132. data/spec/{cli → lib}/parser/iter_spec.rb +1 -1
  133. data/spec/{cli → lib}/parser/lambda_spec.rb +1 -1
  134. data/spec/{cli → lib}/parser/literal_spec.rb +1 -1
  135. data/spec/{cli → lib}/parser/masgn_spec.rb +1 -1
  136. data/spec/{cli → lib}/parser/module_spec.rb +1 -1
  137. data/spec/{cli → lib}/parser/not_spec.rb +1 -1
  138. data/spec/{cli → lib}/parser/op_asgn1_spec.rb +1 -1
  139. data/spec/{cli → lib}/parser/op_asgn2_spec.rb +1 -1
  140. data/spec/{cli → lib}/parser/or_spec.rb +1 -1
  141. data/spec/{cli → lib}/parser/return_spec.rb +1 -1
  142. data/spec/{cli → lib}/parser/sclass_spec.rb +1 -1
  143. data/spec/{cli → lib}/parser/string_spec.rb +8 -1
  144. data/spec/{cli → lib}/parser/super_spec.rb +1 -1
  145. data/spec/lib/parser/unary_spec.rb +48 -0
  146. data/spec/{cli → lib}/parser/undef_spec.rb +1 -1
  147. data/spec/{cli → lib}/parser/unless_spec.rb +1 -1
  148. data/spec/{cli → lib}/parser/variables_spec.rb +1 -1
  149. data/spec/{cli → lib}/parser/while_spec.rb +1 -1
  150. data/spec/{cli → lib}/parser/yield_spec.rb +1 -1
  151. data/spec/lib/path_reader_spec.rb +24 -0
  152. data/spec/lib/shared/path_finder_shared.rb +19 -0
  153. data/spec/lib/shared/path_reader_shared.rb +31 -0
  154. data/spec/lib/spec_helper.rb +9 -0
  155. data/spec/lib/sprockets/environment_spec.rb +30 -0
  156. data/spec/{cli → lib}/sprockets/erb_spec.rb +1 -1
  157. data/spec/lib/sprockets/path_reader_spec.rb +25 -0
  158. data/spec/{cli → lib}/sprockets/processor_spec.rb +9 -2
  159. data/spec/lib/sprockets/server_spec.rb +20 -0
  160. data/spec/opal/compiler/irb_spec.rb +11 -11
  161. data/spec/opal/core/fixtures/require_tree_files/file 1.rb +1 -0
  162. data/spec/opal/core/fixtures/require_tree_files/file 2.rb +1 -0
  163. data/spec/opal/core/fixtures/require_tree_files/file 3.rb +1 -0
  164. data/spec/opal/core/fixtures/require_tree_files/file 4.rb +1 -0
  165. data/spec/opal/core/fixtures/require_tree_files/file 5.rb +1 -0
  166. data/spec/opal/core/kernel/require_tree_spec.rb +7 -0
  167. data/spec/opal/core/kernel/respond_to_spec.rb +2 -2
  168. data/spec/opal/core/runtime/method_missing_spec.rb +19 -0
  169. data/spec/opal/core/source_map_spec.rb +2 -2
  170. data/spec/opal/core/string_spec.rb +11 -0
  171. data/spec/opal/stdlib/erb/erb_spec.rb +0 -1
  172. data/spec/opal/stdlib/thread/mutex_spec.rb +40 -0
  173. data/spec/opal/stdlib/thread/thread_queue_spec.rb +32 -0
  174. data/spec/opal/stdlib/thread/thread_spec.rb +60 -0
  175. data/spec/rubyspecs +54 -11
  176. data/spec/spec_helper.rb +18 -3
  177. data/spec/support/mspec_rspec_adapter.rb +33 -0
  178. data/spec/{cli/spec_helper.rb → support/parser_helpers.rb} +10 -10
  179. data/stdlib/README.md +3 -0
  180. data/stdlib/benchmark.rb +10 -0
  181. data/stdlib/date.rb +2 -2
  182. data/stdlib/dir.rb +1 -5
  183. data/stdlib/file.rb +1 -7
  184. data/stdlib/json.rb +10 -1
  185. data/stdlib/native.rb +5 -5
  186. data/stdlib/nodejs.rb +5 -0
  187. data/stdlib/nodejs/dir.rb +13 -0
  188. data/stdlib/nodejs/file.rb +98 -0
  189. data/stdlib/nodejs/fileutils.rb +26 -0
  190. data/stdlib/nodejs/io.rb +2 -0
  191. data/stdlib/nodejs/irb.rb +45 -0
  192. data/stdlib/nodejs/process.rb +16 -0
  193. data/stdlib/nodejs/require.rb +32 -0
  194. data/stdlib/nodejs/rubygems.rb +68 -0
  195. data/stdlib/nodejs/runtime.rb +25 -0
  196. data/stdlib/nodejs/yaml.rb +11 -0
  197. data/stdlib/opal-parser.rb +1 -2
  198. data/stdlib/opal-source-maps.rb +2 -0
  199. data/stdlib/phantomjs.rb +8 -0
  200. data/stdlib/process.rb +10 -0
  201. data/stdlib/promise.rb +12 -4
  202. data/stdlib/set.rb +27 -0
  203. data/stdlib/source_map.rb +5 -63
  204. data/stdlib/source_map/map.rb +220 -0
  205. data/stdlib/source_map/mapping.rb +26 -0
  206. data/stdlib/source_map/offset.rb +88 -0
  207. data/stdlib/source_map/version.rb +3 -0
  208. data/stdlib/source_map/vlq.rb +77 -101
  209. data/stdlib/sourcemap.rb +1 -0
  210. data/stdlib/strscan.rb +7 -1
  211. data/stdlib/template.rb +1 -1
  212. data/stdlib/thread.rb +147 -7
  213. metadata +238 -104
  214. data/lib/mspec/opal/mspec_fixes.rb +0 -87
  215. data/spec/cli/sprockets/environment_spec.rb +0 -14
  216. data/spec/filters/bugs/symbol.rb +0 -5
  217. data/spec/opal/core/kernel/warn_spec.rb +0 -83
  218. data/spec/opal/core/language/numbers_spec.rb +0 -60
  219. data/stdlib/opal-source-maps.js.erb +0 -2
  220. data/stdlib/source_map/generator.rb +0 -251
  221. data/stdlib/source_map/parser.rb +0 -102
data/bin/opal-build CHANGED
@@ -19,9 +19,9 @@ module Opal
19
19
  end
20
20
 
21
21
  opts.on('-g', '--gem GEM_NAME', String,
22
- 'Adds the specified GEM_NAME to Opal\'s load path.',
23
- 'E.g.: opal-build --require opal-browser browser`',
24
- 'Will build browser.rb from the Opal gem opal-browser') do |g|
22
+ 'Adds the specified GEM_NAME lib dir to Opal\'s load path.',
23
+ 'E.g.: opal-build --gem erubis -- erubis`',
24
+ 'Will build erubis.rb from the regular "erubis" gem') do |g|
25
25
  options[:gems] ||= []
26
26
  options[:gems] << g
27
27
  end
@@ -54,7 +54,7 @@ option_parser = Opal::BuilderOptions.new
54
54
  option_parser.parse!
55
55
 
56
56
  if ARGV.empty?
57
- puts options
57
+ puts option_parser
58
58
  else
59
59
  require 'opal'
60
60
  options = option_parser.options
data/bin/opal-mspec ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ specs = ARGV.map do |s|
4
+ s.end_with?('.rb') ? s : "#{s}/**/*_spec.rb"
5
+ end
6
+ pattern = %Q{MSPEC_PATTERN="{#{specs.join(',')}}"} if specs.any?
7
+ command = [pattern, 'rake mspec'].compact.join(' ')
8
+ exec command
9
+
10
+ # bundle exec mspec run -t opal -pspec/corelib/spec_helper spec/corelib/core/true/*
data/bin/opal-repl CHANGED
@@ -19,7 +19,7 @@ module Opal
19
19
 
20
20
  @v8 = V8::Context.new
21
21
  @v8['console'] = self
22
- @v8.eval @builder.build 'opal'
22
+ @v8.eval Opal::Builder.new.build('opal').to_s
23
23
 
24
24
  if filename
25
25
  if File.exist? filename
@@ -56,8 +56,9 @@ module Opal
56
56
  end
57
57
 
58
58
  def eval_ruby(str)
59
- code = @builder.build_str str, :irb => true, :const_missing => true
60
- @v8.eval "var $_result = #{code} ($_result == null ? 'nil' : $_result.$inspect());"
59
+ code = Opal::Builder.new.build_str(str, '(irb)', :irb => true, :const_missing => true)
60
+ code.processed[0...-1].each{ |c| @v8.eval(c.to_s) }
61
+ @v8.eval "var $_result = #{code.processed.last.to_s} ($_result == null ? 'nil' : $_result.$inspect());"
61
62
  rescue => e
62
63
  puts "#{e.message}\n\t#{e.backtrace.join("\n\t")}"
63
64
  end
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'opal', :path => '../../opal'
3
+ gem 'opal', :path => '../..'
4
4
  gem 'sinatra'
@@ -6,7 +6,7 @@ opal = Opal::Server.new {|s|
6
6
  s.main = 'application'
7
7
  }
8
8
 
9
- map '/__opal_source_maps__' do
9
+ map opal.source_maps.prefix do
10
10
  run opal.source_maps
11
11
  end
12
12
 
@@ -15,14 +15,14 @@ map '/assets' do
15
15
  end
16
16
 
17
17
  get '/' do
18
- <<-EOS
18
+ <<-HTML
19
19
  <!doctype html>
20
20
  <html>
21
21
  <head>
22
22
  <script src="/assets/application.js"></script>
23
23
  </head>
24
24
  </html>
25
- EOS
25
+ HTML
26
26
  end
27
27
 
28
28
  run Sinatra::Application
@@ -1,8 +1,8 @@
1
- <% require_asset 'spec_helper' %>
1
+ require 'spec_helper'
2
2
 
3
3
  # This file just greps for all spec files in spec/ and requires them
4
4
  <% ENV['OPAL_SPEC'].split(',').each do |s| %>
5
- <% require_asset s %>
5
+ require <%= s.inspect %>
6
6
  <% end %>
7
7
 
8
8
  # All specs have been run, so we notify mspec that we are done
@@ -11,10 +11,14 @@ class Opal::Nodes::CallNode
11
11
  compiler.requires << target
12
12
  end
13
13
 
14
- return fragment("nil")
14
+ push fragment("nil")
15
15
  end
16
+ end
16
17
 
17
- nil
18
+ add_special :not_supported_on do
19
+ unless meth == :not_supported_on and arglist[1][1] == :opal
20
+ compile_default!
21
+ end
18
22
  end
19
23
  end
20
24
 
@@ -24,7 +28,6 @@ require 'webrick'
24
28
 
25
29
  module MSpec
26
30
  module Opal
27
- DEFAULT_PATTERN = 'spec/{corelib,opal,stdlib}/**/*_spec.rb'
28
31
  DEFAULT_BASEDIR = 'spec'
29
32
 
30
33
  require 'rake'
@@ -119,18 +122,21 @@ module MSpec
119
122
 
120
123
  def initialize(basedir = nil, pattern = nil)
121
124
  ::Opal::Processor.arity_check_enabled = true
122
- ::Opal::Processor.dynamic_require_severity = :ignore
123
- super()
125
+ ::Opal::Processor.dynamic_require_severity = :error
126
+
124
127
  @pattern = pattern
125
128
  @basedir = basedir = File.expand_path(basedir || DEFAULT_BASEDIR)
126
- append_path basedir
127
- use_gem 'mspec'
129
+
130
+ ::Opal.append_path basedir
131
+ ::Opal.use_gem 'mspec'
128
132
 
129
133
  stubs.each do |asset|
130
134
  ::Opal::Processor.stub_file asset
131
135
  end
132
136
 
133
137
  ENV['OPAL_SPEC'] ||= files_to_run(pattern).join(',')
138
+
139
+ super()
134
140
  end
135
141
 
136
142
  def stubs
@@ -159,25 +165,23 @@ module MSpec
159
165
  @files ||= []
160
166
  end
161
167
 
162
- def add_files specs
163
- puts "Adding #{specs.size} spec files..."
164
- files.concat specs.flatten
165
- end
166
-
167
- def paths_from_glob pattern
168
- Dir.glob(File.expand_path(pattern)).map do |s|
169
- s.sub(/^#{basedir}\//, '').sub(/\.rb$/, '')
170
- end
171
- end
172
-
173
- def rubyspec_paths
174
- rubyspec_white_list.map do |path|
168
+ def add_files specs, tag = ''
169
+ tag = "[#{tag}] "
170
+ puts "#{tag}Adding #{specs.size} spec files..."
171
+ specs = specs.flatten.map do |path|
175
172
  dirname = File.join([basedir, path])
176
173
  if File.directory? dirname
177
174
  rubyspec_paths_in_dir(dirname, path)
178
175
  else
179
176
  path
180
177
  end
178
+ end.flatten
179
+ files.concat specs
180
+ end
181
+
182
+ def paths_from_glob pattern
183
+ Dir.glob(File.expand_path(pattern)).map do |s|
184
+ s.sub(/^#{basedir}\//, '').sub(/\.rb$/, '')
181
185
  end
182
186
  end
183
187
 
@@ -197,18 +201,20 @@ module MSpec
197
201
 
198
202
  def files_to_run(pattern=nil)
199
203
  # add any filters in spec/filters of specs we dont want to run
200
- add_files paths_from_glob("#{basedir}/filters/**/*.rb")
204
+ add_files paths_from_glob("#{basedir}/filters/**/*.rb"), :filters
201
205
 
202
206
  if pattern
203
207
  # add custom opal specs from spec/
204
- add_files paths_from_glob(pattern) & rubyspec_paths
208
+ add_files paths_from_glob(pattern) & rubyspec_white_list, :rubyspec_custom_pattern
209
+ add_files paths_from_glob(pattern).grep(/(?!spec\/(corelib|stdlib)\/)/), :other_custom_pattern
205
210
 
206
211
  else
207
212
  # add opal specific specs
208
- add_files paths_from_glob("#{basedir}/{opal}/**/*_spec.rb")
213
+ add_files paths_from_glob("#{basedir}/opal/**/*_spec.rb"), 'opal/*'
214
+ add_files paths_from_glob("#{basedir}/lib/{lexer_spec.rb,parser/**/*_spec.rb}"), 'lib/{lexer,parser}'
209
215
 
210
216
  # add any rubyspecs we want to run (defined in spec/rubyspecs)
211
- add_files rubyspec_paths
217
+ add_files rubyspec_white_list, :rubyspec_white_list
212
218
  end
213
219
  end
214
220
 
@@ -246,6 +252,7 @@ module MSpec
246
252
  <!DOCTYPE html>
247
253
  <html>
248
254
  <head>
255
+ <meta charset="UTF-8" />
249
256
  <title>Opal Specs</title>
250
257
  </head>
251
258
  <body>
@@ -133,6 +133,22 @@ class PhantomFormatter < BrowserFormatter
133
133
  def log(str)
134
134
  `console.log(str)`
135
135
  end
136
+
137
+ def after(state)
138
+ super
139
+ unless exception?
140
+ print '.'
141
+ else
142
+ print failure? ? 'F' : 'E'
143
+ end
144
+ end
145
+ end
146
+
147
+ class PhantomDebugFormatter < PhantomFormatter
148
+ def after(state = nil)
149
+ (@exception && state) ? red(state.description) : green(state.description)
150
+ super
151
+ end
136
152
  end
137
153
 
138
154
  module MSpec
@@ -178,7 +194,8 @@ module OutputSilencer
178
194
  original_stdout = $stdout
179
195
  new_stdout = IO.new
180
196
  new_stdout.extend IO::Writable
181
- def new_stdout.write(string) end
197
+ new_stdout.write_proc = ->s{}
198
+
182
199
  begin
183
200
  $stdout = new_stdout
184
201
  yield
@@ -14,6 +14,23 @@ page.onInitialized = function() {
14
14
  });
15
15
  };
16
16
 
17
+ var system = require('system');
18
+ page.onCallback = function(data) {
19
+ switch (data[0]) {
20
+ case 'exit':
21
+ var status = data[1] || 0;
22
+ phantom.exit(status);
23
+ case 'stdout':
24
+ system.stdout.write(data[1] || '');
25
+ break;
26
+ case 'stderr':
27
+ system.stderr.write(data[1] || '');
28
+ break;
29
+ default:
30
+ console.error('Unknown callback data: ', data);
31
+ }
32
+ };
33
+
17
34
  page.open(args[0], function(status) {
18
35
  if (status !== 'success') {
19
36
  console.error("Cannot load: " + args[0]);
data/lib/opal.rb CHANGED
@@ -2,43 +2,10 @@ require 'opal/compiler'
2
2
  require 'opal/builder'
3
3
  require 'opal/erb'
4
4
  require 'opal/sprockets'
5
+ require 'opal/paths'
5
6
  require 'opal/version'
6
7
 
7
8
  # Opal is a ruby to javascript compiler, with a runtime for running
8
9
  # in any javascript environment.
9
10
  module Opal
10
- def self.gem_dir
11
- File.expand_path('..', __FILE__.untaint)
12
- end
13
-
14
- def self.core_dir
15
- File.expand_path('../../opal', __FILE__.untaint)
16
- end
17
-
18
- def self.std_dir
19
- File.expand_path('../../stdlib', __FILE__.untaint)
20
- end
21
-
22
- # Add a file path to opals load path. Any gem containing ruby code that Opal
23
- # has access to should add a load path through this method. Load paths added
24
- # here should only be paths which contain code targeted at being compiled by
25
- # Opal.
26
- def self.append_path(path)
27
- paths << path
28
- end
29
-
30
- def self.use_gem(gem_name, include_dependecies = true)
31
- spec = Gem::Specification.find_by_name(gem_name)
32
-
33
- spec.runtime_dependencies.each do |dependency|
34
- use_gem dependency.name
35
- end if include_dependecies
36
-
37
- Opal.append_path File.join(spec.gem_dir, 'lib')
38
- end
39
-
40
- # Private, don't add to these directly (use .append_path instead).
41
- def self.paths
42
- @paths ||= [core_dir.untaint, std_dir.untaint, gem_dir.untaint]
43
- end
44
11
  end
data/lib/opal/builder.rb CHANGED
@@ -1,101 +1,135 @@
1
- require 'opal/compiler'
2
- require 'erb'
3
- require 'pathname'
1
+ require 'opal/path_reader'
2
+ require 'opal/builder_processors'
3
+ require 'set'
4
4
 
5
5
  module Opal
6
6
  class Builder
7
+ include BuilderProcessors
7
8
 
8
- BUILDERS = { ".rb" => :build_ruby, ".js" => :build_js, ".erb" => :build_erb }
9
+ def initialize(options = nil)
10
+ (options || {}).each_pair do |k,v|
11
+ public_send("#{k}=", v)
12
+ end
13
+
14
+ @compiler_options ||= {}
15
+ @default_processor ||= RubyProcessor
16
+ @processors ||= DEFAULT_PROCESSORS
17
+ @stubs ||= []
18
+ @preload ||= []
19
+ @prerequired ||= []
20
+ @path_reader ||= PathReader.new
9
21
 
10
- def self.build(name)
11
- Builder.new.build name
22
+ @processed = []
12
23
  end
13
24
 
14
- def initialize(options = {})
15
- @paths = options.delete(:paths) || Opal.paths.clone
16
- @options = options
17
- @handled = {}
25
+ def self.build(*args, &block)
26
+ new.build(*args, &block)
18
27
  end
19
28
 
20
- def append_path(path)
21
- @paths << path
29
+ def build(path, options = {})
30
+ source = read(path)
31
+ build_str(source, path, options)
22
32
  end
23
33
 
24
- def build(path)
25
- @segments = []
34
+ def build_str source, filename, options = {}
35
+ path = path_reader.expand(filename).to_s unless stub?(filename)
36
+ asset = processor_for(source, filename, path, options)
37
+ requires = preload + asset.requires + tree_requires(asset, path)
38
+ requires.map { |r| process_require(r, options) }
39
+ processed << asset
40
+ self
41
+ end
26
42
 
27
- require_asset path
43
+ def build_require(path, options = {})
44
+ process_require(path, options)
45
+ end
28
46
 
29
- @segments.join
47
+ def to_s
48
+ processed.map(&:to_s).join("\n")
30
49
  end
31
50
 
32
- def build_str(str, options = {})
33
- @segments = []
34
- @segments << compile_ruby(str, options)
35
- @segments.join
51
+ def source_map
52
+ processed.map(&:source_map).reduce(:+).as_json.to_json
36
53
  end
37
54
 
38
- def require_asset(path)
39
- location = find_asset path
55
+ attr_reader :processed
40
56
 
41
- unless @handled[location]
42
- @handled[location] = true
43
- build_asset location
44
- end
45
- end
57
+ attr_accessor :processors, :default_processor, :path_reader,
58
+ :compiler_options, :stubs, :prerequired, :preload
46
59
 
47
- def find_asset(path)
48
- return path if Pathname(path).absolute?
49
60
 
50
- path.untaint if path =~ /\A(\w[-.\w]*\/?)+\Z/
51
- file_types = %w[.rb .js .js.erb]
52
61
 
53
- @paths.each do |root|
54
- file_types.each do |type|
55
- test = File.join root, "#{path}#{type}"
56
62
 
57
- if File.exist? test
58
- return test
59
- end
60
- end
63
+ private
64
+
65
+ def tree_requires(asset, path)
66
+ if path.nil? or path.empty?
67
+ dirname = Dir.pwd
68
+ else
69
+ dirname = File.dirname(File.expand_path(path))
61
70
  end
62
71
 
63
- raise "Could not find asset: #{path}"
64
- end
72
+ paths = path_reader.paths.map{|p| File.expand_path(p)}
65
73
 
66
- def build_asset(path)
67
- ext = File.extname path
74
+ asset.required_trees.flat_map do |tree|
75
+ expanded = File.expand_path(tree, dirname)
76
+ base = paths.find { |p| expanded.start_with?(p) }
77
+ next [] if base.nil?
68
78
 
69
- unless builder = BUILDERS[ext]
70
- raise "Unknown builder for #{ext}"
79
+ globs = extensions.map { |ext| File.join base, tree, "*.#{ext}" }
80
+
81
+ Dir[*globs].map do |file|
82
+ Pathname(file).relative_path_from(Pathname(base)).to_s.gsub(/(\.js)?(\.(?:#{extensions.join '|'}))$/, '')
83
+ end
71
84
  end
85
+ end
86
+
87
+ def processor_for(source, filename, path, options)
88
+ processor = processors.find { |p| p.match? path }
89
+ processor ||= default_processor
90
+ return processor.new(source, filename, compiler_options.merge(options))
91
+ end
72
92
 
73
- @segments << __send__(builder, path)
93
+ def read(path)
94
+ path_reader.read(path) or
95
+ raise ArgumentError, "can't find file: #{path.inspect} in #{path_reader.paths.inspect}"
74
96
  end
75
97
 
76
- def compile_ruby(str, options = nil)
77
- options ||= @options.clone
98
+ def process_require(filename, options)
99
+ return if prerequired.include?(filename)
100
+ return if already_processed.include?(filename)
101
+ already_processed << filename
78
102
 
79
- compiler = Compiler.new
80
- result = compiler.compile str, options
103
+ source = stub?(filename) ? '' : read(filename)
81
104
 
82
- compiler.requires.each do |r|
83
- require_asset r
105
+ if source.nil?
106
+ message = "can't find file: #{filename.inspect}"
107
+ case @compiler_options[:dynamic_require_severity]
108
+ when :error then raise LoadError, message
109
+ when :warning then warn "can't find file: #{filename.inspect}"
110
+ end
84
111
  end
85
112
 
86
- result
113
+ path = path_reader.expand(filename).to_s unless stub?(filename)
114
+ asset = processor_for(source, filename, path, options.merge(requirable: true))
115
+ process_requires(asset.requires+tree_requires(asset, path), options)
116
+ processed << asset
117
+ end
118
+
119
+ def process_requires(requires, options)
120
+ requires.map { |r| process_require(r, options) }
87
121
  end
88
122
 
89
- def build_ruby(path)
90
- compile_ruby File.read(path), @options.clone
123
+ def already_processed
124
+ @already_processed ||= Set.new
91
125
  end
92
126
 
93
- def build_js(path)
94
- File.read(path)
127
+ def stub? filename
128
+ stubs.include?(filename)
95
129
  end
96
130
 
97
- def build_erb(path)
98
- ::ERB.new(File.read(path)).result binding
131
+ def extensions
132
+ @extensions ||= DEFAULT_PROCESSORS.flat_map(&:extensions).compact
99
133
  end
100
134
  end
101
135
  end