opal 0.3.18 → 0.3.19

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 (259) hide show
  1. data/.gitignore +1 -1
  2. data/Gemfile +1 -3
  3. data/README.md +472 -10
  4. data/Rakefile +10 -52
  5. data/core/array.rb +9 -14
  6. data/core/basic_object.rb +7 -10
  7. data/core/boolean.rb +5 -1
  8. data/core/class.rb +15 -38
  9. data/core/dir.rb +89 -0
  10. data/core/enumerable.rb +133 -57
  11. data/core/error.rb +15 -1
  12. data/core/file.rb +85 -0
  13. data/core/hash.rb +186 -32
  14. data/core/kernel.rb +30 -31
  15. data/core/load_order +4 -2
  16. data/core/module.rb +42 -62
  17. data/core/numeric.rb +7 -1
  18. data/core/object.rb +1 -1
  19. data/core/proc.rb +6 -2
  20. data/core/range.rb +16 -28
  21. data/core/regexp.rb +3 -3
  22. data/core/runtime.js +281 -350
  23. data/core/string.rb +100 -110
  24. data/docs/CNAME +1 -0
  25. data/docs/Rakefile +55 -0
  26. data/docs/css/styles.css +50 -0
  27. data/docs/css/syntax.css +63 -0
  28. data/docs/layout/post.html +3 -0
  29. data/docs/layout/pre.html +11 -0
  30. data/examples/dependencies/app.rb +3 -0
  31. data/lib/opal.rb +2 -1
  32. data/lib/opal/builder.rb +36 -10
  33. data/lib/opal/builder_task.rb +51 -24
  34. data/lib/opal/grammar.rb +2509 -2439
  35. data/lib/opal/grammar.y +38 -5
  36. data/lib/opal/lexer.rb +18 -2
  37. data/lib/opal/parser.rb +375 -349
  38. data/lib/opal/scope.rb +24 -2
  39. data/lib/opal/version.rb +1 -1
  40. data/spec/builder/build_order_spec.rb +20 -0
  41. data/spec/builder/lib_name_for_spec.rb +24 -0
  42. data/spec/grammar/call_spec.rb +9 -6
  43. data/spec/grammar/lambda_spec.rb +64 -0
  44. data/spec/grammar/sclass_spec.rb +5 -3
  45. data/{core/spec → test}/core/array/allocate_spec.rb +0 -0
  46. data/{core/spec → test}/core/array/append_spec.rb +0 -0
  47. data/{core/spec → test}/core/array/assoc_spec.rb +0 -0
  48. data/{core/spec → test}/core/array/at_spec.rb +0 -0
  49. data/{core/spec → test}/core/array/clear_spec.rb +0 -0
  50. data/{core/spec → test}/core/array/clone_spec.rb +0 -0
  51. data/{core/spec → test}/core/array/collect_spec.rb +0 -0
  52. data/{core/spec → test}/core/array/compact_spec.rb +0 -0
  53. data/{core/spec → test}/core/array/concat_spec.rb +0 -0
  54. data/{core/spec → test}/core/array/constructor_spec.rb +0 -0
  55. data/{core/spec → test}/core/array/count_spec.rb +0 -0
  56. data/{core/spec → test}/core/array/delete_at_spec.rb +0 -0
  57. data/{core/spec → test}/core/array/delete_if_spec.rb +0 -0
  58. data/{core/spec → test}/core/array/delete_spec.rb +0 -0
  59. data/{core/spec → test}/core/array/each_index_spec.rb +0 -0
  60. data/{core/spec → test}/core/array/each_spec.rb +0 -0
  61. data/{core/spec → test}/core/array/element_reference_spec.rb +0 -0
  62. data/{core/spec → test}/core/array/empty_spec.rb +0 -0
  63. data/{core/spec → test}/core/array/eql_spec.rb +0 -0
  64. data/{core/spec → test}/core/array/fetch_spec.rb +0 -0
  65. data/{core/spec → test}/core/array/first_spec.rb +0 -0
  66. data/{core/spec → test}/core/array/flatten_spec.rb +0 -0
  67. data/{core/spec → test}/core/array/include_spec.rb +0 -0
  68. data/{core/spec → test}/core/array/insert_spec.rb +0 -0
  69. data/{core/spec → test}/core/array/last_spec.rb +0 -0
  70. data/{core/spec → test}/core/array/length_spec.rb +0 -0
  71. data/{core/spec → test}/core/array/map_spec.rb +0 -0
  72. data/{core/spec → test}/core/array/plus_spec.rb +0 -0
  73. data/{core/spec → test}/core/array/pop_spec.rb +0 -0
  74. data/{core/spec → test}/core/array/push_spec.rb +0 -0
  75. data/{core/spec → test}/core/array/rassoc_spec.rb +0 -0
  76. data/{core/spec → test}/core/array/reject_spec.rb +0 -0
  77. data/{core/spec → test}/core/array/replace_spec.rb +0 -0
  78. data/{core/spec → test}/core/array/reverse_each_spec.rb +0 -0
  79. data/{core/spec → test}/core/array/reverse_spec.rb +0 -0
  80. data/{core/spec → test}/core/array/size_spec.rb +0 -0
  81. data/{core/spec → test}/core/array/to_ary_spec.rb +0 -0
  82. data/{core/spec → test}/core/array/uniq_spec.rb +0 -0
  83. data/{core/spec → test}/core/array/zip_spec.rb +0 -0
  84. data/test/core/class/fixtures/classes.rb +9 -0
  85. data/test/core/class/new_spec.rb +108 -0
  86. data/{core/spec → test}/core/enumerable/all_spec.rb +0 -0
  87. data/{core/spec → test}/core/enumerable/any_spec.rb +0 -0
  88. data/{core/spec → test}/core/enumerable/collect_spec.rb +0 -0
  89. data/{core/spec → test}/core/enumerable/count_spec.rb +0 -0
  90. data/test/core/enumerable/detect_spec.rb +48 -0
  91. data/test/core/enumerable/drop_spec.rb +17 -0
  92. data/test/core/enumerable/drop_while_spec.rb +24 -0
  93. data/test/core/enumerable/each_with_index_spec.rb +11 -0
  94. data/test/core/enumerable/each_with_object_spec.rb +17 -0
  95. data/test/core/enumerable/entries_spec.rb +6 -0
  96. data/test/core/enumerable/find_all_spec.rb +13 -0
  97. data/test/core/enumerable/find_index_spec.rb +45 -0
  98. data/test/core/enumerable/find_spec.rb +48 -0
  99. data/test/core/enumerable/first_spec.rb +40 -0
  100. data/{core/spec → test}/core/enumerable/fixtures/classes.rb +19 -0
  101. data/test/core/enumerable/grep_spec.rb +21 -0
  102. data/test/core/enumerable/take_spec.rb +40 -0
  103. data/test/core/enumerable/to_a_spec.rb +6 -0
  104. data/{core/spec → test}/core/false/and_spec.rb +0 -0
  105. data/{core/spec → test}/core/false/inspect_spec.rb +0 -0
  106. data/{core/spec → test}/core/false/or_spec.rb +0 -0
  107. data/{core/spec → test}/core/false/to_s_spec.rb +0 -0
  108. data/{core/spec → test}/core/false/xor_spec.rb +0 -0
  109. data/test/core/file/expand_path_spec.rb +20 -0
  110. data/{core/spec → test}/core/hash/allocate_spec.rb +0 -0
  111. data/{core/spec → test}/core/hash/assoc_spec.rb +0 -0
  112. data/{core/spec → test}/core/hash/clear_spec.rb +0 -0
  113. data/{core/spec → test}/core/hash/clone_spec.rb +0 -0
  114. data/test/core/hash/default_spec.rb +9 -0
  115. data/{core/spec → test}/core/hash/delete_if_spec.rb +0 -0
  116. data/test/core/hash/each_key_spec.rb +15 -0
  117. data/test/core/hash/each_pair_spec.rb +30 -0
  118. data/test/core/hash/each_spec.rb +30 -0
  119. data/test/core/hash/each_value_spec.rb +15 -0
  120. data/{core/spec → test}/core/hash/element_reference_spec.rb +14 -0
  121. data/{core/spec → test}/core/hash/element_set_spec.rb +1 -0
  122. data/test/core/hash/empty_spec.rb +10 -0
  123. data/test/core/hash/fetch_spec.rb +24 -0
  124. data/test/core/hash/flatten_spec.rb +46 -0
  125. data/test/core/hash/has_key_spec.rb +24 -0
  126. data/test/core/hash/has_value_spec.rb +12 -0
  127. data/test/core/hash/include_spec.rb +24 -0
  128. data/test/core/hash/index_spec.rb +13 -0
  129. data/test/core/hash/indexes_spec.rb +9 -0
  130. data/test/core/hash/indices_spec.rb +9 -0
  131. data/test/core/hash/invert_spec.rb +12 -0
  132. data/test/core/hash/keep_if_spec.rb +18 -0
  133. data/test/core/hash/key_spec.rb +24 -0
  134. data/test/core/hash/keys_spec.rb +10 -0
  135. data/test/core/hash/length_spec.rb +10 -0
  136. data/test/core/hash/member_spec.rb +24 -0
  137. data/{core/spec → test}/core/hash/merge_spec.rb +0 -0
  138. data/{core/spec → test}/core/hash/new_spec.rb +0 -0
  139. data/test/core/hash/rassoc_spec.rb +34 -0
  140. data/test/core/hash/replace_spec.rb +7 -0
  141. data/test/core/hash/select_spec.rb +52 -0
  142. data/test/core/hash/shift_spec.rb +19 -0
  143. data/test/core/hash/size_spec.rb +10 -0
  144. data/test/core/hash/update_spec.rb +17 -0
  145. data/test/core/hash/value_spec.rb +12 -0
  146. data/test/core/hash/values_at_spec.rb +9 -0
  147. data/test/core/hash/values_spec.rb +7 -0
  148. data/test/core/kernel/eql_spec.rb +15 -0
  149. data/test/core/kernel/equal_value_spec.rb +12 -0
  150. data/test/core/kernel/loop_spec.rb +23 -0
  151. data/test/core/kernel/nil_spec.rb +7 -0
  152. data/test/core/kernel/proc_spec.rb +9 -0
  153. data/test/core/kernel/rand_spec.rb +14 -0
  154. data/test/core/kernel/respond_to_spec.rb +24 -0
  155. data/test/core/kernel/send_spec.rb +56 -0
  156. data/test/core/kernel/tap_spec.rb +10 -0
  157. data/test/core/kernel/to_s_spec.rb +5 -0
  158. data/{core/spec → test}/core/matchdata/to_a_spec.rb +0 -0
  159. data/{core/spec → test}/core/nil/and_spec.rb +0 -0
  160. data/{core/spec → test}/core/nil/inspect_spec.rb +0 -0
  161. data/{core/spec → test}/core/nil/nil_spec.rb +0 -0
  162. data/{core/spec → test}/core/nil/or_spec.rb +0 -0
  163. data/{core/spec → test}/core/nil/to_a_spec.rb +0 -0
  164. data/{core/spec → test}/core/nil/to_f_spec.rb +0 -0
  165. data/{core/spec → test}/core/nil/to_i_spec.rb +0 -0
  166. data/{core/spec → test}/core/nil/to_s_spec.rb +0 -0
  167. data/{core/spec → test}/core/nil/xor_spec.rb +0 -0
  168. data/{core/spec → test}/core/numeric/equal_value_spec.rb +0 -0
  169. data/test/core/range/begin_spec.rb +9 -0
  170. data/test/core/range/case_compare_spec.rb +16 -0
  171. data/test/core/range/end_spec.rb +9 -0
  172. data/{core/spec → test}/core/regexp/match_spec.rb +0 -0
  173. data/test/core/string/capitalize_spec.rb +10 -0
  174. data/test/core/string/casecmp_spec.rb +16 -0
  175. data/test/core/string/chomp_spec.rb +43 -0
  176. data/test/core/string/chop_spec.rb +10 -0
  177. data/test/core/string/chr_spec.rb +13 -0
  178. data/test/core/string/comparison_spec.rb +13 -0
  179. data/test/core/string/downcase_spec.rb +6 -0
  180. data/test/core/string/element_reference_spec.rb +72 -0
  181. data/test/core/string/empty_spec.rb +8 -0
  182. data/test/core/string/end_with_spec.rb +12 -0
  183. data/test/core/string/fixtures/classes.rb +3 -0
  184. data/test/core/string/gsub_spec.rb +17 -0
  185. data/test/core/string/include_spec.rb +12 -0
  186. data/test/core/string/intern_spec.rb +9 -0
  187. data/test/core/string/length_spec.rb +9 -0
  188. data/test/core/string/lstrip_spec.rb +7 -0
  189. data/test/core/string/match_spec.rb +27 -0
  190. data/test/core/string/next_spec.rb +10 -0
  191. data/test/core/string/ord_spec.rb +9 -0
  192. data/test/core/string/partition_spec.rb +10 -0
  193. data/test/core/string/reverse_spec.rb +7 -0
  194. data/test/core/string/rstrip_spec.rb +7 -0
  195. data/test/core/string/size_spec.rb +9 -0
  196. data/test/core/string/slice_spec.rb +72 -0
  197. data/test/core/string/split_spec.rb +5 -0
  198. data/test/core/string/start_with_spec.rb +12 -0
  199. data/test/core/string/strip_spec.rb +6 -0
  200. data/test/core/string/sub_spec.rb +22 -0
  201. data/test/core/string/succ_spec.rb +10 -0
  202. data/test/core/string/sum_spec.rb +5 -0
  203. data/test/core/string/swapcase_spec.rb +18 -0
  204. data/test/core/string/to_a_spec.rb +9 -0
  205. data/test/core/string/to_f_spec.rb +14 -0
  206. data/test/core/string/to_i_spec.rb +25 -0
  207. data/test/core/string/to_s_spec.rb +13 -0
  208. data/test/core/string/to_str_spec.rb +13 -0
  209. data/test/core/string/to_sym_spec.rb +9 -0
  210. data/test/core/string/upcase_spec.rb +6 -0
  211. data/test/core/symbol/to_proc_spec.rb +12 -0
  212. data/{core/spec → test}/core/true/and_spec.rb +0 -0
  213. data/{core/spec → test}/core/true/inspect_spec.rb +0 -0
  214. data/{core/spec → test}/core/true/or_spec.rb +0 -0
  215. data/{core/spec → test}/core/true/to_s_spec.rb +0 -0
  216. data/{core/spec → test}/core/true/xor_spec.rb +0 -0
  217. data/test/index.html +11 -0
  218. data/{core/spec → test}/language/alias_spec.rb +4 -0
  219. data/{core/spec → test}/language/and_spec.rb +0 -0
  220. data/{core/spec → test}/language/array_spec.rb +0 -0
  221. data/{core/spec → test}/language/block_spec.rb +0 -0
  222. data/{core/spec → test}/language/break_spec.rb +0 -0
  223. data/{core/spec → test}/language/case_spec.rb +0 -0
  224. data/{core/spec → test}/language/defined_spec.rb +0 -0
  225. data/{core/spec → test}/language/ensure_spec.rb +0 -0
  226. data/test/language/fixtures/yield.rb +23 -0
  227. data/{core/spec → test}/language/hash_spec.rb +0 -0
  228. data/{core/spec → test}/language/if_spec.rb +0 -0
  229. data/test/language/literal_lambda_spec.rb +47 -0
  230. data/{core/spec → test}/language/loop_spec.rb +0 -0
  231. data/{core/spec → test}/language/metaclass_spec.rb +0 -0
  232. data/{core/spec → test}/language/next_spec.rb +0 -0
  233. data/{core/spec → test}/language/or_spec.rb +0 -0
  234. data/{core/spec → test}/language/predefined_spec.rb +0 -0
  235. data/{core/spec → test}/language/regexp_spec.rb +0 -0
  236. data/{core/spec → test}/language/send_spec.rb +0 -0
  237. data/{core/spec → test}/language/singleton_class_spec.rb +0 -0
  238. data/{core/spec → test}/language/super_spec.rb +0 -0
  239. data/{core/spec → test}/language/symbol_spec.rb +0 -0
  240. data/{core/spec → test}/language/undef_spec.rb +0 -0
  241. data/{core/spec → test}/language/unless_spec.rb +0 -0
  242. data/{core/spec → test}/language/until_spec.rb +0 -0
  243. data/{core/spec → test}/language/variables_spec.rb +0 -0
  244. data/{core/spec → test}/language/while_spec.rb +0 -0
  245. data/test/language/yield_spec.rb +100 -0
  246. data/test/opal/array/subclassing_spec.rb +32 -0
  247. data/test/opal/class/bridge_class_spec.rb +37 -0
  248. data/test/opal/exception/subclassing_spec.rb +17 -0
  249. data/test/opal/runtime/_methods_spec.rb +48 -0
  250. data/test/opal/runtime/class_hierarchy_spec.rb +22 -0
  251. data/test/opal/runtime/def_spec.rb +23 -0
  252. data/test/opal/string/subclassing_spec.rb +26 -0
  253. data/test/spec_helper.rb +3 -0
  254. metadata +437 -111
  255. data/core/spec/core/class/new_spec.rb +0 -16
  256. data/core/spec/core/hash/default_spec.rb +0 -4
  257. data/core/spec/core/symbol/to_proc_spec.rb +0 -6
  258. data/core/spec/index.html +0 -11
  259. data/spec/builder/build_source_spec.rb +0 -52
