opal 0.3.11 → 0.3.15

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 (282) hide show
  1. data/.gitignore +13 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE +20 -0
  4. data/README.md +11 -116
  5. data/Rakefile +126 -0
  6. data/bin/opal +1 -2
  7. data/docs/spec_runner.html +16 -0
  8. data/index.html +434 -0
  9. data/lib/opal.rb +14 -15
  10. data/lib/opal/builder.rb +46 -148
  11. data/lib/opal/command.rb +45 -115
  12. data/lib/opal/context.rb +139 -78
  13. data/lib/opal/dependency_builder.rb +34 -0
  14. data/lib/opal/environment.rb +92 -0
  15. data/lib/opal/parser/grammar.rb +4915 -0
  16. data/lib/opal/{parser.y → parser/grammar.y} +430 -284
  17. data/lib/opal/parser/lexer.rb +1329 -0
  18. data/lib/opal/parser/parser.rb +1460 -0
  19. data/lib/opal/parser/scope.rb +140 -0
  20. data/lib/opal/parser/sexp.rb +17 -0
  21. data/lib/opal/version.rb +2 -1
  22. data/opal.gemspec +23 -0
  23. data/opal.js +3149 -4162
  24. data/runtime/README.md +25 -0
  25. data/runtime/corelib/alpha.rb +10 -0
  26. data/runtime/corelib/array.rb +962 -0
  27. data/runtime/corelib/basic_object.rb +66 -0
  28. data/runtime/corelib/boolean.rb +44 -0
  29. data/runtime/corelib/class.rb +43 -0
  30. data/runtime/corelib/comparable.rb +25 -0
  31. data/runtime/corelib/complex.rb +2 -0
  32. data/runtime/corelib/dir.rb +29 -0
  33. data/runtime/corelib/enumerable.rb +316 -0
  34. data/runtime/corelib/enumerator.rb +80 -0
  35. data/runtime/corelib/error.rb +25 -0
  36. data/runtime/corelib/file.rb +80 -0
  37. data/runtime/corelib/hash.rb +503 -0
  38. data/runtime/corelib/io.rb +44 -0
  39. data/runtime/corelib/kernel.rb +237 -0
  40. data/runtime/corelib/load_order +29 -0
  41. data/runtime/corelib/match_data.rb +37 -0
  42. data/runtime/corelib/module.rb +171 -0
  43. data/runtime/corelib/native.rb +50 -0
  44. data/runtime/corelib/nil_class.rb +47 -0
  45. data/runtime/corelib/numeric.rb +219 -0
  46. data/runtime/corelib/object.rb +21 -0
  47. data/runtime/corelib/proc.rb +42 -0
  48. data/runtime/corelib/range.rb +38 -0
  49. data/runtime/corelib/rational.rb +16 -0
  50. data/runtime/corelib/regexp.rb +63 -0
  51. data/runtime/corelib/string.rb +185 -0
  52. data/runtime/corelib/struct.rb +97 -0
  53. data/runtime/corelib/time.rb +196 -0
  54. data/runtime/corelib/top_self.rb +7 -0
  55. data/runtime/gemlib/alpha.rb +5 -0
  56. data/runtime/gemlib/kernel.rb +17 -0
  57. data/runtime/gemlib/load_order +2 -0
  58. data/runtime/kernel/class.js +256 -0
  59. data/runtime/kernel/debug.js +42 -0
  60. data/runtime/kernel/init.js +114 -0
  61. data/runtime/kernel/load_order +5 -0
  62. data/runtime/kernel/loader.js +151 -0
  63. data/runtime/kernel/runtime.js +414 -0
  64. data/runtime/spec/README.md +34 -0
  65. data/runtime/spec/core/array/allocate_spec.rb +15 -0
  66. data/runtime/spec/core/array/append_spec.rb +31 -0
  67. data/runtime/spec/core/array/assoc_spec.rb +29 -0
  68. data/runtime/spec/core/array/at_spec.rb +38 -0
  69. data/runtime/spec/core/array/clear_spec.rb +22 -0
  70. data/runtime/spec/core/array/collect_spec.rb +3 -0
  71. data/runtime/spec/core/array/compact_spec.rb +42 -0
  72. data/runtime/spec/core/array/concat_spec.rb +21 -0
  73. data/runtime/spec/core/array/constructor_spec.rb +24 -0
  74. data/runtime/spec/core/array/count_spec.rb +11 -0
  75. data/runtime/spec/core/array/delete_at_spec.rb +31 -0
  76. data/runtime/spec/core/array/delete_if_spec.rb +24 -0
  77. data/runtime/spec/core/array/delete_spec.rb +26 -0
  78. data/runtime/spec/core/array/each_index_spec.rb +33 -0
  79. data/runtime/spec/core/array/each_spec.rb +11 -0
  80. data/runtime/spec/core/array/element_reference_spec.rb +136 -0
  81. data/runtime/spec/core/array/element_set_spec.rb +7 -0
  82. data/runtime/spec/core/array/empty_spec.rb +10 -0
  83. data/runtime/spec/core/array/eql_spec.rb +3 -0
  84. data/runtime/spec/core/array/equal_value_spec.rb +3 -0
  85. data/runtime/spec/core/array/fetch_spec.rb +26 -0
  86. data/runtime/spec/core/array/first_spec.rb +54 -0
  87. data/runtime/spec/core/array/fixtures/classes.rb +8 -0
  88. data/runtime/spec/core/array/flatten_spec.rb +41 -0
  89. data/runtime/spec/core/array/include_spec.rb +20 -0
  90. data/runtime/spec/core/array/insert_spec.rb +59 -0
  91. data/runtime/spec/core/array/last_spec.rb +57 -0
  92. data/runtime/spec/core/array/length_spec.rb +3 -0
  93. data/runtime/spec/core/array/map_spec.rb +3 -0
  94. data/runtime/spec/core/array/plus_spec.rb +16 -0
  95. data/runtime/spec/core/array/pop_spec.rb +79 -0
  96. data/runtime/spec/core/array/push_spec.rb +19 -0
  97. data/runtime/spec/core/array/rassoc_spec.rb +12 -0
  98. data/runtime/spec/core/array/reject_spec.rb +54 -0
  99. data/runtime/spec/core/array/replace_spec.rb +3 -0
  100. data/runtime/spec/core/array/reverse_each_spec.rb +18 -0
  101. data/runtime/spec/core/array/reverse_spec.rb +9 -0
  102. data/runtime/spec/core/array/shared/collect.rb +53 -0
  103. data/runtime/spec/core/array/shared/eql.rb +19 -0
  104. data/runtime/spec/core/array/shared/length.rb +6 -0
  105. data/runtime/spec/core/array/shared/replace.rb +31 -0
  106. data/runtime/spec/core/class/new_spec.rb +19 -0
  107. data/runtime/spec/core/enumerable/all_spec.rb +102 -0
  108. data/runtime/spec/core/enumerable/any_spec.rb +115 -0
  109. data/runtime/spec/core/enumerable/collect_spec.rb +3 -0
  110. data/runtime/spec/core/enumerable/count_spec.rb +29 -0
  111. data/runtime/spec/core/enumerable/detect_spec.rb +3 -0
  112. data/runtime/spec/core/enumerable/find_spec.rb +3 -0
  113. data/runtime/spec/core/enumerable/fixtures/classes.rb +26 -0
  114. data/runtime/spec/core/enumerable/shared/collect.rb +12 -0
  115. data/runtime/spec/core/enumerable/shared/entries.rb +7 -0
  116. data/runtime/spec/core/enumerable/shared/find.rb +49 -0
  117. data/runtime/spec/core/enumerable/to_a_spec.rb +7 -0
  118. data/runtime/spec/core/false/and_spec.rb +11 -0
  119. data/runtime/spec/core/false/inspect_spec.rb +7 -0
  120. data/runtime/spec/core/false/or_spec.rb +11 -0
  121. data/runtime/spec/core/false/to_s_spec.rb +7 -0
  122. data/runtime/spec/core/false/xor_spec.rb +11 -0
  123. data/runtime/spec/core/hash/allocate_spec.rb +15 -0
  124. data/runtime/spec/core/hash/assoc_spec.rb +29 -0
  125. data/runtime/spec/core/hash/clear_spec.rb +21 -0
  126. data/runtime/spec/core/hash/clone_spec.rb +12 -0
  127. data/runtime/spec/core/hash/default_spec.rb +6 -0
  128. data/runtime/spec/core/hash/delete_if_spec.rb +15 -0
  129. data/runtime/spec/core/hash/element_reference_spec.rb +16 -0
  130. data/runtime/spec/core/hash/element_set_spec.rb +8 -0
  131. data/runtime/spec/core/hash/new_spec.rb +13 -0
  132. data/runtime/spec/core/matchdata/to_a_spec.rb +7 -0
  133. data/runtime/spec/core/nil/and_spec.rb +12 -0
  134. data/runtime/spec/core/nil/inspect_spec.rb +8 -0
  135. data/runtime/spec/core/nil/nil_spec.rb +8 -0
  136. data/runtime/spec/core/nil/or_spec.rb +12 -0
  137. data/runtime/spec/core/nil/to_a_spec.rb +8 -0
  138. data/runtime/spec/core/nil/to_f_spec.rb +12 -0
  139. data/runtime/spec/core/nil/to_i_spec.rb +12 -0
  140. data/runtime/spec/core/nil/to_s_spec.rb +8 -0
  141. data/runtime/spec/core/nil/xor_spec.rb +12 -0
  142. data/runtime/spec/core/numeric/equal_value_spec.rb +11 -0
  143. data/runtime/spec/core/object/is_a_spec.rb +2 -0
  144. data/runtime/spec/core/object/shared/kind_of.rb +0 -0
  145. data/runtime/spec/core/regexp/match_spec.rb +23 -0
  146. data/runtime/spec/core/regexp/shared/match.rb +11 -0
  147. data/runtime/spec/core/symbol/to_proc_spec.rb +8 -0
  148. data/runtime/spec/core/true/and_spec.rb +11 -0
  149. data/runtime/spec/core/true/inspect_spec.rb +7 -0
  150. data/runtime/spec/core/true/or_spec.rb +11 -0
  151. data/runtime/spec/core/true/to_s_spec.rb +7 -0
  152. data/runtime/spec/core/true/xor_spec.rb +11 -0
  153. data/runtime/spec/language/alias_spec.rb +25 -0
  154. data/runtime/spec/language/and_spec.rb +62 -0
  155. data/runtime/spec/language/array_spec.rb +68 -0
  156. data/runtime/spec/language/block_spec.rb +105 -0
  157. data/runtime/spec/language/break_spec.rb +49 -0
  158. data/runtime/spec/language/case_spec.rb +165 -0
  159. data/runtime/spec/language/defined_spec.rb +80 -0
  160. data/runtime/spec/language/ensure_spec.rb +82 -0
  161. data/runtime/spec/language/fixtures/block.rb +19 -0
  162. data/runtime/spec/language/fixtures/break.rb +39 -0
  163. data/runtime/spec/language/fixtures/defined.rb +9 -0
  164. data/runtime/spec/language/fixtures/ensure.rb +37 -0
  165. data/runtime/spec/language/fixtures/next.rb +46 -0
  166. data/runtime/spec/language/fixtures/send.rb +36 -0
  167. data/runtime/spec/language/fixtures/super.rb +43 -0
  168. data/runtime/spec/language/hash_spec.rb +43 -0
  169. data/runtime/spec/language/if_spec.rb +278 -0
  170. data/runtime/spec/language/loop_spec.rb +32 -0
  171. data/runtime/spec/language/next_spec.rb +128 -0
  172. data/runtime/spec/language/or_spec.rb +65 -0
  173. data/runtime/spec/language/predefined_spec.rb +21 -0
  174. data/runtime/spec/language/regexp/interpolation_spec.rb +9 -0
  175. data/runtime/spec/language/regexp_spec.rb +7 -0
  176. data/runtime/spec/language/send_spec.rb +105 -0
  177. data/runtime/spec/language/string_spec.rb +4 -0
  178. data/runtime/spec/language/super_spec.rb +18 -0
  179. data/runtime/spec/language/symbol_spec.rb +41 -0
  180. data/runtime/spec/language/undef_spec.rb +16 -0
  181. data/runtime/spec/language/unless_spec.rb +44 -0
  182. data/runtime/spec/language/until_spec.rb +137 -0
  183. data/runtime/spec/language/variables_spec.rb +28 -0
  184. data/runtime/spec/language/versions/hash_1.9.rb +20 -0
  185. data/runtime/spec/language/while_spec.rb +175 -0
  186. data/runtime/spec/library/stringscanner/scan_spec.rb +36 -0
  187. data/runtime/spec/opal/forwardable/def_instance_delegator_spec.rb +49 -0
  188. data/runtime/spec/opal/opal/defined_spec.rb +15 -0
  189. data/runtime/spec/opal/opal/function_spec.rb +11 -0
  190. data/runtime/spec/opal/opal/native_spec.rb +16 -0
  191. data/runtime/spec/opal/opal/null_spec.rb +10 -0
  192. data/runtime/spec/opal/opal/number_spec.rb +11 -0
  193. data/runtime/spec/opal/opal/object_spec.rb +16 -0
  194. data/runtime/spec/opal/opal/string_spec.rb +11 -0
  195. data/runtime/spec/opal/opal/typeof_spec.rb +9 -0
  196. data/runtime/spec/opal/opal/undefined_spec.rb +10 -0
  197. data/runtime/spec/opal/true/case_compare_spec.rb +12 -0
  198. data/runtime/spec/opal/true/class_spec.rb +10 -0
  199. data/runtime/spec/spec_helper.rb +25 -0
  200. data/runtime/stdlib/base64.rb +91 -0
  201. data/runtime/stdlib/date.rb +4 -0
  202. data/{stdlib → runtime/stdlib}/dev.rb +0 -0
  203. data/runtime/stdlib/forwardable.rb +33 -0
  204. data/runtime/stdlib/optparse.rb +0 -0
  205. data/runtime/stdlib/pp.rb +6 -0
  206. data/{stdlib → runtime/stdlib}/racc/parser.rb +0 -0
  207. data/runtime/stdlib/rbconfig.rb +0 -0
  208. data/runtime/stdlib/si.rb +17 -0
  209. data/runtime/stdlib/strscan.rb +53 -0
  210. data/runtime/stdlib/uri.rb +111 -0
  211. data/runtime/stdlib/uri/common.rb +1014 -0
  212. data/runtime/stdlib/uri/ftp.rb +261 -0
  213. data/runtime/stdlib/uri/generic.rb +1599 -0
  214. data/runtime/stdlib/uri/http.rb +106 -0
  215. data/runtime/stdlib/uri/https.rb +22 -0
  216. data/runtime/stdlib/uri/ldap.rb +260 -0
  217. data/runtime/stdlib/uri/ldaps.rb +20 -0
  218. data/runtime/stdlib/uri/mailto.rb +280 -0
  219. data/spec/builder/build_source_spec.rb +52 -0
  220. data/spec/builder/fixtures/build_source/adam.rb +0 -0
  221. data/spec/builder/fixtures/build_source/bar/a.rb +0 -0
  222. data/spec/builder/fixtures/build_source/bar/wow/b.rb +0 -0
  223. data/spec/builder/fixtures/build_source/bar/wow/cow/c.rb +0 -0
  224. data/spec/builder/fixtures/build_source/beynon.rb +0 -0
  225. data/spec/builder/fixtures/build_source/charles.js +0 -0
  226. data/spec/builder/fixtures/build_source/foo/a.rb +0 -0
  227. data/spec/builder/fixtures/build_source/foo/b.rb +0 -0
  228. data/spec/builder/fixtures/build_source/foo/x.js +0 -0
  229. data/spec/builder/fixtures/build_source/foo/y.js +0 -0
  230. data/spec/builder/output_path_spec.rb +50 -0
  231. data/spec/grammar/alias_spec.rb +26 -0
  232. data/spec/grammar/and_spec.rb +13 -0
  233. data/spec/grammar/array_spec.rb +22 -0
  234. data/spec/grammar/attrasgn_spec.rb +28 -0
  235. data/spec/grammar/begin_spec.rb +38 -0
  236. data/spec/grammar/block_spec.rb +12 -0
  237. data/spec/grammar/break_spec.rb +17 -0
  238. data/spec/grammar/call_spec.rb +58 -0
  239. data/spec/grammar/class_spec.rb +35 -0
  240. data/spec/grammar/const_spec.rb +13 -0
  241. data/spec/grammar/cvar_spec.rb +11 -0
  242. data/spec/grammar/def_spec.rb +60 -0
  243. data/spec/grammar/false_spec.rb +17 -0
  244. data/spec/grammar/file_spec.rb +7 -0
  245. data/spec/grammar/gvar_spec.rb +13 -0
  246. data/spec/grammar/hash_spec.rb +17 -0
  247. data/spec/grammar/iasgn_spec.rb +9 -0
  248. data/spec/grammar/if_spec.rb +26 -0
  249. data/spec/grammar/iter_spec.rb +59 -0
  250. data/spec/grammar/ivar_spec.rb +9 -0
  251. data/spec/grammar/lasgn_spec.rb +8 -0
  252. data/spec/grammar/line_spec.rb +8 -0
  253. data/spec/grammar/lvar_spec.rb +38 -0
  254. data/spec/grammar/module_spec.rb +27 -0
  255. data/spec/grammar/nil_spec.rb +17 -0
  256. data/spec/grammar/not_spec.rb +27 -0
  257. data/spec/grammar/op_asgn1_spec.rb +23 -0
  258. data/spec/grammar/op_asgn2_spec.rb +23 -0
  259. data/spec/grammar/or_spec.rb +13 -0
  260. data/spec/grammar/return_spec.rb +17 -0
  261. data/spec/grammar/sclass_spec.rb +20 -0
  262. data/spec/grammar/self_spec.rb +17 -0
  263. data/spec/grammar/str_spec.rb +96 -0
  264. data/spec/grammar/super_spec.rb +20 -0
  265. data/spec/grammar/true_spec.rb +17 -0
  266. data/spec/grammar/undef_spec.rb +15 -0
  267. data/spec/grammar/unless_spec.rb +13 -0
  268. data/spec/grammar/while_spec.rb +15 -0
  269. data/spec/grammar/xstr_spec.rb +116 -0
  270. data/spec/grammar/yield_spec.rb +20 -0
  271. data/spec/spec_helper.rb +9 -0
  272. metadata +346 -21
  273. data/lib/opal/bundle.rb +0 -34
  274. data/lib/opal/lexer.rb +0 -902
  275. data/lib/opal/nodes.rb +0 -2150
  276. data/lib/opal/parser.rb +0 -4894
  277. data/lib/opal/rake/bundle_task.rb +0 -63
  278. data/opal-parser.js +0 -8343
  279. data/stdlib/strscan.rb +0 -52
  280. data/templates/init/Rakefile +0 -7
  281. data/templates/init/index.html +0 -17
  282. data/templates/init/lib/__NAME__.rb +0 -2
