opal 0.3.21 → 0.3.22

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 (297) hide show
  1. data/.travis.yml +1 -4
  2. data/Gemfile +9 -4
  3. data/README.md +10 -589
  4. data/Rakefile +51 -19
  5. data/config.ru +17 -0
  6. data/core/array.rb +42 -34
  7. data/core/basic_object.rb +4 -4
  8. data/core/browser.js +31 -0
  9. data/core/class.rb +7 -7
  10. data/core/enumerable.rb +65 -69
  11. data/core/erb.rb +30 -0
  12. data/core/error.rb +2 -3
  13. data/core/hash.rb +47 -18
  14. data/core/kernel.rb +15 -16
  15. data/core/load_order +2 -1
  16. data/core/module.rb +19 -37
  17. data/core/numeric.rb +4 -2
  18. data/core/object.rb +4 -0
  19. data/core/proc.rb +6 -3
  20. data/core/racc.rb +215 -0
  21. data/core/regexp.rb +16 -21
  22. data/core/runtime.js +141 -153
  23. data/core/string.rb +41 -19
  24. data/core/strscan.rb +61 -0
  25. data/core/time.rb +1 -5
  26. data/docs/index.md +616 -0
  27. data/docs/post.html +2 -8
  28. data/docs/pre.html +29 -26
  29. data/docs/try.html +52 -0
  30. data/lib/opal.rb +33 -3
  31. data/lib/opal/builder.rb +14 -34
  32. data/lib/opal/erb_parser.rb +19 -0
  33. data/lib/opal/grammar.rb +7 -3
  34. data/lib/opal/grammar.y +3 -0
  35. data/lib/opal/lexer.rb +16 -8
  36. data/lib/opal/parser.rb +156 -119
  37. data/lib/opal/rake_task.rb +2 -2
  38. data/lib/opal/scope.rb +9 -10
  39. data/lib/opal/version.rb +1 -1
  40. data/{test → spec}/core/array/allocate_spec.rb +0 -0
  41. data/{test → spec}/core/array/append_spec.rb +0 -0
  42. data/{test → spec}/core/array/assoc_spec.rb +0 -0
  43. data/{test → spec}/core/array/at_spec.rb +0 -0
  44. data/{test → spec}/core/array/clear_spec.rb +0 -0
  45. data/{test → spec}/core/array/clone_spec.rb +0 -0
  46. data/{test → spec}/core/array/collect_spec.rb +0 -0
  47. data/{test → spec}/core/array/compact_spec.rb +0 -0
  48. data/{test → spec}/core/array/concat_spec.rb +0 -0
  49. data/{test → spec}/core/array/constructor_spec.rb +0 -0
  50. data/{test → spec}/core/array/count_spec.rb +0 -0
  51. data/{test → spec}/core/array/delete_at_spec.rb +0 -0
  52. data/{test → spec}/core/array/delete_if_spec.rb +0 -0
  53. data/{test → spec}/core/array/delete_spec.rb +0 -0
  54. data/{test → spec}/core/array/each_index_spec.rb +0 -0
  55. data/{test → spec}/core/array/each_spec.rb +0 -0
  56. data/{test → spec}/core/array/element_reference_spec.rb +0 -0
  57. data/{test → spec}/core/array/empty_spec.rb +0 -0
  58. data/{test → spec}/core/array/eql_spec.rb +0 -0
  59. data/{test → spec}/core/array/fetch_spec.rb +0 -0
  60. data/{test → spec}/core/array/first_spec.rb +0 -0
  61. data/{test → spec}/core/array/flatten_spec.rb +0 -0
  62. data/{test → spec}/core/array/include_spec.rb +0 -0
  63. data/{test → spec}/core/array/insert_spec.rb +0 -0
  64. data/{test → spec}/core/array/last_spec.rb +0 -0
  65. data/{test → spec}/core/array/length_spec.rb +0 -0
  66. data/{test → spec}/core/array/map_spec.rb +0 -0
  67. data/{test → spec}/core/array/minus_spec.rb +0 -0
  68. data/{test → spec}/core/array/plus_spec.rb +0 -0
  69. data/{test → spec}/core/array/pop_spec.rb +0 -0
  70. data/{test → spec}/core/array/push_spec.rb +0 -0
  71. data/{test → spec}/core/array/rassoc_spec.rb +0 -0
  72. data/{test → spec}/core/array/reject_spec.rb +0 -0
  73. data/{test → spec}/core/array/replace_spec.rb +0 -0
  74. data/{test → spec}/core/array/reverse_each_spec.rb +0 -0
  75. data/{test → spec}/core/array/reverse_spec.rb +0 -0
  76. data/{test → spec}/core/array/size_spec.rb +0 -0
  77. data/{test → spec}/core/array/to_ary_spec.rb +0 -0
  78. data/{test → spec}/core/array/uniq_spec.rb +0 -0
  79. data/{test → spec}/core/array/zip_spec.rb +0 -0
  80. data/{test → spec}/core/class/fixtures/classes.rb +0 -0
  81. data/{test → spec}/core/class/new_spec.rb +3 -0
  82. data/{test → spec}/core/enumerable/all_spec.rb +3 -0
  83. data/{test → spec}/core/enumerable/any_spec.rb +0 -0
  84. data/{test → spec}/core/enumerable/collect_spec.rb +0 -0
  85. data/{test → spec}/core/enumerable/count_spec.rb +0 -0
  86. data/{test → spec}/core/enumerable/detect_spec.rb +0 -0
  87. data/{test → spec}/core/enumerable/drop_spec.rb +0 -0
  88. data/{test → spec}/core/enumerable/drop_while_spec.rb +0 -0
  89. data/{test → spec}/core/enumerable/each_with_index_spec.rb +0 -0
  90. data/{test → spec}/core/enumerable/each_with_object_spec.rb +0 -0
  91. data/{test → spec}/core/enumerable/entries_spec.rb +0 -0
  92. data/{test → spec}/core/enumerable/find_all_spec.rb +0 -0
  93. data/{test → spec}/core/enumerable/find_index_spec.rb +0 -0
  94. data/{test → spec}/core/enumerable/find_spec.rb +0 -0
  95. data/{test → spec}/core/enumerable/first_spec.rb +0 -0
  96. data/{test → spec}/core/enumerable/fixtures/classes.rb +0 -0
  97. data/{test → spec}/core/enumerable/grep_spec.rb +0 -0
  98. data/{test → spec}/core/enumerable/take_spec.rb +0 -0
  99. data/{test → spec}/core/enumerable/to_a_spec.rb +0 -0
  100. data/{test → spec}/core/false/and_spec.rb +0 -0
  101. data/{test → spec}/core/false/inspect_spec.rb +0 -0
  102. data/{test → spec}/core/false/or_spec.rb +0 -0
  103. data/{test → spec}/core/false/to_s_spec.rb +0 -0
  104. data/{test → spec}/core/false/xor_spec.rb +0 -0
  105. data/{test → spec}/core/hash/allocate_spec.rb +0 -0
  106. data/{test → spec}/core/hash/assoc_spec.rb +0 -0
  107. data/{test → spec}/core/hash/clear_spec.rb +0 -0
  108. data/{test → spec}/core/hash/clone_spec.rb +0 -0
  109. data/{test → spec}/core/hash/default_spec.rb +0 -0
  110. data/{test → spec}/core/hash/delete_if_spec.rb +0 -0
  111. data/{test → spec}/core/hash/each_key_spec.rb +0 -0
  112. data/{test → spec}/core/hash/each_pair_spec.rb +0 -0
  113. data/{test → spec}/core/hash/each_spec.rb +0 -0
  114. data/{test → spec}/core/hash/each_value_spec.rb +0 -0
  115. data/{test → spec}/core/hash/element_reference_spec.rb +14 -1
  116. data/{test → spec}/core/hash/element_set_spec.rb +0 -0
  117. data/{test → spec}/core/hash/empty_spec.rb +0 -0
  118. data/{test → spec}/core/hash/fetch_spec.rb +0 -0
  119. data/{test → spec}/core/hash/flatten_spec.rb +0 -0
  120. data/{test → spec}/core/hash/has_key_spec.rb +0 -0
  121. data/{test → spec}/core/hash/has_value_spec.rb +0 -0
  122. data/{test → spec}/core/hash/include_spec.rb +0 -0
  123. data/{test → spec}/core/hash/index_spec.rb +0 -0
  124. data/{test → spec}/core/hash/indexes_spec.rb +0 -0
  125. data/{test → spec}/core/hash/indices_spec.rb +0 -0
  126. data/{test → spec}/core/hash/invert_spec.rb +0 -0
  127. data/{test → spec}/core/hash/keep_if_spec.rb +0 -0
  128. data/{test → spec}/core/hash/key_spec.rb +0 -0
  129. data/{test → spec}/core/hash/keys_spec.rb +0 -0
  130. data/{test → spec}/core/hash/length_spec.rb +0 -0
  131. data/{test → spec}/core/hash/member_spec.rb +0 -0
  132. data/{test → spec}/core/hash/merge_spec.rb +0 -0
  133. data/{test → spec}/core/hash/new_spec.rb +8 -0
  134. data/{test → spec}/core/hash/rassoc_spec.rb +0 -0
  135. data/{test → spec}/core/hash/replace_spec.rb +0 -0
  136. data/{test → spec}/core/hash/select_spec.rb +0 -0
  137. data/{test → spec}/core/hash/shift_spec.rb +0 -0
  138. data/{test → spec}/core/hash/size_spec.rb +0 -0
  139. data/{test → spec}/core/hash/update_spec.rb +0 -0
  140. data/{test → spec}/core/hash/value_spec.rb +0 -0
  141. data/{test → spec}/core/hash/values_at_spec.rb +0 -0
  142. data/{test → spec}/core/hash/values_spec.rb +0 -0
  143. data/{test → spec}/core/kernel/define_singleton_method_spec.rb +0 -0
  144. data/{test → spec}/core/kernel/eql_spec.rb +0 -0
  145. data/{test → spec}/core/kernel/equal_value_spec.rb +0 -0
  146. data/{test → spec}/core/kernel/loop_spec.rb +0 -0
  147. data/{test → spec}/core/kernel/nil_spec.rb +0 -0
  148. data/{test → spec}/core/kernel/proc_spec.rb +4 -0
  149. data/{test → spec}/core/kernel/rand_spec.rb +0 -0
  150. data/{test → spec}/core/kernel/respond_to_spec.rb +0 -0
  151. data/{test → spec}/core/kernel/send_spec.rb +0 -0
  152. data/{test → spec}/core/kernel/tap_spec.rb +0 -0
  153. data/{test → spec}/core/kernel/to_s_spec.rb +0 -0
  154. data/{test → spec}/core/matchdata/to_a_spec.rb +0 -0
  155. data/{test → spec}/core/nil/and_spec.rb +0 -0
  156. data/{test → spec}/core/nil/inspect_spec.rb +0 -0
  157. data/{test → spec}/core/nil/nil_spec.rb +0 -0
  158. data/{test → spec}/core/nil/or_spec.rb +0 -0
  159. data/{test → spec}/core/nil/to_a_spec.rb +0 -0
  160. data/{test → spec}/core/nil/to_f_spec.rb +0 -0
  161. data/{test → spec}/core/nil/to_i_spec.rb +0 -0
  162. data/{test → spec}/core/nil/to_s_spec.rb +0 -0
  163. data/{test → spec}/core/nil/xor_spec.rb +0 -0
  164. data/{test → spec}/core/numeric/equal_value_spec.rb +0 -0
  165. data/spec/core/proc/proc_tricks_spec.rb +7 -0
  166. data/{test → spec}/core/range/begin_spec.rb +0 -0
  167. data/{test → spec}/core/range/case_compare_spec.rb +0 -0
  168. data/{test → spec}/core/range/end_spec.rb +0 -0
  169. data/{test → spec}/core/regexp/match_spec.rb +0 -0
  170. data/{test → spec}/core/string/capitalize_spec.rb +0 -0
  171. data/{test → spec}/core/string/casecmp_spec.rb +0 -0
  172. data/{test → spec}/core/string/chomp_spec.rb +0 -0
  173. data/{test → spec}/core/string/chop_spec.rb +0 -0
  174. data/{test → spec}/core/string/chr_spec.rb +0 -0
  175. data/{test → spec}/core/string/comparison_spec.rb +0 -0
  176. data/{test → spec}/core/string/downcase_spec.rb +0 -0
  177. data/{test → spec}/core/string/element_reference_spec.rb +14 -2
  178. data/{test → spec}/core/string/empty_spec.rb +0 -0
  179. data/{test → spec}/core/string/end_with_spec.rb +0 -0
  180. data/{test → spec}/core/string/fixtures/classes.rb +0 -0
  181. data/{test → spec}/core/string/gsub_spec.rb +0 -0
  182. data/{test → spec}/core/string/include_spec.rb +0 -0
  183. data/{test → spec}/core/string/intern_spec.rb +0 -0
  184. data/{test → spec}/core/string/length_spec.rb +0 -0
  185. data/{test → spec}/core/string/lstrip_spec.rb +0 -0
  186. data/{test → spec}/core/string/match_spec.rb +0 -0
  187. data/{test → spec}/core/string/next_spec.rb +0 -0
  188. data/{test → spec}/core/string/ord_spec.rb +0 -0
  189. data/{test → spec}/core/string/partition_spec.rb +0 -0
  190. data/{test → spec}/core/string/reverse_spec.rb +0 -0
  191. data/{test → spec}/core/string/rstrip_spec.rb +0 -0
  192. data/{test → spec}/core/string/size_spec.rb +0 -0
  193. data/{test → spec}/core/string/slice_spec.rb +4 -1
  194. data/{test → spec}/core/string/split_spec.rb +0 -0
  195. data/{test → spec}/core/string/start_with_spec.rb +0 -0
  196. data/{test → spec}/core/string/strip_spec.rb +0 -0
  197. data/{test → spec}/core/string/sub_spec.rb +0 -0
  198. data/{test → spec}/core/string/succ_spec.rb +0 -0
  199. data/{test → spec}/core/string/sum_spec.rb +0 -0
  200. data/{test → spec}/core/string/swapcase_spec.rb +0 -0
  201. data/{test → spec}/core/string/to_a_spec.rb +0 -0
  202. data/{test → spec}/core/string/to_f_spec.rb +0 -0
  203. data/{test → spec}/core/string/to_i_spec.rb +0 -0
  204. data/{test → spec}/core/string/to_s_spec.rb +0 -0
  205. data/{test → spec}/core/string/to_str_spec.rb +0 -0
  206. data/{test → spec}/core/string/to_sym_spec.rb +0 -0
  207. data/{test → spec}/core/string/upcase_spec.rb +0 -0
  208. data/{test → spec}/core/symbol/to_proc_spec.rb +0 -0
  209. data/{test → spec}/core/time/at_spec.rb +0 -0
  210. data/{test → spec}/core/time/day_spec.rb +0 -0
  211. data/{test → spec}/core/time/friday_spec.rb +0 -0
  212. data/{test → spec}/core/time/hour_spec.rb +0 -0
  213. data/{test → spec}/core/time/min_spec.rb +0 -0
  214. data/{test → spec}/core/time/monday_spec.rb +0 -0
  215. data/{test → spec}/core/time/month_spec.rb +0 -0
  216. data/{test → spec}/core/time/now_spec.rb +0 -0
  217. data/{test → spec}/core/time/saturday_spec.rb +0 -0
  218. data/{test → spec}/core/true/and_spec.rb +0 -0
  219. data/{test → spec}/core/true/inspect_spec.rb +0 -0
  220. data/{test → spec}/core/true/or_spec.rb +0 -0
  221. data/{test → spec}/core/true/to_s_spec.rb +0 -0
  222. data/{test → spec}/core/true/xor_spec.rb +0 -0
  223. data/spec/grammar/lvar_spec.rb +2 -1
  224. data/spec/grammar/str_spec.rb +1 -1
  225. data/spec/grammar/xstr_spec.rb +1 -1
  226. data/{test → spec}/index.html +3 -3
  227. data/{test → spec}/language/alias_spec.rb +0 -0
  228. data/{test → spec}/language/and_spec.rb +0 -0
  229. data/{test → spec}/language/array_spec.rb +0 -0
  230. data/{test → spec}/language/block_spec.rb +0 -0
  231. data/{test → spec}/language/break_spec.rb +0 -0
  232. data/{test → spec}/language/case_spec.rb +0 -0
  233. data/{test → spec}/language/defined_spec.rb +0 -0
  234. data/{test → spec}/language/ensure_spec.rb +2 -2
  235. data/{test → spec}/language/fixtures/next.rb +0 -0
  236. data/{test → spec}/language/fixtures/yield.rb +0 -0
  237. data/{test → spec}/language/hash_spec.rb +0 -0
  238. data/{test → spec}/language/if_spec.rb +0 -0
  239. data/{test → spec}/language/literal_lambda_spec.rb +0 -0
  240. data/{test → spec}/language/loop_spec.rb +0 -0
  241. data/{test → spec}/language/metaclass_spec.rb +0 -0
  242. data/{test → spec}/language/next_spec.rb +2 -0
  243. data/{test → spec}/language/or_spec.rb +0 -0
  244. data/{test → spec}/language/predefined_spec.rb +0 -0
  245. data/{test → spec}/language/regexp_spec.rb +0 -0
  246. data/{test → spec}/language/send_spec.rb +0 -0
  247. data/{test → spec}/language/singleton_class_spec.rb +0 -0
  248. data/{test → spec}/language/super_spec.rb +0 -0
  249. data/{test → spec}/language/symbol_spec.rb +0 -0
  250. data/{test → spec}/language/undef_spec.rb +0 -0
  251. data/{test → spec}/language/unless_spec.rb +0 -0
  252. data/{test → spec}/language/until_spec.rb +0 -0
  253. data/{test → spec}/language/variables_spec.rb +0 -0
  254. data/{test → spec}/language/while_spec.rb +0 -0
  255. data/{test → spec}/language/yield_spec.rb +2 -0
  256. data/{test → spec}/opal/array/subclassing_spec.rb +0 -0
  257. data/{test → spec}/opal/array/to_json_spec.rb +0 -0
  258. data/{test → spec}/opal/boolean/singleton_class_spec.rb +0 -0
  259. data/{test → spec}/opal/boolean/to_json_spec.rb +0 -0
  260. data/{test → spec}/opal/class/bridge_class_spec.rb +0 -0
  261. data/spec/opal/erb/erb_spec.rb +15 -0
  262. data/{test → spec}/opal/exception/subclassing_spec.rb +0 -0
  263. data/{test → spec}/opal/hash/to_json_spec.rb +0 -0
  264. data/spec/opal/hash/to_native_spec.rb +5 -0
  265. data/{test → spec}/opal/json/parse_spec.rb +0 -0
  266. data/{test → spec}/opal/kernel/to_json_spec.rb +0 -0
  267. data/{test → spec}/opal/nil/to_json_spec.rb +0 -0
  268. data/{test → spec}/opal/numeric/to_json_spec.rb +0 -0
  269. data/{test → spec}/opal/runtime/call_spec.rb +0 -0
  270. data/{test → spec}/opal/runtime/class_hierarchy_spec.rb +0 -0
  271. data/{test → spec}/opal/runtime/def_spec.rb +0 -0
  272. data/{test → spec}/opal/runtime/defined_spec.rb +0 -0
  273. data/{test → spec}/opal/runtime/method_missing_spec.rb +3 -3
  274. data/{test → spec}/opal/runtime/super_spec.rb +0 -0
  275. data/{test → spec}/opal/string/subclassing_spec.rb +0 -0
  276. data/{test → spec}/opal/string/to_json_spec.rb +0 -0
  277. data/spec/opal/strscan/check_spec.rb +13 -0
  278. data/spec/opal/strscan/scan_spec.rb +33 -0
  279. data/spec/parser/simple_spec.rb +44 -0
  280. data/spec/spec_helper.rb +7 -7
  281. metadata +487 -497
  282. data/core/dir.rb +0 -89
  283. data/core/file.rb +0 -85
  284. data/spec/browser_spec.rb +0 -28
  285. data/spec/builder/fixtures/build_source/adam.rb +0 -0
  286. data/spec/builder/fixtures/build_source/bar/a.rb +0 -0
  287. data/spec/builder/fixtures/build_source/bar/wow/b.rb +0 -0
  288. data/spec/builder/fixtures/build_source/bar/wow/cow/c.rb +0 -0
  289. data/spec/builder/fixtures/build_source/beynon.rb +0 -0
  290. data/spec/builder/fixtures/build_source/charles.js +0 -0
  291. data/spec/builder/fixtures/build_source/foo/a.rb +0 -0
  292. data/spec/builder/fixtures/build_source/foo/b.rb +0 -0
  293. data/spec/builder/fixtures/build_source/foo/x.js +0 -0
  294. data/spec/builder/fixtures/build_source/foo/y.js +0 -0
  295. data/spec/builder/lib_name_for_spec.rb +0 -19
  296. data/test/index.min.html +0 -12
  297. data/test/spec_helper.rb +0 -4
