opal 0.8.1 → 0.9.0.beta1

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 (331) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.gitmodules +3 -3
  4. data/.jshintrc +17 -20
  5. data/.travis.yml +22 -11
  6. data/CHANGELOG.md +51 -1
  7. data/CODE_OF_CONDUCT.md +15 -0
  8. data/CONTRIBUTING.md +125 -9
  9. data/Gemfile +1 -1
  10. data/Guardfile +2 -2
  11. data/README.md +95 -29
  12. data/Rakefile +1 -1
  13. data/benchmark/benchmarks +103 -0
  14. data/benchmark/bm_array_flatten.rb +9 -0
  15. data/benchmark/bm_array_intersection_numbers.rb +7 -0
  16. data/benchmark/bm_array_intersection_objects.rb +7 -0
  17. data/benchmark/bm_array_intersection_strings.rb +7 -0
  18. data/benchmark/bm_array_join_ary.rb +9 -0
  19. data/benchmark/bm_array_minus_numbers.rb +7 -0
  20. data/benchmark/bm_array_minus_objects.rb +7 -0
  21. data/benchmark/bm_array_minus_strings.rb +7 -0
  22. data/benchmark/bm_array_union_numbers.rb +7 -0
  23. data/benchmark/bm_array_union_objects.rb +7 -0
  24. data/benchmark/bm_array_union_strings.rb +7 -0
  25. data/benchmark/bm_array_uniq_bang_numbers.rb +5 -0
  26. data/benchmark/bm_array_uniq_bang_objects.rb +5 -0
  27. data/benchmark/bm_array_uniq_bang_strings.rb +5 -0
  28. data/benchmark/bm_array_uniq_numbers.rb +5 -0
  29. data/benchmark/bm_array_uniq_objects.rb +5 -0
  30. data/benchmark/bm_array_uniq_strings.rb +5 -0
  31. data/benchmark/bm_dispatch_bind_table.rb +57 -0
  32. data/benchmark/bm_dispatch_code_gen.rb +65 -0
  33. data/benchmark/bm_dispatch_code_gen_if.rb +64 -0
  34. data/benchmark/bm_dispatch_hardcoded.rb +44 -0
  35. data/benchmark/bm_dispatch_send.rb +38 -0
  36. data/benchmark/bm_dispatch_send_table.rb +57 -0
  37. data/benchmark/bm_hash_assoc_object.rb +11 -0
  38. data/benchmark/bm_hash_assoc_string.rb +9 -0
  39. data/benchmark/bm_hash_clone_object.rb +9 -0
  40. data/benchmark/bm_hash_clone_string.rb +9 -0
  41. data/benchmark/bm_hash_delete_object.rb +11 -0
  42. data/benchmark/bm_hash_delete_string.rb +9 -0
  43. data/benchmark/bm_hash_each_key_object.rb +9 -0
  44. data/benchmark/bm_hash_each_key_string.rb +9 -0
  45. data/benchmark/bm_hash_each_object.rb +9 -0
  46. data/benchmark/bm_hash_each_string.rb +9 -0
  47. data/benchmark/bm_hash_each_value_object.rb +9 -0
  48. data/benchmark/bm_hash_each_value_string.rb +9 -0
  49. data/benchmark/bm_hash_element_reference_object.rb +11 -0
  50. data/benchmark/bm_hash_element_reference_string.rb +9 -0
  51. data/benchmark/bm_hash_element_set_object.rb +5 -0
  52. data/benchmark/bm_hash_element_set_string.rb +5 -0
  53. data/benchmark/bm_hash_equal_value_object.rb +14 -0
  54. data/benchmark/bm_hash_equal_value_string.rb +11 -0
  55. data/benchmark/bm_hash_fetch_object.rb +11 -0
  56. data/benchmark/bm_hash_fetch_string.rb +9 -0
  57. data/benchmark/bm_hash_flatten_object.rb +9 -0
  58. data/benchmark/bm_hash_flatten_string.rb +9 -0
  59. data/benchmark/bm_hash_has_key_object.rb +11 -0
  60. data/benchmark/bm_hash_has_key_string.rb +9 -0
  61. data/benchmark/bm_hash_has_value_object.rb +9 -0
  62. data/benchmark/bm_hash_has_value_string.rb +9 -0
  63. data/benchmark/bm_hash_hash_object.rb +9 -0
  64. data/benchmark/bm_hash_hash_string.rb +9 -0
  65. data/benchmark/bm_hash_inspect_object.rb +9 -0
  66. data/benchmark/bm_hash_inspect_string.rb +9 -0
  67. data/benchmark/bm_hash_invert_object.rb +9 -0
  68. data/benchmark/bm_hash_invert_string.rb +9 -0
  69. data/benchmark/bm_hash_keep_if_object.rb +9 -0
  70. data/benchmark/bm_hash_keep_if_string.rb +9 -0
  71. data/benchmark/bm_hash_key_object.rb +9 -0
  72. data/benchmark/bm_hash_key_string.rb +9 -0
  73. data/benchmark/bm_hash_keys_object.rb +9 -0
  74. data/benchmark/bm_hash_keys_string.rb +9 -0
  75. data/benchmark/bm_hash_literal_mixed_large.rb +3 -0
  76. data/benchmark/bm_hash_literal_mixed_small.rb +3 -0
  77. data/benchmark/bm_hash_literal_object_large.rb +4 -0
  78. data/benchmark/bm_hash_literal_object_small.rb +3 -0
  79. data/benchmark/bm_hash_literal_string_large.rb +4 -0
  80. data/benchmark/bm_hash_literal_string_small.rb +3 -0
  81. data/benchmark/bm_hash_merge_object.rb +22 -0
  82. data/benchmark/bm_hash_merge_string.rb +18 -0
  83. data/benchmark/bm_hash_rassoc_object.rb +9 -0
  84. data/benchmark/bm_hash_rassoc_string.rb +9 -0
  85. data/benchmark/bm_hash_rehash_object.rb +9 -0
  86. data/benchmark/bm_hash_rehash_string.rb +9 -0
  87. data/benchmark/bm_hash_reject_bang_object.rb +9 -0
  88. data/benchmark/bm_hash_reject_bang_string.rb +9 -0
  89. data/benchmark/bm_hash_reject_object.rb +9 -0
  90. data/benchmark/bm_hash_reject_string.rb +9 -0
  91. data/benchmark/bm_hash_replace_object.rb +18 -0
  92. data/benchmark/bm_hash_replace_string.rb +14 -0
  93. data/benchmark/bm_hash_select_bang_object.rb +9 -0
  94. data/benchmark/bm_hash_select_bang_string.rb +9 -0
  95. data/benchmark/bm_hash_select_object.rb +9 -0
  96. data/benchmark/bm_hash_select_string.rb +9 -0
  97. data/benchmark/bm_hash_shift_object.rb +10 -0
  98. data/benchmark/bm_hash_shift_string.rb +10 -0
  99. data/benchmark/bm_hash_to_a_object.rb +9 -0
  100. data/benchmark/bm_hash_to_a_string.rb +9 -0
  101. data/benchmark/bm_hash_to_h_object.rb +10 -0
  102. data/benchmark/bm_hash_to_h_string.rb +10 -0
  103. data/benchmark/bm_hash_values_object.rb +9 -0
  104. data/benchmark/bm_hash_values_string.rb +9 -0
  105. data/benchmark/run.rb +48 -0
  106. data/bin/opal-mspec +1 -1
  107. data/bin/opal-repl +4 -4
  108. data/docs/compiled_ruby.md +214 -56
  109. data/docs/configuring_gems.md +2 -2
  110. data/docs/faq.md +2 -2
  111. data/docs/getting_started.md +19 -2
  112. data/docs/jquery.md +5 -5
  113. data/docs/opal_parser.md +53 -0
  114. data/docs/unsupported_features.md +2 -2
  115. data/docs/upgrading.md +22 -0
  116. data/docs/using_sprockets.md +15 -0
  117. data/examples/rack/config.ru +13 -0
  118. data/examples/sinatra/config.ru +4 -5
  119. data/lib/mspec/opal/runner.rb +54 -11
  120. data/lib/opal.rb +1 -1
  121. data/lib/opal/builder.rb +1 -1
  122. data/lib/opal/builder_processors.rb +1 -1
  123. data/lib/opal/cli.rb +17 -13
  124. data/lib/opal/cli_options.rb +1 -1
  125. data/lib/opal/compiler.rb +12 -0
  126. data/lib/opal/config.rb +4 -0
  127. data/lib/opal/nodes/arglist.rb +5 -7
  128. data/lib/opal/nodes/call.rb +6 -1
  129. data/lib/opal/nodes/call_special.rb +74 -0
  130. data/lib/opal/nodes/def.rb +35 -28
  131. data/lib/opal/nodes/definitions.rb +3 -5
  132. data/lib/opal/nodes/for.rb +13 -0
  133. data/lib/opal/nodes/helpers.rb +15 -1
  134. data/lib/opal/nodes/if.rb +5 -5
  135. data/lib/opal/nodes/iter.rb +6 -1
  136. data/lib/opal/nodes/literal.rb +1 -1
  137. data/lib/opal/nodes/logic.rb +2 -2
  138. data/lib/opal/nodes/masgn.rb +1 -2
  139. data/lib/opal/nodes/module.rb +2 -1
  140. data/lib/opal/nodes/rescue.rb +10 -1
  141. data/lib/opal/nodes/scope.rb +8 -2
  142. data/lib/opal/nodes/singleton_class.rb +1 -1
  143. data/lib/opal/nodes/top.rb +11 -0
  144. data/lib/opal/nodes/variables.rb +4 -4
  145. data/lib/opal/parser.rb +21 -3
  146. data/lib/opal/parser/grammar.rb +3115 -2961
  147. data/lib/opal/parser/grammar.y +29 -6
  148. data/lib/opal/parser/lexer.rb +18 -8
  149. data/lib/opal/sprockets.rb +85 -0
  150. data/lib/opal/sprockets/processor.rb +11 -35
  151. data/lib/opal/sprockets/server.rb +3 -15
  152. data/lib/opal/version.rb +2 -2
  153. data/opal.gemspec +4 -4
  154. data/opal/README.md +9 -0
  155. data/opal/corelib/array.rb +433 -181
  156. data/opal/corelib/basic_object.rb +48 -4
  157. data/opal/corelib/boolean.rb +15 -6
  158. data/opal/corelib/class.rb +6 -5
  159. data/opal/corelib/comparable.rb +12 -0
  160. data/opal/corelib/complex.rb +282 -0
  161. data/opal/corelib/constants.rb +9 -0
  162. data/opal/corelib/enumerable.rb +83 -34
  163. data/opal/corelib/enumerator.rb +3 -1
  164. data/opal/corelib/error.rb +49 -10
  165. data/opal/corelib/file.rb +1 -0
  166. data/opal/corelib/hash.rb +353 -577
  167. data/opal/corelib/helpers.rb +20 -0
  168. data/opal/corelib/kernel.rb +114 -59
  169. data/opal/corelib/math.rb +470 -0
  170. data/opal/corelib/method.rb +11 -2
  171. data/opal/corelib/module.rb +96 -96
  172. data/opal/corelib/{nil_class.rb → nil.rb} +20 -1
  173. data/opal/corelib/number.rb +751 -0
  174. data/opal/corelib/numeric.rb +77 -437
  175. data/opal/corelib/proc.rb +81 -1
  176. data/opal/corelib/process.rb +27 -0
  177. data/opal/corelib/rational.rb +358 -0
  178. data/opal/corelib/regexp.rb +156 -27
  179. data/opal/corelib/runtime.js +724 -335
  180. data/opal/corelib/string.rb +93 -104
  181. data/opal/corelib/string/encoding.rb +177 -0
  182. data/opal/corelib/string/inheritance.rb +2 -0
  183. data/opal/corelib/struct.rb +105 -18
  184. data/opal/corelib/time.rb +267 -146
  185. data/opal/corelib/unsupported.rb +216 -0
  186. data/opal/corelib/variables.rb +0 -6
  187. data/opal/opal.rb +8 -22
  188. data/opal/opal/base.rb +9 -0
  189. data/opal/opal/mini.rb +17 -0
  190. data/spec/README.md +1 -1
  191. data/spec/filters/bugs/array.rb +38 -136
  192. data/spec/filters/bugs/{basic_object.rb → basicobject.rb} +14 -15
  193. data/spec/filters/bugs/class.rb +6 -12
  194. data/spec/filters/bugs/complex.rb +3 -0
  195. data/spec/filters/bugs/date.rb +162 -10
  196. data/spec/filters/bugs/enumerable.rb +31 -58
  197. data/spec/filters/bugs/enumerator.rb +42 -0
  198. data/spec/filters/bugs/exception.rb +66 -10
  199. data/spec/filters/bugs/float.rb +17 -0
  200. data/spec/filters/bugs/hash.rb +11 -97
  201. data/spec/filters/bugs/inheritance.rb +5 -0
  202. data/spec/filters/bugs/integer.rb +28 -0
  203. data/spec/filters/bugs/kernel.rb +304 -12
  204. data/spec/filters/bugs/language.rb +133 -399
  205. data/spec/filters/bugs/language_opal.rb +88 -0
  206. data/spec/filters/bugs/module.rb +203 -62
  207. data/spec/filters/bugs/numeric.rb +32 -0
  208. data/spec/filters/bugs/proc.rb +39 -0
  209. data/spec/filters/bugs/range.rb +148 -0
  210. data/spec/filters/bugs/regexp.rb +168 -0
  211. data/spec/filters/bugs/set.rb +46 -3
  212. data/spec/filters/bugs/singleton.rb +1 -2
  213. data/spec/filters/bugs/string.rb +59 -90
  214. data/spec/filters/bugs/strscan.rb +80 -0
  215. data/spec/filters/bugs/struct.rb +10 -20
  216. data/spec/filters/bugs/time.rb +17 -184
  217. data/spec/filters/bugs/unboundmethod.rb +22 -0
  218. data/spec/filters/unsupported/array.rb +163 -0
  219. data/spec/filters/unsupported/basicobject.rb +14 -0
  220. data/spec/filters/unsupported/bignum.rb +46 -0
  221. data/spec/filters/unsupported/class.rb +4 -0
  222. data/spec/filters/unsupported/delegator.rb +5 -0
  223. data/spec/filters/unsupported/enumerable.rb +11 -0
  224. data/spec/filters/unsupported/enumerator.rb +8 -9
  225. data/spec/filters/unsupported/fixnum.rb +14 -0
  226. data/spec/filters/unsupported/float.rb +41 -7
  227. data/spec/filters/unsupported/freeze.rb +45 -0
  228. data/spec/filters/unsupported/hash.rb +50 -0
  229. data/spec/filters/unsupported/integer.rb +3 -0
  230. data/spec/filters/unsupported/kernel.rb +31 -0
  231. data/spec/filters/unsupported/language.rb +17 -0
  232. data/spec/filters/unsupported/matchdata.rb +30 -0
  233. data/spec/filters/unsupported/math.rb +3 -0
  234. data/spec/filters/unsupported/module.rb +5 -3
  235. data/spec/filters/unsupported/pathname.rb +3 -0
  236. data/spec/filters/unsupported/privacy.rb +136 -0
  237. data/spec/filters/unsupported/proc.rb +3 -0
  238. data/spec/filters/unsupported/regexp.rb +59 -0
  239. data/spec/filters/unsupported/set.rb +4 -0
  240. data/spec/filters/unsupported/{marshal.rb → singleton.rb} +4 -2
  241. data/spec/filters/unsupported/{mutable_strings.rb → string.rb} +456 -336
  242. data/spec/filters/unsupported/struct.rb +3 -0
  243. data/spec/filters/unsupported/symbol.rb +5 -0
  244. data/spec/filters/unsupported/taint.rb +16 -0
  245. data/spec/filters/unsupported/thread.rb +5 -0
  246. data/spec/filters/unsupported/time.rb +197 -16
  247. data/spec/lib/cli_spec.rb +14 -4
  248. data/spec/lib/compiler_spec.rb +9 -1
  249. data/spec/lib/parser/call_spec.rb +18 -0
  250. data/spec/lib/parser/not_spec.rb +2 -8
  251. data/spec/lib/sprockets_spec.rb +24 -0
  252. data/spec/opal/core/array/intersection_spec.rb +38 -0
  253. data/spec/opal/core/array/minus_spec.rb +38 -0
  254. data/spec/opal/core/array/union_spec.rb +38 -0
  255. data/spec/opal/core/array/uniq_spec.rb +49 -0
  256. data/spec/opal/core/exception_spec.rb +7 -0
  257. data/spec/opal/core/fixtures/require_tree_with_dot/file 1.rb +1 -0
  258. data/spec/opal/core/fixtures/require_tree_with_dot/file 2.rb +1 -0
  259. data/spec/opal/core/fixtures/require_tree_with_dot/file 3.rb +1 -0
  260. data/spec/opal/core/fixtures/require_tree_with_dot/index.rb +3 -0
  261. data/spec/opal/core/hash/internals_spec.rb +332 -0
  262. data/spec/opal/core/helpers_spec.rb +14 -0
  263. data/spec/opal/core/kernel/freeze_spec.rb +1 -1
  264. data/spec/opal/core/kernel/raise_spec.rb +13 -0
  265. data/spec/opal/core/kernel/require_tree_spec.rb +9 -0
  266. data/spec/opal/core/language/class_spec.rb +55 -0
  267. data/spec/opal/core/language/fixtures/send.rb +1 -0
  268. data/spec/opal/core/language/keyword_arguments_spec.rb +11 -0
  269. data/spec/opal/core/language/send_spec.rb +5 -0
  270. data/spec/opal/core/method/to_proc_spec.rb +28 -0
  271. data/spec/opal/core/module/name_spec.rb +0 -17
  272. data/spec/opal/core/runtime/bridged_classes_spec.rb +2 -2
  273. data/spec/opal/core/runtime/eval_spec.rb +1 -1
  274. data/spec/opal/core/runtime/method_missing_spec.rb +6 -0
  275. data/spec/opal/core/runtime_spec.rb +51 -0
  276. data/spec/opal/stdlib/js_spec.rb +66 -0
  277. data/spec/opal/stdlib/native/hash_spec.rb +36 -0
  278. data/spec/rubyspecs +152 -273
  279. data/spec/spec_helper.rb +10 -11
  280. data/stdlib/base64.rb +9 -9
  281. data/stdlib/benchmark.rb +551 -4
  282. data/stdlib/console.rb +94 -0
  283. data/stdlib/date.rb +1 -1
  284. data/stdlib/encoding.rb +1 -170
  285. data/stdlib/js.rb +56 -0
  286. data/stdlib/json.rb +9 -14
  287. data/stdlib/math.rb +1 -370
  288. data/stdlib/native.rb +133 -63
  289. data/stdlib/nodejs/file.rb +5 -0
  290. data/stdlib/nodejs/fileutils.rb +13 -6
  291. data/stdlib/nodejs/node_modules/js-yaml/node_modules/argparse/README.md +1 -1
  292. data/stdlib/opal-parser.rb +1 -2
  293. data/stdlib/ostruct.rb +65 -6
  294. data/stdlib/pp.rb +2 -4
  295. data/stdlib/rbconfig.rb +1 -3
  296. data/stdlib/strscan.rb +164 -28
  297. data/tasks/benchmarking.rake +88 -0
  298. data/tasks/testing.rake +181 -55
  299. data/{lib/mspec/opal/special_calls.rb → tasks/testing/mspec_special_calls.rb} +1 -1
  300. data/{lib/mspec/opal/sprockets.js → tasks/testing/phantomjs1-sprockets.js} +17 -6
  301. data/test/opal/test_keyword.rb +590 -0
  302. data/vendored-minitest/minitest.rb +2 -2
  303. data/vendored-minitest/test/unit.rb +5 -0
  304. metadata +229 -62
  305. data/benchmarks/operators.rb +0 -11
  306. data/benchmarks/prova.js.rb +0 -13
  307. data/docs/libraries.md +0 -36
  308. data/lib/mspec/opal/new.html.erb +0 -1
  309. data/lib/mspec/opal/rake_task.rb +0 -248
  310. data/opal/corelib/match_data.rb +0 -128
  311. data/spec/filters/bugs/math.rb +0 -95
  312. data/spec/filters/bugs/nil.rb +0 -7
  313. data/spec/filters/bugs/opal.rb +0 -9
  314. data/spec/filters/bugs/regular_expressions.rb +0 -41
  315. data/spec/filters/bugs/stringscanner.rb +0 -33
  316. data/spec/filters/unsupported/encoding.rb +0 -102
  317. data/spec/filters/unsupported/frozen.rb +0 -92
  318. data/spec/filters/unsupported/hash_compare_by_identity.rb +0 -16
  319. data/spec/filters/unsupported/integer_size.rb +0 -59
  320. data/spec/filters/unsupported/method_added.rb +0 -10
  321. data/spec/filters/unsupported/private_constants.rb +0 -30
  322. data/spec/filters/unsupported/private_methods.rb +0 -55
  323. data/spec/filters/unsupported/random.rb +0 -4
  324. data/spec/filters/unsupported/rational_numbers.rb +0 -4
  325. data/spec/filters/unsupported/regular_expressions.rb +0 -137
  326. data/spec/filters/unsupported/ruby_exe.rb +0 -5
  327. data/spec/filters/unsupported/symbols.rb +0 -17
  328. data/spec/filters/unsupported/tainted.rb +0 -180
  329. data/spec/filters/unsupported/trusted.rb +0 -88
  330. data/stdlib/process.rb +0 -10
  331. data/tasks/documenting.rake +0 -37
data/spec/spec_helper.rb CHANGED
@@ -6,9 +6,6 @@ require 'mspec/version'
6
6
  require 'support/mspec_rspec_adapter'
7
7
  require 'mspec/opal/runner'
8
8
 
9
- require 'math'
10
- require 'encoding'
11
-
12
9
  # Node v0.12 as well as Google Chrome/V8 42.0.2311.135 (64-bit)
13
10
  # showed to need more tolerance (rubyspec default is 0.00003)
14
11
  TOLERANCE = 0.00004
@@ -30,16 +27,18 @@ module Kernel
30
27
  end
31
28
  end
32
29
 
30
+ is_node = `typeof(process) == 'object' && !!process.versions.node`
31
+ is_browser = `(typeof(window) !== 'undefined')`
32
+ is_phantom = is_browser && `!!window.OPAL_SPEC_PHANTOM`
33
+
33
34
  case
34
- when defined?(NodeJS)
35
+ when is_node
35
36
  formatter_class = NodeJSFormatter
36
- when `(typeof(window) !== 'undefined')`
37
- if `!!window.OPAL_SPEC_PHANTOM`
38
- require 'phantomjs'
39
- formatter_class = PhantomFormatter
40
- else
41
- formatter_class = BrowserFormatter
42
- end
37
+ when is_phantom
38
+ require 'phantomjs'
39
+ formatter_class = PhantomFormatter
40
+ else
41
+ formatter_class = BrowserFormatter
43
42
  end