data/lib/opal.rb CHANGED
@@ -1,20 +1,19 @@
1
- require "opal/parser"
2
- require "opal/builder"
3
- require "opal/context"
4
- require "opal/version"
1
+ require 'opal/parser/parser'
2
+ require 'opal/builder'
3
+ require 'opal/dependency_builder'
4
+ require 'opal/context'
5
+ require 'opal/version'
5
6
 
6
- # Opal is a set of build tools and runtime utilies for compiling ruby
7
- # source code into javascript. Opal can use therubyracer to provide a
8
- # ruby context for evaluating the generated javascript against the
9
- # provided runtime.
10
7
  module Opal
11
- # Root opal directory (root of gem)
12
- OPAL_DIR = File.expand_path('../..', __FILE__)
8
+ def self.opal_dir
9
+ File.expand_path '../..', __FILE__
10
+ end
13
11
 
14
- # Full path to our opal.js runtime file
15
- OPAL_JS_PATH = File.join OPAL_DIR, "opal.js"
12
+ def self.runtime_code
13
+ File.read File.join(opal_dir, 'opal.js')
14
+ end
16
15
 
17
- # Full path to our opal-parser.js parser file
18
- OPAL_PARSER_JS_PATH = File.join OPAL_DIR, "opal-parser.js"
16
+ def self.runtime_debug_code
17
+ File.read File.join(opal_dir, 'opal.debug.js')
18
+ end
19
19
  end
