backports 2.8.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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):
@@ -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
- *Note*: Ruby 2.0.0 will not included by default until 2.0.0 is released (and specs are thus finalized). To play around with these today, <tt>require "backports/2.0"</tt>.
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
- I am aware of the following backport gem which will hopefully be part of backports soon:
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
 
@@ -1,4 +1,4 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/backports/tools")
2
2
  Backports.require_relative "backports/version"
3
- Backports.require_relative "backports/1.9"
3
+ Backports.require_relative "backports/2.0"
4
4
  Backports.require_relative "backports/rails"
@@ -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(Generator.new(&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
@@ -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
- replace(Hash.new(&Backports.coerce_to(proc, Proc, :to_proc)).merge!(self))
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
- module Enumerable
2
- def lazy
3
- Enumerator::Lazy.new(self){|yielder, *val| yielder.<<(*val)}
4
- end unless method_defined? :lazy
5
- end
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
- require_relative 'enumerator/lazy' unless const_defined? :Lazy
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
- return super(obj.object, :non_lazy_cycle, obj.n) if obj.is_a?(@@cycler)
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
- return Lazy.new([]){} if n == 0
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,5 @@
1
+ class NilClass
2
+ def to_h
3
+ {}
4
+ end unless method_defined? :to_h
5
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ class Struct
2
+ def to_h
3
+ Hash[
4
+ self.class.members.each{|m| [m.to_sym, self[m]]}
5
+ ]
6
+ end unless method_defined? :to_h
7
+ end
@@ -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.class_eval do
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
@@ -1,3 +1,3 @@
1
1
  module Backports
2
- VERSION = "2.8.2"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -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: 2.8.2
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-03 00:00:00.000000000 Z
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: