opal 0.3.18 → 0.3.19

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