opal 0.9.0.beta1 → 0.9.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -20
- data/CONTRIBUTING.md +8 -16
- data/lib/opal/compiler.rb +5 -0
- data/lib/opal/nodes/def.rb +10 -3
- data/lib/opal/nodes/definitions.rb +14 -3
- data/lib/opal/paths.rb +21 -4
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array.rb +1 -1
- data/opal/corelib/basic_object.rb +9 -9
- data/opal/corelib/constants.rb +2 -2
- data/opal/corelib/enumerable.rb +79 -2
- data/opal/corelib/error.rb +18 -0
- data/opal/corelib/helpers.rb +2 -8
- data/opal/corelib/kernel.rb +7 -7
- data/opal/corelib/module.rb +10 -10
- data/opal/corelib/number.rb +1 -1
- data/opal/corelib/regexp.rb +31 -30
- data/opal/corelib/string.rb +1 -1
- data/opal/corelib/struct.rb +8 -10
- data/opal/corelib/time.rb +4 -2
- data/opal/corelib/unsupported.rb +2 -2
- data/spec/filters/bugs/enumerable.rb +0 -19
- data/spec/filters/bugs/exception.rb +0 -4
- data/spec/filters/bugs/language.rb +7 -5
- data/spec/filters/bugs/module.rb +18 -19
- data/spec/filters/bugs/regexp.rb +0 -3
- data/spec/filters/bugs/set.rb +0 -8
- data/spec/filters/bugs/struct.rb +2 -2
- data/spec/filters/unsupported/bignum.rb +1 -0
- data/spec/filters/unsupported/language.rb +7 -0
- data/spec/lib/compiler_spec.rb +5 -0
- data/spec/lib/parser/undef_spec.rb +4 -0
- data/spec/lib/paths_spec.rb +11 -0
- data/spec/lib/spec_helper.rb +1 -1
- data/spec/opal/core/arity_spec.rb +142 -0
- data/spec/rubyspecs +1 -0
- data/stdlib/json.rb +13 -8
- data/stdlib/native.rb +1 -1
- data/stdlib/observer.rb +1 -1
- data/stdlib/ostruct.rb +1 -1
- data/stdlib/set.rb +33 -0
- data/tasks/testing.rake +8 -7
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a71d75efaebcd98ae54fc1221323252c84d83725
|
4
|
+
data.tar.gz: 81f52eea1fb84c5bb009ccd90bdf4cbc2f8344a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9fa8aa94a8350f9ec2bde008a844c4fb09d5b05917abc21045791b584adef85951106190840e50b29e047ad0f464e0acfbee5e8ac5ba2872ffac59574efc136
|
7
|
+
data.tar.gz: 3744c8d573fa179442543ad09d876ee64d56b2d0114c151cc2789821741c52206edce4c0ba798658d91ee3c25679aa37b37c3eb5548e6d1611a3a68b42409f5c
|
data/CHANGELOG.md
CHANGED
@@ -1,43 +1,62 @@
|
|
1
1
|
## 0.9.0 (edge)
|
2
2
|
|
3
|
-
*
|
3
|
+
* A `console` wrapper has been added to the stdlib, requiring it will make available the `$console` global variable.
|
4
4
|
|
5
|
-
*
|
5
|
+
* `Kernel#pp` no longer forwards arguments directly to `console.log`, this behavior has been * `replaced by stdlib's own `console.rb` (see above).
|
6
6
|
|
7
|
-
*
|
7
|
+
* `method_added`, `method_removed` and `method_undefined` reflection now works.
|
8
8
|
|
9
|
-
*
|
9
|
+
* `singleton_method_added`, `singleton_method_removed` and `singleton_method_undefined` reflection now works.
|
10
10
|
|
11
|
-
*
|
11
|
+
* Now you can bridge a native class to a Ruby class that inherits from another Ruby class
|
12
12
|
|
13
|
-
*
|
13
|
+
* `Numeric` semantics are now compliant with Ruby.
|
14
14
|
|
15
|
-
*
|
15
|
+
* `Complex` has been fully implemented.
|
16
16
|
|
17
|
-
*
|
17
|
+
* `Rational` has been fully implemented.
|
18
18
|
|
19
|
-
*
|
19
|
+
* `Opal::Sprockets.javascript_include_tag` has been add to allow easy debug mode (i.e. with source maps) when including a sprockets asset into an HTML page.
|
20
20
|
|
21
|
-
*
|
21
|
+
* `Opal::Processor.load_asset_code(sprockets, name)` has been deprecated in favor of `Opal::Sprockets.load_asset(name, sprockets)`.
|
22
22
|
|
23
|
-
*
|
23
|
+
* `Struct#hash` now works properly based on struct contents
|
24
24
|
|
25
|
-
*
|
25
|
+
* No longer crashes when calling a method with an opt arg followed by an optional kwarg when called without the kwarg
|
26
26
|
|
27
|
-
*
|
28
|
-
|
27
|
+
* Newly compliant with RubySpec:
|
28
|
+
* `Enumerable#chunk`
|
29
|
+
* `Enumerable#each_cons`
|
30
|
+
* `Enumerable#minmax`
|
31
|
+
|
32
|
+
* Operator methods (e.g. `+`, `<`, etc.) can be handled by `method_missing`
|
33
|
+
|
34
|
+
* `OpenStruct` - fixed `#method missing`, `#inspect`, `#to_s`, `#delete_field`. Fully compliant except for frozen and marshal behavior.
|
35
|
+
|
36
|
+
* Fix issue where passing a block after a parameter and a hash was causing block to not be passed (e.g. `method1 some_param, 'a' => 1, &block`)
|
37
|
+
|
38
|
+
* `Kernel#raise` now properly re-raises exceptions (regardless of how many levels deep you are) and works properly if supplied a class that has an exception method.
|
39
|
+
|
40
|
+
* `Exception#exception`, `Exception::exception`, `Exception#message`, and `Exception#to_s` are fully implemented
|
41
|
+
|
42
|
+
* Method defs issued inside `Module#instance_eval` and `Class#instance_eval`, and the respective `exec` now create class methods
|
43
|
+
|
44
|
+
* You can make direct JavaScript method calls on using the `recv.JS.method`syntax. Has support for method calls, final callback (as a block), property getter and setter (via `#[]` and `#[]=`), splats, JavaScript keywords (via the `::JS` module) and global functions (after `require "js"`).
|
45
|
+
|
46
|
+
* `Set#superset?`, `Set#subset?`, and the respective 'proper_' variant of each are now implemented
|
47
|
+
|
48
|
+
* Now with enabled arity checks calling a method with more arguments than those supported by its signature raises an `ArgumentError` as well.
|
29
49
|
|
30
|
-
*
|
50
|
+
* `NameError` and `NoMethodError` - add `#name` and `#args` attributes
|
31
51
|
|
32
|
-
*
|
52
|
+
* Previously arity checks would raise an error without clearing the block for a method, the could lead to strange bugs in case the error was rescued.
|
33
53
|
|
34
|
-
*
|
54
|
+
* `RegExp#match` now works correctly in multiline mode with white space
|
35
55
|
|
36
|
-
* `
|
56
|
+
* `Regexp#===` returns false when the right hand side of the expression cannot be coereced to a string (instead of throwing a TypeError)
|
37
57
|
|
38
|
-
* `
|
58
|
+
* `Regexp#options` has been optimized and correctly returns 0 when called on a Regexp literal without any options (e.g. //)
|
39
59
|
|
40
|
-
* Method defs issued inside `Module#instance_eval` and `Class#instance_eval`, and the respective `exec` now create class methods
|
41
60
|
|
42
61
|
## 0.8.1 2015-10-12
|
43
62
|
|
data/CONTRIBUTING.md
CHANGED
@@ -38,7 +38,7 @@ $ bundle install
|
|
38
38
|
$ npm install -g jshint
|
39
39
|
```
|
40
40
|
|
41
|
-
RubySpec related repos must be cloned as
|
41
|
+
RubySpec related repos must be cloned as git submodules:
|
42
42
|
|
43
43
|
```
|
44
44
|
$ git submodule update --init
|
@@ -58,22 +58,22 @@ You are now ready to make your first contribution to Opal! At a high level, your
|
|
58
58
|
|
59
59
|
## Down The Rabbit Hole
|
60
60
|
|
61
|
-
Before making changes to Opal source, you need to understand a little about how the test suite works. Every spec that Opal test suite executes is listed in `spec/rubyspecs` file. Each line in that file is a path to either a spec file or a directory full of spec files. If it's a path to a directory, all spec files in that directory will be executed when you run the test suite. All paths are relative to the top-level `specs` directory. Let's follow one of these paths - `rubyspec/core/string/sub_spec` - and see where it goes.
|
61
|
+
Before making changes to Opal source, you need to understand a little about how the test suite works. Every spec that Opal test suite executes is listed in `spec/rubyspecs` file. Each line in that file is a path to either a spec file or a directory full of spec files. If it's a path to a directory, all spec files in that directory will be executed when you run the test suite. Lines starting with a `!` represent files that are excluded (i.e. "execute all files in a given directory, *except* this file"), and lines starting with a `#` are ignored as comments. All paths are relative to the top-level `specs` directory. Let's follow one of these paths - `rubyspec/core/string/sub_spec` - and see where it goes.
|
62
62
|
|
63
|
-
Navigating to `spec/rubyspec/core` directory, you see that it contains multiple sub-directories, usually named after the Ruby class or module. Drilling further down into `spec/rubyspec/core/string` you see all the spec files for the various `String` behaviors under test, usually named by a method name followed by `_spec.rb`. Opening `spec/rubyspec/core/string/sub_spec.rb` you finally see the code that checks the correctness of Opal's implementation of `String#sub` method's behavior.
|
63
|
+
Navigating to `spec/rubyspec/core` directory, you see that it contains multiple sub-directories, usually named after the Ruby class or module. Drilling further down into `spec/rubyspec/core/string` you see all the spec files for the various `String` behaviors under test, usually named by a method name followed by `_spec.rb`. Opening `spec/rubyspec/core/string/sub_spec.rb` you finally see the code that checks the correctness of Opal's implementation of the `String#sub` method's behavior.
|
64
64
|
|
65
65
|
When you execute `$ bundle exec rake`, the code in this file is executed, along with all the other specs in the entire test suite. It's a good idea to run the entire test suite when you feel you reached a certain milestone in the course of making your changes (exactly what that means is up to you), and definitely do `$ bundle exec rake` before commiting your changes to make sure they have not introduced regressions or other unintended side effects.
|
66
66
|
|
67
67
|
But you will want to run tests as often as possible, after every small change, and running the entire test suite will slow you down. You need to be able to execute a single spec that is concerned with the feature you are currently working on. To accomplish this, just add `PATTERN` to your spec invocation command, like this:
|
68
68
|
|
69
69
|
```
|
70
|
-
$
|
70
|
+
$ bundle exec rake mspec_rubyspec_node PATTERN=spec/rubyspec/core/string/sub_spec.rb
|
71
71
|
```
|
72
72
|
|
73
73
|
This will make sure that only `spec/rubyspec/core/string/sub_spec.rb` is run, and no other specs are executed. Globs can be used too:
|
74
74
|
|
75
75
|
```
|
76
|
-
$
|
76
|
+
$ bundle exec rake mspec_rubyspec_node PATTERN=spec/rubyspec/core/string/*_spec.rb
|
77
77
|
```
|
78
78
|
|
79
79
|
Another way to quickly validate ideas and play with your changes is to use `opal-repl`, a tool similar to `irb`. Running `opal-repl` drops you into an interactive environment with your current version of Opal loaded, including any changes you have made.
|
@@ -168,17 +168,9 @@ If I were to continue running benchmarks, more columns would be added to the rep
|
|
168
168
|
This type of benchmarking relies on a feature of MSpec whereby you can ask it to execute every example in a given spec multiple times. Adding `BM=<number of times>` to your regular spec suite invocation command will hook into this MSpec functionality, collect timing information, and dump the results into the benchmarking workspace, making them available for reporting. Below is an example run with a single spec and `BM` set to `100`, meaning each example in the spec would be run 100 times.
|
169
169
|
|
170
170
|
```
|
171
|
-
$ bundle exec rake
|
172
|
-
|
173
|
-
|
174
|
-
mkdir -p tmp
|
175
|
-
mkdir -p tmp/bench
|
176
|
-
ruby -rbundler/setup -rmspec/opal/special_calls bin/opal -gmspec -Ispec -Ilib -smspec/helpers/tmp -smspec/helpers/environment -smspec/guards/block_device -smspec/guards/endian -rnodejs/io -rnodejs/kernel -Dwarning -A tmp/mspec_node.rb -c > tmp/mspec_node.js
|
177
|
-
jshint --verbose tmp/mspec_node.js
|
178
|
-
NODE_PATH=stdlib/nodejs/node_modules node tmp/mspec_node.js
|
179
|
-
................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
|
180
|
-
Finished
|
181
|
-
1200 examples, 0 failures (time taken: 0.7880001068115234)
|
171
|
+
$ bundle exec rake mspec_rubyspec_node PATTERN=spec/rubyspec/core/array/permutation_spec.rb BM=100
|
172
|
+
|
173
|
+
...
|
182
174
|
|
183
175
|
Benchmark results have been written to tmp/bench/Spec1
|
184
176
|
To view the results, run bundle exec rake bench:report
|
data/lib/opal/compiler.rb
CHANGED
@@ -318,6 +318,11 @@ module Opal
|
|
318
318
|
return returns s(:nil) unless sexp
|
319
319
|
|
320
320
|
case sexp.type
|
321
|
+
# Undefs go from 1 ruby undef a,b,c to multiple JS Opal.udef() calls, so need to treat them as individual statements
|
322
|
+
# and put the return on the last one
|
323
|
+
when :undef
|
324
|
+
last = sexp.pop
|
325
|
+
sexp << returns(last)
|
321
326
|
when :break, :next, :redo
|
322
327
|
sexp
|
323
328
|
when :yield
|
data/lib/opal/nodes/def.rb
CHANGED
@@ -80,9 +80,10 @@ module Opal
|
|
80
80
|
end
|
81
81
|
|
82
82
|
unshift "\n#{current_indent}", scope.to_vars
|
83
|
-
line stmt_code
|
84
83
|
|
85
|
-
|
84
|
+
line arity_code if arity_code
|
85
|
+
|
86
|
+
line stmt_code
|
86
87
|
|
87
88
|
unshift "var $zuper = $slice.call(arguments, 0);" if scope.uses_zuper
|
88
89
|
|
@@ -243,7 +244,13 @@ module Opal
|
|
243
244
|
aritycode = "var $arity = arguments.length;"
|
244
245
|
|
245
246
|
if arity < 0 # splat or opt args
|
246
|
-
|
247
|
+
min_arity = -(arity + 1)
|
248
|
+
max_arity = args.size - 1
|
249
|
+
max_arity -= 1 if block_name
|
250
|
+
checks = []
|
251
|
+
checks << "$arity < #{min_arity}" if min_arity > 0
|
252
|
+
checks << "$arity > #{max_arity}" if max_arity and not(splat)
|
253
|
+
aritycode + "if (#{checks.join(' || ')}) { Opal.ac($arity, #{arity}, this, #{meth}); }" if checks.size > 0
|
247
254
|
else
|
248
255
|
aritycode + "if ($arity !== #{arity}) { Opal.ac($arity, #{arity}, this, #{meth}); }"
|
249
256
|
end
|
@@ -16,10 +16,21 @@ module Opal
|
|
16
16
|
class UndefNode < Base
|
17
17
|
handle :undef
|
18
18
|
|
19
|
-
children :mid
|
20
|
-
|
21
19
|
def compile
|
22
|
-
|
20
|
+
children.each do |child|
|
21
|
+
value = child[1]
|
22
|
+
statements = []
|
23
|
+
if child[0] == :js_return
|
24
|
+
value = value[1]
|
25
|
+
statements << expr(s(:js_return))
|
26
|
+
end
|
27
|
+
statements << "Opal.udef(self, '$#{value.to_s}');"
|
28
|
+
if children.length > 1 && child != children.first
|
29
|
+
line *statements
|
30
|
+
else
|
31
|
+
push *statements
|
32
|
+
end
|
33
|
+
end
|
23
34
|
end
|
24
35
|
end
|
25
36
|
|
data/lib/opal/paths.rb
CHANGED
@@ -18,15 +18,25 @@ module Opal
|
|
18
18
|
def self.append_path(path)
|
19
19
|
append_paths(path)
|
20
20
|
end
|
21
|
+
|
22
|
+
# Same as #append_path but can take multiple paths.
|
21
23
|
def self.append_paths(*paths)
|
22
|
-
|
24
|
+
@paths.concat(paths)
|
25
|
+
nil
|
23
26
|
end
|
24
27
|
|
25
28
|
module UseGem
|
29
|
+
# Adds the "require_paths" (usually `lib/`) of gem with the given name to
|
30
|
+
# Opal paths. By default will include the "require_paths" from all the
|
31
|
+
# dependent gems.
|
32
|
+
#
|
33
|
+
# @param gem_name [String] the name of the gem
|
34
|
+
# @param include_dependencies [Boolean] whether or not to add recursively
|
35
|
+
# the gem's dependencies
|
26
36
|
def use_gem(gem_name, include_dependencies = true)
|
27
37
|
append_paths(*require_paths_for_gem(gem_name, include_dependencies))
|
28
38
|
end
|
29
|
-
|
39
|
+
|
30
40
|
private
|
31
41
|
|
32
42
|
def require_paths_for_gem(gem_name, include_dependencies)
|
@@ -48,8 +58,15 @@ module Opal
|
|
48
58
|
|
49
59
|
extend UseGem
|
50
60
|
|
51
|
-
# Private, don't add to these directly (use .append_path instead).
|
52
61
|
def self.paths
|
53
|
-
@paths
|
62
|
+
@paths.dup.freeze
|
54
63
|
end
|
64
|
+
|
65
|
+
# Resets Opal.paths to the default value (includes `corelib`, `stdlib`, `opal/lib`)
|
66
|
+
def self.reset_paths!
|
67
|
+
@paths = [core_dir.untaint, std_dir.untaint, gem_dir.untaint]
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
|
71
|
+
reset_paths!
|
55
72
|
end
|
data/lib/opal/version.rb
CHANGED
data/opal/corelib/array.rb
CHANGED
@@ -1262,7 +1262,7 @@ class Array < `Array`
|
|
1262
1262
|
}
|
1263
1263
|
}
|
1264
1264
|
|
1265
|
-
#{raise NoMethodError
|
1265
|
+
#{raise NoMethodError.new("#{Opal.inspect(`item`)} doesn't respond to #to_str, #to_ary or #to_s", 'to_str')};
|
1266
1266
|
}
|
1267
1267
|
|
1268
1268
|
if (sep === nil) {
|
@@ -52,12 +52,12 @@ class BasicObject
|
|
52
52
|
result;
|
53
53
|
|
54
54
|
block.$$s = null;
|
55
|
-
|
55
|
+
|
56
56
|
// need to pass $$eval so that method definitions know if this is being done on a class/module. Cannot be compiler driven since
|
57
57
|
// send(:instance_eval) needs to work
|
58
58
|
if (self.$$is_class || self.$$is_module) {
|
59
59
|
self.$$eval = true;
|
60
|
-
try {
|
60
|
+
try {
|
61
61
|
result = block.call(self, self);
|
62
62
|
}
|
63
63
|
finally {
|
@@ -67,7 +67,7 @@ class BasicObject
|
|
67
67
|
else {
|
68
68
|
result = block.call(self, self);
|
69
69
|
}
|
70
|
-
|
70
|
+
|
71
71
|
block.$$s = old;
|
72
72
|
|
73
73
|
return result;
|
@@ -80,17 +80,17 @@ class BasicObject
|
|
80
80
|
%x{
|
81
81
|
var block_self = block.$$s,
|
82
82
|
result;
|
83
|
-
|
83
|
+
|
84
84
|
block.$$s = null;
|
85
|
-
|
85
|
+
|
86
86
|
if (self.$$is_class || self.$$is_module) {
|
87
87
|
self.$$eval = true;
|
88
|
-
try {
|
88
|
+
try {
|
89
89
|
result = block.apply(self, args);
|
90
90
|
}
|
91
91
|
finally {
|
92
92
|
self.$$eval = false;
|
93
|
-
}
|
93
|
+
}
|
94
94
|
}
|
95
95
|
else {
|
96
96
|
result = block.apply(self, args);
|
@@ -112,8 +112,8 @@ class BasicObject
|
|
112
112
|
end
|
113
113
|
|
114
114
|
def method_missing(symbol, *args, &block)
|
115
|
-
Kernel.raise NoMethodError
|
115
|
+
Kernel.raise NoMethodError.new(`self.$inspect && !self.$inspect.$$stub` ?
|
116
116
|
"undefined method `#{symbol}' for #{inspect}:#{`self.$$class`}" :
|
117
|
-
"undefined method `#{symbol}' for #{`self.$$class`}"
|
117
|
+
"undefined method `#{symbol}' for #{`self.$$class`}", symbol)
|
118
118
|
end
|
119
119
|
end
|
data/opal/corelib/constants.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
RUBY_PLATFORM = 'opal'
|
2
2
|
RUBY_ENGINE = 'opal'
|
3
3
|
RUBY_VERSION = '2.1.5'
|
4
|
-
RUBY_ENGINE_VERSION = '0.9.0.
|
5
|
-
RUBY_RELEASE_DATE = '2015-
|
4
|
+
RUBY_ENGINE_VERSION = '0.9.0.beta2'
|
5
|
+
RUBY_RELEASE_DATE = '2015-11-06'
|
6
6
|
RUBY_PATCHLEVEL = 0
|
7
7
|
RUBY_REVISION = 0
|
8
8
|
RUBY_COPYRIGHT = 'opal - Copyright (C) 2013-2015 Adam Beynon'
|
data/opal/corelib/enumerable.rb
CHANGED
@@ -341,7 +341,52 @@ module Enumerable
|
|
341
341
|
end
|
342
342
|
|
343
343
|
def each_cons(n, &block)
|
344
|
-
|
344
|
+
if `arguments.length != 1`
|
345
|
+
raise ArgumentError, "wrong number of arguments (#{`arguments.length`} for 1)"
|
346
|
+
end
|
347
|
+
|
348
|
+
n = Opal.try_convert n, Integer, :to_int
|
349
|
+
|
350
|
+
if `n <= 0`
|
351
|
+
raise ArgumentError, 'invalid size'
|
352
|
+
end
|
353
|
+
|
354
|
+
unless block_given?
|
355
|
+
return enum_for(:each_cons, n) {
|
356
|
+
enum_size = self.enumerator_size
|
357
|
+
if enum_size.nil?
|
358
|
+
nil
|
359
|
+
elsif enum_size == 0 || enum_size < n
|
360
|
+
0
|
361
|
+
else
|
362
|
+
enum_size - n + 1
|
363
|
+
end
|
364
|
+
}
|
365
|
+
end
|
366
|
+
|
367
|
+
%x{
|
368
|
+
var buffer = [], result = nil;
|
369
|
+
|
370
|
+
self.$each.$$p = function() {
|
371
|
+
var element = #{Opal.destructure(`arguments`)};
|
372
|
+
buffer.push(element);
|
373
|
+
if (buffer.length > n) {
|
374
|
+
buffer.shift();
|
375
|
+
}
|
376
|
+
if (buffer.length == n) {
|
377
|
+
var value = Opal.yield1(block, buffer.slice(0, n));
|
378
|
+
|
379
|
+
if (value == $breaker) {
|
380
|
+
result = $breaker.$v;
|
381
|
+
return $breaker;
|
382
|
+
}
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
self.$each();
|
387
|
+
|
388
|
+
return result;
|
389
|
+
}
|
345
390
|
end
|
346
391
|
|
347
392
|
def each_entry(&block)
|
@@ -900,7 +945,39 @@ module Enumerable
|
|
900
945
|
end
|
901
946
|
|
902
947
|
def minmax(&block)
|
903
|
-
|
948
|
+
block ||= proc { |a,b| a <=> b }
|
949
|
+
|
950
|
+
%x{
|
951
|
+
var min = nil, max = nil, first_time = true;
|
952
|
+
|
953
|
+
self.$each.$$p = function() {
|
954
|
+
var element = #{Opal.destructure(`arguments`)};
|
955
|
+
if (first_time) {
|
956
|
+
min = max = element;
|
957
|
+
first_time = false;
|
958
|
+
} else {
|
959
|
+
var min_cmp = #{block.call(`min`, `element`)};
|
960
|
+
|
961
|
+
if (min_cmp === nil) {
|
962
|
+
#{raise ArgumentError, 'comparison failed'}
|
963
|
+
} else if (min_cmp > 0) {
|
964
|
+
min = element;
|
965
|
+
}
|
966
|
+
|
967
|
+
var max_cmp = #{block.call(`max`, `element`)};
|
968
|
+
|
969
|
+
if (max_cmp === nil) {
|
970
|
+
#{raise ArgumentError, 'comparison failed'}
|
971
|
+
} else if (max_cmp < 0) {
|
972
|
+
max = element;
|
973
|
+
}
|
974
|
+
}
|
975
|
+
}
|
976
|
+
|
977
|
+
self.$each();
|
978
|
+
|
979
|
+
return [min, max];
|
980
|
+
}
|
904
981
|
end
|
905
982
|
|
906
983
|
def minmax_by(&block)
|