data/core/string.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class String < `String`
2
- `String.prototype._isString = true`
2
+ `String_prototype._isString = true`
3
3
 
4
4
  include Comparable
5
5
 
@@ -11,15 +11,17 @@ class String < `String`
11
11
 
12
12
  def self.new(str = '')
13
13
  %x{
14
- var s = new String(#{str.to_s});
15
- s.$m = #{self}.$m_tbl;
16
- s.$k = #{self};
17
- return s;
14
+ return #{allocate str}
18
15
  }
19
16
  end
20
17
 
21
18
  def %(data)
22
- sprintf self, data
19
+ %x{
20
+ var idx = 0;
21
+ return #{self}.replace(/%((%)|s)/g, function (match) {
22
+ return match[2] || data[idx++] || '';
23
+ });
24
+ }
23
25
  end
24
26
 
25
27
  def *(count)
@@ -74,7 +76,7 @@ class String < `String`
74
76
  end
75
77
 
76
78
  def ==(other)
77
- `#{self} == other`
79
+ `other == String(#{self})`
78
80
  end
79
81
 
80
82
  alias === ==
@@ -92,20 +94,35 @@ class String < `String`
92
94
  # TODO: implement range based accessors
93
95
  def [](index, length)
94
96
  %x{
95
- if (length == null) {
96
- if (index < 0) {
97
- index += #{self}.length;
98
- }
97
+ var size = #{self}.length;
99
98
 
100
- if (index >= #{self}.length || index < 0) {
99
+ if (index._isRange) {
100
+ var exclude = index.exclude,
101
+ length = index.end,
102
+ index = index.begin;
103
+
104
+ if (index > size) {
101
105
  return nil;
102
106
  }
103
107
 
104
- return #{self}.substr(index, 1);
108
+ if (length < 0) {
109
+ length += size;
110
+ }
111
+
112
+ if (exclude) length -= 1;
113
+ return #{self}.substr(index, length);
105
114
  }
106
115
 
107
116
  if (index < 0) {
108
- index += #{self}.length + 1;
117
+ index += #{self}.length;
118
+ }
119
+
120
+ if (length == null) {
121
+ if (index >= #{self}.length || index < 0) {
122
+ return nil;
123
+ }
124
+
125
+ return #{self}.substr(index, 1);
109
126
  }
110
127
 
111
128
  if (index > #{self}.length || index < 0) {
@@ -163,6 +180,10 @@ class String < `String`
163
180
  `#{self}.charAt(0)`
164
181
  end
165
182
 
183
+ def count(str)
184
+ `(#{self}.length - #{self}.replace(new RegExp(str,"g"), '').length) / str.length`
185
+ end
186
+
166
187
  def downcase
167
188
  `#{self}.toLowerCase()`
168
189
  end
@@ -384,8 +405,9 @@ class String < `String`
384
405
  return #{self}.replace(pattern, replace);
385
406
  }
386
407
  if (block !== nil) {
387
- return #{self}.replace(pattern, function(str) {
388
- return block(__context, str);
408
+ return #{self}.replace(pattern, function(str, a) {
409
+ #{ $1 = `a` };
410
+ return block.call(__context, str);
389
411
  });
390
412
  }
391
413
  else if (replace != null) {
@@ -432,7 +454,7 @@ class String < `String`
432
454
  return $1 ? $0.toUpperCase() : $0.toLowerCase();
433
455
  });