20
-
data/lib/opal/builder.rb CHANGED
@@ -1,177 +1,75 @@
1
1
  require 'fileutils'
2
- require 'opal/parser'
3
- require 'opal/version'
4
2
 
5
3
  module Opal
6
- # The Builder class is used for building single ruby sources, or
7
- # building the core library ready for the browser/v8 context. It
8
- # is not used directly for building gem.
9
4
  class Builder
5
+ def initialize(sources, options = {})
6
+ @sources = Array(sources)
7
+ @options = options
10
8
 
11
- OPAL_PATH = File.expand_path(File.join('..', '..', '..'), __FILE__)
12
-
13
- STDLIB_PATH = File.join OPAL_PATH, 'stdlib'
14
-
15
- def initialize
16
- @parser = Parser.new
17
- end
18
-
19
- def parse(source, options = {})
20
- @parser.parse source, options
21
- end
22
-
23
- # Returns the result of the compiled file ready for opal to load.
24
- #
25
- # `relative_path` is used for the name the built file should have.
26
- # This is used for building a singular rb or js file into the
27
- # compiled output, and will avoid the user's dir setup being exposed
28
- # in production code. It will be of the form
29
- # `lib/some_lib/some_lib.rb`
30
- #
31
- # @param [String] full_path The full pathname to the file to build
32
- # @paeam [String] relative_path The pathname to be used in the build
33
- # file.
34
- #
35
- # @return [String]
36
- def wrap_source(full_path, relative_path = nil)
37
- relative_path ||= full_path
38
- ext = File.extname full_path
39
- # relative_path = relative_path.sub(/\.rb/, '.js') if ext == '.rb'
40
- content = compile_source full_path
41
-
42
- "opal.lib('#{relative_path}', #{content});\n"
9
+ @options[:out] = '.' if @options[:out] == '' or !@options[:out]
43
10
  end
44
11
 
45
- # Simply compile the given source code at the given path. This is
46
- # for compiling ruby or javascript sources only. This can be used
47
- # for any method that builds for the browser.
48
- #
49
- # @param [String] full_path location of the source to build
50
- # @return [String] compiled source
51
- def compile_source(full_path)
52
- ext = File.extname full_path
53
- src = File.read full_path
12
+ def build
13
+ @parser = Parser.new @options
14
+ @factories = {}
54
15
 
55
- case ext
56
- when '.js'
57
- "function($rb, self, __FILE__) { #{src} }"
16
+ @sources.each { |s| build_source '.', s }
58
17
 
59
- when '.rb'
60
- return parse src
61
-
62
- else
63
- raise "Bad file type for wrapping. Must be ruby or javascript"
64
- end
65
- end
66
-
67
- # Build the given sources from the standard library. These can be
68
- # globs. Returns a string of all content.
69
- def build_stdlib(*files)
70
- code = []
71
- Dir.chdir(STDLIB_PATH) do
72
- files.each do |file|
73
- lib = Dir[file + '.rb']
74
- full_path = File.join STDLIB_PATH, lib.first
75
- code << wrap_source(full_path, file)
18
+ if @options[:join]
19
+ File.open(@options[:join], 'w+') do |o|
20
+ @factories.each { |path, factory| o.write factory }
76
21
  end