44
43
 
45
44
  # Uncomment the following to see example titles when they're executed.
data/stdlib/base64.rb CHANGED
@@ -40,22 +40,22 @@ module Base64
40
40
 
41
41
  function decode(string) {
42
42
  var buffer = from(string),
43
- result = [];
43
+ result = [], a, b, c;
44
44
 
45
45
  for (var i = 0, length = buffer.length; i < length; i++) {
46
46
  if (buffer[i] < 128) {
47
47
  result.push(String.fromCharCode(buffer[i]));
48
48
  }
49
49
  else if (buffer[i] > 191 && buffer[i] < 224) {
50
- var a = (buffer[i] & 31) << 6,
51
- b = buffer[++i] & 63;
50
+ a = (buffer[i] & 31) << 6;
51
+ b = buffer[++i] & 63;
52
52
 
53
53
  result.push(String.fromCharCode(a | b));
54
54
  }
55
55
  else {
56
- var a = (buffer[i] & 15) << 12,
57
- b = (buffer[++i] & 63) << 6,
58
- c = buffer[++i] & 63;
56
+ a = (buffer[i] & 15) << 12;
57
+ b = (buffer[++i] & 63) << 6;
58
+ c = buffer[++i] & 63;
59
59
 
60
60
  result.push(String.fromCharCode(a | b | c));
61
61
  }
@@ -65,15 +65,15 @@ module Base64
65
65
  }
66
66
 
67
67
  function to(string) {
68
- var buffer = [];
68
+ var buffer = [], i, length;
69
69
 
70
70
  if (/^[\x00-\x7f]*$/.test(string)) {
71
- for (var i = 0, length = string.length; i < length; i++) {
71
+ for (i = 0, length = string.length; i < length; i++) {
72
72
  buffer.push(string.charCodeAt(i));
73
73
  }
74
74
  }
75
75
  else {
76
- for (var i = 0, length = string.length; i < length; i++) {
76
+ for (i = 0, length = string.length; i < length; i++) {
77
77
  var ch = string.charCodeAt(i);
78
78
 
79
79
  if (ch < 128) {
data/stdlib/benchmark.rb CHANGED
@@ -1,10 +1,557 @@
1
+ #--
2
+ # benchmark.rb - a performance benchmarking library
3
+ #
4
+ # $Id$
5
+ #
6
+ # Created by Gotoken (gotoken@notwork.org).
7
+ #
8
+ # Documentation by Gotoken (original RD), Lyle Johnson (RDoc conversion), and
9
+ # Gavin Sinclair (editing).
10
+ #++
11
+ #
12
+ # == Overview
13
+ #
14
+ # The Benchmark module provides methods for benchmarking Ruby code, giving
15
+ # detailed reports on the time taken for each task.
16
+ #
17
+
18
+ # The Benchmark module provides methods to measure and report the time
19
+ # used to execute Ruby code.
20
+ #
21
+ # * Measure the time to construct the string given by the expression
22
+ # <code>"a"*1_000_000_000</code>:
23
+ #
24
+ # require 'benchmark'
25
+ #
26
+ # puts Benchmark.measure { "a"*1_000_000_000 }
27
+ #
28
+ # On my machine (OSX 10.8.3 on i5 1.7 Ghz) this generates:
29
+ #
30
+ # 0.350000 0.400000 0.750000 ( 0.835234)
31
+ #
32
+ # This report shows the user CPU time, system CPU time, the sum of
33
+ # the user and system CPU times, and the elapsed real time. The unit
34
+ # of time is seconds.
35
+ #
36
+ # * Do some experiments sequentially using the #bm method:
37
+ #
38
+ # require 'benchmark'
39
+ #
40
+ # n = 5000000
41
+ # Benchmark.bm do |x|
42
+ # x.report { for i in 1..n; a = "1"; end }
43
+ # x.report { n.times do ; a = "1"; end }
44
+ # x.report { 1.upto(n) do ; a = "1"; end }
45
+ # end
46
+ #
47
+ # The result:
48
+ #
49
+ # user system total real
50
+ # 1.010000 0.000000 1.010000 ( 1.014479)
51
+ # 1.000000 0.000000 1.000000 ( 0.998261)
52
+ # 0.980000 0.000000 0.980000 ( 0.981335)
53
+ #
54
+ # * Continuing the previous example, put a label in each report:
55
+ #
56
+ # require 'benchmark'
57
+ #
58
+ # n = 5000000
59
+ # Benchmark.bm(7) do |x|
60
+ # x.report("for:") { for i in 1..n; a = "1"; end }
61
+ # x.report("times:") { n.times do ; a = "1"; end }
62
+ # x.report("upto:") { 1.upto(n) do ; a = "1"; end }
63
+ # end
64
+ #
65
+ # The result:
66
+ #
67
+ # user system total real
68
+ # for: 1.010000 0.000000 1.010000 ( 1.015688)
69
+ # times: 1.000000 0.000000 1.000000 ( 1.003611)
70
+ # upto: 1.030000 0.000000 1.030000 ( 1.028098)
71
+ #
72
+ # * The times for some benchmarks depend on the order in which items
73
+ # are run. These differences are due to the cost of memory
74
+ # allocation and garbage collection. To avoid these discrepancies,
75
+ # the #bmbm method is provided. For example, to compare ways to
76
+ # sort an array of floats:
77
+ #
78
+ # require 'benchmark'
79
+ #
80
+ # array = (1..1000000).map { rand }
81
+ #
82
+ # Benchmark.bmbm do |x|
83
+ # x.report("sort!") { array.dup.sort! }
84
+ # x.report("sort") { array.dup.sort }
85
+ # end
86
+ #
87
+ # The result:
88
+ #
89
+ # Rehearsal -----------------------------------------
90
+ # sort! 1.490000 0.010000 1.500000 ( 1.490520)
91
+ # sort 1.460000 0.000000 1.460000 ( 1.463025)
92
+ # -------------------------------- total: 2.960000sec
93
+ #
94
+ # user system total real
95
+ # sort! 1.460000 0.000000 1.460000 ( 1.460465)
96
+ # sort 1.450000 0.010000 1.460000 ( 1.448327)
97
+ #
98
+ # * Report statistics of sequential experiments with unique labels,
99
+ # using the #benchmark method:
100
+ #
101
+ # require 'benchmark'
102
+ # include Benchmark # we need the CAPTION and FORMAT constants
103
+ #
104
+ # n = 5000000
105
+ # Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x|
106
+ # tf = x.report("for:") { for i in 1..n; a = "1"; end }
107
+ # tt = x.report("times:") { n.times do ; a = "1"; end }
108
+ # tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end }
109
+ # [tf+tt+tu, (tf+tt+tu)/3]
110
+ # end
111
+ #
112
+ # The result:
113
+ #
114
+ # user system total real
115
+ # for: 0.950000 0.000000 0.950000 ( 0.952039)
116
+ # times: 0.980000 0.000000 0.980000 ( 0.984938)
117
+ # upto: 0.950000 0.000000 0.950000 ( 0.946787)
118
+ # >total: 2.880000 0.000000 2.880000 ( 2.883764)
119
+ # >avg: 0.960000 0.000000 0.960000 ( 0.961255)
120
+
1
121
  module Benchmark
2
122
 
3
- def measure(&block)
4
- start = Time.now
123
+ BENCHMARK_VERSION = "2002-04-25" # :nodoc:
124
+
125
+ # Invokes the block with a Benchmark::Report object, which
126
+ # may be used to collect and report on the results of individual
127
+ # benchmark tests. Reserves +label_width+ leading spaces for
128
+ # labels on each line. Prints +caption+ at the top of the
129
+ # report, and uses +format+ to format each line.
130
+ # Returns an array of Benchmark::Tms objects.
131
+ #
132
+ # If the block returns an array of
133
+ # Benchmark::Tms objects, these will be used to format
134
+ # additional lines of output. If +label+ parameters are
135
+ # given, these are used to label these extra lines.
136
+ #
137
+ # _Note_: Other methods provide a simpler interface to this one, and are
138
+ # suitable for nearly all benchmarking requirements. See the examples in
139
+ # Benchmark, and the #bm and #bmbm methods.
140
+ #
141
+ # Example:
142
+ #
143
+ # require 'benchmark'
144
+ # include Benchmark # we need the CAPTION and FORMAT constants
145
+ #
146
+ # n = 5000000
147
+ # Benchmark.benchmark(CAPTION, 7, FORMAT, ">total:", ">avg:") do |x|
148
+ # tf = x.report("for:") { for i in 1..n; a = "1"; end }
149
+ # tt = x.report("times:") { n.times do ; a = "1"; end }
150
+ # tu = x.report("upto:") { 1.upto(n) do ; a = "1"; end }
151
+ # [tf+tt+tu, (tf+tt+tu)/3]
152
+ # end
153
+ #
154
+ # Generates:
155
+ #
156
+ # user system total real
157
+ # for: 0.970000 0.000000 0.970000 ( 0.970493)
158
+ # times: 0.990000 0.000000 0.990000 ( 0.989542)
159
+ # upto: 0.970000 0.000000 0.970000 ( 0.972854)
160
+ # >total: 2.930000 0.000000 2.930000 ( 2.932889)
161
+ # >avg: 0.976667 0.000000 0.976667 ( 0.977630)
162
+ #
163
+
164
+ def benchmark(caption = "", label_width = nil, format = nil, *labels) # :yield: report
165
+ sync = STDOUT.sync
166
+ STDOUT.sync = true
167
+ label_width ||= 0
168
+ label_width += 1
169
+ format ||= FORMAT
170
+ print ' '*label_width + caption unless caption.empty?
171
+ report = Report.new(label_width, format)
172
+ results = yield(report)
173
+ Array === results and results.grep(Tms).each {|t|
174
+ print((labels.shift || t.label || "").ljust(label_width), t.format(format))
175
+ }
176
+ report.list
177
+ ensure
178
+ STDOUT.sync = sync unless sync.nil?
179
+ end
180
+
181
+
182
+ # A simple interface to the #benchmark method, #bm generates sequential
183
+ # reports with labels. The parameters have the same meaning as for
184
+ # #benchmark.
185
+ #
186
+ # require 'benchmark'
187
+ #
188
+ # n = 5000000
189
+ # Benchmark.bm(7) do |x|
190
+ # x.report("for:") { for i in 1..n; a = "1"; end }
191
+ # x.report("times:") { n.times do ; a = "1"; end }
192
+ # x.report("upto:") { 1.upto(n) do ; a = "1"; end }
193
+ # end
194
+ #
195
+ # Generates:
196
+ #
197
+ # user system total real
198
+ # for: 0.960000 0.000000 0.960000 ( 0.957966)
199
+ # times: 0.960000 0.000000 0.960000 ( 0.960423)
200
+ # upto: 0.950000 0.000000 0.950000 ( 0.954864)
201
+ #
202
+
203
+ def bm(label_width = 0, *labels, &blk) # :yield: report
204
+ benchmark(CAPTION, label_width, FORMAT, *labels, &blk)
205
+ end
206
+
207
+
208
+ # Sometimes benchmark results are skewed because code executed
209
+ # earlier encounters different garbage collection overheads than
210
+ # that run later. #bmbm attempts to minimize this effect by running
211
+ # the tests twice, the first time as a rehearsal in order to get the
212
+ # runtime environment stable, the second time for
213
+ # real. GC.start is executed before the start of each of
214
+ # the real timings; the cost of this is not included in the
215
+ # timings. In reality, though, there's only so much that #bmbm can
216
+ # do, and the results are not guaranteed to be isolated from garbage
217
+ # collection and other effects.
218
+ #
219
+ # Because #bmbm takes two passes through the tests, it can
220
+ # calculate the required label width.
221
+ #
222
+ # require 'benchmark'
223
+ #
224
+ # array = (1..1000000).map { rand }
225
+ #
226
+ # Benchmark.bmbm do |x|
227
+ # x.report("sort!") { array.dup.sort! }
228
+ # x.report("sort") { array.dup.sort }
229
+ # end
230
+ #
231
+ # Generates:
232
+ #
233
+ # Rehearsal -----------------------------------------
234
+ # sort! 1.440000 0.010000 1.450000 ( 1.446833)
235
+ # sort 1.440000 0.000000 1.440000 ( 1.448257)
236
+ # -------------------------------- total: 2.890000sec
237
+ #
238
+ # user system total real
239
+ # sort! 1.460000 0.000000 1.460000 ( 1.458065)
240
+ # sort 1.450000 0.000000 1.450000 ( 1.455963)
241
+ #
242
+ # #bmbm yields a Benchmark::Job object and returns an array of
243
+ # Benchmark::Tms objects.
244
+ #
245
+ def bmbm(width = 0) # :yield: job
246
+ job = Job.new(width)
247
+ yield(job)
248
+ width = job.width + 1
249
+ sync = STDOUT.sync
250
+ STDOUT.sync = true
251
+
252
+ # rehearsal
253
+ puts 'Rehearsal '.ljust(width+CAPTION.length,'-')
254
+ ets = job.list.inject(Tms.new) { |sum,(label,item)|
255
+ print label.ljust(width)
256
+ res = Benchmark.measure(&item)
257
+ print res.format
258
+ sum + res
259
+ }.format("total: %tsec")
260
+ print " #{ets}\n\n".rjust(width+CAPTION.length+2,'-')
261
+
262
+ # take
263
+ print ' '*width + CAPTION
264
+ job.list.map { |label,item|
265
+ GC.start
266
+ print label.ljust(width)
267
+ Benchmark.measure(label, &item).tap { |res| print res }
268
+ }
269
+ ensure
270
+ STDOUT.sync = sync unless sync.nil?
271
+ end
272
+
273
+ # :stopdoc:
274
+ case
275
+ when defined?(Process::CLOCK_MONOTONIC)
276
+ BENCHMARK_CLOCK = Process::CLOCK_MONOTONIC
277
+ else
278
+ BENCHMARK_CLOCK = Process::CLOCK_REALTIME
279
+ end
280
+ # :startdoc:
281
+
282
+ #
283
+ # Returns the time used to execute the given block as a
284
+ # Benchmark::Tms object.
285
+ #
286
+ def measure(label = "") # :yield:
287
+ t0, r0 = Process.times, Process.clock_gettime(BENCHMARK_CLOCK)
5
288
  yield
6
- Time.now - start
289
+ t1, r1 = Process.times, Process.clock_gettime(BENCHMARK_CLOCK)
290
+ Benchmark::Tms.new(t1.utime - t0.utime,
291
+ t1.stime - t0.stime,
292
+ t1.cutime - t0.cutime,
293
+ t1.cstime - t0.cstime,
294
+ r1 - r0,
295
+ label)
296
+ end
297
+
298
+ #
299
+ # Returns the elapsed real time used to execute the given block.
300
+ #
301
+ def realtime # :yield:
302
+ r0 = Process.clock_gettime(BENCHMARK_CLOCK)
303
+ yield
304
+ Process.clock_gettime(BENCHMARK_CLOCK) - r0
305
+ end
306
+
307
+ module_function :benchmark, :measure, :realtime, :bm, :bmbm
308
+
309
+ #
310
+ # A Job is a sequence of labelled blocks to be processed by the
311
+ # Benchmark.bmbm method. It is of little direct interest to the user.
312
+ #
313
+ class Job # :nodoc:
314
+ #
315
+ # Returns an initialized Job instance.
316
+ # Usually, one doesn't call this method directly, as new
317
+ # Job objects are created by the #bmbm method.
318
+ # +width+ is a initial value for the label offset used in formatting;
319
+ # the #bmbm method passes its +width+ argument to this constructor.
320
+ #
321
+ def initialize(width)
322
+ @width = width
323
+ @list = []
324
+ end
325
+
326
+ #
327
+ # Registers the given label and block pair in the job list.
328
+ #
329
+ def item(label = "", &blk) # :yield:
330
+ raise ArgumentError, "no block" unless block_given?
331
+ label = label.to_s
332
+ w = label.length
333
+ @width = w if @width < w
334
+ @list << [label, blk]
335
+ self
336
+ end
337
+
338
+ alias report item
339
+
340
+ # An array of 2-element arrays, consisting of label and block pairs.
341
+ attr_reader :list
342
+
343
+ # Length of the widest label in the #list.
344
+ attr_reader :width
345
+ end
346
+
347
+ #
348
+ # This class is used by the Benchmark.benchmark and Benchmark.bm methods.
349
+ # It is of little direct interest to the user.
350
+ #
351
+ class Report # :nodoc:
352
+ #
353
+ # Returns an initialized Report instance.
354
+ # Usually, one doesn't call this method directly, as new
355
+ # Report objects are created by the #benchmark and #bm methods.
356
+ # +width+ and +format+ are the label offset and
357
+ # format string used by Tms#format.
358
+ #
359
+ def initialize(width = 0, format = nil)
360
+ @width, @format, @list = width, format, []
361
+ end
362
+
363
+ #
364
+ # Prints the +label+ and measured time for the block,
365
+ # formatted by +format+. See Tms#format for the
366
+ # formatting rules.
367
+ #
368
+ def item(label = "", *format, &blk) # :yield:
369
+ print label.to_s.ljust(@width)
370
+ @list << res = Benchmark.measure(label, &blk)
371
+ print res.format(@format, *format)
372
+ res
373
+ end
374
+
375
+ alias report item
376
+
377
+ # An array of Benchmark::Tms objects representing each item.
378
+ attr_reader :list
7
379
  end
8
380
 
9
- module_function :measure
381
+
382
+
383
+ #
384
+ # A data object, representing the times associated with a benchmark
385
+ # measurement.
386
+ #
387
+ class Tms
388
+
389
+ # Default caption, see also Benchmark::CAPTION
390
+ CAPTION = " user system total real\n"
391
+
392
+ # Default format string, see also Benchmark::FORMAT
393
+ FORMAT = "%10.6u %10.6y %10.6t %10.6r\n"
394
+
395
+ # User CPU time
396
+ attr_reader :utime
397
+
398
+ # System CPU time
399
+ attr_reader :stime
400
+
401
+ # User CPU time of children
402
+ attr_reader :cutime
403
+
404
+ # System CPU time of children
405
+ attr_reader :cstime
406
+
407
+ # Elapsed real time
408
+ attr_reader :real
409
+
410
+ # Total time, that is +utime+ + +stime+ + +cutime+ + +cstime+
411
+ attr_reader :total
412
+
413
+ # Label
414
+ attr_reader :label
415
+
416
+ #
417
+ # Returns an initialized Tms object which has
418
+ # +utime+ as the user CPU time, +stime+ as the system CPU time,
419
+ # +cutime+ as the children's user CPU time, +cstime+ as the children's
420
+ # system CPU time, +real+ as the elapsed real time and +label+ as the label.
421
+ #
422
+ def initialize(utime = 0.0, stime = 0.0, cutime = 0.0, cstime = 0.0, real = 0.0, label = nil)
423
+ @utime, @stime, @cutime, @cstime, @real, @label = utime, stime, cutime, cstime, real, label.to_s
424
+ @total = @utime + @stime + @cutime + @cstime
425
+ end
426
+
427
+ #
428
+ # Returns a new Tms object whose times are the sum of the times for this
429
+ # Tms object, plus the time required to execute the code block (+blk+).
430
+ #
431
+ def add(&blk) # :yield:
432
+ self + Benchmark.measure(&blk)
433
+ end
434
+
435
+ #
436
+ # An in-place version of #add.
437
+ #
438
+ def add!(&blk)
439
+ t = Benchmark.measure(&blk)
440
+ @utime = utime + t.utime
441
+ @stime = stime + t.stime
442
+ @cutime = cutime + t.cutime
443
+ @cstime = cstime + t.cstime
444
+ @real = real + t.real
445
+ self
446
+ end
447
+
448
+ #
449
+ # Returns a new Tms object obtained by memberwise summation
450
+ # of the individual times for this Tms object with those of the other
451
+ # Tms object.
452
+ # This method and #/() are useful for taking statistics.
453
+ #
454
+ def +(other); memberwise(:+, other) end
455
+
456
+ #
457
+ # Returns a new Tms object obtained by memberwise subtraction
458
+ # of the individual times for the other Tms object from those of this
459
+ # Tms object.
460
+ #
461
+ def -(other); memberwise(:-, other) end
462
+
463
+ #
464
+ # Returns a new Tms object obtained by memberwise multiplication
465
+ # of the individual times for this Tms object by _x_.
466
+ #
467
+ def *(x); memberwise(:*, x) end
468
+
469
+ #
470
+ # Returns a new Tms object obtained by memberwise division
471
+ # of the individual times for this Tms object by _x_.
472
+ # This method and #+() are useful for taking statistics.
473
+ #
474
+ def /(x); memberwise(:/, x) end
475
+
476
+ #
477
+ # Returns the contents of this Tms object as
478
+ # a formatted string, according to a format string
479
+ # like that passed to Kernel.format. In addition, #format
480
+ # accepts the following extensions:
481
+ #
482
+ # <tt>%u</tt>:: Replaced by the user CPU time, as reported by Tms#utime.
483
+ # <tt>%y</tt>:: Replaced by the system CPU time, as reported by #stime (Mnemonic: y of "s*y*stem")
484
+ # <tt>%U</tt>:: Replaced by the children's user CPU time, as reported by Tms#cutime
485
+ # <tt>%Y</tt>:: Replaced by the children's system CPU time, as reported by Tms#cstime
486
+ # <tt>%t</tt>:: Replaced by the total CPU time, as reported by Tms#total
487
+ # <tt>%r</tt>:: Replaced by the elapsed real time, as reported by Tms#real
488
+ # <tt>%n</tt>:: Replaced by the label string, as reported by Tms#label (Mnemonic: n of "*n*ame")
489
+ #
490
+ # If _format_ is not given, FORMAT is used as default value, detailing the
491
+ # user, system and real elapsed time.
492
+ #
493
+ def format(format = nil, *args)
494
+ str = (format || FORMAT).dup
495
+ .gsub(/(%[-+.\d]*)n/) { "#{$1}s" % label }
496
+ .gsub(/(%[-+.\d]*)u/) { "#{$1}f" % utime }
497
+ .gsub(/(%[-+.\d]*)y/) { "#{$1}f" % stime }
498
+ .gsub(/(%[-+.\d]*)U/) { "#{$1}f" % cutime }
499
+ .gsub(/(%[-+.\d]*)Y/) { "#{$1}f" % cstime }
500
+ .gsub(/(%[-+.\d]*)t/) { "#{$1}f" % total }
501
+ .gsub(/(%[-+.\d]*)r/) { "(#{$1}f)" % real }
502
+ format ? str % args : str
503
+ end
504
+
505
+ #
506
+ # Same as #format.
507
+ #
508
+ def to_s
509
+ format
510
+ end
511
+
512
+ #
513
+ # Returns a new 6-element array, consisting of the
514
+ # label, user CPU time, system CPU time, children's
515
+ # user CPU time, children's system CPU time and elapsed
516
+ # real time.
517
+ #
518
+ def to_a
519
+ [@label, @utime, @stime, @cutime, @cstime, @real]
520
+ end
521
+
522
+ protected
523
+
524
+ #
525
+ # Returns a new Tms object obtained by memberwise operation +op+
526
+ # of the individual times for this Tms object with those of the other
527
+ # Tms object.
528
+ #
529
+ # +op+ can be a mathematical operation such as <tt>+</tt>, <tt>-</tt>,
530
+ # <tt>*</tt>, <tt>/</tt>
531
+ #
532
+ def memberwise(op, x)
533
+ case x
534
+ when Benchmark::Tms
535
+ Benchmark::Tms.new(utime.__send__(op, x.utime),
536
+ stime.__send__(op, x.stime),
537
+ cutime.__send__(op, x.cutime),
538
+ cstime.__send__(op, x.cstime),
539
+ real.__send__(op, x.real)
540
+ )
541
+ else
542
+ Benchmark::Tms.new(utime.__send__(op, x),
543
+ stime.__send__(op, x),
544
+ cutime.__send__(op, x),
545
+ cstime.__send__(op, x),
546
+ real.__send__(op, x)
547
+ )
548
+ end
549
+ end
550
+ end
551
+
552
+ # The default caption string (heading above the output times).
553
+ CAPTION = Benchmark::Tms::CAPTION
554
+
555
+ # The default format string used to display times. See also Benchmark::Tms#format.
556
+ FORMAT = Benchmark::Tms::FORMAT
10
557
  end