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.
@@ -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: