backports 2.8.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +11 -0
- data/README.rdoc +13 -3
- data/lib/backports.rb +1 -1
- data/lib/backports/1.8.7/enumerator.rb +8 -0
- data/lib/backports/1.9.1/enumerator.rb +2 -2
- data/lib/backports/1.9.1/hash.rb +6 -1
- data/lib/backports/2.0.0/enumerable.rb +10 -7
- data/lib/backports/2.0.0/enumerator/lazy.rb +57 -15
- data/lib/backports/2.0.0/hash.rb +16 -0
- data/lib/backports/2.0.0/nil_class.rb +5 -0
- data/lib/backports/2.0.0/stdlib.rb +1 -0
- data/lib/backports/2.0.0/stdlib/ostruct.rb +27 -0
- data/lib/backports/2.0.0/struct.rb +7 -0
- data/lib/backports/tools.rb +1 -1
- data/lib/backports/version.rb +1 -1
- data/test/test_lazy.rb +481 -0
- metadata +9 -2
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
= Backports --- History
|
2
2
|
|
3
|
+
== Version 3.0.0 - February 24th, 2013
|
4
|
+
|
5
|
+
* Features of 2.0.0 are now required when requiring 'backports'.
|
6
|
+
|
7
|
+
* Additional features of 2.0.0
|
8
|
+
* Struct#to_h, NilClass#to_h, Hash#to_h
|
9
|
+
* Hash#default_proc = nil
|
10
|
+
* OpenStruct lib
|
11
|
+
|
12
|
+
* 1.8.7's Enumerator#with_index (it wasn't in the 1.8.7 NEWS file...)
|
13
|
+
|
3
14
|
== Version 2.8.0 - February 3rd, 2013
|
4
15
|
|
5
16
|
* Added some features of 2.0.0 (must be required explicitly until official release):
|
data/README.rdoc
CHANGED
@@ -189,7 +189,7 @@ Some features of Ruby 1.9.3 have been backported:
|
|
189
189
|
* +byteslice+
|
190
190
|
* +prepend+
|
191
191
|
|
192
|
-
To include all Ruby backports but not those of Rails, <tt>require "backports/1.9.3"</tt> (or "backports/1.9")
|
192
|
+
To include all Ruby backports but not those of Ruby 2.0 or Rails, <tt>require "backports/1.9.3"</tt> (or "backports/1.9")
|
193
193
|
|
194
194
|
== Ruby 2.0.0
|
195
195
|
|
@@ -201,10 +201,16 @@ Some features of Ruby 2.0.0 have been backported:
|
|
201
201
|
* +lazy+
|
202
202
|
* Enumerator::Lazy
|
203
203
|
* all methods
|
204
|
+
* Hash
|
205
|
+
* <tt>default_proc=</tt> (with nil argument)
|
206
|
+
* +to_h+
|
207
|
+
* nil.to_h
|
204
208
|
* Range
|
205
209
|
* +bsearch+
|
210
|
+
* Struct
|
211
|
+
* +to_h+
|
206
212
|
|
207
|
-
|
213
|
+
To include all Ruby backports but not those of Rails, <tt>require "backports/2.0"</tt> (or "backports/2.0.0")
|
208
214
|
|
209
215
|
== Rails
|
210
216
|
|
@@ -245,7 +251,11 @@ The following libraries are up to date with Ruby 1.9.3:
|
|
245
251
|
* Prime
|
246
252
|
* Set
|
247
253
|
|
248
|
-
|
254
|
+
The following library is to date with Ruby 2.0.0:
|
255
|
+
|
256
|
+
* OpenStruct (ostruct)
|
257
|
+
|
258
|
+
I am aware of the following backport gem, which probably won't make it into this gem:
|
249
259
|
|
250
260
|
* Net::SMTP for Ruby 1.8.6: smtp_tls[http://seattlerb.rubyforge.org/smtp_tls/]
|
251
261
|
|
data/lib/backports.rb
CHANGED
@@ -19,6 +19,14 @@ if (Enumerable::Enumerator rescue false)
|
|
19
19
|
@generator.rewind
|
20
20
|
self
|
21
21
|
end unless method_defined? :rewind
|
22
|
+
|
23
|
+
def with_index(offset = 0)
|
24
|
+
to_enum :with_index, offset unless block_given?
|
25
|
+
each do |*args|
|
26
|
+
yield args.size == 1 ? args[0] : args, index
|
27
|
+
index += 1
|
28
|
+
end
|
29
|
+
end unless method_defined? :with_index
|
22
30
|
end if const_defined? :Enumerator
|
23
31
|
end
|
24
32
|
end
|
@@ -20,7 +20,7 @@ class Enumerator
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
class Generator
|
23
|
+
class GeneratorBP # Avoid conflict with 1.8's ::Generator class
|
24
24
|
def initialize(&block)
|
25
25
|
@main_block = block
|
26
26
|
end
|
@@ -32,7 +32,7 @@ class Enumerator
|
|
32
32
|
|
33
33
|
def initialize_with_optional_block(*arg, &block)
|
34
34
|
return initialize_without_optional_block(*arg, &nil) unless arg.empty? # Ruby 1.9 apparently ignores the block if any argument is present
|
35
|
-
initialize_without_optional_block(
|
35
|
+
initialize_without_optional_block(GeneratorBP.new(&block))
|
36
36
|
end
|
37
37
|
Backports.alias_method_chain self, :initialize, :optional_block
|
38
38
|
end
|
data/lib/backports/1.9.1/hash.rb
CHANGED
@@ -8,7 +8,12 @@ class Hash
|
|
8
8
|
|
9
9
|
# Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Hash.html]
|
10
10
|
def default_proc=(proc)
|
11
|
-
|
11
|
+
if proc == nil # nil accepted in Ruby 2.0
|
12
|
+
self.default = nil
|
13
|
+
self
|
14
|
+
else
|
15
|
+
replace(Hash.new(&Backports.coerce_to(proc, Proc, :to_proc)).merge!(self))
|
16
|
+
end
|
12
17
|
end unless method_defined? :default_proc=
|
13
18
|
|
14
19
|
# Standard in Ruby 1.9. See official documentation[http://ruby-doc.org/core-1.9/classes/Hash.html]
|
@@ -1,9 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
unless Enumerable.method_defined? :lazy
|
2
|
+
module Enumerable
|
3
|
+
def lazy
|
4
|
+
klass = Enumerator::Lazy.send :class_variable_get, :@@lazy_with_no_block # Note: class_variable_get is private in 1.8
|
5
|
+
Enumerator::Lazy.new(klass.new(self, :each, []))
|
6
|
+
end
|
7
|
+
end
|
6
8
|
|
7
|
-
class Enumerator
|
8
|
-
|
9
|
+
class Enumerator
|
10
|
+
require_relative 'enumerator/lazy'
|
11
|
+
end
|
9
12
|
end
|
@@ -10,13 +10,16 @@ class Enumerator
|
|
10
10
|
|
11
11
|
class Lazy < Enumerator
|
12
12
|
@@done = :__backports_lazy_enumeration_done__ # used internally to bail out of an iteration
|
13
|
-
|
14
|
-
alias_method :non_lazy_cycle, :cycle # cycle must be handled in a tricky way
|
15
|
-
@@cycler = Struct.new(:object, :n)
|
13
|
+
@@lazy_with_no_block = Struct.new(:object, :method, :args) # used internally to create lazy without block
|
16
14
|
|
17
15
|
def initialize(obj)
|
18
|
-
|
16
|
+
if obj.is_a?(@@lazy_with_no_block)
|
17
|
+
@inspect_info = obj
|
18
|
+
return super(@receiver = obj.object, @method = obj.method || :each, * @args = obj.args)
|
19
|
+
end
|
19
20
|
raise ArgumentError, "must supply a block" unless block_given?
|
21
|
+
@receiver = obj
|
22
|
+
@method = caller[1][/`([^']*)'/, 1]
|
20
23
|
super() do |yielder, *args|
|
21
24
|
catch @@done do
|
22
25
|
obj.each(*args) do |*x|
|
@@ -32,6 +35,41 @@ class Enumerator
|
|
32
35
|
self
|
33
36
|
end
|
34
37
|
|
38
|
+
def to_enum(method = :each, *args)
|
39
|
+
Lazy.new(@@lazy_with_no_block.new(self, method, args))
|
40
|
+
end
|
41
|
+
alias_method :enum_for, :to_enum
|
42
|
+
|
43
|
+
def inspect
|
44
|
+
suff = ''
|
45
|
+
suff << ":#{@method}" unless @method == :each
|
46
|
+
suff << "(#{@args.inspect[1...-1]})" if @args && !@args.empty?
|
47
|
+
"#<#{self.class}: #{@receiver.inspect}#{suff}>"
|
48
|
+
end
|
49
|
+
|
50
|
+
{
|
51
|
+
:slice_before => //,
|
52
|
+
:with_index => [],
|
53
|
+
:cycle => [],
|
54
|
+
:each_with_object => 42,
|
55
|
+
:each_slice => 42,
|
56
|
+
:each_entry => [],
|
57
|
+
:each_cons => 42,
|
58
|
+
}.each do |method, args|
|
59
|
+
unless [].lazy.send(method, *args).is_a?(Lazy) # Nothing to do if already backported, since it would use to_enum...
|
60
|
+
module_eval <<-EOT, __FILE__, __LINE__ + 1
|
61
|
+
def #{method}(*args) # def cycle(*args)
|
62
|
+
return to_enum(:#{method}, *args) unless block_given? # return to_enum(:cycle, *args) unless block_given?
|
63
|
+
super # super
|
64
|
+
end # end
|
65
|
+
EOT
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def chunk(*)
|
70
|
+
super.lazy
|
71
|
+
end unless [].lazy.chunk{}.is_a?(Lazy)
|
72
|
+
|
35
73
|
def map
|
36
74
|
raise ArgumentError, "tried to call lazy map without a block" unless block_given?
|
37
75
|
Lazy.new(self) do |yielder, *values|
|
@@ -69,7 +107,7 @@ class Enumerator
|
|
69
107
|
values = values.first unless values.size > 1
|
70
108
|
yielder.yield(values) if pattern === values
|
71
109
|
end
|
72
|
-
end
|
110
|
+
end.__set_inspect([pattern])
|
73
111
|
end
|
74
112
|
|
75
113
|
def drop(n)
|
@@ -81,7 +119,7 @@ class Enumerator
|
|
81
119
|
else
|
82
120
|
yielder.yield(*values)
|
83
121
|
end
|
84
|
-
end
|
122
|
+
end.__set_inspect([n])
|
85
123
|
end
|
86
124
|
|
87
125
|
def drop_while
|
@@ -95,12 +133,11 @@ class Enumerator
|
|
95
133
|
def take(n)
|
96
134
|
n = Backports::coerce_to_int(n)
|
97
135
|
raise ArgumentError, 'attempt to take negative size' if n < 0
|
98
|
-
|
99
|
-
Lazy.new(self) do |yielder, *values|
|
136
|
+
Lazy.new(n == 0 ? [] : self) do |yielder, *values|
|
100
137
|
data = yielder.backports_memo ||= {:remain => n}
|
101
138
|
yielder.yield(*values)
|
102
139
|
throw @@done if (data[:remain] -= 1) == 0
|
103
|
-
end
|
140
|
+
end.__set_inspect([n], self)
|
104
141
|
end
|
105
142
|
|
106
143
|
def take_while
|
@@ -125,11 +162,6 @@ class Enumerator
|
|
125
162
|
end
|
126
163
|
alias_method :collect_concat, :flat_map
|
127
164
|
|
128
|
-
def cycle(n = nil)
|
129
|
-
return super if block_given?
|
130
|
-
Lazy.new(@@cycler.new(self, n))
|
131
|
-
end
|
132
|
-
|
133
165
|
def zip(*args)
|
134
166
|
return super if block_given?
|
135
167
|
arys = args.map{ |arg| Backports.is_array?(arg) }
|
@@ -143,6 +175,9 @@ class Enumerator
|
|
143
175
|
data[:iter] += 1
|
144
176
|
end
|
145
177
|
else
|
178
|
+
args.each do |a|
|
179
|
+
raise TypeError, "wrong argument type #{a.class} (must respond to :each)" unless a.respond_to? :each
|
180
|
+
end
|
146
181
|
Lazy.new(self) do |yielder, *values|
|
147
182
|
enums = yielder.backports_memo ||= args.map(&:to_enum)
|
148
183
|
values = values.first unless values.size > 1
|
@@ -155,7 +190,14 @@ class Enumerator
|
|
155
190
|
end
|
156
191
|
yielder << others.unshift(values)
|
157
192
|
end
|
158
|
-
end
|
193
|
+
end.__set_inspect(args)
|
194
|
+
end
|
195
|
+
|
196
|
+
protected
|
197
|
+
def __set_inspect(args, receiver = nil)
|
198
|
+
@args = args
|
199
|
+
@receiver = receiver if receiver
|
200
|
+
self
|
159
201
|
end
|
160
202
|
end
|
161
203
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Hash
|
2
|
+
def to_h
|
3
|
+
self
|
4
|
+
end unless method_defined :to_h
|
5
|
+
|
6
|
+
def default_proc_with_nil=(proc)
|
7
|
+
if proc == nil
|
8
|
+
self.default = nil
|
9
|
+
self
|
10
|
+
else
|
11
|
+
self.default_proc_without_nil=(proc)
|
12
|
+
end
|
13
|
+
end if ({}.default_proc = nil rescue true)
|
14
|
+
end
|
15
|
+
|
16
|
+
Backports.alias_method(ENV, :to_h, :to_hash)
|
@@ -0,0 +1 @@
|
|
1
|
+
Backports::StdLib.extend_relative
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class OpenStruct
|
2
|
+
def [](name)
|
3
|
+
@table[name.to_sym]
|
4
|
+
end unless method_defined? :[]
|
5
|
+
|
6
|
+
def []=(name, value)
|
7
|
+
modifiable[new_ostruct_member(name)] = value
|
8
|
+
end unless method_defined? :[]=
|
9
|
+
|
10
|
+
def eql?(other)
|
11
|
+
return false unless other.kind_of?(OpenStruct)
|
12
|
+
@table.eql?(other.table)
|
13
|
+
end unless method_defined? :eql?
|
14
|
+
|
15
|
+
def hash
|
16
|
+
@table.hash
|
17
|
+
end unless method_defined? :hash
|
18
|
+
|
19
|
+
def each_pair
|
20
|
+
return to_enum __method__ unless block_given?
|
21
|
+
@table.each_pair{|p| yield p}
|
22
|
+
end unless method_defined? :each_pair
|
23
|
+
|
24
|
+
def to_h
|
25
|
+
@table.dup
|
26
|
+
end unless method_defined? :to_h
|
27
|
+
end
|
data/lib/backports/tools.rb
CHANGED
@@ -248,7 +248,7 @@ module Backports
|
|
248
248
|
# Used internally.
|
249
249
|
# Safe alias_method that will only alias if the source exists and destination doesn't
|
250
250
|
def self.alias_method(mod, new_name, old_name)
|
251
|
-
mod.
|
251
|
+
mod.instance_eval do
|
252
252
|
alias_method new_name, old_name if method_defined?(old_name) and not method_defined?(new_name)
|
253
253
|
end
|
254
254
|
end
|
data/lib/backports/version.rb
CHANGED
data/test/test_lazy.rb
ADDED
@@ -0,0 +1,481 @@
|
|
1
|
+
# This is copied & modified from MRI
|
2
|
+
require 'test/unit'
|
3
|
+
#require_relative 'envutil'
|
4
|
+
|
5
|
+
class TestLazyEnumerator < Test::Unit::TestCase
|
6
|
+
class Step
|
7
|
+
include Enumerable
|
8
|
+
attr_reader :current, :args
|
9
|
+
|
10
|
+
def initialize(enum)
|
11
|
+
@enum = enum
|
12
|
+
@current = nil
|
13
|
+
@args = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(*args)
|
17
|
+
@args = args
|
18
|
+
@enum.each {|i| @current = i; yield i}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_initialize
|
23
|
+
assert_equal([1, 2, 3], [1, 2, 3].lazy.to_a)
|
24
|
+
assert_equal([1, 2, 3], Enumerator::Lazy.new([1, 2, 3]){|y, v| y << v}.to_a)
|
25
|
+
assert_raise(ArgumentError) { Enumerator::Lazy.new([1, 2, 3]) }
|
26
|
+
end
|
27
|
+
|
28
|
+
### Backports: Disabled because of Enumerator#each not passing args in MRI < 2.0
|
29
|
+
# def test_each_args
|
30
|
+
# a = Step.new(1..3)
|
31
|
+
# assert_equal(1, a.lazy.each(4).first)
|
32
|
+
# assert_equal([4], a.args)
|
33
|
+
# end
|
34
|
+
|
35
|
+
def test_each_line
|
36
|
+
name = lineno = nil
|
37
|
+
File.open(__FILE__) do |f|
|
38
|
+
f.each("").map do |paragraph|
|
39
|
+
paragraph[/\A\s*(.*)/, 1]
|
40
|
+
end.find do |line|
|
41
|
+
if name = line[/^class\s+(\S+)/, 1]
|
42
|
+
lineno = f.lineno
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
assert_equal(self.class.name, name)
|
48
|
+
assert_operator(lineno, :>, 2)
|
49
|
+
|
50
|
+
name = lineno = nil
|
51
|
+
File.open(__FILE__) do |f|
|
52
|
+
### Backports: Modified to avoid bug of Enumerator#each not passing args in MRI < 2.0
|
53
|
+
f.each("").lazy.map do |paragraph| #
|
54
|
+
paragraph[/\A\s*(.*)/, 1]
|
55
|
+
end.find do |line|
|
56
|
+
if name = line[/^class\s+(\S+)/, 1]
|
57
|
+
lineno = f.lineno
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
assert_equal(self.class.name, name)
|
63
|
+
assert_equal(2, lineno)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_select
|
67
|
+
a = Step.new(1..6)
|
68
|
+
assert_equal(4, a.select {|x| x > 3}.first)
|
69
|
+
assert_equal(6, a.current)
|
70
|
+
assert_equal(4, a.lazy.select {|x| x > 3}.first)
|
71
|
+
assert_equal(4, a.current)
|
72
|
+
|
73
|
+
a = Step.new(['word', nil, 1])
|
74
|
+
assert_raise(TypeError) {a.select {|x| "x"+x}.first}
|
75
|
+
assert_equal(nil, a.current)
|
76
|
+
assert_equal("word", a.lazy.select {|x| "x"+x}.first)
|
77
|
+
assert_equal("word", a.current)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_select_multiple_values
|
81
|
+
e = Enumerator.new { |yielder|
|
82
|
+
for i in 1..5
|
83
|
+
yielder.yield(i, i.to_s)
|
84
|
+
end
|
85
|
+
}
|
86
|
+
assert_equal([[2, "2"], [4, "4"]],
|
87
|
+
e.select {|x| x[0] % 2 == 0})
|
88
|
+
assert_equal([[2, "2"], [4, "4"]],
|
89
|
+
e.lazy.select {|x| x[0] % 2 == 0}.force)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_map
|
93
|
+
a = Step.new(1..3)
|
94
|
+
assert_equal(2, a.map {|x| x * 2}.first)
|
95
|
+
assert_equal(3, a.current)
|
96
|
+
assert_equal(2, a.lazy.map {|x| x * 2}.first)
|
97
|
+
assert_equal(1, a.current)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_flat_map
|
101
|
+
a = Step.new(1..3)
|
102
|
+
assert_equal(2, a.flat_map {|x| [x * 2]}.first)
|
103
|
+
assert_equal(3, a.current)
|
104
|
+
assert_equal(2, a.lazy.flat_map {|x| [x * 2]}.first)
|
105
|
+
assert_equal(1, a.current)
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_flat_map_nested
|
109
|
+
a = Step.new(1..3)
|
110
|
+
assert_equal([1, "a"],
|
111
|
+
a.flat_map {|x| ("a".."c").map {|y| [x, y]}}.first)
|
112
|
+
assert_equal(3, a.current)
|
113
|
+
assert_equal([1, "a"],
|
114
|
+
a.lazy.flat_map {|x| ("a".."c").lazy.map {|y| [x, y]}}.first)
|
115
|
+
assert_equal(1, a.current)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_flat_map_to_ary
|
119
|
+
to_ary = Class.new {
|
120
|
+
def initialize(value)
|
121
|
+
@value = value
|
122
|
+
end
|
123
|
+
|
124
|
+
def to_ary
|
125
|
+
[:to_ary, @value]
|
126
|
+
end
|
127
|
+
}
|
128
|
+
assert_equal([:to_ary, 1, :to_ary, 2, :to_ary, 3],
|
129
|
+
[1, 2, 3].flat_map {|x| to_ary.new(x)})
|
130
|
+
assert_equal([:to_ary, 1, :to_ary, 2, :to_ary, 3],
|
131
|
+
[1, 2, 3].lazy.flat_map {|x| to_ary.new(x)}.force)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_flat_map_non_array
|
135
|
+
assert_equal(["1", "2", "3"], [1, 2, 3].flat_map {|x| x.to_s})
|
136
|
+
assert_equal(["1", "2", "3"], [1, 2, 3].lazy.flat_map {|x| x.to_s}.force)
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_flat_map_hash
|
140
|
+
assert_equal([{?a=>97}, {?b=>98}, {?c=>99}], [?a, ?b, ?c].flat_map {|x| {x=>x.ord}})
|
141
|
+
assert_equal([{?a=>97}, {?b=>98}, {?c=>99}], [?a, ?b, ?c].lazy.flat_map {|x| {x=>x.ord}}.force)
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_reject
|
145
|
+
a = Step.new(1..6)
|
146
|
+
assert_equal(4, a.reject {|x| x < 4}.first)
|
147
|
+
assert_equal(6, a.current)
|
148
|
+
assert_equal(4, a.lazy.reject {|x| x < 4}.first)
|
149
|
+
assert_equal(4, a.current)
|
150
|
+
|
151
|
+
a = Step.new(['word', nil, 1])
|
152
|
+
assert_equal(nil, a.reject {|x| x}.first)
|
153
|
+
assert_equal(1, a.current)
|
154
|
+
assert_equal(nil, a.lazy.reject {|x| x}.first)
|
155
|
+
assert_equal(nil, a.current)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_reject_multiple_values
|
159
|
+
e = Enumerator.new { |yielder|
|
160
|
+
for i in 1..5
|
161
|
+
yielder.yield(i, i.to_s)
|
162
|
+
end
|
163
|
+
}
|
164
|
+
assert_equal([[2, "2"], [4, "4"]],
|
165
|
+
e.reject {|x| x[0] % 2 != 0})
|
166
|
+
assert_equal([[2, "2"], [4, "4"]],
|
167
|
+
e.lazy.reject {|x| x[0] % 2 != 0}.force)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_grep
|
171
|
+
a = Step.new('a'..'f')
|
172
|
+
assert_equal('c', a.grep(/c/).first)
|
173
|
+
assert_equal('f', a.current)
|
174
|
+
assert_equal('c', a.lazy.grep(/c/).first)
|
175
|
+
assert_equal('c', a.current)
|
176
|
+
assert_equal(%w[a e], a.grep(proc {|x| /[aeiou]/ =~ x}))
|
177
|
+
assert_equal(%w[a e], a.lazy.grep(proc {|x| /[aeiou]/ =~ x}).to_a)
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_grep_with_block
|
181
|
+
a = Step.new('a'..'f')
|
182
|
+
assert_equal('C', a.grep(/c/) {|i| i.upcase}.first)
|
183
|
+
assert_equal('C', a.lazy.grep(/c/) {|i| i.upcase}.first)
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_grep_multiple_values
|
187
|
+
e = Enumerator.new { |yielder|
|
188
|
+
3.times { |i|
|
189
|
+
yielder.yield(i, i.to_s)
|
190
|
+
}
|
191
|
+
}
|
192
|
+
assert_equal([[2, "2"]], e.grep(proc {|x| x == [2, "2"]}))
|
193
|
+
assert_equal([[2, "2"]], e.lazy.grep(proc {|x| x == [2, "2"]}).force)
|
194
|
+
assert_equal(["22"],
|
195
|
+
e.lazy.grep(proc {|x| x == [2, "2"]}, &:join).force)
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_zip
|
199
|
+
a = Step.new(1..3)
|
200
|
+
assert_equal([1, "a"], a.zip("a".."c").first)
|
201
|
+
assert_equal(3, a.current)
|
202
|
+
assert_equal([1, "a"], a.lazy.zip("a".."c").first)
|
203
|
+
assert_equal(1, a.current)
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_zip_short_arg
|
207
|
+
a = Step.new(1..5)
|
208
|
+
assert_equal([5, nil], a.zip("a".."c").last)
|
209
|
+
assert_equal([5, nil], a.lazy.zip("a".."c").force.last)
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_zip_without_arg
|
213
|
+
a = Step.new(1..3)
|
214
|
+
assert_equal([1], a.zip.first)
|
215
|
+
assert_equal(3, a.current)
|
216
|
+
assert_equal([1], a.lazy.zip.first)
|
217
|
+
assert_equal(1, a.current)
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_zip_bad_arg
|
221
|
+
a = Step.new(1..3)
|
222
|
+
assert_raise(TypeError){ a.lazy.zip(42) }
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_zip_with_block
|
226
|
+
# zip should be eager when a block is given
|
227
|
+
a = Step.new(1..3)
|
228
|
+
ary = []
|
229
|
+
assert_equal(nil, a.lazy.zip("a".."c") {|x, y| ary << [x, y]})
|
230
|
+
assert_equal(a.zip("a".."c"), ary)
|
231
|
+
assert_equal(3, a.current)
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_take
|
235
|
+
a = Step.new(1..10)
|
236
|
+
assert_equal(1, a.take(5).first)
|
237
|
+
assert_equal(5, a.current)
|
238
|
+
assert_equal(1, a.lazy.take(5).first)
|
239
|
+
assert_equal(1, a.current)
|
240
|
+
assert_equal((1..5).to_a, a.lazy.take(5).force)
|
241
|
+
assert_equal(5, a.current)
|
242
|
+
a = Step.new(1..10)
|
243
|
+
assert_equal([], a.lazy.take(0).force)
|
244
|
+
assert_equal(nil, a.current)
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_take_recycle
|
248
|
+
bug6428 = '[ruby-dev:45634]'
|
249
|
+
a = Step.new(1..10)
|
250
|
+
take5 = a.lazy.take(5)
|
251
|
+
assert_equal((1..5).to_a, take5.force, bug6428)
|
252
|
+
assert_equal((1..5).to_a, take5.force, bug6428)
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_take_nested
|
256
|
+
bug7696 = '[ruby-core:51470]'
|
257
|
+
a = Step.new(1..10)
|
258
|
+
take5 = a.lazy.take(5)
|
259
|
+
assert_equal([*(1..5)]*5, take5.flat_map{take5}.force, bug7696)
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_drop_while_nested
|
263
|
+
bug7696 = '[ruby-core:51470]'
|
264
|
+
a = Step.new(1..10)
|
265
|
+
drop5 = a.lazy.drop_while{|x| x < 6}
|
266
|
+
assert_equal([*(6..10)]*5, drop5.flat_map{drop5}.force, bug7696)
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_drop_nested
|
270
|
+
bug7696 = '[ruby-core:51470]'
|
271
|
+
a = Step.new(1..10)
|
272
|
+
drop5 = a.lazy.drop(5)
|
273
|
+
assert_equal([*(6..10)]*5, drop5.flat_map{drop5}.force, bug7696)
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_zip_nested
|
277
|
+
bug7696 = '[ruby-core:51470]'
|
278
|
+
enum = ('a'..'z').each
|
279
|
+
enum.next
|
280
|
+
zip = (1..3).lazy.zip(enum, enum)
|
281
|
+
assert_equal([[1, 'a', 'a'], [2, 'b', 'b'], [3, 'c', 'c']]*3, zip.flat_map{zip}.force, bug7696)
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_zip_lazy_on_args
|
285
|
+
zip = Step.new(1..2).lazy.zip(42..Float::INFINITY)
|
286
|
+
assert_equal [[1, 42], [2, 43]], zip.force
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_zip_efficient_on_array_args
|
290
|
+
ary = [42, :foo]
|
291
|
+
[:to_enum, :enum_for, :lazy, :each].each do |forbid|
|
292
|
+
ary.define_singleton_method(forbid){ fail "#{forbid} was called"}
|
293
|
+
end
|
294
|
+
zip = Step.new(1..2).lazy.zip(ary)
|
295
|
+
assert_equal [[1, 42], [2, :foo]], zip.force
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_take_rewound
|
299
|
+
bug7696 = '[ruby-core:51470]'
|
300
|
+
e=(1..42).lazy.take(2)
|
301
|
+
assert_equal 1, e.next
|
302
|
+
assert_equal 2, e.next
|
303
|
+
e.rewind
|
304
|
+
assert_equal 1, e.next
|
305
|
+
assert_equal 2, e.next
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_take_while
|
309
|
+
a = Step.new(1..10)
|
310
|
+
assert_equal(1, a.take_while {|i| i < 5}.first)
|
311
|
+
assert_equal(5, a.current)
|
312
|
+
assert_equal(1, a.lazy.take_while {|i| i < 5}.first)
|
313
|
+
assert_equal(1, a.current)
|
314
|
+
assert_equal((1..4).to_a, a.lazy.take_while {|i| i < 5}.to_a)
|
315
|
+
end
|
316
|
+
|
317
|
+
def test_drop
|
318
|
+
a = Step.new(1..10)
|
319
|
+
assert_equal(6, a.drop(5).first)
|
320
|
+
assert_equal(10, a.current)
|
321
|
+
assert_equal(6, a.lazy.drop(5).first)
|
322
|
+
assert_equal(6, a.current)
|
323
|
+
assert_equal((6..10).to_a, a.lazy.drop(5).to_a)
|
324
|
+
end
|
325
|
+
|
326
|
+
def test_drop_while
|
327
|
+
a = Step.new(1..10)
|
328
|
+
assert_equal(5, a.drop_while {|i| i < 5}.first)
|
329
|
+
assert_equal(10, a.current)
|
330
|
+
assert_equal(5, a.lazy.drop_while {|i| i < 5}.first)
|
331
|
+
assert_equal(5, a.current)
|
332
|
+
assert_equal((5..10).to_a, a.lazy.drop_while {|i| i < 5}.to_a)
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_drop_and_take
|
336
|
+
assert_equal([4, 5], (1..Float::INFINITY).lazy.drop(3).take(2).to_a)
|
337
|
+
end
|
338
|
+
|
339
|
+
def test_cycle
|
340
|
+
a = Step.new(1..3)
|
341
|
+
assert_equal("1", a.cycle(2).map(&:to_s).first)
|
342
|
+
assert_equal(3, a.current)
|
343
|
+
assert_equal("1", a.lazy.cycle(2).map(&:to_s).first)
|
344
|
+
assert_equal(1, a.current)
|
345
|
+
end
|
346
|
+
|
347
|
+
def test_cycle_with_block
|
348
|
+
# cycle should be eager when a block is given
|
349
|
+
a = Step.new(1..3)
|
350
|
+
ary = []
|
351
|
+
assert_equal(nil, a.lazy.cycle(2) {|i| ary << i})
|
352
|
+
assert_equal(a.cycle(2).to_a, ary)
|
353
|
+
assert_equal(3, a.current)
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_cycle_chain
|
357
|
+
a = 1..3
|
358
|
+
assert_equal([1,2,3,1,2,3,1,2,3,1], a.lazy.cycle.take(10).force)
|
359
|
+
assert_equal([2,2,2,2,2,2,2,2,2,2], a.lazy.cycle.select {|x| x == 2}.take(10).force)
|
360
|
+
assert_equal([2,2,2,2,2,2,2,2,2,2], a.lazy.select {|x| x == 2}.cycle.take(10).force)
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_force
|
364
|
+
assert_equal([1, 2, 3], (1..Float::INFINITY).lazy.take(3).force)
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_inspect
|
368
|
+
assert_equal("#<Enumerator::Lazy: 1..10>", (1..10).lazy.inspect)
|
369
|
+
assert_equal('#<Enumerator::Lazy: #<Enumerator: "foo":each_char>>',
|
370
|
+
"foo".each_char.lazy.inspect)
|
371
|
+
assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:map>",
|
372
|
+
(1..10).lazy.map {}.inspect)
|
373
|
+
assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:take(0)>",
|
374
|
+
(1..10).lazy.take(0).inspect)
|
375
|
+
assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:take(3)>",
|
376
|
+
(1..10).lazy.take(3).inspect)
|
377
|
+
assert_equal('#<Enumerator::Lazy: #<Enumerator::Lazy: "a".."c">:grep(/b/)>',
|
378
|
+
("a".."c").lazy.grep(/b/).inspect)
|
379
|
+
assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle(3)>",
|
380
|
+
(1..10).lazy.cycle(3).inspect)
|
381
|
+
assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle>",
|
382
|
+
(1..10).lazy.cycle.inspect)
|
383
|
+
assert_equal("#<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:cycle(3)>",
|
384
|
+
(1..10).lazy.cycle(3).inspect)
|
385
|
+
l = (1..10).lazy.map {}.collect {}.flat_map {}.collect_concat {}.select {}.find_all {}.reject {}.grep(1).zip(?a..?c).take(10).take_while {}.drop(3).drop_while {}.cycle(3)
|
386
|
+
### Backport: Modified because I don't think the actual name we were called under in case of aliases is important enough to care
|
387
|
+
assert_equal(<<EOS.chomp, l.inspect)
|
388
|
+
#<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 1..10>:map>:map>:flat_map>:flat_map>:select>:select>:reject>:grep(1)>:zip("a".."c")>:take(10)>:take_while>:drop(3)>:drop_while>:cycle(3)>
|
389
|
+
EOS
|
390
|
+
end
|
391
|
+
|
392
|
+
def test_lazy_to_enum
|
393
|
+
lazy = [1, 2, 3].lazy
|
394
|
+
def lazy.foo(*args)
|
395
|
+
yield args
|
396
|
+
yield args
|
397
|
+
end
|
398
|
+
enum = lazy.to_enum(:foo, :hello, :world)
|
399
|
+
assert_equal Enumerator::Lazy, enum.class
|
400
|
+
# assert_equal nil, enum.size ### Backport: see below
|
401
|
+
assert_equal [[:hello, :world], [:hello, :world]], enum.to_a
|
402
|
+
|
403
|
+
assert_equal [1, 2, 3], lazy.to_enum.to_a
|
404
|
+
end
|
405
|
+
|
406
|
+
### Backport: way too much work to shim #size
|
407
|
+
# def test_size
|
408
|
+
# lazy = [1, 2, 3].lazy
|
409
|
+
# assert_equal 3, lazy.size
|
410
|
+
# assert_equal 42, Enumerator::Lazy.new([],->{42}){}.size
|
411
|
+
# assert_equal 42, Enumerator::Lazy.new([],42){}.size
|
412
|
+
# assert_equal 42, Enumerator::Lazy.new([],42){}.lazy.size
|
413
|
+
# assert_equal 42, lazy.to_enum{ 42 }.size
|
414
|
+
|
415
|
+
# [:map, :collect].each do |m|
|
416
|
+
# assert_equal 3, lazy.send(m){}.size
|
417
|
+
# end
|
418
|
+
# assert_equal 3, lazy.zip([4]).size
|
419
|
+
# [:flat_map, :collect_concat, :select, :find_all, :reject, :take_while, :drop_while].each do |m|
|
420
|
+
# assert_equal nil, lazy.send(m){}.size
|
421
|
+
# end
|
422
|
+
# assert_equal nil, lazy.grep(//).size
|
423
|
+
|
424
|
+
# assert_equal 2, lazy.take(2).size
|
425
|
+
# assert_equal 3, lazy.take(4).size
|
426
|
+
# assert_equal 4, loop.lazy.take(4).size
|
427
|
+
# assert_equal nil, lazy.select{}.take(4).size
|
428
|
+
|
429
|
+
# assert_equal 1, lazy.drop(2).size
|
430
|
+
# assert_equal 0, lazy.drop(4).size
|
431
|
+
# assert_equal Float::INFINITY, loop.lazy.drop(4).size
|
432
|
+
# assert_equal nil, lazy.select{}.drop(4).size
|
433
|
+
|
434
|
+
# assert_equal 0, lazy.cycle(0).size
|
435
|
+
# assert_equal 6, lazy.cycle(2).size
|
436
|
+
# assert_equal 3 << 80, 4.times.inject(lazy){|enum| enum.cycle(1 << 20)}.size
|
437
|
+
# assert_equal Float::INFINITY, lazy.cycle.size
|
438
|
+
# assert_equal Float::INFINITY, loop.lazy.cycle(4).size
|
439
|
+
# assert_equal Float::INFINITY, loop.lazy.cycle.size
|
440
|
+
# assert_equal nil, lazy.select{}.cycle(4).size
|
441
|
+
# assert_equal nil, lazy.select{}.cycle.size
|
442
|
+
# end
|
443
|
+
|
444
|
+
# def test_map_zip
|
445
|
+
# bug7507 = '[ruby-core:50545]'
|
446
|
+
# assert_ruby_status(["-e", "GC.stress = true", "-e", "(1..10).lazy.map{}.zip(){}"], bug7507)
|
447
|
+
# assert_ruby_status(["-e", "GC.stress = true", "-e", "(1..10).lazy.map{}.zip().to_a"], bug7507)
|
448
|
+
# end
|
449
|
+
|
450
|
+
def test_require_block
|
451
|
+
[:select, :reject, :drop_while, :take_while, :map, :flat_map].each do |method|
|
452
|
+
assert_raise(ArgumentError){ [].lazy.send(method) }
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
def test_laziness_conservation
|
457
|
+
bug7507 = '[ruby-core:51510]'
|
458
|
+
{
|
459
|
+
:slice_before => //,
|
460
|
+
:with_index => [],
|
461
|
+
:cycle => [],
|
462
|
+
:each_with_object => 42,
|
463
|
+
:each_slice => 42,
|
464
|
+
:each_entry => [],
|
465
|
+
:each_cons => 42,
|
466
|
+
}.each do |method, arg|
|
467
|
+
assert_equal Enumerator::Lazy, [].lazy.send(method, *arg).class, bug7507
|
468
|
+
end
|
469
|
+
assert_equal Enumerator::Lazy, [].lazy.chunk{}.class, bug7507
|
470
|
+
end
|
471
|
+
|
472
|
+
### Backport: assert_warning not defined, we're ok anyways
|
473
|
+
# def test_no_warnings
|
474
|
+
# le = (1..3).lazy
|
475
|
+
# assert_warning("") {le.zip([4,5,6]).force}
|
476
|
+
# assert_warning("") {le.zip(4..6).force}
|
477
|
+
# assert_warning("") {le.take(1).force}
|
478
|
+
# assert_warning("") {le.drop(1).force}
|
479
|
+
# assert_warning("") {le.drop_while{false}.force}
|
480
|
+
# end
|
481
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-25 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Essential backports that enable some of the really nice features of ruby
|
15
15
|
1.8.7, ruby 1.9 and rails from ruby 1.8.6 and earlier.
|
@@ -105,7 +105,12 @@ files:
|
|
105
105
|
- lib/backports/2.0.0/array.rb
|
106
106
|
- lib/backports/2.0.0/enumerable.rb
|
107
107
|
- lib/backports/2.0.0/enumerator/lazy.rb
|
108
|
+
- lib/backports/2.0.0/hash.rb
|
109
|
+
- lib/backports/2.0.0/nil_class.rb
|
108
110
|
- lib/backports/2.0.0/range.rb
|
111
|
+
- lib/backports/2.0.0/stdlib.rb
|
112
|
+
- lib/backports/2.0.0/stdlib/ostruct.rb
|
113
|
+
- lib/backports/2.0.0/struct.rb
|
109
114
|
- lib/backports/2.0.rb
|
110
115
|
- lib/backports/basic_object.rb
|
111
116
|
- lib/backports/force/array_map.rb
|
@@ -125,6 +130,7 @@ files:
|
|
125
130
|
- test/README
|
126
131
|
- test/std_lib_loading_test.rb
|
127
132
|
- test/test_helper.rb
|
133
|
+
- test/test_lazy.rb
|
128
134
|
- test/test_socket_interaction.rb
|
129
135
|
homepage: http://github.com/marcandre/backports
|
130
136
|
licenses: []
|
@@ -154,5 +160,6 @@ test_files:
|
|
154
160
|
- test/README
|
155
161
|
- test/std_lib_loading_test.rb
|
156
162
|
- test/test_helper.rb
|
163
|
+
- test/test_lazy.rb
|
157
164
|
- test/test_socket_interaction.rb
|
158
165
|
has_rdoc:
|