backports 2.8.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|