434
456
 
435
- if (#{self}.$k === String) {
457
+ if (#{self}._klass === String) {
436
458
  return str;
437
459
  }
438
460
 
@@ -474,9 +496,9 @@ class String < `String`
474
496
 
475
497
  def to_proc
476
498
  %x{
477
- var name = #{self};
499
+ var name = '$' + #{self};
478
500
 
479
- return function(s, arg) { return arg.$m[name](arg); };
501
+ return function(arg) { return arg[name](arg); };
480
502
  }
481
503
  end
482
504
 
data/core/strscan.rb ADDED
@@ -0,0 +1,61 @@
1
+ class StringScanner
2
+ attr_reader :pos
3
+ attr_reader :matched
4
+
5
+ def initialize(string)
6
+ @string = string
7
+ @pos = 0
8
+ @matched = ''
9
+ @working = string
10
+ end
11
+
12
+ def scan(regex)
13
+ %x{
14
+ var regex = new RegExp('^' + regex.toString().substring(1, regex.toString().length - 1)),
15
+ result = regex.exec(#@working);
16
+
17
+ if (result == null) {
18
+ #@matched = '';
19
+
20
+ return nil;
21
+ }
22
+ else if (typeof(result) === 'object') {
23
+ #@pos += result[0].length;
24
+ #@working = #@working.substring(result[0].length);
25
+ #@matched = result[0];
26
+
27
+ return result[0];
28
+ }
29
+ else if (typeof(result) === 'string') {
30
+ #@pos += result.length;
31
+ #@working = #@working.substring(result.length);
32
+
33
+ return result;
34
+ }
35
+ else {
36
+ return nil;
37
+ }
38
+ }
39
+ end
40
+
41
+ def check(regex)
42
+ %x{
43
+ var regexp = new RegExp('^' + regex.toString().substring(1, regex.toString().length - 1)),
44
+ result = regexp.exec(#@working);
45
+
46
+ if (result == null) {
47
+ return this.matched = nil;
48
+ }
49
+
50
+ return this.matched = result[0];
51
+ }
52
+ end
53
+
54
+ def peek(length)
55
+ `#@working.substring(0, length)`
56
+ end
57
+
58
+ def eos?
59
+ `#@working.length === 0`
60
+ end
61
+ end
data/core/time.rb CHANGED
@@ -1,17 +1,13 @@
1
1
  class Time < `Date`
2
2
  include Comparable
3
3
 
4
- def self.allocate(t)
5
- `new Date(t)`
6
- end
7
-
8
4
  def self.at(seconds, frac = 0)
9
5
  allocate `seconds * 1000 + frac`
10
6
  end
11
7
 
12
8
  def self.new(year, month, day, hour, minute, second, millisecond)
13
9
  %x{
14
- switch (arguments.length - 1) {
10
+ switch (arguments.length) {
15
11
  case 1:
16
12
  return new Date(year);
17
13
  case 2:
data/docs/index.md ADDED
@@ -0,0 +1,616 @@
1
+ <div class="hero-unit">
2
+ <h1 class="main-title">Opal</h1>
3
+ <p><strong>Opal is a ruby to javascript compiler</strong>.
4
+ Opal aims to take ruby files
5
+ and generate efficient javascript that maintains rubys features. Opal
6
+ will, by default, generate fast and efficient code in preference to
7
+ keeping all ruby features.
8
+ </p>
9
+
10
+ <p>
11
+ Opal comes with an implementation of the ruby corelib, written in ruby,
12
+ that uses a bundled runtime (written in javascript) that tie all the
13
+ features together. Whenever possible Opal bridges to native javascript
14
+ features under the hood. The Opal gem includes the compiler used to
15
+ convert ruby sources into javascript.
16
+ </p>
17
+
18
+ <p>
19
+ Opal is <a href="http://github.com/adambeynon/opal">hosted on github</a>,
20
+ and there is a Freenode IRC channel at <code>#opal</code>.
21
+ </div>
22
+
23
+ ## Downloads
24
+
25
+ The Opal runtime and corelib are distributed here, and are required to
26
+ run any code generated by opal.
27
+
28
+ [Opal version 0.3.21](http://opalrb.org/opal.js) _(13.1kb Minified And Gzipped)_
29
+
30
+ ## Installation
31
+
32
+ Opal should be added to your Gemfile:
33
+
34
+ ```ruby
35
+ gem "opal"
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ The easiest way to use opal is to create a rake task using the
41
+ `RakeTask` helper class. Assuming you have a single ruby file in
42
+ your Opal app called `app.rb`:
43
+
44
+ ```ruby
45
+ # app.rb
46
+ puts "Hello world"
47
+ ```
48
+
49
+ Then create a rake task similar to:
50
+
51
+ ```ruby
52
+ # Rakefile
53
+ require 'opal/rake_task'
54
+
55
+ Opal::RakeTask.new do |t|
56
+ t.files = ['app.rb']
57
+ end
58
+ ```
59
+
60
+ ### Building the app
61
+
62
+ Building the app is as simple as running:
63
+
64
+ ```
65
+ rake opal:build
66
+ ```
67
+
68
+ This will build all your listed files into `build/app_name.js`. The
69
+ output name is based on the directory name. This can be overriden by
70
+ setting the `.name` property in the task:
71
+
72
+ ```ruby
73
+ Opal::RakeTask.new do |t|
74
+ t.files = ['app.rb']
75
+ t.name = 'my_awesome_app'
76
+ end
77
+ ```
78
+
79
+ ### Building opal runtime
80
+
81
+ To run the app in the browser, the opal runtime is required. This can
82
+ be built using:
83
+
84
+ ```
85
+ rake opal:dependencies
86
+ ```
87
+
88
+ Which will build `opal.js` into `./build`.
89
+
90
+ The output directory can also be overriden inside the rake task:
91
+
92
+ ```ruby
93
+ Opal::RakeTask.new do |t|
94
+ t.files = ['app.rb']
95
+ t.build_dir = 'out_dir'
96
+ end
97
+ ```
98
+
99
+ The output directory will be created if it doesn't exist.
100
+
101
+ ### Running the app
102
+
103
+ The two compiled files need to be added to a html page so that they
104
+ can run in the browser:
105
+
106
+ ```html
107
+ <!doctype html>
108
+ <html>
109
+ <head>
110
+ <title>My awesome Opal app</title>
111
+
112
+ <script src="build/opal.js"></script>
113
+ <script src="build/my_awesome_app.js"></script>
114
+
115
+ <script>
116
+ // Run opal app
117
+ Opal.require('app')
118
+ </script>
119
+ </head>
120
+ <body>
121
+ </body>
122
+ </html>
123
+ ```
124
+
125
+ If you open the html file, observe the console and you should see
126
+ `"Hello World"` printed to the console.
127
+
128
+ It is necessary to run `Opal.require('app')` as all files built for
129
+ opal are registered so that they can be required inside the ruby
130
+ code.
131
+
132
+ ### Adding dependencies
133
+
134
+ The `opal:dependencies` rake task above can be used to build gems which
135
+ are designed to run in the browser. `opal-dom` is a gem that given opal
136
+ access to the DOM in the browser.
137
+
138
+ `opal-dom` first needs to be installed as a gem (currently it is only
139
+ available from git):
140
+
141
+ ```ruby
142
+ # Gemfile
143
+ gem "opal"
144
+ gem "opal-dom", :git => 'git://github.com/adambeynon/opal-dom.git'
145
+ ```
146
+
147
+ Then add it to the dependencies to build:
148
+
149
+ ```ruby
150
+ Opal::RakeTask.new do |t|
151
+ t.files = ['app.rb']
152
+ t.dependencies = ['opal-dom']
153
+ end
154
+ ```
155
+
156
+ Running `rake opal:dependencies` now will also build
157
+ `build/opal-dom.js`.
158
+
159
+ We can now update our application code:
160
+
161
+ ```ruby
162
+ # app.rb
163
+ require 'opal-dom'
164
+
165
+ alert "Hello!"
166
+ ```
167
+
168
+ And rebuild:
169
+
170
+ ```
171
+ rake opal:build
172
+ ```
173
+
174
+ And add `opal-dom` to the html page:
175
+
176
+ ```html
177
+ <script src="build/opal.js"></script>
178
+ <script src="build/opal-dom.js"></script>
179
+ <script src="build/app.js"></script>
180
+ ```
181
+
182
+ Now running the app should cause an alert box to display.
183
+
184
+ ## Features And Implementation
185
+
186
+ Opal is a source-to-source compiler, so there is no VM as such and the
187
+ compiled code aims to be as fast and efficient as possible, mapping
188
+ directly to underlying javascript features and objects where possible.
189
+
190
+ ### Literals
191
+
192
+ **self** is always compiled to `self`. Any context inside the generated
193
+ code is usually a function body; whether it be a method body, a block,
194
+ a class/module body or the file itself.
195
+
196
+ **true** and **false** are compiled directly into their native boolean
197
+ equivalents. This makes interaction a lot easier as there is no need
198
+ to convert values to opal specific values. It does mean that there is
199
+ only a `Boolean` ruby class available, not seperate `TrueClass` and
200
+ `FalseClass` classes.
201
+
202
+ **nil** is compiled into a `nil` reference, which inside all generated
203
+ files points to a special object which is just an instance of the ruby
204
+ `NilClass` class. This object is available externally to javascript as
205
+ `Opal.nil`.
206
+
207
+ ```ruby
208
+ nil # => nil
209
+ true # => true
210
+ false # => false
211
+ self # => self
212
+ ```
213
+
214
+ #### Strings
215
+
216
+ Ruby strings are compiled directly into javascript strings for
217
+ performance as well as readability. This has the side effect that Opal
218
+ does not support mutable strings - i.e. all strings are immutable.
219
+
220
+ #### Symbols
221
+
222
+ For performance reasons, symbols compile directly into strings. Opal
223
+ supports all the symbol syntaxes, but does not have a real `Symbol`
224
+ class. Symbols and Strings can therefore be used interchangeably.
225
+
226
+ ```ruby
227
+ "hello world!" # => "hello world!"
228
+ :foo # => "foo"
229
+ <<-EOS # => "\nHello there.\n"
230
+ Hello there.
231
+ EOS
232
+ ```
233
+
234
+ #### Numbers
235
+
236
+ In Opal there is a single class for numbers; `Numeric`. To keep opal
237
+ as performant as possible, ruby numbers are mapped to native numbers.
238
+ This has the side effect that all numbers must be of the same class.
239
+ Most relevant methods from `Integer`, `Float` and `Numeric` are
240
+ implemented on this class.
241
+
242
+ ```ruby
243
+ 42 # => 42
244
+ 3.142 # => 3.142
245
+ ```
246
+
247
+ #### Arrays
248
+
249
+ Ruby arrays are compiled directly into javascript arrays. Special
250
+ ruby syntaxes for word arrays etc are also supported.
251
+
252
+ ```ruby
253
+ [1, 2, 3, 4] # => [1, 2, 3, 4]
254
+ %w[foo bar baz] # => ["foo", "bar", "baz"]
255
+ ```
256
+
257
+ #### Hash
258
+
259
+ Inside a generated ruby script, a function `__hash` is available which
260
+ creates a new hash. This is also available in javascript as `Opal.hash`
261
+ and simply returns a new instance of the `Hash` class.
262
+
263
+ ```ruby
264
+ { :foo => 100, :baz => 700 } # => __hash("foo", 100, "baz", 700)
265
+ { foo: 42, bar: [1, 2, 3] } # => __hash("foo", 42, "bar", [1, 2, 3])
266
+ ```
267
+
268
+ #### Range
269
+
270
+ Similar to hash, there is a function `__range` available to create
271
+ range instances.
272
+
273
+ ```ruby
274
+ 1..4 # => __range(1, 4, true)
275
+ 3...7 # => __range(3, 7, false)
276
+ ```
277
+
278
+ #### Optimized Math Operators
279
+
280
+ In ruby, all math operators are method calls, but compiling this into
281
+ javascript would end up being too slow. For this reason, math
282
+ operators are optimized to test first if the receiver is a number, and
283
+ if so then to just carry out the math call.
284
+
285
+ ```ruby
286
+ 3 + 4
287
+ ```
288
+
289
+ This ruby code will then be compiled into the following javascript:
290
+
291
+ ```javascript
292
+ (a = 3, b = 4, typeof(a) === "number" ? a + b : /* method call */)
293
+ ```
294
+
295
+ This ternary statement falls back on sending a method to the receiver
296
+ so all non-numeric receivers will still have the normal method call
297
+ being sent. This optimization makes math operators a **lot faster**.
298
+ Currently, the optimized method calls are `+`, `-`, `*` and `/`.
299
+
300
+ ### method_missing
301
+
302
+ Method missing is fully supported in Opal. It is implemented as
303
+ efficiently as possible.
304
+
305
+ ### Logic and conditionals
306
+
307
+ As per ruby, Opal treats only `false` and `nil` as falsy, everything
308
+ else is a truthy value including `""`, `0` and `[]`. This differs from
309
+ javascript as these values are also treated as false.
310
+
311
+ For this reason, most truthy tests must check if values are `false` or
312
+ `nil`.
313
+
314
+ Taking the following test:
315
+
316
+ ```javascript
317
+ val = 42
318
+
319
+ if val
320
+ return 3.142;
321
+ end
322
+ ```
323
+
324
+ This would be compiled into:
325
+
326
+ ```ruby
327
+ val = 42;
328
+
329
+ if (val !== false && val !== nil) {
330
+ return 3.142;
331
+ }
332
+ ```
333
+
334
+ This makes the generated truthy tests (`if` statements, `and` checks and
335
+ `or` statements) a litle more verbose in the generated code.
336
+
337
+ ### Instance variables
338
+
339
+ Instance variables in Opal work just as expected. When ivars are set or
340
+ retrieved on an object, they are set natively without the `@` prefix.
341
+ This allows real javascript identifiers to be used which is more
342
+ efficient then accessing variables by string name.
343
+
344
+ ```ruby
345
+ @foo = 200
346
+ @foo # => 200
347
+
348
+ @bar # => nil
349
+ ```
350
+
351
+ This gets compiled into:
352
+
353
+ ```javascript
354
+ this.foo = 200;
355
+ this.foo; // => 200
356
+
357
+ this.bar; // => nil
358
+ ```
359
+
360
+ The only point of warning is that when variables are used for the
361
+ first time in ruby, they default to `nil`. In javascript, they default
362
+ to `undefined`/`null`.
363
+
364
+ To keep things working in opal, ivars must be preset to `nil` before
365
+ they can be used. In the top scope and other corner cases, this needs
366
+ to be done on a per scope basis, which can add overhead.
367
+
368
+ To improve performance, once a class body is compiled, all ivars used
369
+ within methods in that class are preset on the prototype of the class
370
+ to be `nil`. This means that all known ivars are already set to nil,
371
+ and this is done just once during the lifespan of the app.
372
+
373
+ ```ruby
374
+ class Foo
375
+ def bar
376
+ @lol
377
+ end
378
+
379
+ def woosh
380
+ @kapow
381
+ end
382
+ end
383
+ ```
384
+
385
+ This example gets compiled into something similar to:
386
+
387
+ ```javascript
388
+ (function() {
389
+ function Foo(){}
390
+ // ...
391
+
392
+ Foo.prototype.lol = Foo.prototype.woosh = nil;
393
+
394
+ Foo.prototype.$bar = function() {
395
+ return this.lol;
396
+ };
397
+
398
+ // etc ...
399
+ })()
400
+ ```
401
+
402
+ ### Interacting with javascript
403
+
404
+ Opal tries to interact as cleanly with javascript and its api as much
405
+ as possible. Ruby arrays, strings, numbers, regexps, blocks and booleans
406
+ are just javascript native equivalents. The only boxed core features are
407
+ hashes and nil.
408
+
409
+ As most of the corelib deals with these low level details, opal provides
410
+ a special syntax for inlining javascript code. This is done with
411
+ x-strings or "backticks", as their ruby use has no useful translation
412
+ in the browser.
413
+
414
+ ```ruby
415
+ `window.title`
416
+ # => "Opal: ruby to javascript compiler"
417
+
418
+ %x{
419
+ console.log("ruby version is:");
420
+ console.log(#{ OPAL_VERSION });
421
+ }
422
+
423
+ # => ruby version is:
424
+ # => 0.3.19
425
+ ```
426
+
427
+ Even interpolations are supported, as seen here.
428
+
429
+ This feature of inlining code is used extensively, for example in
430
+ Array#length:
431
+
432
+ ```ruby
433
+ class Array
434
+ def length
435
+ `this.length`
436
+ end
437
+ end
438
+ ```
439
+
440
+ X-Strings also have the ability to automatically return their value,
441
+ as used by this example.
442
+
443
+ ### Compiled Files
444
+
445
+ As described above, a compiled ruby source gets generated into a string
446
+ of javascript code that is wrapped inside an anonymous function. This
447
+ looks similar to the following:
448
+
449
+ ```javascript
450
+ (function() {
451
+ var nil = Opal.nil, self = Opal.top;
452
+ // generated code
453
+ })();
454
+ ```
455
+
456
+ Inside the function, `nil` is assigned to ensure a local copy is
457
+ available, as well as all the helper methods used within the
458
+ generated file. There is no return value from these functions as they
459
+ are not used anywhere.
460
+
461
+ As a complete example, assuming the following code:
462
+
463
+ ```ruby
464
+ puts "foo"
465
+ ```
466
+
467
+ This would compile directly into:
468
+
469
+ ```javascript
470
+ (function() {
471
+ var nil = Opal.nil, self = Opal.top;
472
+ self.$puts("foo");
473
+ })();
474
+ ```
475
+
476
+ Most of the helpers are no longer present as they are not used in this
477
+ example.
478
+
479
+ ### Using compiled sources
480
+
481
+ If you write the generated code as above into a file `app.js` and add
482
+ that to your HTML page, then it is obvious that `"foo"` would be
483
+ written to the browser's console.
484
+
485
+ ### JSON
486
+
487
+ The opal corelib includes JSON support instead of treating it as an
488
+ external lib. The `JSON` module provides the usual parsing methods.
489
+
490
+ ```ruby
491
+ JSON.parse '{"a": 10, "b": [1, 2, 3], "c": null}'
492
+ # => { "a" => 10, "b" => [1, 2, 3], "c" => nil }
493
+ ```
494
+
495
+ Opal expects `JSON` to be present in the browser, so older browsers
496
+ may require a shim (json2.js) to work with opal. Most mobile browsers
497
+ and modern desktop browsers include json support natively.
498
+
499
+ ## Debugging and finding errors
500
+
501
+ Because Opal does not aim to be fully compatible with ruby, there are
502
+ some instances where things can break and it may not be entirely
503
+ obvious what went wrong.
504
+
505
+ ### Undefined methods
506
+
507
+ By default, opal aims to be as fast as possible, so `method_missing` is
508
+ not turned on by default. Instead, when calling a method that doesn't
509
+ exist, a native error will be raised.
510
+
511
+ ```ruby
512
+ self.do_something()
513
+ ```
514
+
515
+ Might raise an error similar to:
516
+
517
+ ```
518
+ Error: 'undefined' is not a function (evaluating 'this.$do_something()')
519
+ ```
520
+
521
+ As described above, all ruby methods will have a `$` prefix which gives
522
+ a good indication that it is a opal method that doesnt exist, and most
523
+ js engines output the missing function name.
524
+
525
+ ### Undefined constants
526
+
527
+ If trying to access a constant that doesn't exist, there is no runtime
528
+ error. Instead, the value of that expression is just `undefined` as
529
+ constants are retrieved from objects that hold all constants in the
530
+ scope. Trying to send a method to an undefined constant will therefore
531
+ just raise an ugly javascript `TypeError`.
532
+
533
+ If you are using the constant as a reference, it may not be until much
534
+ later that the error occurs.
535
+
536
+ ### Using javascript debuggers
537
+
538
+ As opal just generates javascript, it is useful to use a native
539
+ debugger to work through javascript code. To use a debugger, simply
540
+ add an x-string similar to the following at the place you wish to
541
+ debug:
542
+
543
+ ```ruby
544
+ # .. code
545
+ `debugger`
546
+ # .. more code
547
+ ```
548
+ The x-strings just pass the debugger statement straight through to the
549
+ javascript output.
550
+
551
+ Inside methods and blocks, the current `self` value is always the
552
+ native `this` value. You will not see `self` inside debuggers as it is
553
+ never used to refer to the actual ruby self value.
554
+
555
+ All local variables and method/block arguments also keep their ruby
556
+ names except in the rare cases when the name is reserved in javascript.
557
+ In these cases, a `$` suffix is added to the name (e.g. `try` =>
558
+ `try$`).
559
+
560
+ ## License
561
+
562
+ Opal is released under the MIT license.
563
+
564
+ ## Change Log
565
+
566
+ **0.3.21** _(16 July 2012)_
567
+
568
+ * Add `method_missing` support to all objects and classes
569
+ * Add `Opal.build_gem()` method to quickly build installed gem
570
+ * Add `Opal.build_files()` method to build directories of files
571
+
572
+ **0.3.20** _(23 June 2012)_
573
+
574
+ * Merge JSON into core. JSON module and various #to_json methods are
575
+ now included as part of corelib
576
+ * Make `Time` class bridge to native `Date` constructor
577
+ * Use named functions as class constuctors to make debugging easier
578
+ * Classes are now real functions with prototypes. Bridged classes are
579
+ now directly corresponding to the ruby class (e.g. Array === Opal.Array)
580
+ * Set ivars used inside methods in class to `nil` inside class definition
581
+ to avoid doing it everytime method is called
582
+ * Add debug comments to output for def, class and module stating the file
583
+ and line number the given code was generated from
584
+
585
+ **0.3.19** _(30 May 2012)_
586
+
587
+ * Add BasicObject as the root class
588
+ * Add `Opal.define` and `Opal.require` for requiring files
589
+ * Builder uses a `main` option to dictate which file to require on load
590
+ * Completely revamp runtime to reduce helper methods
591
+ * Allow native bridges (Array, String, etc) to be subclassed
592
+ * Make sure `.js` files can be built with `Opal::Builder`
593
+ * Include the current file name when raising parse errors
594
+
595
+ **0.3.18** _(20 May 2012)_
596
+
597
+ * Fix various core lib bugs
598
+ * Completely remove `require` from corelib
599
+ * Improve Builder to detect dependencies in files
600
+
601
+ **0.3.17** _(19 May 2012)_
602
+
603
+ * Revamp of Builder and Parser tools
604
+ * Remove opal-repl
605
+ * Added a lot of specs for core lib
606
+
607
+ **0.3.16** _(15 January 2012)_
608
+
609
+ * Added HEREDOCS support in parser
610
+ * Parser now handles masgn (mass/multi assignments)
611
+ * More useful DependencyBuilder class to build gems dependencies
612
+ * Blocks no longer passed as an argument in method calls
613
+
614
+ **0.3.15**
615
+
616
+ * Initial Release.