77
22
  end
78
-
79
- code.join ''
80
23
  end
81
24
 
82
- # Takes a hash of build options.
83
- #
84
- # :project_dir - The base directory to work in. If not given then cwd is used.
85
- #
86
- # :files - May be a single source, a directory, or an array of ruby/js src
87
- #
88
- # :out - The output file. All sources are built into a single output file.
89
- # If this is not given, it will default to project_dir/javascripts/name.js
90
- # where name is the basename of the given project_dir or cwd.
91
- #
92
- # :main - only useful when more than one input is given to determine which
93
- # file is automatically loaded on running in the browser.
94
- #
95
- # :watch - watch all sources and automatically recompile if one changes
96
- #
97
- # :pre - pre content to add. Could be copyright, or extra code etc
98
- #
99
- # :post - post content.. could be extra code etc
100
- #
101
- # Also, if no output is given, then one file will be used for all sources,
102
- # and the files name will be taken as the basename of the root_dir/cwd.
103
- #
104
- # @param {Hash} options Build options to use
105
- def build(options = {})
106
- files = options[:files] || []
107
- files = [files] unless files.is_a? Array
108
- options[:files] = files = Dir.[](*files)
109
-
110
- raise "Opal::Builder - No input files could be found" if files.empty?
25
+ def build_source(base, source)
26
+ path = base == '.' ? source : File.join(base, source)
111
27
 
112
- main = options[:main]
28
+ if File.directory? path
29
+ Dir.entries(path).each do |e|
30
+ next if e == '.' or e == '..'
31
+ build_source path, e
32
+ end
113
33
 
114
- if main == true
115
- options[:main] = files.first
116
- elsif main
117
- raise "Opal::Builder - Main file does not exist!" unless File.exists? main
118
- files << main unless files.include? main
119
- elsif main == false
120
- options[:main] = false
121
- else
122
- options[:main] = files.first
34
+ elsif File.extname(path) == '.rb'
35
+ build_file base, source
123
36
  end
37
+ end
124
38
 
125
- main = options[:main]
39
+ def build_file(base, source)
40
+ path = base == '.' ? source : File.join(base, source)
41
+ code = @parser.parse File.read(path), path
126
42
 
127
- unless options[:out]
128
- options[:out] = main.sub /\.rb$/, '.js'
43
+ if /^lib/ =~ path
44
+ code = "opal.lib('#{path[4..-4]}', function() {\n#{code}\n});\n"
45
+ else
46
+ code = "opal.file('/#{path}', function() {\n#{code}\n});\n"
129
47
  end
130
48
 
131
- FileUtils.mkdir_p File.dirname(options[:out])
49
+ if @options[:join]
50
+ @factories[path] = code
51
+ elsif @options[:out]
52
+ out = output_path base, source
132
53
 
133
- rebuild options
134
- if options[:watch]
135
- puts "Watching for changes.."
136
- loop do
137
- out_mtime = File.stat(options[:out]).mtime
138
- options[:files].each do |file|
139
- if File.stat(file).mtime > out_mtime
140
- puts "#{Time.now} rebuilding - changes detected in #{file}"
141
- rebuild options
142
- end
143
- end
144
-
145
- begin
146
- sleep 1
147
- rescue Interrupt
148
- exit 0
149
- end
150
- end
54
+ FileUtils.mkdir_p File.dirname(out)
55
+ File.open(out, 'w+') { |o| o.write code }
151
56
  end
152
57
  end
153
58
 
