opal 0.8.1 → 0.9.0.beta1

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