data/.gitignore CHANGED
@@ -9,6 +9,6 @@ Gemfile.lock
9
9
  pkg/*
10
10
  /runtime/*.js
11
11
  /*.js
12
- /gh-pages
12
+ /docs/gh-pages
13
13
  /examples/**/*.js
14
14
  /build
data/Gemfile CHANGED
@@ -6,7 +6,5 @@ gem "rake"
6
6
  # gem "racc"
7
7
 
8
8
  group :browser do
9
- gem "opal-racc"
10
- gem "opal-spec"
11
- gem "opal-strscan"
9
+ gem "opal-spec", "0.1.6"
12
10
  end
data/README.md CHANGED
@@ -1,25 +1,487 @@
1
1
  # Opal
2
2
 
3
- Opal is a ruby to javascript compiler and runtime for the browser.
3
+ **Opal is a ruby to javascript compiler.** Opal aims to take ruby files
4
+ and generate efficient javascript that maintains rubys features. Opal
5
+ will, by default, generate fast and efficient code in preference to
6
+ keeping all ruby features.
4
7
 
5
- For docs, visit the website [http://opalrb.org](http://opalrb.org), or visit the [github wiki](http://github.com/adambeynon/opal/wiki).
8
+ Opal comes with an implementation of the ruby corelib, written in ruby,
9
+ that uses a bundled runtime (written in javascript) that tie all the
10
+ features together. Whenever possible Opal bridges to native javascript
11
+ features under the hood. The Opal gem includes the compiler used to
12
+ convert ruby sources into javascript.
6
13
 
7
- There is also a [Google group for opal](https://groups.google.com/forum/#!forum/opalrb), or join the IRC channel on Freenode: `#opal`.
14
+ Opal is [hosted on github](http://github.com/adambeynon/opal), and there
15
+ is a Freenode IRC channel at `#opal`.
8
16
 
9
- ## Installation And Usage
17
+ ## Downloads
10
18
 
11
- Install via rubygems:
19
+ The Opal runtime and corelib are distributed here, and are required to
20
+ run any code generated by opal.
21
+
22
+ [Opal version 0.3.19](http://opalrb.org/opal.js) _(14.9kb Minified And Gzipped)_
23
+
24
+ ## Installation
25
+
26
+ Opal comes distributed as a gem, so either install with:
12
27
 
13
28
  gem install opal
14
29
 
15
- Or using Bundler:
30
+ Or add to your Gemfile:
31
+
32
+ ```ruby
33
+ gem "opal"
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ To quickly compile ruby code into javascript, use the `Opal.parse()`
39
+ method which returns a string of javascript code:
40
+
41
+ ```ruby
42
+ require 'opal'
43
+
44
+ Opal.parse("[1, 2, 3, 4].each { |a| puts a }")
45
+ ```
46
+
47
+ This will return a string of javascript similar to the following:
48
+
49
+ ```javascript
50
+ (function() {
51
+ // compiled ruby
52
+ }).call(Opal.top);
53
+ ```
54
+
55
+ This can then be written to a file and run in any browser.
56
+
57
+ ### Creating a rake task
58
+
59
+ Using a Rakefile makes it simple to build your application code.
60
+ Assuming your code is in a file `app.rb`, add a rake task:
61
+
62
+ ```ruby
63
+ # Rakefile
64
+
65
+ require 'opal'
66
+
67
+ desc "Build opal application"
68
+ task :build do
69
+ src = File.read 'app.rb'
70
+ js = Opal.parse src
71
+
72
+ File.open('app.js', 'w+') do |out|
73
+ out.write js
74
+ end
75
+ end
76
+ ```
77
+
78
+ Running `rake build` will then read your app code, compile it and then
79
+ write it out to a file ready to load in a web browser.
80
+
81
+ ### Setting up html file
82
+
83
+ The generated `app.js` file can just be added into any HTML page. The
84
+ opal runtime needs to be loaded first (you can download that above).
85
+
86
+ ```html
87
+ <!doctype html>
88
+ <html>
89
+ <head>
90
+ <title>Test Opal App</title>
91
+ </head>
92
+ <body>
93
+ <script src="opal.js"></script>
94
+ <script src="app.js"></script>
95
+ </body>
96
+ </html>
97
+ ```
98
+
99
+ When using `Opal.parse()` as above, the generated code will be run
100
+ as soon as the page loads. Open the browsers console and you should
101
+ see the 4 numbers printed to the console.
102
+
103
+ ## Builder and Dependency Builder
104
+
105
+ The previous example was useful for building very simple apps using
106
+ opal. For more complex apps with dependencies, Opal provides useful
107
+ rake tasks to get started. Assuming opal is in your lib path, create
108
+ a `Rakefile` similar to:
109
+
110
+ ```ruby
111
+ # Rakefile
112
+
113
+ require 'opal'
114
+
115
+ Opal::BuilderTask.new do |t|
116
+ t.name = 'my-first-app'
117
+ t.dependencies = ['opal-json']
118
+ t.files = ['app.rb']
119
+ end
120
+ ```
121
+
122
+ This simple rake task is all you need to build an app with its
123
+ dependencies.
124
+
125
+ ### Building dependencies
126
+
127
+ To build the opal runtime `opal.js`, as well as `opal-json` into
128
+ `build/`, run the simple rake task:
129
+
130
+ ```ruby
131
+ rake dependencies
132
+ ```
133
+
134
+ This will try and find the `opal-json` gem installed, so either
135
+ install globally with `gem install opal-json`, or add it to your
136
+ Gemfile as `gem "opal-json"` and run `bundle install`.
137
+
138
+ ### Building app
139
+
140
+ To build the listed files into your application, run:
141
+
142
+ ```ruby
143
+ rake build
144
+ ```
145
+
146
+ This will build to `/build/my-first-app.js`. To customize the output
147
+ filename, change the `name` property in the raketask.
148
+
149
+ ### Running the app
150
+
151
+ You should now be able to run the built app using a standard HTML page.
152
+
153
+ ```html
154
+ <!doctype html>
155
+ <html>
156
+ <head>
157
+ <title>Test Opal App</title>
158
+ </head>
159
+ <body>
160
+ <script src="build/opal.js"></script>
161
+ <script src="build/opal-json.js"></script>
162
+ <script src="build/my-first-app.js"></script>
163
+ </body>
164
+ </html>
165
+ ```
166
+
167
+ ### Main file
168
+
169
+ When using the `BuilderTask`, the files generated will not be run
170
+ automatically on page load. The files are registered so they can be
171
+ loaded using `require()`. Builder is clever enough though that it will,
172
+ by default, automatically require the first file in the app to be
173
+ loaded. This will appear at the bottom of `my-first-app.js`:
174
+
175
+ ```javascript
176
+ Opal.define('app', function() {
177
+ // app.rb code
178
+ });
179
+
180
+ Opal.require('app');
181
+ ```
182
+
183
+ ## Features And Implementation
184
+
185
+ Opal is a source-to-source compiler, so there is no VM as such and the
186
+ compiled code aims to be as fast and efficient as possible, mapping
187
+ directly to underlying javascript features and objects where possible.
188
+
189
+ ### Literals
190
+
191
+ **self** is always compiled to `this`. Any context inside the generated
192
+ code is usually a function body; whether it be a method body, a block,
193
+ a class/module body or the file itself.
194
+
195
+ **true** and **false** are compiled directly into their native boolean
196
+ equivalents. This makes interaction a lot easier as there is no need
197
+ to convert values to opal specific values. It does mean that there is
198
+ only a `Boolean` ruby class available, not seperate `TrueClass` and
199
+ `FalseClass` classes.
200
+
201
+ **nil** is compiled into a `nil` reference, which inside all generated
202
+ files points to a special object which is just an instance of the ruby
203
+ `NilClass` class. This object is available externally to javascript as
204
+ `Opal.nil`.
205
+
206
+ ```ruby
207
+ nil # => nil
208
+ true # => true
209
+ false # => false
210
+ self # => this
211
+ ```
212
+
213
+ #### Strings
214
+
215
+ Ruby strings are compiled directly into javascript strings for
216
+ performance as well as readability. This has the side effect that Opal
217
+ does not support mutable strings - i.e. all strings are immutable.
218
+
219
+ #### Symbols
220
+
221
+ For performance reasons, symbols compile directly into strings. Opal
222
+ supports all the symbol syntaxes, but does not have a real `Symbol`
223
+ class. Symbols and Strings can therefore be used interchangeably.
224
+
225
+ ```ruby
226
+ "hello world!" # => "hello world!"
227
+ :foo # => "foo"
228
+ <<-EOS # => "\nHello there.\n"
229
+ Hello there.
230
+ EOS
231
+ ```
232
+
233
+ #### Numbers
234
+
235
+ In Opal there is a single class for numbers; `Numeric`. To keep opal
236
+ as performant as possible, ruby numbers are mapped to native numbers.
237
+ This has the side effect that all numbers must be of the same class.
238
+ Most relevant methods from `Integer`, `Float` and `Numeric` are
239
+ implemented on this class.
240
+
241
+ ```ruby
242
+ 42 # => 42
243
+ 3.142 # => 3.142
244
+ ```
245
+
246
+ #### Arrays
247
+
248
+ Ruby arrays are compiled directly into javascript arrays. Special
249
+ ruby syntaxes for word arrays etc are also supported.
250
+
251
+ ```ruby
252
+ [1, 2, 3, 4] # => [1, 2, 3, 4]
253
+ %w[foo bar baz] # => ["foo", "bar", "baz"]
254
+ ```
16
255
 
17
- gem "opal"
256
+ #### Hash
18
257
 
19
- Ruby scripts can be compiled using:
258
+ Inside a generated ruby script, a function `__hash` is available which
259
+ creates a new hash. This is also available in javascript as `Opal.hash`
260
+ and simply returns a new instance of the `Hash` class.
20
261
 
21
- opal -c foo.rb -o foo.js
262
+ ```ruby
263
+ { :foo => 100, :baz => 700 } # => __hash("foo", 100, "baz", 700)
264
+ { foo: 42, bar: [1, 2, 3] } # => __hash("foo", 42, "bar", [1, 2, 3])
265
+ ```
266
+
267
+ #### Range
268
+
269
+ Similar to hash, there is a function `__range` available to create
270
+ range instances.
271
+
272
+ ```ruby
273
+ 1..4 # => __range(1, 4, true)
274
+ 3...7 # => __range(3, 7, false)
275
+ ```
276
+
277
+ ### Methods
278
+
279
+ A ruby method is just compiled directly into a function definition.
280
+ These functions are added to the constructor's prototype so they can
281
+ be called just like any javascript function. All ruby methods are
282
+ defined with a `$` prefix to try and isolate them from javascript
283
+ methods.
284
+
285
+ #### Method Calls
286
+
287
+ All method arguments are passed to the native function just like normal
288
+ javascript function calls. Therefore, the given ruby code:
289
+
290
+ ```ruby
291
+ do_something 1, 2, 3
292
+ self.length
293
+ [1, 2, 3].push 5
294
+ ```
295
+
296
+ Will be compiled into the easy to read javascript:
297
+
298
+ ```javascript
299
+ this.$do_something(1, 2, 3);
300
+ this.$length();
301
+ [1, 2, 3].$push(5);
302
+ ```
303
+
304
+ There are some certain characters which are valid as ruby method names
305
+ but not as javascript identifiers. These method calls are encoded to
306
+ keep the generated method names sane.
307
+
308
+ ```ruby
309
+ self.loaded? # => this.$loaded$p()
310
+ self.load! # => this.$load$b()
311
+ self.loaded = true # => this.$loaded$e(true)
312
+ self << :bar # => this.$lshift$("bar")
313
+ ```
314
+
315
+ Finally, method calls with splat arguments are also supported:
316
+
317
+ ```ruby
318
+ self.push *[1, 2, 3]
319
+ # => this.$push.apply(this, [1, 2, 3])
320
+ ```
321
+
322
+ #### Optimized Math Operators
323
+
324
+ In ruby, all math operators are method calls, but compiling this into
325
+ javascript would end up being too slow. For this reason, math
326
+ operators are optimized to test first if the receiver is a number, and
327
+ if so then to just carry out the math call.
328
+
329
+ ```ruby
330
+ 3 + 4
331
+ ```
332
+
333
+ This ruby code will then be compiled into the following javascript:
334
+
335
+ ```javascript
336
+ (a = 3, b = 4, typeof(a) === "number" ? a + b : a.$plus(b))
337
+ ```
338
+
339
+ This ternary statement falls back on sending a method to the receiver
340
+ so all non-numeric receivers will still have the normal method call
341
+ being sent. This optimization makes math operators a **lot faster**.
342
+ Currently, the optimized method calls are `+`, `-`, `*` and `/`.
343
+
344
+ #### Method Definitions
345
+
346
+ Methods are implemented as regular javascript functions. Assuming the
347
+ following method is defined inside a class body:
348
+
349
+ ```ruby
350
+ def to_s
351
+ inspect
352
+ end
353
+ ```
354
+
355
+ This would generate the following javascript. (`def.` is a local
356
+ variable set to be the class's instance prototype. It is used
357
+ for minimization of code as well as trying to be readable).
358
+
359
+ ```javascript
360
+ def.$to_s = function() {
361
+ return this.$inspect();
362
+ };
363
+ ```
364
+
365
+ The defined name retains the `$` prefix outlined above, and the `self`
366
+ value for the method is `this`, which will be the receiver.
367
+
368
+ Normal arguments, splat args and optional args are all supported:
369
+
370
+ ```ruby
371
+ def norm(a, b, c)
372
+
373
+ end
374
+
375
+ def opt(a, b = 100)
376
+
377
+ end
378
+
379
+ def rest(a, *b)
380
+
381
+ end
382
+ ```
383
+
384
+ The generated code reads as expected:
385
+
386
+ ```javascript
387
+ def.$norm = function(a, b, c) {
388
+ return nil;
389
+ };
390
+
391
+ def.$opt = function(a, b) {
392
+ if (b == null) b = 100;
393
+ return nil;
394
+ };
395
+
396
+ def.$rest = function(a, b) {
397
+ b = __slice.call(arguments, 1);
398
+ return nil;
399
+ };
400
+ ```
401
+
402
+ Currently, in opal there is no argument length checking to ensure that
403
+ the correct number of arguments get passed to a function. This can be
404
+ enabled in debug mode, but is not included in production builds as it
405
+ adds a lot of overhead to **every** method call.
406
+
407
+ ### Compiled Files
408
+
409
+ As described above, a compiled ruby source gets generated into a string
410
+ of javascript code that is wrapped inside an anonymous function. This
411
+ looks similar to the following:
412
+
413
+ ```javascript
414
+ (function(undefined) {
415
+ var nil = Opal.nil, __slice = Opal.slice, __klass = Opal.klass;
416
+ // generated code
417
+ }).call(Opal.top);
418
+ ```
419
+
420
+ This function gets called with `Opal.top` as the context, which is the
421
+ top level object available to ruby (`main`). Inside the function, `nil`
422
+ is assigned to ensure a local copy is available, as well as all the
423
+ helper methods used within the generated file. There is no return value
424
+ from these functions as they are not used anywhere.
425
+
426
+ As a complete example, assuming the following code:
427
+
428
+ ```ruby
429
+ puts "foo"
430
+ ```
431
+
432
+ This would compile directly into:
433
+
434
+ ```javascript
435
+ (function(undefined) {
436
+ var nil = Opal.nil;
437
+ this.$puts("foo");
438
+ }).call(Opal.top);
439
+ ```
440
+
441
+ Most of the helpers are no longer present as they are not used in this
442
+ example.
443
+
444
+ ### Using compiled sources
445
+
446
+ If you write the generated code as above into a file `app.js` and add
447
+ that to your HTML page, then it is obvious that `"foo"` would be
448
+ written to the browser's console.
22
449
 
23
450
  ## License
24
451
 
25
- Opal is released under the MIT license.
452
+ Opal is released under the MIT license.
453
+
454
+ ## Change Log
455
+
456
+ **0.3.19** _(30 May 2012)_
457
+
458
+ * Add BasicObject as the root class
459
+ * Add `Opal.define` and `Opal.require` for requiring files
460
+ * Builder uses a `main` option to dictate which file to require on load
461
+ * Completely revamp runtime to reduce helper methods
462
+ * Allow native bridges (Array, String, etc) to be subclassed
463
+ * Make sure `.js` files can be built with `Opal::Builder`
464
+ * Include the current file name when raising parse errors
465
+
466
+ **0.3.18** _(20 May 2012)_
467
+
468
+ * Fix various core lib bugs
469
+ * Completely remove `require` from corelib
470
+ * Improve Builder to detect dependencies in files
471
+
472
+ **0.3.17** _(19 May 2012)_
473
+
474
+ * Revamp of Builder and Parser tools
475
+ * Remove opal-repl
476
+ * Added a lot of specs for core lib
477
+
478
+ **0.3.16** _(15 January 2012)_
479
+
480
+ * Added HEREDOCS support in parser
481
+ * Parser now handles masgn (mass/multi assignments)
482
+ * More useful DependencyBuilder class to build gems dependencies
483
+ * Blocks no longer passed as an argument in method calls
484
+
485
+ **0.3.15**
486
+
487
+ * Initial Release.