154
- private
155
-
156
- # Does the actual rebuild of a project
157
- def rebuild(options)
158
- puts "rebuilding to #{options[:out]}"
159
- puts options[:files].inspect
160
- File.open(options[:out], 'w') do |out|
161
- # out.write @pre if @pre
162
-
163
- options[:files].each do |file|
164
- out.write wrap_source file
165
- end
166
-
167
- if options[:main]
168
- main = options[:main].sub(/\.rb$/, '')
169
- out.write "opal.require('#{main}');\n"
59
+ def output_path(base, source)
60
+ fname = source.chomp('.rb') + '.js'
61
+ if @options[:out] == '.'
62
+ base == '.' ? fname : File.join(base, fname)
63
+ else
64
+ if base == '.'
65
+ File.join @options[:out], fname
66
+ else
67
+ parts = base.split '/'
68
+ parts[0] = @options[:out]
69
+ parts << fname
70
+ File.join *parts
170
71
  end
171
-
172
- # out.write @post if @post
173
72
  end
174
73
  end
175
74
  end
176
75
  end
177
-
data/lib/opal/command.rb CHANGED
@@ -1,143 +1,73 @@
1
1
  require 'optparse'
2
2
  require 'fileutils'
3
3
  require 'opal/builder'
4
+ require 'opal/version'
4
5
 
5
6
  module Opal
6
- # Command runner. When using the `opal` bin file, this class is used to
7
- # delegate commands based on the options passed from the command line.
8
7
  class Command
9
8
 
10
- # Valid command line arguments
11
- COMMANDS = [:help, :irb, :compile, :bundle, :exec, :eval, :install, :init]
12
-
13
9
  def initialize(args)
14
- command = args.shift
15
-
16
- if command and COMMANDS.include?(command.to_sym)
17
- __send__ command.to_sym
18
- elsif command and File.exists? command
19
- eval command
20
- else
21
- help
10
+ options = {}
11
+ if ARGV.first == 'init'
12
+ options[:init] = true
13
+ ARGV.shift
22
14
  end
23
- end
24
-
25
- # Initialize a project either in current directory, or directory
26
- # specified in ARGV.
27
- def init
28
- path = File.expand_path(ARGV.first || Dir.getwd)
29
- base = File.basename(path)
30
- template = File.join(OPAL_DIR, "templates", "init")
31
-
32
- Dir.chdir(template) do
33
- Dir["**/*"].each do |f|
34
- next if File.directory? f
35
-
36
- full = File.expand_path f, template
37
- dest = File.join path, f.sub(/__NAME__/, base)
38
15
 
39
- if File.exists? dest
40
- puts "Skipping #{f}"
41
- next
42
- end
43
-
44
- FileUtils.mkdir_p File.dirname(dest)
45
-
46
- File.open(dest, 'w+') do |o|
47
- o.write File.read(full).gsub(/__NAME__/, base)
48
- end
16
+ OptionParser.new do |opts|
17
+ opts.on('-c', '--compile', 'Compile ruby') do |c|
18
+ options[:compile] = c
49
19
  end
50
- end
51
20
 
52
- FileUtils.mkdir_p File.join(path, "js")
53
-
54
- %w[opal.js opal-parser.js].each do |src|
55
- File.open(File.join(path, "js", src), "w+") do |o|
56
- o.write File.read(File.join(OPAL_DIR, src))
21
+ opts.on('-o', '--out [DIR]', 'Output directory') do |o|
22
+ options[:out] = o || ''
57
23
  end
58
- end
59
- end
60
24
 
61
- def help
62
- puts "need to print help"
63
- end
25
+ opts.on('-j', '--join [OUT]', 'Join out') do |j|
26
+ options[:join] = j || ''
27
+ end
64
28
 
65
- # Starts an irb session using an inline v8 context. Commands can be
66
- # entered just like IRB. Use Ctrl-C or type `exit` to quit.
67
- def irb(*)
68
- ctx = Context.new :method_missing => true,
69
- :overload_arithmetic => true,
70
- :overload_comparison => true,
71
- :overload_bitwise => true
72
- ctx.start_repl
73
- end
29
+ opts.on('-d', '--debug', 'Debug mode') do |d|
30
+ options[:debug] = true
31
+ end
74
32
 
75
- # If the given arg exists as a file, then the source code is compiled
76
- # and then run through a javascript context and the result printed out.
77
- #
78
- # If the arg isn't a file, then it is assumed to be raw ruby code and it
79
- # is compiled and run directly with the result being printed out.
80
- #
81
- # Usage:
82
- #
83
- # opal eval path/to/some/file.rb
84
- # # => "some result"
85
- #
86
- # opal eval "1.class"
87
- # # => Numeric
88
- #
89
- # @param [String] code path or ruby code to eval
90
- def eval(code = nil, *)
91
- abort "Usage: opal eval [Ruby code or file path]" unless code
33
+ opts.on_tail("-v", "--version", "Show version") do
34
+ puts Opal::VERSION
35
+ exit
36
+ end
37
+ end.parse!
92
38
 
93
- if File.exists? code
94
- code = Parser.new.parse File.read(code)
39
+ if options[:init]
40
+ init options
41
+ elsif options[:compile]
42
+ build options
43
+ else
44
+ run options
95
45
  end
96
-
97
- context = Context.new :method_missing => true,
98
- :overload_arithmetic => true,
99
- :overload_comparison => true,
100
- :overload_bitwise => true
101
-
102
- puts context.eval code
103
46
  end
104
47
 
