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.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/.gitmodules +3 -3
- data/.jshintrc +17 -20
- data/.travis.yml +22 -11
- data/CHANGELOG.md +51 -1
- data/CODE_OF_CONDUCT.md +15 -0
- data/CONTRIBUTING.md +125 -9
- data/Gemfile +1 -1
- data/Guardfile +2 -2
- data/README.md +95 -29
- data/Rakefile +1 -1
- data/benchmark/benchmarks +103 -0
- data/benchmark/bm_array_flatten.rb +9 -0
- data/benchmark/bm_array_intersection_numbers.rb +7 -0
- data/benchmark/bm_array_intersection_objects.rb +7 -0
- data/benchmark/bm_array_intersection_strings.rb +7 -0
- data/benchmark/bm_array_join_ary.rb +9 -0
- data/benchmark/bm_array_minus_numbers.rb +7 -0
- data/benchmark/bm_array_minus_objects.rb +7 -0
- data/benchmark/bm_array_minus_strings.rb +7 -0
- data/benchmark/bm_array_union_numbers.rb +7 -0
- data/benchmark/bm_array_union_objects.rb +7 -0
- data/benchmark/bm_array_union_strings.rb +7 -0
- data/benchmark/bm_array_uniq_bang_numbers.rb +5 -0
- data/benchmark/bm_array_uniq_bang_objects.rb +5 -0
- data/benchmark/bm_array_uniq_bang_strings.rb +5 -0
- data/benchmark/bm_array_uniq_numbers.rb +5 -0
- data/benchmark/bm_array_uniq_objects.rb +5 -0
- data/benchmark/bm_array_uniq_strings.rb +5 -0
- data/benchmark/bm_dispatch_bind_table.rb +57 -0
- data/benchmark/bm_dispatch_code_gen.rb +65 -0
- data/benchmark/bm_dispatch_code_gen_if.rb +64 -0
- data/benchmark/bm_dispatch_hardcoded.rb +44 -0
- data/benchmark/bm_dispatch_send.rb +38 -0
- data/benchmark/bm_dispatch_send_table.rb +57 -0
- data/benchmark/bm_hash_assoc_object.rb +11 -0
- data/benchmark/bm_hash_assoc_string.rb +9 -0
- data/benchmark/bm_hash_clone_object.rb +9 -0
- data/benchmark/bm_hash_clone_string.rb +9 -0
- data/benchmark/bm_hash_delete_object.rb +11 -0
- data/benchmark/bm_hash_delete_string.rb +9 -0
- data/benchmark/bm_hash_each_key_object.rb +9 -0
- data/benchmark/bm_hash_each_key_string.rb +9 -0
- data/benchmark/bm_hash_each_object.rb +9 -0
- data/benchmark/bm_hash_each_string.rb +9 -0
- data/benchmark/bm_hash_each_value_object.rb +9 -0
- data/benchmark/bm_hash_each_value_string.rb +9 -0
- data/benchmark/bm_hash_element_reference_object.rb +11 -0
- data/benchmark/bm_hash_element_reference_string.rb +9 -0
- data/benchmark/bm_hash_element_set_object.rb +5 -0
- data/benchmark/bm_hash_element_set_string.rb +5 -0
- data/benchmark/bm_hash_equal_value_object.rb +14 -0
- data/benchmark/bm_hash_equal_value_string.rb +11 -0
- data/benchmark/bm_hash_fetch_object.rb +11 -0
- data/benchmark/bm_hash_fetch_string.rb +9 -0
- data/benchmark/bm_hash_flatten_object.rb +9 -0
- data/benchmark/bm_hash_flatten_string.rb +9 -0
- data/benchmark/bm_hash_has_key_object.rb +11 -0
- data/benchmark/bm_hash_has_key_string.rb +9 -0
- data/benchmark/bm_hash_has_value_object.rb +9 -0
- data/benchmark/bm_hash_has_value_string.rb +9 -0
- data/benchmark/bm_hash_hash_object.rb +9 -0
- data/benchmark/bm_hash_hash_string.rb +9 -0
- data/benchmark/bm_hash_inspect_object.rb +9 -0
- data/benchmark/bm_hash_inspect_string.rb +9 -0
- data/benchmark/bm_hash_invert_object.rb +9 -0
- data/benchmark/bm_hash_invert_string.rb +9 -0
- data/benchmark/bm_hash_keep_if_object.rb +9 -0
- data/benchmark/bm_hash_keep_if_string.rb +9 -0
- data/benchmark/bm_hash_key_object.rb +9 -0
- data/benchmark/bm_hash_key_string.rb +9 -0
- data/benchmark/bm_hash_keys_object.rb +9 -0
- data/benchmark/bm_hash_keys_string.rb +9 -0
- data/benchmark/bm_hash_literal_mixed_large.rb +3 -0
- data/benchmark/bm_hash_literal_mixed_small.rb +3 -0
- data/benchmark/bm_hash_literal_object_large.rb +4 -0
- data/benchmark/bm_hash_literal_object_small.rb +3 -0
- data/benchmark/bm_hash_literal_string_large.rb +4 -0
- data/benchmark/bm_hash_literal_string_small.rb +3 -0
- data/benchmark/bm_hash_merge_object.rb +22 -0
- data/benchmark/bm_hash_merge_string.rb +18 -0
- data/benchmark/bm_hash_rassoc_object.rb +9 -0
- data/benchmark/bm_hash_rassoc_string.rb +9 -0
- data/benchmark/bm_hash_rehash_object.rb +9 -0
- data/benchmark/bm_hash_rehash_string.rb +9 -0
- data/benchmark/bm_hash_reject_bang_object.rb +9 -0
- data/benchmark/bm_hash_reject_bang_string.rb +9 -0
- data/benchmark/bm_hash_reject_object.rb +9 -0
- data/benchmark/bm_hash_reject_string.rb +9 -0
- data/benchmark/bm_hash_replace_object.rb +18 -0
- data/benchmark/bm_hash_replace_string.rb +14 -0
- data/benchmark/bm_hash_select_bang_object.rb +9 -0
- data/benchmark/bm_hash_select_bang_string.rb +9 -0
- data/benchmark/bm_hash_select_object.rb +9 -0
- data/benchmark/bm_hash_select_string.rb +9 -0
- data/benchmark/bm_hash_shift_object.rb +10 -0
- data/benchmark/bm_hash_shift_string.rb +10 -0
- data/benchmark/bm_hash_to_a_object.rb +9 -0
- data/benchmark/bm_hash_to_a_string.rb +9 -0
- data/benchmark/bm_hash_to_h_object.rb +10 -0
- data/benchmark/bm_hash_to_h_string.rb +10 -0
- data/benchmark/bm_hash_values_object.rb +9 -0
- data/benchmark/bm_hash_values_string.rb +9 -0
- data/benchmark/run.rb +48 -0
- data/bin/opal-mspec +1 -1
- data/bin/opal-repl +4 -4
- data/docs/compiled_ruby.md +214 -56
- data/docs/configuring_gems.md +2 -2
- data/docs/faq.md +2 -2
- data/docs/getting_started.md +19 -2
- data/docs/jquery.md +5 -5
- data/docs/opal_parser.md +53 -0
- data/docs/unsupported_features.md +2 -2
- data/docs/upgrading.md +22 -0
- data/docs/using_sprockets.md +15 -0
- data/examples/rack/config.ru +13 -0
- data/examples/sinatra/config.ru +4 -5
- data/lib/mspec/opal/runner.rb +54 -11
- data/lib/opal.rb +1 -1
- data/lib/opal/builder.rb +1 -1
- data/lib/opal/builder_processors.rb +1 -1
- data/lib/opal/cli.rb +17 -13
- data/lib/opal/cli_options.rb +1 -1
- data/lib/opal/compiler.rb +12 -0
- data/lib/opal/config.rb +4 -0
- data/lib/opal/nodes/arglist.rb +5 -7
- data/lib/opal/nodes/call.rb +6 -1
- data/lib/opal/nodes/call_special.rb +74 -0
- data/lib/opal/nodes/def.rb +35 -28
- data/lib/opal/nodes/definitions.rb +3 -5
- data/lib/opal/nodes/for.rb +13 -0
- data/lib/opal/nodes/helpers.rb +15 -1
- data/lib/opal/nodes/if.rb +5 -5
- data/lib/opal/nodes/iter.rb +6 -1
- data/lib/opal/nodes/literal.rb +1 -1
- data/lib/opal/nodes/logic.rb +2 -2
- data/lib/opal/nodes/masgn.rb +1 -2
- data/lib/opal/nodes/module.rb +2 -1
- data/lib/opal/nodes/rescue.rb +10 -1
- data/lib/opal/nodes/scope.rb +8 -2
- data/lib/opal/nodes/singleton_class.rb +1 -1
- data/lib/opal/nodes/top.rb +11 -0
- data/lib/opal/nodes/variables.rb +4 -4
- data/lib/opal/parser.rb +21 -3
- data/lib/opal/parser/grammar.rb +3115 -2961
- data/lib/opal/parser/grammar.y +29 -6
- data/lib/opal/parser/lexer.rb +18 -8
- data/lib/opal/sprockets.rb +85 -0
- data/lib/opal/sprockets/processor.rb +11 -35
- data/lib/opal/sprockets/server.rb +3 -15
- data/lib/opal/version.rb +2 -2
- data/opal.gemspec +4 -4
- data/opal/README.md +9 -0
- data/opal/corelib/array.rb +433 -181
- data/opal/corelib/basic_object.rb +48 -4
- data/opal/corelib/boolean.rb +15 -6
- data/opal/corelib/class.rb +6 -5
- data/opal/corelib/comparable.rb +12 -0
- data/opal/corelib/complex.rb +282 -0
- data/opal/corelib/constants.rb +9 -0
- data/opal/corelib/enumerable.rb +83 -34
- data/opal/corelib/enumerator.rb +3 -1
- data/opal/corelib/error.rb +49 -10
- data/opal/corelib/file.rb +1 -0
- data/opal/corelib/hash.rb +353 -577
- data/opal/corelib/helpers.rb +20 -0
- data/opal/corelib/kernel.rb +114 -59
- data/opal/corelib/math.rb +470 -0
- data/opal/corelib/method.rb +11 -2
- data/opal/corelib/module.rb +96 -96
- data/opal/corelib/{nil_class.rb → nil.rb} +20 -1
- data/opal/corelib/number.rb +751 -0
- data/opal/corelib/numeric.rb +77 -437
- data/opal/corelib/proc.rb +81 -1
- data/opal/corelib/process.rb +27 -0
- data/opal/corelib/rational.rb +358 -0
- data/opal/corelib/regexp.rb +156 -27
- data/opal/corelib/runtime.js +724 -335
- data/opal/corelib/string.rb +93 -104
- data/opal/corelib/string/encoding.rb +177 -0
- data/opal/corelib/string/inheritance.rb +2 -0
- data/opal/corelib/struct.rb +105 -18
- data/opal/corelib/time.rb +267 -146
- data/opal/corelib/unsupported.rb +216 -0
- data/opal/corelib/variables.rb +0 -6
- data/opal/opal.rb +8 -22
- data/opal/opal/base.rb +9 -0
- data/opal/opal/mini.rb +17 -0
- data/spec/README.md +1 -1
- data/spec/filters/bugs/array.rb +38 -136
- data/spec/filters/bugs/{basic_object.rb → basicobject.rb} +14 -15
- data/spec/filters/bugs/class.rb +6 -12
- data/spec/filters/bugs/complex.rb +3 -0
- data/spec/filters/bugs/date.rb +162 -10
- data/spec/filters/bugs/enumerable.rb +31 -58
- data/spec/filters/bugs/enumerator.rb +42 -0
- data/spec/filters/bugs/exception.rb +66 -10
- data/spec/filters/bugs/float.rb +17 -0
- data/spec/filters/bugs/hash.rb +11 -97
- data/spec/filters/bugs/inheritance.rb +5 -0
- data/spec/filters/bugs/integer.rb +28 -0
- data/spec/filters/bugs/kernel.rb +304 -12
- data/spec/filters/bugs/language.rb +133 -399
- data/spec/filters/bugs/language_opal.rb +88 -0
- data/spec/filters/bugs/module.rb +203 -62
- data/spec/filters/bugs/numeric.rb +32 -0
- data/spec/filters/bugs/proc.rb +39 -0
- data/spec/filters/bugs/range.rb +148 -0
- data/spec/filters/bugs/regexp.rb +168 -0
- data/spec/filters/bugs/set.rb +46 -3
- data/spec/filters/bugs/singleton.rb +1 -2
- data/spec/filters/bugs/string.rb +59 -90
- data/spec/filters/bugs/strscan.rb +80 -0
- data/spec/filters/bugs/struct.rb +10 -20
- data/spec/filters/bugs/time.rb +17 -184
- data/spec/filters/bugs/unboundmethod.rb +22 -0
- data/spec/filters/unsupported/array.rb +163 -0
- data/spec/filters/unsupported/basicobject.rb +14 -0
- data/spec/filters/unsupported/bignum.rb +46 -0
- data/spec/filters/unsupported/class.rb +4 -0
- data/spec/filters/unsupported/delegator.rb +5 -0
- data/spec/filters/unsupported/enumerable.rb +11 -0
- data/spec/filters/unsupported/enumerator.rb +8 -9
- data/spec/filters/unsupported/fixnum.rb +14 -0
- data/spec/filters/unsupported/float.rb +41 -7
- data/spec/filters/unsupported/freeze.rb +45 -0
- data/spec/filters/unsupported/hash.rb +50 -0
- data/spec/filters/unsupported/integer.rb +3 -0
- data/spec/filters/unsupported/kernel.rb +31 -0
- data/spec/filters/unsupported/language.rb +17 -0
- data/spec/filters/unsupported/matchdata.rb +30 -0
- data/spec/filters/unsupported/math.rb +3 -0
- data/spec/filters/unsupported/module.rb +5 -3
- data/spec/filters/unsupported/pathname.rb +3 -0
- data/spec/filters/unsupported/privacy.rb +136 -0
- data/spec/filters/unsupported/proc.rb +3 -0
- data/spec/filters/unsupported/regexp.rb +59 -0
- data/spec/filters/unsupported/set.rb +4 -0
- data/spec/filters/unsupported/{marshal.rb → singleton.rb} +4 -2
- data/spec/filters/unsupported/{mutable_strings.rb → string.rb} +456 -336
- data/spec/filters/unsupported/struct.rb +3 -0
- data/spec/filters/unsupported/symbol.rb +5 -0
- data/spec/filters/unsupported/taint.rb +16 -0
- data/spec/filters/unsupported/thread.rb +5 -0
- data/spec/filters/unsupported/time.rb +197 -16
- data/spec/lib/cli_spec.rb +14 -4
- data/spec/lib/compiler_spec.rb +9 -1
- data/spec/lib/parser/call_spec.rb +18 -0
- data/spec/lib/parser/not_spec.rb +2 -8
- data/spec/lib/sprockets_spec.rb +24 -0
- data/spec/opal/core/array/intersection_spec.rb +38 -0
- data/spec/opal/core/array/minus_spec.rb +38 -0
- data/spec/opal/core/array/union_spec.rb +38 -0
- data/spec/opal/core/array/uniq_spec.rb +49 -0
- data/spec/opal/core/exception_spec.rb +7 -0
- data/spec/opal/core/fixtures/require_tree_with_dot/file 1.rb +1 -0
- data/spec/opal/core/fixtures/require_tree_with_dot/file 2.rb +1 -0
- data/spec/opal/core/fixtures/require_tree_with_dot/file 3.rb +1 -0
- data/spec/opal/core/fixtures/require_tree_with_dot/index.rb +3 -0
- data/spec/opal/core/hash/internals_spec.rb +332 -0
- data/spec/opal/core/helpers_spec.rb +14 -0
- data/spec/opal/core/kernel/freeze_spec.rb +1 -1
- data/spec/opal/core/kernel/raise_spec.rb +13 -0
- data/spec/opal/core/kernel/require_tree_spec.rb +9 -0
- data/spec/opal/core/language/class_spec.rb +55 -0
- data/spec/opal/core/language/fixtures/send.rb +1 -0
- data/spec/opal/core/language/keyword_arguments_spec.rb +11 -0
- data/spec/opal/core/language/send_spec.rb +5 -0
- data/spec/opal/core/method/to_proc_spec.rb +28 -0
- data/spec/opal/core/module/name_spec.rb +0 -17
- data/spec/opal/core/runtime/bridged_classes_spec.rb +2 -2
- data/spec/opal/core/runtime/eval_spec.rb +1 -1
- data/spec/opal/core/runtime/method_missing_spec.rb +6 -0
- data/spec/opal/core/runtime_spec.rb +51 -0
- data/spec/opal/stdlib/js_spec.rb +66 -0
- data/spec/opal/stdlib/native/hash_spec.rb +36 -0
- data/spec/rubyspecs +152 -273
- data/spec/spec_helper.rb +10 -11
- data/stdlib/base64.rb +9 -9
- data/stdlib/benchmark.rb +551 -4
- data/stdlib/console.rb +94 -0
- data/stdlib/date.rb +1 -1
- data/stdlib/encoding.rb +1 -170
- data/stdlib/js.rb +56 -0
- data/stdlib/json.rb +9 -14
- data/stdlib/math.rb +1 -370
- data/stdlib/native.rb +133 -63
- data/stdlib/nodejs/file.rb +5 -0
- data/stdlib/nodejs/fileutils.rb +13 -6
- data/stdlib/nodejs/node_modules/js-yaml/node_modules/argparse/README.md +1 -1
- data/stdlib/opal-parser.rb +1 -2
- data/stdlib/ostruct.rb +65 -6
- data/stdlib/pp.rb +2 -4
- data/stdlib/rbconfig.rb +1 -3
- data/stdlib/strscan.rb +164 -28
- data/tasks/benchmarking.rake +88 -0
- data/tasks/testing.rake +181 -55
- data/{lib/mspec/opal/special_calls.rb → tasks/testing/mspec_special_calls.rb} +1 -1
- data/{lib/mspec/opal/sprockets.js → tasks/testing/phantomjs1-sprockets.js} +17 -6
- data/test/opal/test_keyword.rb +590 -0
- data/vendored-minitest/minitest.rb +2 -2
- data/vendored-minitest/test/unit.rb +5 -0
- metadata +229 -62
- data/benchmarks/operators.rb +0 -11
- data/benchmarks/prova.js.rb +0 -13
- data/docs/libraries.md +0 -36
- data/lib/mspec/opal/new.html.erb +0 -1
- data/lib/mspec/opal/rake_task.rb +0 -248
- data/opal/corelib/match_data.rb +0 -128
- data/spec/filters/bugs/math.rb +0 -95
- data/spec/filters/bugs/nil.rb +0 -7
- data/spec/filters/bugs/opal.rb +0 -9
- data/spec/filters/bugs/regular_expressions.rb +0 -41
- data/spec/filters/bugs/stringscanner.rb +0 -33
- data/spec/filters/unsupported/encoding.rb +0 -102
- data/spec/filters/unsupported/frozen.rb +0 -92
- data/spec/filters/unsupported/hash_compare_by_identity.rb +0 -16
- data/spec/filters/unsupported/integer_size.rb +0 -59
- data/spec/filters/unsupported/method_added.rb +0 -10
- data/spec/filters/unsupported/private_constants.rb +0 -30
- data/spec/filters/unsupported/private_methods.rb +0 -55
- data/spec/filters/unsupported/random.rb +0 -4
- data/spec/filters/unsupported/rational_numbers.rb +0 -4
- data/spec/filters/unsupported/regular_expressions.rb +0 -137
- data/spec/filters/unsupported/ruby_exe.rb +0 -5
- data/spec/filters/unsupported/symbols.rb +0 -17
- data/spec/filters/unsupported/tainted.rb +0 -180
- data/spec/filters/unsupported/trusted.rb +0 -88
- data/stdlib/process.rb +0 -10
- data/tasks/documenting.rake +0 -37
data/lib/opal/parser/grammar.y
CHANGED
@@ -8,14 +8,14 @@ token kCLASS kMODULE kDEF kUNDEF kBEGIN kRESCUE kENSURE kEND kIF kUNLESS
|
|
8
8
|
k__FILE__ k__ENCODING__ tIDENTIFIER tFID tGVAR tIVAR tCONSTANT
|
9
9
|
tLABEL tCVAR tNTH_REF tBACK_REF tSTRING_CONTENT tINTEGER tFLOAT
|
10
10
|
tREGEXP_END tUPLUS tUMINUS tUMINUS_NUM tPOW tCMP tEQ tEQQ tNEQ tGEQ tLEQ tANDOP
|
11
|
-
tOROP tMATCH tNMATCH tDOT tDOT2 tDOT3 tAREF tASET tLSHFT tRSHFT
|
11
|
+
tOROP tMATCH tNMATCH tJSDOT tDOT tDOT2 tDOT3 tAREF tASET tLSHFT tRSHFT
|
12
12
|
tCOLON2 tCOLON3 tOP_ASGN tASSOC tLPAREN tLPAREN2 tRPAREN tLPAREN_ARG
|
13
13
|
ARRAY_BEG tRBRACK tLBRACE tLBRACE_ARG tSTAR tSTAR2 tAMPER tAMPER2
|
14
14
|
tTILDE tPERCENT tDIVIDE tPLUS tMINUS tLT tGT tPIPE tBANG tCARET
|
15
15
|
tLCURLY tRCURLY tBACK_REF2 tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG
|
16
16
|
tWORDS_BEG tAWORDS_BEG tSTRING_DBEG tSTRING_DVAR tSTRING_END tSTRING
|
17
17
|
tSYMBOL tNL tEH tCOLON tCOMMA tSPACE tSEMI tLAMBDA tLAMBEG
|
18
|
-
tLBRACK2 tLBRACK tDSTAR
|
18
|
+
tLBRACK2 tLBRACK tJSLBRACK tDSTAR
|
19
19
|
|
20
20
|
prechigh
|
21
21
|
right tBANG tTILDE tUPLUS
|
@@ -150,6 +150,7 @@ rule
|
|
150
150
|
result = new_op_asgn val[1], val[0], val[2]
|
151
151
|
}
|
152
152
|
| primary_value tLBRACK2 aref_args tRBRACK tOP_ASGN command_call
|
153
|
+
| primary_value tJSLBRACK aref_args tRBRACK tOP_ASGN command_call
|
153
154
|
| primary_value tDOT tIDENTIFIER tOP_ASGN command_call
|
154
155
|
{
|
155
156
|
result = s(:op_asgn2, val[0], op_to_setter(val[2]), value(val[3]).to_sym, val[4])
|
@@ -208,6 +209,7 @@ rule
|
|
208
209
|
}
|
209
210
|
|
210
211
|
block_command: block_call
|
212
|
+
| block_call tJSDOT operation2 command_args
|
211
213
|
| block_call tDOT operation2 command_args
|
212
214
|
| block_call tCOLON2 operation2 command_args
|
213
215
|
|
@@ -218,6 +220,11 @@ rule
|
|
218
220
|
result = new_call(nil, val[0], val[1])
|
219
221
|
}
|
220
222
|
| operation command_args cmd_brace_block
|
223
|
+
| primary_value tJSDOT operation2 command_args =tLOWEST
|
224
|
+
{
|
225
|
+
result = new_js_call(val[0], val[2], val[3])
|
226
|
+
}
|
227
|
+
| primary_value tJSDOT operation2 command_args cmd_brace_block
|
221
228
|
| primary_value tDOT operation2 command_args =tLOWEST
|
222
229
|
{
|
223
230
|
result = new_call(val[0], val[2], val[3])
|
@@ -327,6 +334,10 @@ rule
|
|
327
334
|
{
|
328
335
|
result = new_assignable val[0]
|
329
336
|
}
|
337
|
+
| primary_value tJSLBRACK aref_args tRBRACK
|
338
|
+
{
|
339
|
+
result = new_js_attrasgn(val[0], val[2])
|
340
|
+
}
|
330
341
|
| primary_value tLBRACK2 aref_args tRBRACK
|
331
342
|
{
|
332
343
|
result = new_attrasgn(val[0], :[]=, val[2])
|
@@ -428,6 +439,10 @@ rule
|
|
428
439
|
{
|
429
440
|
result = new_op_asgn1(val[0], val[2], val[4], val[5])
|
430
441
|
}
|
442
|
+
| primary_value tJSLBRACK aref_args tRBRACK tOP_ASGN arg
|
443
|
+
{
|
444
|
+
raise ".JS[...] #{val[4]} is not supported"
|
445
|
+
}
|
431
446
|
| primary_value tDOT tIDENTIFIER tOP_ASGN arg
|
432
447
|
{
|
433
448
|
result = s(:op_asgn2, val[0], op_to_setter(val[2]), value(val[3]).to_sym, val[4])
|
@@ -537,8 +552,7 @@ rule
|
|
537
552
|
}
|
538
553
|
| arg tNEQ arg
|
539
554
|
{
|
540
|
-
result =
|
541
|
-
val[0], ['==', []], val[2]))
|
555
|
+
result = new_binary_call(val[0], val[1], val[2])
|
542
556
|
}
|
543
557
|
| arg tMATCH arg
|
544
558
|
{
|
@@ -546,8 +560,7 @@ rule
|
|
546
560
|
}
|
547
561
|
| arg tNMATCH arg
|
548
562
|
{
|
549
|
-
result =
|
550
|
-
val[0], ['=~', []], val[2]))
|
563
|
+
result = new_binary_call(val[0], val[1], val[2])
|
551
564
|
}
|
552
565
|
| tBANG arg
|
553
566
|
{
|
@@ -657,6 +670,7 @@ rule
|
|
657
670
|
{
|
658
671
|
result = val[0]
|
659
672
|
result << new_hash(nil, val[2], nil)
|
673
|
+
result << val[3] if val[3]
|
660
674
|
}
|
661
675
|
| block_arg
|
662
676
|
{
|
@@ -769,6 +783,10 @@ rule
|
|
769
783
|
{
|
770
784
|
result = new_call val[0], [:[], []], val[2]
|
771
785
|
}
|
786
|
+
| primary_value tJSLBRACK aref_args tRBRACK
|
787
|
+
{
|
788
|
+
result = new_js_call val[0], [:[], []], val[2]
|
789
|
+
}
|
772
790
|
| tLBRACK aref_args tRBRACK
|
773
791
|
{
|
774
792
|
result = new_array(val[0], val[1], val[2])
|
@@ -1098,6 +1116,7 @@ opt_block_args_tail: tCOMMA block_args_tail
|
|
1098
1116
|
val[0] << val[1]
|
1099
1117
|
result = val[0]
|
1100
1118
|
}
|
1119
|
+
| block_call tJSDOT operation2 opt_paren_args
|
1101
1120
|
| block_call tDOT operation2 opt_paren_args
|
1102
1121
|
| block_call tCOLON2 operation2 opt_paren_args
|
1103
1122
|
|
@@ -1109,6 +1128,10 @@ opt_block_args_tail: tCOMMA block_args_tail
|
|
1109
1128
|
{
|
1110
1129
|
result = new_call(val[0], val[2], val[3])
|
1111
1130
|
}
|
1131
|
+
| primary_value tJSDOT operation2 opt_paren_args
|
1132
|
+
{
|
1133
|
+
result = new_js_call(val[0], val[2], val[3])
|
1134
|
+
}
|
1112
1135
|
| primary_value tDOT paren_args
|
1113
1136
|
{
|
1114
1137
|
result = new_call(val[0], [:call, []], val[2])
|
data/lib/opal/parser/lexer.rb
CHANGED
@@ -987,6 +987,16 @@ module Opal
|
|
987
987
|
@lex_state = :expr_beg
|
988
988
|
return :tDOT2
|
989
989
|
|
990
|
+
elsif @lex_state != :expr_fname && scan(/\.JS\[/)
|
991
|
+
@lex_state = :expr_beg
|
992
|
+
cond_push 0
|
993
|
+
cmdarg_push 0
|
994
|
+
return :tJSLBRACK
|
995
|
+
|
996
|
+
elsif @lex_state != :expr_fname && scan(/\.JS\./)
|
997
|
+
@lex_state = :expr_dot
|
998
|
+
return :tJSDOT
|
999
|
+
|
990
1000
|
elsif scan(/\./)
|
991
1001
|
@lex_state = :expr_dot unless @lex_state == :expr_fname
|
992
1002
|
return :tDOT
|
@@ -1031,16 +1041,16 @@ module Opal
|
|
1031
1041
|
self.set_arg_state
|
1032
1042
|
return :tCARET
|
1033
1043
|
|
1034
|
-
elsif check(
|
1035
|
-
if scan(
|
1044
|
+
elsif check(/</)
|
1045
|
+
if scan(/<<\=/)
|
1036
1046
|
@lex_state = :expr_beg
|
1037
1047
|
return new_op_asgn('<<')
|
1038
1048
|
|
1039
|
-
elsif scan(
|
1049
|
+
elsif scan(/<</)
|
1040
1050
|
if after_operator?
|
1041
1051
|
@lex_state = :expr_arg
|
1042
1052
|
return :tLSHFT
|
1043
|
-
elsif !after_operator? && !end? && (!arg? || @space_seen)
|
1053
|
+
elsif !after_operator? && !end? && (!arg? || @space_seen) && @lex_state != :expr_class
|
1044
1054
|
if token = heredoc_identifier
|
1045
1055
|
return token
|
1046
1056
|
end
|
@@ -1050,7 +1060,7 @@ module Opal
|
|
1050
1060
|
end
|
1051
1061
|
@lex_state = :expr_beg
|
1052
1062
|
return :tLSHFT
|
1053
|
-
elsif scan(
|
1063
|
+
elsif scan(/<\=\>/)
|
1054
1064
|
if after_operator?
|
1055
1065
|
@lex_state = :expr_arg
|
1056
1066
|
else
|
@@ -1062,11 +1072,11 @@ module Opal
|
|
1062
1072
|
end
|
1063
1073
|
|
1064
1074
|
return :tCMP
|
1065
|
-
elsif scan(
|
1075
|
+
elsif scan(/<\=/)
|
1066
1076
|
self.set_arg_state
|
1067
1077
|
return :tLEQ
|
1068
1078
|
|
1069
|
-
elsif scan(
|
1079
|
+
elsif scan(/</)
|
1070
1080
|
self.set_arg_state
|
1071
1081
|
return :tLT
|
1072
1082
|
end
|
@@ -1228,7 +1238,7 @@ module Opal
|
|
1228
1238
|
elsif check(/[0-9]/)
|
1229
1239
|
return process_numeric
|
1230
1240
|
|
1231
|
-
elsif scan(/(\w)+
|
1241
|
+
elsif scan(/(\w)+(\?|(\!(?!=)))?/)
|
1232
1242
|
return process_identifier scanner.matched, cmd_start
|
1233
1243
|
end
|
1234
1244
|
|
data/lib/opal/sprockets.rb
CHANGED
@@ -1,3 +1,88 @@
|
|
1
1
|
require 'opal/sprockets/processor'
|
2
2
|
require 'opal/sprockets/erb'
|
3
3
|
require 'opal/sprockets/server'
|
4
|
+
|
5
|
+
module Opal
|
6
|
+
module Sprockets
|
7
|
+
# Public: Bootstraps modules loaded by sprockets on `Opal.modules` marking any
|
8
|
+
# non-Opal asset as already loaded.
|
9
|
+
#
|
10
|
+
# name - The name of the main asset to be loaded (with or without ext)
|
11
|
+
# sprockets - A Sprockets::Environment instance
|
12
|
+
#
|
13
|
+
# Example
|
14
|
+
#
|
15
|
+
# Opal::Sprockets.load_asset(Rails.application.assets, 'application')
|
16
|
+
#
|
17
|
+
# Will output the following JavaScript:
|
18
|
+
#
|
19
|
+
# if (typeof(Opal) !== 'undefined') {
|
20
|
+
# Opal.mark_as_loaded("opal");
|
21
|
+
# Opal.mark_as_loaded("jquery.self");
|
22
|
+
# Opal.load("application");
|
23
|
+
# }
|
24
|
+
#
|
25
|
+
# Returns a String containing JavaScript code.
|
26
|
+
def self.load_asset(name, sprockets)
|
27
|
+
asset = sprockets[name.sub(/(\.(js|rb|opal))*#{REGEXP_END}/, '.js')]
|
28
|
+
return '' if asset.nil?
|
29
|
+
|
30
|
+
opal_extnames = sprockets.engines.map do |ext, engine|
|
31
|
+
ext if engine <= ::Opal::Processor
|
32
|
+
end.compact
|
33
|
+
|
34
|
+
module_name = -> asset { asset.logical_path.sub(/\.js#{REGEXP_END}/, '') }
|
35
|
+
path_extnames = -> path { File.basename(path).scan(/\.[^.]+/) }
|
36
|
+
mark_loaded = -> paths { "Opal.loaded([#{paths.map(&:inspect).join(',')}]);" }
|
37
|
+
processed_by_opal = -> asset { (path_extnames[asset.pathname] & opal_extnames).any? }
|
38
|
+
stubbed_files = ::Opal::Processor.stubbed_files
|
39
|
+
|
40
|
+
non_opal_assets = ([asset]+asset.dependencies)
|
41
|
+
.select { |asset| not(processed_by_opal[asset]) }
|
42
|
+
.map { |asset| module_name[asset] }
|
43
|
+
|
44
|
+
loaded = ['opal'] + non_opal_assets + stubbed_files.to_a
|
45
|
+
|
46
|
+
if processed_by_opal[asset]
|
47
|
+
load_asset_code = "Opal.load(#{module_name[asset].inspect});"
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
"if (typeof(Opal) !== 'undefined') { "\
|
52
|
+
"#{mark_loaded[loaded]} "\
|
53
|
+
"#{load_asset_code} "\
|
54
|
+
"}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Public: Generate a `<script>` tag for Opal assets.
|
58
|
+
#
|
59
|
+
# name - The name of the asset to be loaded
|
60
|
+
# options - (default: {}):
|
61
|
+
# :sprockets - A Sprockets::Environment instance
|
62
|
+
# :prefix - The prefix String at which is mounted Sprockets
|
63
|
+
# :debug - Wether to enable debug mode along with sourcemaps support
|
64
|
+
#
|
65
|
+
# Returns a string of HTML code containing `<script>` tags.
|
66
|
+
def self.javascript_include_tag(name, options = {})
|
67
|
+
sprockets = options.fetch(:sprockets)
|
68
|
+
prefix = options.fetch(:prefix)
|
69
|
+
debug = options.fetch(:debug)
|
70
|
+
|
71
|
+
asset = sprockets[name]
|
72
|
+
raise "Cannot find asset: #{name}" if asset.nil?
|
73
|
+
scripts = []
|
74
|
+
|
75
|
+
if debug
|
76
|
+
asset.to_a.map do |dependency|
|
77
|
+
scripts << %{<script src="#{prefix}/#{dependency.logical_path}?body=1"></script>}
|
78
|
+
end
|
79
|
+
else
|
80
|
+
scripts << %{<script src="#{prefix}/#{name}.js"></script>}
|
81
|
+
end
|
82
|
+
|
83
|
+
scripts << %{<script>#{::Opal::Sprockets.load_asset(name, sprockets)}</script>}
|
84
|
+
|
85
|
+
scripts.join "\n"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -8,12 +8,12 @@ require 'opal/sprockets/source_map_server'
|
|
8
8
|
$OPAL_SOURCE_MAPS = {}
|
9
9
|
|
10
10
|
module Opal
|
11
|
-
# The Processor class is used to make ruby files (with rb or opal
|
12
|
-
# available to any sprockets based server. Processor will then
|
13
|
-
# ruby source file to build.
|
11
|
+
# Internal: The Processor class is used to make ruby files (with .rb or .opal
|
12
|
+
# extensions) available to any sprockets based server. Processor will then
|
13
|
+
# get passed any ruby source file to build.
|
14
14
|
class Processor < TiltTemplate
|
15
|
-
#
|
16
|
-
#
|
15
|
+
# Deprecated: Support legacy accessors to default options,
|
16
|
+
# now moved to Opal::Config
|
17
17
|
Opal::Config.default_config.keys.each do |config_option|
|
18
18
|
define_singleton_method(config_option) { Opal::Config.config[config_option] }
|
19
19
|
define_singleton_method("#{config_option}=") { |value| Opal::Config.config[config_option] = value }
|
@@ -36,7 +36,8 @@ module Opal
|
|
36
36
|
# In Sprockets 3 logical_path has an odd behavior when the filename is "index"
|
37
37
|
# thus we need to bake our own logical_path
|
38
38
|
filename = context.respond_to?(:filename) ? context.filename : context.pathname.to_s
|
39
|
-
|
39
|
+
root_path_regexp = Regexp.escape(context.root_path)
|
40
|
+
logical_path = filename.gsub(%r{^#{root_path_regexp}/?(.*?)#{sprockets_extnames_regexp}}, '\1')
|
40
41
|
|
41
42
|
compiler_options = self.compiler_options.merge(file: logical_path)
|
42
43
|
|
@@ -78,6 +79,8 @@ module Opal
|
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
82
|
+
# Internal: Add files required with `require_tree` as asset dependencies.
|
83
|
+
#
|
81
84
|
# Mimics (v2) Sprockets::DirectiveProcessor#process_require_tree_directive
|
82
85
|
def process_required_trees(required_trees, context)
|
83
86
|
return if required_trees.empty?
|
@@ -122,36 +125,9 @@ module Opal
|
|
122
125
|
end
|
123
126
|
end
|
124
127
|
|
128
|
+
# Deprecated: Moved to Opal::Sprockets.load_asset(sprockets, name)
|
125
129
|
def self.load_asset_code(sprockets, name)
|
126
|
-
|
127
|
-
return '' if asset.nil?
|
128
|
-
|
129
|
-
opal_extnames = sprockets.engines.map do |ext, engine|
|
130
|
-
ext if engine <= ::Opal::Processor
|
131
|
-
end.compact
|
132
|
-
|
133
|
-
module_name = -> asset { asset.logical_path.sub(/\.js#{REGEXP_END}/, '') }
|
134
|
-
path_extnames = -> path { File.basename(path).scan(/\.[^.]+/) }
|
135
|
-
mark_as_loaded = -> path { "Opal.mark_as_loaded(#{path.inspect});" }
|
136
|
-
processed_by_opal = -> asset { (path_extnames[asset.pathname] & opal_extnames).any? }
|
137
|
-
|
138
|
-
non_opal_assets = ([asset]+asset.dependencies)
|
139
|
-
.select { |asset| not(processed_by_opal[asset]) }
|
140
|
-
.map { |asset| module_name[asset] }
|
141
|
-
|
142
|
-
mark_as_loaded = (['opal'] + non_opal_assets + stubbed_files.to_a)
|
143
|
-
.map { |path| mark_as_loaded[path] }
|
144
|
-
|
145
|
-
if processed_by_opal[asset]
|
146
|
-
load_asset_code = "Opal.load(#{module_name[asset].inspect});"
|
147
|
-
end
|
148
|
-
|
149
|
-
<<-JS
|
150
|
-
if (typeof(Opal) !== 'undefined') {
|
151
|
-
#{mark_as_loaded.join("\n")}
|
152
|
-
#{load_asset_code}
|
153
|
-
}
|
154
|
-
JS
|
130
|
+
::Opal::Sprockets.load_asset(name, sprockets)
|
155
131
|
end
|
156
132
|
|
157
133
|
def self.stubbed_files
|
@@ -117,6 +117,7 @@ module Opal
|
|
117
117
|
raise "index does not exist: #{@index_path}" unless File.exist?(@index_path)
|
118
118
|
Tilt.new(@index_path).render(self)
|
119
119
|
else
|
120
|
+
raise "Main asset path not configured (set 'main' within Opal::Server.new block)" if @server.main.nil?
|
120
121
|
source
|
121
122
|
end
|
122
123
|
end
|
@@ -124,21 +125,7 @@ module Opal
|
|
124
125
|
def javascript_include_tag name
|
125
126
|
sprockets = @server.sprockets
|
126
127
|
prefix = @server.prefix
|
127
|
-
|
128
|
-
raise "Cannot find asset: #{name}" if asset.nil?
|
129
|
-
scripts = []
|
130
|
-
|
131
|
-
if @server.debug
|
132
|
-
asset.to_a.map do |dependency|
|
133
|
-
scripts << %{<script src="#{prefix}/#{dependency.logical_path}?body=1"></script>}
|
134
|
-
end
|
135
|
-
else
|
136
|
-
scripts << %{<script src="#{prefix}/#{name}.js"></script>}
|
137
|
-
end
|
138
|
-
|
139
|
-
scripts << %{<script>#{Opal::Processor.load_asset_code(sprockets, name)}</script>}
|
140
|
-
|
141
|
-
scripts.join "\n"
|
128
|
+
::Opal::Sprockets.javascript_include_tag(name, sprockets: @server.sprockets, prefix: @server.prefix, debug: @server.debug)
|
142
129
|
end
|
143
130
|
|
144
131
|
def source
|
@@ -146,6 +133,7 @@ module Opal
|
|
146
133
|
<!DOCTYPE html>
|
147
134
|
<html>
|
148
135
|
<head>
|
136
|
+
<meta charset="utf-8">
|
149
137
|
<title>Opal Server</title>
|
150
138
|
</head>
|
151
139
|
<body>
|
data/lib/opal/version.rb
CHANGED
data/opal.gemspec
CHANGED
@@ -9,16 +9,16 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.author = 'Adam Beynon'
|
10
10
|
s.email = 'adam.beynon@gmail.com'
|
11
11
|
s.homepage = 'http://opalrb.org'
|
12
|
-
s.summary = 'Ruby runtime and core library for
|
13
|
-
s.description = 'Ruby runtime and core library for
|
12
|
+
s.summary = 'Ruby runtime and core library for JavaScript'
|
13
|
+
s.description = 'Ruby runtime and core library for JavaScript.'
|
14
14
|
s.license = 'MIT'
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
|
21
|
-
required_ruby_version = '>= 1.9.3'
|
21
|
+
s.required_ruby_version = '>= 1.9.3'
|
22
22
|
|
23
23
|
s.add_dependency 'sourcemap', '~> 0.1.0'
|
24
24
|
s.add_dependency 'sprockets', '~> 3.1'
|
data/opal/README.md
CHANGED
@@ -4,3 +4,12 @@ This is the Opal corelib implementation API documentation.
|
|
4
4
|
The whole corelib is loaded upon `require 'opal'`.
|
5
5
|
|
6
6
|
The `runtime.js` documentation is [available here](runtime.js.html)
|
7
|
+
|
8
|
+
# Cherry-picking
|
9
|
+
|
10
|
+
Note that `require 'opal'` will load all of the corelib, which is likely to
|
11
|
+
have a ton of stuff you don't need.
|
12
|
+
|
13
|
+
If you're concerned about runtime size, you can `require 'opal/base'` and
|
14
|
+
require anything you need, or `require 'opal/mini'` to have a working Ruby
|
15
|
+
without *useless* stuff.
|
data/opal/corelib/array.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'corelib/enumerable'
|
2
|
+
require 'corelib/numeric'
|
2
3
|
|
3
|
-
class Array
|
4
|
+
class Array < `Array`
|
4
5
|
include Enumerable
|
5
6
|
|
6
7
|
# Mark all javascript arrays as being valid ruby arrays
|
@@ -10,18 +11,17 @@ class Array
|
|
10
11
|
objects
|
11
12
|
end
|
12
13
|
|
13
|
-
def initialize(
|
14
|
-
self.class.new(*args)
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.new(size = nil, obj = nil, &block)
|
14
|
+
def initialize(size = nil, obj = nil, &block)
|
18
15
|
if `arguments.length > 2`
|
19
16
|
raise ArgumentError, "wrong number of arguments (#{`arguments.length`} for 0..2)"
|
20
17
|
end
|
21
18
|
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
%x{
|
20
|
+
if (arguments.length === 0) {
|
21
|
+
self.splice(0, self.length);
|
22
|
+
return self;
|
23
|
+
}
|
24
|
+
}
|
25
25
|
|
26
26
|
if `arguments.length === 1`
|
27
27
|
if Array === size
|
@@ -38,29 +38,34 @@ class Array
|
|
38
38
|
end
|
39
39
|
|
40
40
|
%x{
|
41
|
-
|
41
|
+
self.splice(0, self.length);
|
42
|
+
var i, value;
|
42
43
|
|
43
44
|
if (block === nil) {
|
44
|
-
for (
|
45
|
-
|
45
|
+
for (i = 0; i < size; i++) {
|
46
|
+
self.push(obj);
|
46
47
|
}
|
47
48
|
}
|
48
49
|
else {
|
49
|
-
for (
|
50
|
+
for (i = 0, value; i < size; i++) {
|
50
51
|
value = block(i);
|
51
52
|
|
52
53
|
if (value === $breaker) {
|
53
54
|
return $breaker.$v;
|
54
55
|
}
|
55
56
|
|
56
|
-
|
57
|
+
self[i] = value;
|
57
58
|
}
|
58
59
|
}
|
59
60
|
|
60
|
-
return
|
61
|
+
return self;
|
61
62
|
}
|
62
63
|
end
|
63
64
|
|
65
|
+
def self.new(*args, &block)
|
66
|
+
[].initialize(*args, &block)
|
67
|
+
end
|
68
|
+
|
64
69
|
def self.try_convert(obj)
|
65
70
|
Opal.coerce_to? obj, Array, :to_ary
|
66
71
|
end
|
@@ -73,21 +78,16 @@ class Array
|
|
73
78
|
end
|
74
79
|
|
75
80
|
%x{
|
76
|
-
var result = [],
|
77
|
-
seen = {};
|
78
|
-
|
79
|
-
for (var i = 0, length = self.length; i < length; i++) {
|
80
|
-
var item = self[i];
|
81
|
+
var result = [], hash = #{{}}, i, length, item;
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
for (i = 0, length = other.length; i < length; i++) {
|
84
|
+
Opal.hash_put(hash, other[i], true);
|
85
|
+
}
|
85
86
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
}
|
87
|
+
for (i = 0, length = self.length; i < length; i++) {
|
88
|
+
item = self[i];
|
89
|
+
if (Opal.hash_delete(hash, item) !== undefined) {
|
90
|
+
result.push(item);
|
91
91
|
}
|
92
92
|
}
|
93
93
|
|
@@ -103,32 +103,22 @@ class Array
|
|
103
103
|
end
|
104
104
|
|
105
105
|
%x{
|
106
|
-
var
|
107
|
-
seen = {};
|
106
|
+
var hash = #{{}}, i, length, item;
|
108
107
|
|
109
|
-
for (
|
110
|
-
|
111
|
-
|
112
|
-
if (!seen[item]) {
|
113
|
-
seen[item] = true;
|
114
|
-
result.push(item);
|
115
|
-
}
|
108
|
+
for (i = 0, length = self.length; i < length; i++) {
|
109
|
+
Opal.hash_put(hash, self[i], true);
|
116
110
|
}
|
117
111
|
|
118
|
-
for (
|
119
|
-
|
120
|
-
|
121
|
-
if (!seen[item]) {
|
122
|
-
seen[item] = true;
|
123
|
-
result.push(item);
|
124
|
-
}
|
112
|
+
for (i = 0, length = other.length; i < length; i++) {
|
113
|
+
Opal.hash_put(hash, other[i], true);
|
125
114
|
}
|
126
|
-
|
115
|
+
|
116
|
+
return hash.$keys();
|
127
117
|
}
|
128
118
|
end
|
129
119
|
|
130
120
|
def *(other)
|
131
|
-
return
|
121
|
+
return join(other.to_str) if other.respond_to? :to_str
|
132
122
|
|
133
123
|
unless other.respond_to? :to_int
|
134
124
|
raise TypeError, "no implicit conversion of #{other.class} into Integer"
|
@@ -172,17 +162,15 @@ class Array
|
|
172
162
|
return clone if `other.length === 0`
|
173
163
|
|
174
164
|
%x{
|
175
|
-
var
|
176
|
-
result = [];
|
165
|
+
var result = [], hash = #{{}}, i, length, item;
|
177
166
|
|
178
|
-
for (
|
179
|
-
|
167
|
+
for (i = 0, length = other.length; i < length; i++) {
|
168
|
+
Opal.hash_put(hash, other[i], true);
|
180
169
|
}
|
181
170
|
|
182
|
-
for (
|
183
|
-
|
184
|
-
|
185
|
-
if (!seen[item]) {
|
171
|
+
for (i = 0, length = self.length; i < length; i++) {
|
172
|
+
item = self[i];
|
173
|
+
if (Opal.hash_get(hash, item) === undefined) {
|
186
174
|
result.push(item);
|
187
175
|
}
|
188
176
|
}
|
@@ -211,11 +199,9 @@ class Array
|
|
211
199
|
return 0;
|
212
200
|
}
|
213
201
|
|
214
|
-
|
215
|
-
return (self.length > other.length) ? 1 : -1;
|
216
|
-
}
|
202
|
+
var count = Math.min(self.length, other.length);
|
217
203
|
|
218
|
-
for (var i = 0
|
204
|
+
for (var i = 0; i < count; i++) {
|
219
205
|
var tmp = #{`self[i]` <=> `other[i]`};
|
220
206
|
|
221
207
|
if (tmp !== 0) {
|
@@ -223,7 +209,7 @@ class Array
|
|
223
209
|
}
|
224
210
|
}
|
225
211
|
|
226
|
-
return
|
212
|
+
return #{`self.length` <=> `other.length`};
|
227
213
|
}
|
228
214
|
end
|
229
215
|
|
@@ -277,12 +263,14 @@ class Array
|
|
277
263
|
end
|
278
264
|
|
279
265
|
def [](index, length = undefined)
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
266
|
+
%x{
|
267
|
+
var size = self.length,
|
268
|
+
exclude, from, to;
|
269
|
+
|
270
|
+
if (index.$$is_range) {
|
271
|
+
exclude = index.exclude;
|
272
|
+
from = #{Opal.coerce_to `index.begin`, Integer, :to_int};
|
273
|
+
to = #{Opal.coerce_to `index.end`, Integer, :to_int};
|
286
274
|
|
287
275
|
if (from < 0) {
|
288
276
|
from += size;
|
@@ -310,11 +298,8 @@ class Array
|
|
310
298
|
|
311
299
|
return self.slice(from, to);
|
312
300
|
}
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
%x{
|
317
|
-
var size = self.length;
|
301
|
+
else {
|
302
|
+
index = #{Opal.coerce_to(index, Integer, :to_int)};
|
318
303
|
|
319
304
|
if (index < 0) {
|
320
305
|
index += size;
|
@@ -341,10 +326,14 @@ class Array
|
|
341
326
|
return self.slice(index, index + length);
|
342
327
|
}
|
343
328
|
}
|
344
|
-
|
329
|
+
}
|
345
330
|
end
|
346
331
|
|
347
332
|
def []=(index, value, extra = undefined)
|
333
|
+
%x{
|
334
|
+
var i, size = self.length;
|
335
|
+
}
|
336
|
+
|
348
337
|
if Range === index
|
349
338
|
if Array === value
|
350
339
|
data = value.to_a
|
@@ -355,8 +344,7 @@ class Array
|
|
355
344
|
end
|
356
345
|
|
357
346
|
%x{
|
358
|
-
var
|
359
|
-
exclude = index.exclude,
|
347
|
+
var exclude = index.exclude,
|
360
348
|
from = #{Opal.coerce_to `index.begin`, Integer, :to_int},
|
361
349
|
to = #{Opal.coerce_to `index.end`, Integer, :to_int};
|
362
350
|
|
@@ -377,7 +365,7 @@ class Array
|
|
377
365
|
}
|
378
366
|
|
379
367
|
if (from > size) {
|
380
|
-
for (
|
368
|
+
for (i = size; i < from; i++) {
|
381
369
|
self[i] = nil;
|
382
370
|
}
|
383
371
|
}
|
@@ -408,10 +396,10 @@ class Array
|
|
408
396
|
end
|
409
397
|
|
410
398
|
%x{
|
411
|
-
var
|
412
|
-
|
413
|
-
|
414
|
-
|
399
|
+
var old;
|
400
|
+
|
401
|
+
index = #{Opal.coerce_to index, Integer, :to_int};
|
402
|
+
length = #{Opal.coerce_to length, Integer, :to_int};
|
415
403
|
|
416
404
|
if (index < 0) {
|
417
405
|
old = index;
|
@@ -427,7 +415,7 @@ class Array
|
|
427
415
|
}
|
428
416
|
|
429
417
|
if (index > size) {
|
430
|
-
for (
|
418
|
+
for (i = size; i < index; i++) {
|
431
419
|
self[i] = nil;
|
432
420
|
}
|
433
421
|
}
|
@@ -515,15 +503,24 @@ class Array
|
|
515
503
|
end
|
516
504
|
|
517
505
|
def cycle(n = nil, &block)
|
506
|
+
return enum_for(:cycle, n) {
|
507
|
+
if n == nil
|
508
|
+
Float::INFINITY
|
509
|
+
else
|
510
|
+
n = Opal.coerce_to!(n, Integer, :to_int)
|
511
|
+
n > 0 ? self.enumerator_size * n : 0
|
512
|
+
end
|
513
|
+
} unless block_given?
|
514
|
+
|
518
515
|
return if empty? || n == 0
|
519
516
|
|
520
|
-
|
517
|
+
%x{
|
518
|
+
var i, length, value;
|
521
519
|
|
522
|
-
|
523
|
-
%x{
|
520
|
+
if (n === nil) {
|
524
521
|
while (true) {
|
525
|
-
for (
|
526
|
-
|
522
|
+
for (i = 0, length = self.length; i < length; i++) {
|
523
|
+
value = Opal.yield1(block, self[i]);
|
527
524
|
|
528
525
|
if (value === $breaker) {
|
529
526
|
return $breaker.$v;
|
@@ -531,17 +528,15 @@ class Array
|
|
531
528
|
}
|
532
529
|
}
|
533
530
|
}
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
%x{
|
531
|
+
else {
|
532
|
+
n = #{Opal.coerce_to!(n, Integer, :to_int)};
|
538
533
|
if (n <= 0) {
|
539
534
|
return self;
|
540
535
|
}
|
541
536
|
|
542
537
|
while (n > 0) {
|
543
|
-
for (
|
544
|
-
|
538
|
+
for (i = 0, length = self.length; i < length; i++) {
|
539
|
+
value = Opal.yield1(block, self[i]);
|
545
540
|
|
546
541
|
if (value === $breaker) {
|
547
542
|
return $breaker.$v;
|
@@ -551,7 +546,7 @@ class Array
|
|
551
546
|
n--;
|
552
547
|
}
|
553
548
|
}
|
554
|
-
|
549
|
+
}
|
555
550
|
|
556
551
|
self
|
557
552
|
end
|
@@ -564,6 +559,7 @@ class Array
|
|
564
559
|
|
565
560
|
def clone
|
566
561
|
copy = []
|
562
|
+
copy.copy_singleton_methods(self)
|
567
563
|
copy.initialize_clone(self)
|
568
564
|
copy
|
569
565
|
end
|
@@ -579,7 +575,7 @@ class Array
|
|
579
575
|
end
|
580
576
|
|
581
577
|
def collect(&block)
|
582
|
-
return enum_for
|
578
|
+
return enum_for(:collect){self.size} unless block_given?
|
583
579
|
|
584
580
|
%x{
|
585
581
|
var result = [];
|
@@ -599,7 +595,7 @@ class Array
|
|
599
595
|
end
|
600
596
|
|
601
597
|
def collect!(&block)
|
602
|
-
return enum_for
|
598
|
+
return enum_for(:collect!){self.size} unless block_given?
|
603
599
|
|
604
600
|
%x{
|
605
601
|
for (var i = 0, length = self.length; i < length; i++) {
|
@@ -616,9 +612,23 @@ class Array
|
|
616
612
|
self
|
617
613
|
end
|
618
614
|
|
615
|
+
%x{
|
616
|
+
function binomial_coefficient(n, k) {
|
617
|
+
if (n === k || k === 0) {
|
618
|
+
return 1;
|
619
|
+
}
|
620
|
+
|
621
|
+
if (k > 0 && n > k) {
|
622
|
+
return binomial_coefficient(n - 1, k - 1) + binomial_coefficient(n - 1, k);
|
623
|
+
}
|
624
|
+
|
625
|
+
return 0;
|
626
|
+
}
|
627
|
+
}
|
628
|
+
|
619
629
|
def combination(n)
|
620
630
|
num = Opal.coerce_to! n, Integer, :to_int
|
621
|
-
return enum_for
|
631
|
+
return enum_for(:combination, num){ `binomial_coefficient(#{self}.length, num)` } unless block_given?
|
622
632
|
|
623
633
|
%x{
|
624
634
|
var i, length, stack, chosen, lev, done, next;
|
@@ -755,7 +765,7 @@ class Array
|
|
755
765
|
end
|
756
766
|
|
757
767
|
def delete_if(&block)
|
758
|
-
return enum_for
|
768
|
+
return enum_for(:delete_if){self.size} unless block_given?
|
759
769
|
|
760
770
|
%x{
|
761
771
|
for (var i = 0, length = self.length, value; i < length; i++) {
|
@@ -785,10 +795,8 @@ class Array
|
|
785
795
|
}
|
786
796
|
end
|
787
797
|
|
788
|
-
alias dup clone
|
789
|
-
|
790
798
|
def each(&block)
|
791
|
-
return enum_for
|
799
|
+
return enum_for(:each){self.size} unless block_given?
|
792
800
|
|
793
801
|
%x{
|
794
802
|
for (var i = 0, length = self.length; i < length; i++) {
|
@@ -804,7 +812,7 @@ class Array
|
|
804
812
|
end
|
805
813
|
|
806
814
|
def each_index(&block)
|
807
|
-
return enum_for
|
815
|
+
return enum_for(:each_index){self.size} unless block_given?
|
808
816
|
|
809
817
|
%x{
|
810
818
|
for (var i = 0, length = self.length; i < length; i++) {
|
@@ -900,6 +908,10 @@ class Array
|
|
900
908
|
end
|
901
909
|
|
902
910
|
def fill(*args, &block)
|
911
|
+
%x{
|
912
|
+
var i, length, value;
|
913
|
+
}
|
914
|
+
|
903
915
|
if block
|
904
916
|
if `args.length > 2`
|
905
917
|
raise ArgumentError, "wrong number of arguments (#{args.length} for 0..2)"
|
@@ -949,7 +961,7 @@ class Array
|
|
949
961
|
|
950
962
|
if `left > #@length`
|
951
963
|
%x{
|
952
|
-
for (
|
964
|
+
for (i = #@length; i < right; i++) {
|
953
965
|
self[i] = nil;
|
954
966
|
}
|
955
967
|
}
|
@@ -961,8 +973,8 @@ class Array
|
|
961
973
|
|
962
974
|
if block
|
963
975
|
%x{
|
964
|
-
for (
|
965
|
-
|
976
|
+
for (length = #@length; left < right; left++) {
|
977
|
+
value = block(left);
|
966
978
|
|
967
979
|
if (value === $breaker) {
|
968
980
|
return $breaker.$v;
|
@@ -973,7 +985,7 @@ class Array
|
|
973
985
|
}
|
974
986
|
else
|
975
987
|
%x{
|
976
|
-
for (
|
988
|
+
for (length = #@length; left < right; left++) {
|
977
989
|
self[left] = #{obj};
|
978
990
|
}
|
979
991
|
}
|
@@ -1000,14 +1012,13 @@ class Array
|
|
1000
1012
|
|
1001
1013
|
def flatten(level = undefined)
|
1002
1014
|
%x{
|
1003
|
-
var object_id = #{`self`.object_id};
|
1004
|
-
|
1005
1015
|
function _flatten(array, level) {
|
1006
|
-
var
|
1007
|
-
result = [],
|
1016
|
+
var result = [],
|
1008
1017
|
i, length,
|
1009
1018
|
item, ary;
|
1010
1019
|
|
1020
|
+
array = #{`array`.to_a};
|
1021
|
+
|
1011
1022
|
for (i = 0, length = array.length; i < length; i++) {
|
1012
1023
|
item = array[i];
|
1013
1024
|
|
@@ -1027,7 +1038,7 @@ class Array
|
|
1027
1038
|
#{raise TypeError};
|
1028
1039
|
}
|
1029
1040
|
|
1030
|
-
if (
|
1041
|
+
if (ary === self) {
|
1031
1042
|
#{raise ArgumentError};
|
1032
1043
|
}
|
1033
1044
|
|
@@ -1077,17 +1088,42 @@ class Array
|
|
1077
1088
|
|
1078
1089
|
def hash
|
1079
1090
|
%x{
|
1080
|
-
var
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1091
|
+
var top = (Opal.hash_ids == undefined),
|
1092
|
+
result = ['A'],
|
1093
|
+
hash_id = self.$object_id(),
|
1094
|
+
item, i, key;
|
1095
|
+
|
1096
|
+
try {
|
1097
|
+
if (top) {
|
1098
|
+
Opal.hash_ids = {};
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
if (Opal.hash_ids.hasOwnProperty(hash_id)) {
|
1102
|
+
return 'self';
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
for (key in Opal.hash_ids) {
|
1106
|
+
if (Opal.hash_ids.hasOwnProperty(key)) {
|
1107
|
+
item = Opal.hash_ids[key];
|
1108
|
+
if (#{eql?(`item`)}) {
|
1109
|
+
return 'self';
|
1110
|
+
}
|
1111
|
+
}
|
1112
|
+
}
|
1113
|
+
|
1114
|
+
Opal.hash_ids[hash_id] = self;
|
1115
|
+
|
1116
|
+
for (i = 0; i < self.length; i++) {
|
1117
|
+
item = self[i];
|
1118
|
+
result.push(item.$hash());
|
1119
|
+
}
|
1120
|
+
|
1121
|
+
return result.join(',');
|
1122
|
+
} finally {
|
1123
|
+
if (top) {
|
1124
|
+
delete Opal.hash_ids;
|
1088
1125
|
}
|
1089
1126
|
}
|
1090
|
-
return hash.join(',');
|
1091
1127
|
}
|
1092
1128
|
end
|
1093
1129
|
|
@@ -1105,15 +1141,17 @@ class Array
|
|
1105
1141
|
|
1106
1142
|
def index(object=undefined, &block)
|
1107
1143
|
%x{
|
1144
|
+
var i, length, value;
|
1145
|
+
|
1108
1146
|
if (object != null) {
|
1109
|
-
for (
|
1147
|
+
for (i = 0, length = self.length; i < length; i++) {
|
1110
1148
|
if (#{`self[i]` == object}) {
|
1111
1149
|
return i;
|
1112
1150
|
}
|
1113
1151
|
}
|
1114
1152
|
}
|
1115
1153
|
else if (block !== nil) {
|
1116
|
-
for (
|
1154
|
+
for (i = 0, length = self.length; i < length; i++) {
|
1117
1155
|
if ((value = block(self[i])) === $breaker) {
|
1118
1156
|
return $breaker.$v;
|
1119
1157
|
}
|
@@ -1185,13 +1223,13 @@ class Array
|
|
1185
1223
|
|
1186
1224
|
%x{
|
1187
1225
|
var result = [];
|
1188
|
-
var
|
1226
|
+
var i, length, item, tmp;
|
1189
1227
|
|
1190
|
-
for (
|
1191
|
-
|
1228
|
+
for (i = 0, length = self.length; i < length; i++) {
|
1229
|
+
item = self[i];
|
1192
1230
|
|
1193
1231
|
if (#{Opal.respond_to? `item`, :to_str}) {
|
1194
|
-
|
1232
|
+
tmp = #{`item`.to_str};
|
1195
1233
|
|
1196
1234
|
if (tmp !== nil) {
|
1197
1235
|
result.push(#{`tmp`.to_s});
|
@@ -1201,9 +1239,9 @@ class Array
|
|
1201
1239
|
}
|
1202
1240
|
|
1203
1241
|
if (#{Opal.respond_to? `item`, :to_ary}) {
|
1204
|
-
|
1242
|
+
tmp = #{`item`.to_ary};
|
1205
1243
|
|
1206
|
-
if (
|
1244
|
+
if (tmp === self) {
|
1207
1245
|
#{raise ArgumentError};
|
1208
1246
|
}
|
1209
1247
|
|
@@ -1215,7 +1253,7 @@ class Array
|
|
1215
1253
|
}
|
1216
1254
|
|
1217
1255
|
if (#{Opal.respond_to? `item`, :to_s}) {
|
1218
|
-
|
1256
|
+
tmp = #{`item`.to_s};
|
1219
1257
|
|
1220
1258
|
if (tmp !== nil) {
|
1221
1259
|
result.push(tmp);
|
@@ -1237,7 +1275,7 @@ class Array
|
|
1237
1275
|
end
|
1238
1276
|
|
1239
1277
|
def keep_if(&block)
|
1240
|
-
return enum_for
|
1278
|
+
return enum_for(:keep_if){self.size} unless block_given?
|
1241
1279
|
|
1242
1280
|
%x{
|
1243
1281
|
for (var i = 0, length = self.length, value; i < length; i++) {
|
@@ -1284,7 +1322,73 @@ class Array
|
|
1284
1322
|
alias map collect
|
1285
1323
|
|
1286
1324
|
alias map! collect!
|
1325
|
+
|
1326
|
+
def permutation(num = undefined, &block)
|
1327
|
+
return enum_for(:permutation, num){self.size} unless block_given?
|
1328
|
+
|
1329
|
+
%x{
|
1330
|
+
var permute, offensive, output;
|
1331
|
+
|
1332
|
+
if (num === undefined) {
|
1333
|
+
num = self.length;
|
1334
|
+
}
|
1335
|
+
else {
|
1336
|
+
num = #{ Opal.coerce_to num, Integer, :to_int }
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
if (num < 0 || self.length < num) {
|
1340
|
+
// no permutations, yield nothing
|
1341
|
+
}
|
1342
|
+
else if (num === 0) {
|
1343
|
+
// exactly one permutation: the zero-length array
|
1344
|
+
#{ yield [] }
|
1345
|
+
}
|
1346
|
+
else if (num === 1) {
|
1347
|
+
// this is a special, easy case
|
1348
|
+
for (var i = 0; i < self.length; i++) {
|
1349
|
+
#{ yield `[self[i]]` }
|
1350
|
+
}
|
1351
|
+
}
|
1352
|
+
else {
|
1353
|
+
// this is the general case
|
1354
|
+
#{ perm = Array.new(num) }
|
1355
|
+
#{ used = Array.new(`self.length`, false) }
|
1356
|
+
|
1357
|
+
permute = function(num, perm, index, used, blk) {
|
1358
|
+
self = this;
|
1359
|
+
for(var i = 0; i < self.length; i++){
|
1360
|
+
if(#{ !used[`i`] }) {
|
1361
|
+
perm[index] = i;
|
1362
|
+
if(index < num - 1) {
|
1363
|
+
used[i] = true;
|
1364
|
+
permute.call(self, num, perm, index + 1, used, blk);
|
1365
|
+
used[i] = false;
|
1366
|
+
}
|
1367
|
+
else {
|
1368
|
+
output = [];
|
1369
|
+
for (var j = 0; j < perm.length; j++) {
|
1370
|
+
output.push(self[perm[j]]);
|
1371
|
+
}
|
1372
|
+
Opal.yield1(blk, output);
|
1373
|
+
}
|
1374
|
+
}
|
1375
|
+
}
|
1376
|
+
}
|
1377
|
+
|
1378
|
+
if (#{block_given?}) {
|
1379
|
+
// offensive (both definitions) copy.
|
1380
|
+
offensive = self.slice();
|
1381
|
+
permute.call(offensive, num, perm, 0, used, block);
|
1382
|
+
}
|
1383
|
+
else {
|
1384
|
+
permute.call(self, num, perm, 0, used, block);
|
1385
|
+
}
|
1386
|
+
}
|
1387
|
+
}
|
1287
1388
|
|
1389
|
+
self
|
1390
|
+
end
|
1391
|
+
|
1288
1392
|
def pop(count = undefined)
|
1289
1393
|
if `count === undefined`
|
1290
1394
|
return if `self.length === 0`
|
@@ -1383,7 +1487,7 @@ class Array
|
|
1383
1487
|
end
|
1384
1488
|
|
1385
1489
|
def reject(&block)
|
1386
|
-
return enum_for
|
1490
|
+
return enum_for(:reject){self.size} unless block_given?
|
1387
1491
|
|
1388
1492
|
%x{
|
1389
1493
|
var result = [];
|
@@ -1402,7 +1506,7 @@ class Array
|
|
1402
1506
|
end
|
1403
1507
|
|
1404
1508
|
def reject!(&block)
|
1405
|
-
return enum_for
|
1509
|
+
return enum_for(:reject!){self.size} unless block_given?
|
1406
1510
|
|
1407
1511
|
original = length
|
1408
1512
|
delete_if(&block)
|
@@ -1436,7 +1540,7 @@ class Array
|
|
1436
1540
|
end
|
1437
1541
|
|
1438
1542
|
def reverse_each(&block)
|
1439
|
-
return enum_for
|
1543
|
+
return enum_for(:reverse_each){self.size} unless block_given?
|
1440
1544
|
|
1441
1545
|
reverse.each &block
|
1442
1546
|
self
|
@@ -1444,19 +1548,26 @@ class Array
|
|
1444
1548
|
|
1445
1549
|
def rindex(object = undefined, &block)
|
1446
1550
|
%x{
|
1551
|
+
var i, value;
|
1552
|
+
|
1447
1553
|
if (object != null) {
|
1448
|
-
for (
|
1554
|
+
for (i = self.length - 1; i >= 0; i--) {
|
1555
|
+
if (i >= self.length) {
|
1556
|
+
break;
|
1557
|
+
}
|
1449
1558
|
if (#{`self[i]` == `object`}) {
|
1450
1559
|
return i;
|
1451
1560
|
}
|
1452
1561
|
}
|
1453
1562
|
}
|
1454
1563
|
else if (block !== nil) {
|
1455
|
-
for (
|
1564
|
+
for (i = self.length - 1; i >= 0; i--) {
|
1565
|
+
if (i >= self.length) {
|
1566
|
+
break;
|
1567
|
+
}
|
1456
1568
|
if ((value = block(self[i])) === $breaker) {
|
1457
1569
|
return $breaker.$v;
|
1458
1570
|
}
|
1459
|
-
|
1460
1571
|
if (value !== false && value !== nil) {
|
1461
1572
|
return i;
|
1462
1573
|
}
|
@@ -1492,8 +1603,6 @@ class Array
|
|
1492
1603
|
end
|
1493
1604
|
|
1494
1605
|
def rotate!(cnt=1)
|
1495
|
-
raise RuntimeError, "can't modify frozen Array" if frozen?
|
1496
|
-
|
1497
1606
|
%x{
|
1498
1607
|
if (self.length === 0 || self.length === 1) {
|
1499
1608
|
return self;
|
@@ -1504,21 +1613,133 @@ class Array
|
|
1504
1613
|
replace ary
|
1505
1614
|
end
|
1506
1615
|
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1616
|
+
class SampleRandom
|
1617
|
+
def initialize(rng)
|
1618
|
+
@rng = rng
|
1619
|
+
end
|
1510
1620
|
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1621
|
+
def rand(size)
|
1622
|
+
random = Opal.coerce_to @rng.rand(size), Integer, :to_int
|
1623
|
+
raise RangeError, "random value must be >= 0" if `random < 0`
|
1624
|
+
raise RangeError, "random value must be less than Array size" unless `random < size`
|
1625
|
+
|
1626
|
+
random
|
1517
1627
|
end
|
1518
1628
|
end
|
1519
1629
|
|
1630
|
+
def sample(count = undefined, options = undefined)
|
1631
|
+
return at Kernel.rand(`self.length`) if `count === undefined`
|
1632
|
+
|
1633
|
+
if `options === undefined`
|
1634
|
+
if (o = Opal.coerce_to? count, Hash, :to_hash)
|
1635
|
+
options = o
|
1636
|
+
count = nil
|
1637
|
+
else
|
1638
|
+
options = nil
|
1639
|
+
count = Opal.coerce_to count, Integer, :to_int
|
1640
|
+
end
|
1641
|
+
else
|
1642
|
+
count = Opal.coerce_to count, Integer, :to_int
|
1643
|
+
options = Opal.coerce_to options, Hash, :to_hash
|
1644
|
+
end
|
1645
|
+
|
1646
|
+
if count and `count < 0`
|
1647
|
+
raise ArgumentError, "count must be greater than 0"
|
1648
|
+
end
|
1649
|
+
|
1650
|
+
rng = options[:random] if options
|
1651
|
+
if rng and rng.respond_to? :rand
|
1652
|
+
rng = SampleRandom.new rng
|
1653
|
+
else
|
1654
|
+
rng = Kernel
|
1655
|
+
end
|
1656
|
+
|
1657
|
+
return `self[#{rng.rand(`self.length`)}]` unless count
|
1658
|
+
|
1659
|
+
%x{
|
1660
|
+
|
1661
|
+
var abandon, spin, result, i, j, k, targetIndex, oldValue;
|
1662
|
+
|
1663
|
+
if (count > self.length) {
|
1664
|
+
count = self.length;
|
1665
|
+
}
|
1666
|
+
|
1667
|
+
switch (count) {
|
1668
|
+
case 0:
|
1669
|
+
return [];
|
1670
|
+
break;
|
1671
|
+
case 1:
|
1672
|
+
return [self[#{rng.rand(`self.length`)}]];
|
1673
|
+
break;
|
1674
|
+
case 2:
|
1675
|
+
i = #{rng.rand(`self.length`)};
|
1676
|
+
j = #{rng.rand(`self.length`)};
|
1677
|
+
if (i === j) {
|
1678
|
+
j = i === 0 ? i + 1 : i - 1;
|
1679
|
+
}
|
1680
|
+
return [self[i], self[j]];
|
1681
|
+
break;
|
1682
|
+
default:
|
1683
|
+
if (self.length / count > 3) {
|
1684
|
+
abandon = false;
|
1685
|
+
spin = 0;
|
1686
|
+
|
1687
|
+
result = #{ Array.new(count) };
|
1688
|
+
i = 1;
|
1689
|
+
|
1690
|
+
result[0] = #{rng.rand(`self.length`)};
|
1691
|
+
while (i < count) {
|
1692
|
+
k = #{rng.rand(`self.length`)};
|
1693
|
+
j = 0;
|
1694
|
+
|
1695
|
+
while (j < i) {
|
1696
|
+
while (k === result[j]) {
|
1697
|
+
spin++;
|
1698
|
+
if (spin > 100) {
|
1699
|
+
abandon = true;
|
1700
|
+
break;
|
1701
|
+
}
|
1702
|
+
k = #{rng.rand(`self.length`)};
|
1703
|
+
}
|
1704
|
+
if (abandon) { break; }
|
1705
|
+
|
1706
|
+
j++;
|
1707
|
+
}
|
1708
|
+
|
1709
|
+
if (abandon) { break; }
|
1710
|
+
|
1711
|
+
result[i] = k;
|
1712
|
+
|
1713
|
+
i++;
|
1714
|
+
}
|
1715
|
+
|
1716
|
+
if (!abandon) {
|
1717
|
+
i = 0;
|
1718
|
+
while (i < count) {
|
1719
|
+
result[i] = self[result[i]];
|
1720
|
+
i++;
|
1721
|
+
}
|
1722
|
+
|
1723
|
+
return result;
|
1724
|
+
}
|
1725
|
+
}
|
1726
|
+
|
1727
|
+
result = self.slice();
|
1728
|
+
|
1729
|
+
for (var c = 0; c < count; c++) {
|
1730
|
+
targetIndex = #{rng.rand(`self.length`)};
|
1731
|
+
oldValue = result[c];
|
1732
|
+
result[c] = result[targetIndex];
|
1733
|
+
result[targetIndex] = oldValue;
|
1734
|
+
}
|
1735
|
+
|
1736
|
+
return count === self.length ? result : #{`result`[0, count]};
|
1737
|
+
}
|
1738
|
+
}
|
1739
|
+
end
|
1740
|
+
|
1520
1741
|
def select(&block)
|
1521
|
-
return enum_for
|
1742
|
+
return enum_for(:select){self.size} unless block_given?
|
1522
1743
|
|
1523
1744
|
%x{
|
1524
1745
|
var result = [];
|
@@ -1540,7 +1761,7 @@ class Array
|
|
1540
1761
|
end
|
1541
1762
|
|
1542
1763
|
def select!(&block)
|
1543
|
-
return enum_for
|
1764
|
+
return enum_for(:select!){self.size} unless block_given?
|
1544
1765
|
|
1545
1766
|
%x{
|
1546
1767
|
var original = self.length;
|
@@ -1568,22 +1789,49 @@ class Array
|
|
1568
1789
|
|
1569
1790
|
alias size length
|
1570
1791
|
|
1571
|
-
def shuffle
|
1572
|
-
|
1792
|
+
def shuffle(rng = undefined)
|
1793
|
+
dup.shuffle!(rng)
|
1573
1794
|
end
|
1574
1795
|
|
1575
|
-
def shuffle!
|
1796
|
+
def shuffle!(rng = undefined)
|
1576
1797
|
%x{
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1798
|
+
var randgen, i = self.length, j, tmp;
|
1799
|
+
|
1800
|
+
if (rng !== undefined) {
|
1801
|
+
rng = #{Opal.coerce_to?(rng, Hash, :to_hash)};
|
1802
|
+
|
1803
|
+
if (rng !== nil) {
|
1804
|
+
rng = #{rng[:random]};
|
1805
|
+
|
1806
|
+
if (rng !== nil && #{rng.respond_to?(:rand)}) {
|
1807
|
+
randgen = rng;
|
1808
|
+
}
|
1809
|
+
}
|
1810
|
+
}
|
1811
|
+
|
1812
|
+
while (i) {
|
1813
|
+
if (randgen) {
|
1814
|
+
j = randgen.$rand(i).$to_int();
|
1815
|
+
|
1816
|
+
if (j < 0) {
|
1817
|
+
#{raise RangeError, "random number too small #{`j`}"}
|
1818
|
+
}
|
1819
|
+
|
1820
|
+
if (j >= i) {
|
1821
|
+
#{raise RangeError, "random number too big #{`j`}"}
|
1822
|
+
}
|
1823
|
+
}
|
1824
|
+
else {
|
1825
|
+
j = Math.floor(Math.random() * i);
|
1826
|
+
}
|
1580
1827
|
|
1828
|
+
tmp = self[--i];
|
1581
1829
|
self[i] = self[j];
|
1582
1830
|
self[j] = tmp;
|
1583
1831
|
}
|
1584
|
-
}
|
1585
1832
|
|
1586
|
-
|
1833
|
+
return self;
|
1834
|
+
}
|
1587
1835
|
end
|
1588
1836
|
|
1589
1837
|
alias slice []
|
@@ -1610,7 +1858,7 @@ class Array
|
|
1610
1858
|
return self unless `self.length > 1`
|
1611
1859
|
|
1612
1860
|
%x{
|
1613
|
-
if (
|
1861
|
+
if (block === nil) {
|
1614
1862
|
block = function(a, b) {
|
1615
1863
|
return #{`a` <=> `b`};
|
1616
1864
|
};
|
@@ -1713,7 +1961,7 @@ class Array
|
|
1713
1961
|
}
|
1714
1962
|
key = ary[0];
|
1715
1963
|
val = ary[1];
|
1716
|
-
hash
|
1964
|
+
Opal.hash_put(hash, key, val);
|
1717
1965
|
}
|
1718
1966
|
|
1719
1967
|
return hash;
|
@@ -1750,47 +1998,51 @@ class Array
|
|
1750
1998
|
result
|
1751
1999
|
end
|
1752
2000
|
|
1753
|
-
def uniq
|
2001
|
+
def uniq(&block)
|
1754
2002
|
%x{
|
1755
|
-
var
|
1756
|
-
seen = {};
|
2003
|
+
var hash = #{{}}, i, length, item, key;
|
1757
2004
|
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
2005
|
+
if (block === nil) {
|
2006
|
+
for (i = 0, length = self.length; i < length; i++) {
|
2007
|
+
item = self[i];
|
2008
|
+
if (Opal.hash_get(hash, item) === undefined) {
|
2009
|
+
Opal.hash_put(hash, item, item);
|
2010
|
+
}
|
2011
|
+
}
|
2012
|
+
}
|
2013
|
+
else {
|
2014
|
+
for (i = 0, length = self.length; i < length; i++) {
|
2015
|
+
item = self[i];
|
2016
|
+
key = Opal.yield1(block, item);
|
2017
|
+
if (Opal.hash_get(hash, key) === undefined) {
|
2018
|
+
Opal.hash_put(hash, key, item);
|
2019
|
+
}
|
1766
2020
|
}
|
1767
2021
|
}
|
1768
2022
|
|
1769
|
-
return
|
2023
|
+
return hash.$values();
|
1770
2024
|
}
|
1771
2025
|
end
|
1772
2026
|
|
1773
|
-
def uniq!
|
2027
|
+
def uniq!(&block)
|
1774
2028
|
%x{
|
1775
|
-
var
|
1776
|
-
seen = {};
|
2029
|
+
var original_length = self.length, hash = #{{}}, i, length, item, key;
|
1777
2030
|
|
1778
|
-
for (
|
2031
|
+
for (i = 0, length = original_length; i < length; i++) {
|
1779
2032
|
item = self[i];
|
1780
|
-
|
2033
|
+
key = (block === nil ? item : Opal.yield1(block, item));
|
1781
2034
|
|
1782
|
-
if (
|
1783
|
-
|
2035
|
+
if (Opal.hash_get(hash, key) === undefined) {
|
2036
|
+
Opal.hash_put(hash, key, item);
|
2037
|
+
continue;
|
1784
2038
|
}
|
1785
|
-
else {
|
1786
|
-
self.splice(i, 1);
|
1787
2039
|
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
2040
|
+
self.splice(i, 1);
|
2041
|
+
length--;
|
2042
|
+
i--;
|
1791
2043
|
}
|
1792
2044
|
|
1793
|
-
return self.length ===
|
2045
|
+
return self.length === original_length ? nil : self;
|
1794
2046
|
}
|
1795
2047
|
end
|
1796
2048
|
|