105
- # If the given path exists, then compiles the source code of that
106
- # file and spits out the generated javascript.
107
- #
108
- # If this file does not exist, then assumes the input is ruby code
109
- # to compile and return.
110
- #
111
- # Usage:
112
- #
113
- # opal compile path/to/ruby.rb
114
- # # => "generated code"
115
- #
116
- # opal compile "some ruby code"
117
- # # => generated code
118
- #
119
- # @param [String] path file path or ruby code
120
- def compile(path = nil, *)
121
- abort "Usage: opal compile [Ruby code or file path]" unless path
122
-
123
- if File.exists? path
124
- puts Parser.new.parse File.read(path)
48
+ def run(options)
49
+ if ARGV.empty?
50
+ Context.new.start_repl
51
+ elsif File.exists? ARGV.first
52
+ Context.runner ARGV.first
125
53
  else
126
- puts Parser.new.parse path
54
+ puts "#{ARGV.first} does not exist"
127
55
  end
128
56
  end
129
57
 
130
- # Bundle the gem (browserify) ready for the browser
131
- def bundle(*)
132
- # lazy load incase user does not have rbp installed
133
- require 'opal/bundle'
58
+ def init(options)
59
+ out = options[:out]
60
+ src = options[:debug] ? Opal.runtime_debug_code : Opal.runtime_code
61
+ out ||= (options[:debug] ? 'opal.debug.js' : 'opal.js')
134
62
 
135
- path = File.join Dir.getwd, 'package.yml'
136
- package = Rbp::Package.load_path path
137
- bundle = Bundle.new package
63
+ FileUtils.mkdir_p File.dirname(out)
64
+ File.open(out, 'w+') { |o| o.write src }
138
65
 
139
- puts bundle.build
66
+ puts "Wrote Opal to #{out}#{options[:debug] && ' (debug)'}"
140
67
  end
141
- end
142
- end
143
68
 
69
+ def build(options)
70
+ Builder.new(ARGV, options).build
71
+ end
72
+ end # Command
73
+ end
data/lib/opal/context.rb CHANGED
@@ -1,30 +1,38 @@
1
+ require 'opal/environment'
2
+
1
3
  module Opal
2
4
  class Context
3
- # Options are mainly just passed onto the builder/parser.
4
- def initialize(options = {})
5
- @options = options
6
- @root_dir = options[:dir] || Dir.getwd
7
- @builder = Opal::Builder.new
8
- @loaded_paths = false
9
5
 
10
- setup_v8
11
- end
6
+ attr_reader :v8
7
+ attr_reader :parser
8
+ attr_reader :environment
12
9
 
13
10
  ##
14
- # Require the given id as if it was required in the context. This simply
15
- # passes the require through to the underlying context.
11
+ # Glob may be a file or glob path, as a string.
16
12
 
17
- def require_file(path)
18
- setup_v8
19
- @v8.eval "opal.run(function() {opal.require('#{path}');});", path
20
- finish
13
+ def self.runner(glob)
14
+ ctx = self.new
15
+ ctx.v8['opal_tmp_glob'] = Dir[glob]
16
+
17
+ runner = <<-CODE
18
+ files = `opal_tmp_glob`
19
+
20
+ files.each do |a|
21
+ require a
22
+ end
23
+ CODE
24
+
25
+ ctx.eval_irb runner, '(runner)'
26
+ ctx.finish
21
27
  end
22
28
 
23
- # Set ARGV for the context.
24
- # @param [Array<String>] args
25
- def argv=(args)
26
- puts "setting argv to #{args.inspect}"
27
- @v8.eval "opal.runtime.cs(opal.runtime.Object, 'ARGV', #{args.inspect});"
29
+ def initialize root = Dir.getwd
30
+ @environment = Environment.load root
31
+ @root = root
32
+ @parser = Opal::Parser.new :debug => true
33
+ @loaded_paths = false
34
+
35
+ setup_v8
28
36
  end
29
37
 
30
38
  # Start normal js repl
@@ -42,18 +50,33 @@ module Opal
42
50
  break
43
51
  end
44
52
 
45
- puts "=> #{eval line, '(opal)'}"
53
+ puts "=> #{eval_irb line, '(irb)'}"
46
54
  end
47
55
 
48
56
  finish
49
57
  end
50
58
 
51
- def eval(content, file = "(opal)", line = "")
52
- js = @builder.parse content, @options
53
- code = "opal.run(function() { var result = (#{js})(opal.runtime, "
54
- code += "opal.runtime.top, '(opal)'); if (result == null || !result"
55
- code += ".m$inspect) { return '(Object does not support #inspect)'; }"
56
- code += "else { return result.m$inspect() } });"
59
+ def eval_builder(content, file)
60
+ @parser.parse content, file
61
+ end
62
+
63
+ def eval(content, file = "(irb)", line = "")
64
+ @v8.eval eval_builder(content, file), file
65
+ end
66
+
67
+ def eval_irb(content, file = '(irb)')
68
+ code = <<-CODE
69
+ (function() { try {
70
+ opal.FILE = '#{file}';
71
+ var res = #{ eval_builder content, file };
72
+ return res.m$inspect();
73
+ }
74
+ catch (e) {
75
+ opal.bt(e);
76
+ return "nil";
77
+ }
78
+ })()
79
+ CODE
57
80
 
58
81
  @v8.eval code, file
59
82
  end
@@ -64,7 +87,7 @@ module Opal
64
87
  # #setup_v8
65
88
  def finish
66
89
  return unless @v8
67
- @v8.eval "opal.runtime.do_at_exit()", "(opal)"
90
+ @v8.eval "opal.do_at_exit()", "(irb)"
68
91
 
69
92
  @v8 = nil
70
93
  end
@@ -83,13 +106,30 @@ module Opal
83
106
 
84
107
  @v8 = V8::Context.new
85
108
  @v8['console'] = Console.new
109
+ @v8['opal_filesystem'] = FileSystem.new(self)
110
+
111
+ load_runtime
112
+ load_gem_runtime
113
+ end
86
114
 
87
- @v8.eval File.read(OPAL_JS_PATH), "(opal)"
88
- opal = @v8['opal']
89
- opal['fs'] = FileSystem.new self
115
+ ##
116
+ # Loads the runtime from build/*.js. This isnt included in the git repo,
117
+ # so needs to be built before running (gems should have these files included)
118
+
119
+ def load_runtime
120
+ @v8.eval Opal.runtime_debug_code, '(runtime)'
121
+ end
90
122
 
91
- # FIXME: we cant use a ruby array as a js array :(
92
- opal['loader'] = Loader.new self, @v8.eval("[]")
123
+ ##
124
+ # Load gem specific runtime.
125
+
126
+ def load_gem_runtime
127
+ dir = File.join Opal.opal_dir, 'runtime', 'gemlib'
128
+ order = File.read(File.join dir, 'load_order').strip.split("\n")
129
+ order.each do |f|
130
+ path = File.join dir, "#{f}.rb"
131
+ eval File.read(path), path
132
+ end
93
133
  end
94
134
 
95
135
  ##
@@ -110,78 +150,99 @@ module Opal
110
150
 
111
151
  class FileSystem
112
152
 
113
- def initialize(context)
114
- @context = context
153
+ def initialize context
154
+ @context = context
155
+ @environment = context.environment
156
+ @cache = {}
115
157
  end
116
158
 
117
- def cwd
118
- Dir.getwd
119
- end
159
+ ##
160
+ # Used to bootstrap loadpaths.
120
161
 
121
- def glob(*arr)
122
- Dir.glob arr
123
- end
162
+ def find_paths
163
+ return @paths if @paths
124
164
 
125
- def exist_p(path)
126
- File.exist? path
127
- end
165
+ paths = [File.join(Opal.opal_dir, 'runtime', 'stdlib')]
128
166
 
129
- def expand_path(filename, dir_string = nil)
130
- File.expand_path filename, dir_string
131
- end
167
+ @environment.require_paths.each do |p|
168
+ paths << File.join(@environment.root, p)
169
+ end
132
170
 
133
- def dirname(file)
134
- File.dirname file
135
- end
171
+ @environment.specs.each do |spec|
172
+ paths.push *spec.load_paths
173
+ end
136
174
 
137
- def join(*parts)
138
- File.join *parts
175
+ @paths = @context.v8.eval paths.inspect
139
176
  end
140
- end
141
177
 
142
- # Loader for v8 context
143
- class Loader
178
+ ##
179
+ # Require a file from context
144
180
 
145
- attr_reader :paths
181
+ def require path, paths
182
+ resolved = find_lib path, paths
146
183
 
147
- def initialize(context, paths)
148
- @context = context
149
- @paths = paths
150
- end
184
+ return nil unless resolved
185
+
186
+ return false if @cache[resolved]
151
187
 
152
- def resolve_lib(id)
153
- resolved = find_lib id
154
- raise "Cannot find lib `#{id}'" unless resolved
188
+ @cache[resolved] = true
189
+ @context.v8.eval "opal.FILE = '#{resolved}'"
190
+ @context.eval File.read(resolved), resolved
155
191
 
156
- resolved
192
+ true
157
193
  end
158
194
 
159
- def find_lib(id)
160
- @paths.each do |path|
161
- candidate = File.join path, "#{id}.rb"
195
+ def find_lib path, paths
196
+ paths.each do |l|
197
+ candidate = File.join l, "#{path}.rb"
162
198
  return candidate if File.exists? candidate
163
199
 
164
- candidate = File.join path, id
200
+ candidate = File.join l, path
165
201
  return candidate if File.exists? candidate
166
- end
167
202
 
168
- return File.expand_path id if File.exists? id
169
- return File.expand_path(id + '.rb') if File.exists?(id + '.rb')
203
+ candidate = File.expand_path path
204
+ return candidate if File.exists? candidate
205
+
206
+ candidate = File.expand_path("#{path}.rb")
207
+ return candidate if File.exists? candidate
208
+ end
170
209
 
171
210
  nil
172
211
  end
173
212
 
174
- def ruby_file_contents(filename)
175
- Opal::Parser.new.parse File.read(filename)
213
+ ##
214
+ # Build body for given ruby file. Should return a function
215
+ # capable of being executed by opal of form:
216
+ #
217
+ # function(self, FILE) { ... }
218
+
219
+ def file_body(path)
220
+ @context.eval File.read(path), path
176
221
  end
177
222
 
178
- def wrap(content, filename)
179
- code = "(function($rb, self, __FILE__) { #{content} });"
180
- @context.eval code, filename
181
- # code
223
+ def cwd
224
+ Dir.getwd
182
225
  end
183
- end
184
226
 
227
+ def glob(*arr)
228
+ Dir.glob arr
229
+ end
230
+
231
+ def exist_p(path)
232
+ File.exist? path
233
+ end
234
+
235
+ def expand_path(filename, dir_string = nil)
236
+ File.expand_path filename, dir_string
237
+ end
238
+
239
+ def dirname(file)
240
+ File.dirname file
241
+ end
242
+
243
+ def join(*parts)
244
+ File.join *parts
245
+ end
246
+ end # FileSystem
185
247
  end
186
248
  end
187
-