quality_extensions 1.1.4 → 1.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/Xfind_bug_test.rb +28 -0
- data/lib/quality_extensions/array/all_same.rb +40 -0
- data/lib/quality_extensions/array/delete_if_bang.rb +145 -0
- data/lib/quality_extensions/array/expand_ranges.rb +3 -53
- data/lib/quality_extensions/array/include_any_of.rb +23 -0
- data/lib/quality_extensions/array/justify.rb +305 -0
- data/lib/quality_extensions/array/{average.rb → mean.rb} +1 -1
- data/lib/quality_extensions/array/select_if_bang.rb +0 -0
- data/lib/quality_extensions/array/sum.rb +30 -0
- data/lib/quality_extensions/enumerable/all_same.rb +43 -0
- data/lib/quality_extensions/enumerable/group_by_and_map.rb +110 -0
- data/lib/quality_extensions/enumerable/select_bang.rb +49 -0
- data/lib/quality_extensions/enumerable/select_while.rb +337 -52
- data/lib/quality_extensions/enumerable/select_with_index.rb +145 -0
- data/lib/quality_extensions/hash/hash_select.rb +5 -2
- data/lib/quality_extensions/hash/merge_if.rb +48 -0
- data/lib/quality_extensions/kernel/example_printer.rb +10 -3
- data/lib/quality_extensions/kernel/require_all.rb +24 -8
- data/lib/quality_extensions/kernel/sleep_loudly.rb +108 -0
- data/lib/quality_extensions/kernel/uninterruptable.rb +22 -0
- data/lib/quality_extensions/matrix/indexable.rb +68 -0
- data/lib/quality_extensions/matrix/linked_vectors.rb +137 -0
- data/lib/quality_extensions/module/class_methods.rb +2 -0
- data/lib/quality_extensions/object/non.rb +12 -0
- data/lib/quality_extensions/pathname.rb +435 -7
- data/lib/quality_extensions/range_list.rb +222 -0
- data/lib/quality_extensions/safe_nil.rb +5 -3
- data/lib/quality_extensions/string/each_char_with_index.rb +1 -2
- data/lib/quality_extensions/string/integer_eh.rb +3 -0
- data/lib/quality_extensions/string/numeric_eh.rb +74 -0
- data/lib/quality_extensions/string/safe_in_comment.rb +38 -0
- data/lib/quality_extensions/string/safe_numeric_conversion.rb +102 -0
- data/lib/quality_extensions/string/shell_escape.rb +4 -4
- data/lib/quality_extensions/string/with_knowledge_of_color.rb +8 -0
- data/lib/quality_extensions/table.rb +116 -0
- data/lib/quality_extensions/template.rb +4 -5
- data/lib/quality_extensions/template.rb_test_unit.rb +33 -0
- data/lib/quality_extensions/test/difference_highlighting-minitest.rb +321 -0
- data/lib/quality_extensions/test/difference_highlighting-test_unit.rb +325 -0
- data/lib/quality_extensions/test/difference_highlighting.rb +6 -314
- data/lib/quality_extensions/timeout/countdown_timer.rb +1 -0
- data/lib/quality_extensions/vector/enumerable.rb +51 -0
- metadata +35 -5
@@ -0,0 +1,110 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: Tyler Rick, Erik Veenstra
|
3
|
+
# Copyright:: -
|
4
|
+
# License:: -
|
5
|
+
# Submit to Facets?:: Maybe
|
6
|
+
# Developer notes::
|
7
|
+
# Changes::
|
8
|
+
# * Created, based on Facets group_by
|
9
|
+
#++
|
10
|
+
|
11
|
+
module Enumerable
|
12
|
+
|
13
|
+
# #group_by_and_map is used to group items in a collection by something they
|
14
|
+
# have in common. The common factor is the key in the resulting hash, the
|
15
|
+
# array of like elements is the value.
|
16
|
+
#
|
17
|
+
# This differs from the normal group_by in that it lets you map the values
|
18
|
+
# (perhaps removing the key from the value since that would be redundant)
|
19
|
+
# all in one step.
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# # need better example
|
23
|
+
# (1..6).group_by_and_map { |n| next n % 3, n }
|
24
|
+
# # => { 0 => [3,6], 1 => [1, 4], 2 => [2,5] }
|
25
|
+
#
|
26
|
+
# [
|
27
|
+
# ['31a4', 'v1.3'],
|
28
|
+
# ['9f2b', 'current'],
|
29
|
+
# ['9f2b', 'v2.0']
|
30
|
+
# ].group_by_and_map { |e| e[0], e[1] }
|
31
|
+
# # => {"31a4"=>["v1.3"], "9f2b"=>["current", "v2.0"]}
|
32
|
+
#
|
33
|
+
# results.group_by_and_map { |a| a[0], a[1..-1] }
|
34
|
+
#
|
35
|
+
# CREDIT: Erik Veenstra, Tyler Rick
|
36
|
+
|
37
|
+
def group_by_and_map #:yield:
|
38
|
+
h = Hash.new
|
39
|
+
each { |e|
|
40
|
+
result = yield(e)
|
41
|
+
#p result
|
42
|
+
(h[result[0]] ||= []) << result[1]
|
43
|
+
}
|
44
|
+
h
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
# _____ _
|
50
|
+
# |_ _|__ ___| |_
|
51
|
+
# | |/ _ \/ __| __|
|
52
|
+
# | | __/\__ \ |_
|
53
|
+
# |_|\___||___/\__|
|
54
|
+
#
|
55
|
+
=begin test
|
56
|
+
require 'spec'
|
57
|
+
|
58
|
+
describe 'Enumerable#group_by_and_map' do
|
59
|
+
it '' do
|
60
|
+
(1..6).group_by_and_map { |n| next n % 3, n }.should ==
|
61
|
+
{0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}
|
62
|
+
end
|
63
|
+
|
64
|
+
it '' do
|
65
|
+
[
|
66
|
+
['r1', 'v1.3'],
|
67
|
+
['r9', 'current'],
|
68
|
+
['r9', 'v2.0']
|
69
|
+
].group_by_and_map { |e| next e[0], e[1] }.should ==
|
70
|
+
{"r1"=>["v1.3"], "r9"=>["current", "v2.0"]}
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'beats the alternatives' do
|
74
|
+
expected = {1=>["a", "b"], 2=>["c"], 3=>["d"]}
|
75
|
+
result = [
|
76
|
+
[1, 'a'],
|
77
|
+
[1, 'b'],
|
78
|
+
[2, 'c'],
|
79
|
+
[3, 'd'],
|
80
|
+
].group_by_and_map { |e| next e[0], e[1] }
|
81
|
+
result.should == expected
|
82
|
+
result.should be_instance_of Hash
|
83
|
+
result[1].should == ['a', 'b']
|
84
|
+
|
85
|
+
# group_by and then map? Then it's no longer a hash and is icky to work with.
|
86
|
+
result = [
|
87
|
+
[1, 'a'],
|
88
|
+
[1, 'b'],
|
89
|
+
[2, 'c'],
|
90
|
+
[3, 'd'],
|
91
|
+
].group_by { |e| e[0] }.map { |(k,v)| [k,v.map(&:last)]}
|
92
|
+
result.should == expected.to_a
|
93
|
+
result.should be_instance_of Array
|
94
|
+
# Yuck
|
95
|
+
result[0].should == [1, ['a', 'b']]
|
96
|
+
result[1].should == [2, ['c']]
|
97
|
+
|
98
|
+
# map and then group_by? As soon as you use map to discard the key so it's not in the value, that information is lost and can't be used by the group_by.
|
99
|
+
result = [
|
100
|
+
[1, 'a'],
|
101
|
+
[1, 'b'],
|
102
|
+
[2, 'c'],
|
103
|
+
[3, 'd'],
|
104
|
+
].map {|a| a[1]}
|
105
|
+
result.should == ["a", "b", "c", "d"] # oops, now how do we do a group_by on the key we just removed?
|
106
|
+
result.should be_instance_of Array
|
107
|
+
end
|
108
|
+
end
|
109
|
+
=end
|
110
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#--
|
2
|
+
# Author:: Tyler Rick
|
3
|
+
# Copyright:: Copyright (c) 2009, Tyler Rick
|
4
|
+
# License:: Ruby License
|
5
|
+
# Submit to Facets?:: Yes
|
6
|
+
# Developer notes::
|
7
|
+
# History::
|
8
|
+
#++
|
9
|
+
|
10
|
+
module Enumerable
|
11
|
+
# def reject!
|
12
|
+
# if self.is_a? Range
|
13
|
+
# to_a.reject! { yield }
|
14
|
+
# else
|
15
|
+
# raise NoMethodError
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
|
19
|
+
def select!
|
20
|
+
reject! { |x| !yield(x) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# _____ _
|
26
|
+
# |_ _|__ ___| |_
|
27
|
+
# | |/ _ \/ __| __|
|
28
|
+
# | | __/\__ \ |_
|
29
|
+
# |_|\___||___/\__|
|
30
|
+
#
|
31
|
+
=begin test
|
32
|
+
require 'spec'
|
33
|
+
|
34
|
+
describe 'Enumerable#select!' do
|
35
|
+
it 'reject!' do
|
36
|
+
a = %w[a b c d]
|
37
|
+
a.reject! {|e| e =~ /[ab]/}.should == a
|
38
|
+
a.should == %w[c d]
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'select!' do
|
42
|
+
a = %w[a b c d]
|
43
|
+
a.select! {|e| e =~ /[ab]/}.should == a
|
44
|
+
a.should == %w[a b]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
=end
|
48
|
+
|
49
|
+
|
@@ -5,48 +5,200 @@
|
|
5
5
|
# Submit to Facets?:: Yes.
|
6
6
|
# Developer notes::
|
7
7
|
# Changes::
|
8
|
+
# To do::
|
9
|
+
# * !! Why does Hash#each_with_index yield |(k,v), i| but my select_with_index yields flat |k, v, i| ?
|
8
10
|
#++
|
9
11
|
|
12
|
+
require 'facets/kernel/require_local'
|
13
|
+
require_local 'select_with_index'
|
10
14
|
|
11
15
|
module Enumerable
|
16
|
+
# Original version before I changed it to use select so that Hash#select_until would return a hash instead of an array.
|
17
|
+
# def select_until(inclusive = true)
|
18
|
+
# return self unless block_given?
|
19
|
+
#
|
20
|
+
# selected = []
|
21
|
+
# if inclusive
|
22
|
+
# each do |item|
|
23
|
+
# selected << item
|
24
|
+
# break if yield(item)
|
25
|
+
# end
|
26
|
+
# else
|
27
|
+
# each do |item|
|
28
|
+
# break if yield(item)
|
29
|
+
# selected << item
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# selected
|
33
|
+
# end
|
34
|
+
|
12
35
|
# Returns an array containing all _consecutive_ elements of +enum+ for which +block+ is not false, starting at the first element.
|
13
|
-
# So it is very much like select
|
36
|
+
# So it is very much like +select+, but unlike +select+, it stops searching as soon as +block+ ceases to be true. (That means it will stop searching immediately if the first element doesn't match.)
|
14
37
|
#
|
15
38
|
# This might be preferable to +select+, for example, if:
|
16
39
|
# * you have a very large collection of elements
|
17
40
|
# * the desired elements are expected to all be consecutively occuring and are all at the beginning of the collection
|
18
41
|
# * it would be costly to continue iterating all the way to the very end
|
19
42
|
#
|
20
|
-
#
|
43
|
+
# If +inclusive+ is false, only those elements occuring _before_ the first element for which +block+ is true will be returned.
|
44
|
+
# If +inclusive+ is true (the default), those elements occuring up to and _including_ the first element for which +block+ is true will be returned.
|
45
|
+
#
|
46
|
+
# (0..3).select_until {|v| v == 1} # => [0, 1]
|
47
|
+
# (0..3).select_until(false) {|v| v == 1} # => [0]
|
48
|
+
#
|
49
|
+
# {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until {|k, v| v == 2} ) # => {"a"=>1, "b"=>2}
|
50
|
+
# {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until(false) {|k, v| v == 2} ) # => {"a"=>1}
|
51
|
+
#
|
52
|
+
def select_until(inclusive = true)
|
53
|
+
return self unless block_given?
|
54
|
+
|
55
|
+
done = false
|
56
|
+
if inclusive
|
57
|
+
select do |*args|
|
58
|
+
returning = !done
|
59
|
+
done = true if yield(*args)
|
60
|
+
returning
|
61
|
+
end
|
62
|
+
else
|
63
|
+
select do |*args|
|
64
|
+
done = true if yield(*args)
|
65
|
+
!done
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Same as select_until but each time an element of the enum is yielded, an index/counter is also included as an argument.
|
21
71
|
#
|
22
|
-
#
|
72
|
+
# This is probably only useful for collections that have some kind of predictable ordering (such as Arrays). Fortunately, Hashes have a predictable order in Ruby 1.9.
|
23
73
|
#
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
74
|
+
def select_until_with_index(inclusive = true)
|
75
|
+
return self unless block_given?
|
76
|
+
|
77
|
+
done = false
|
78
|
+
if inclusive
|
79
|
+
select_with_index do |*args|
|
80
|
+
returning = !done
|
81
|
+
done = true if yield(*args)
|
82
|
+
returning
|
30
83
|
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
84
|
+
else
|
85
|
+
select_with_index do |*args|
|
86
|
+
done = true if yield(*args)
|
87
|
+
!done
|
35
88
|
end
|
36
|
-
|
37
|
-
selected
|
89
|
+
end
|
38
90
|
end
|
39
91
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
92
|
+
# Better name? select_consec?
|
93
|
+
def select_while(include_first_false_element = false)
|
94
|
+
return self unless block_given?
|
95
|
+
|
96
|
+
done = false
|
97
|
+
if include_first_false_element
|
98
|
+
select do |*args|
|
99
|
+
returning = !done
|
100
|
+
done = true if !yield(*args)
|
101
|
+
returning
|
102
|
+
end
|
103
|
+
else
|
104
|
+
select do |*args|
|
105
|
+
#puts "!done=#{!done}; !yield(#{args}) => #{!yield(*args)}"
|
106
|
+
done = true if !yield(*args)
|
107
|
+
!done
|
108
|
+
end
|
45
109
|
end
|
46
|
-
selected
|
47
110
|
end
|
48
|
-
end
|
49
111
|
|
112
|
+
def select_while_with_index(include_first_false_element = false)
|
113
|
+
return self unless block_given?
|
114
|
+
|
115
|
+
done = false
|
116
|
+
if include_first_false_element
|
117
|
+
select_with_index do |*args|
|
118
|
+
returning = !done
|
119
|
+
done = true if !yield(*args)
|
120
|
+
returning
|
121
|
+
end
|
122
|
+
else
|
123
|
+
select_with_index do |*args|
|
124
|
+
#puts "!done=#{!done}; !yield(#{args}) => #{!yield(*args)}"
|
125
|
+
done = true if !yield(*args)
|
126
|
+
!done
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Whereas select_until goes until it reaches the _first_ element for which +block+ is true, select_until_last goes until it reaches the _last_ element for which +block+ is true.
|
132
|
+
#
|
133
|
+
def select_until_last(inclusive = true)
|
134
|
+
return self unless block_given?
|
135
|
+
|
136
|
+
# Find the index of the last-matching element
|
137
|
+
last = nil
|
138
|
+
#each_with_index do |item, i|
|
139
|
+
# last = i if yield(item)
|
140
|
+
#end
|
141
|
+
each_with_index do |*args|
|
142
|
+
i = args.pop
|
143
|
+
last = i if yield(*args.first)
|
144
|
+
end
|
145
|
+
|
146
|
+
# If they want to exclude the last-matching element, adjust the index by -1 (if possible)
|
147
|
+
#if last && !inclusive
|
148
|
+
# if last == 0
|
149
|
+
# # If the last-matching element was also the first element, then we want to select *none* of the elements
|
150
|
+
# last = nil
|
151
|
+
# else
|
152
|
+
# last -= 1
|
153
|
+
# end
|
154
|
+
#end
|
155
|
+
# Select all elements up to last-matching element
|
156
|
+
#self.to_a[0 .. last] # (didn't work for hashes)
|
157
|
+
#select_with_index do |item, i|
|
158
|
+
# true if last && i <= last
|
159
|
+
#end
|
160
|
+
#select_while_with_index do |item, i|
|
161
|
+
# #puts "#{i} <= #{last} => #{last && i <= last}"
|
162
|
+
# last && i <= last
|
163
|
+
#end
|
164
|
+
|
165
|
+
# Select all elements up to last-matching element
|
166
|
+
if last.nil?
|
167
|
+
select do |*args|
|
168
|
+
false
|
169
|
+
end
|
170
|
+
else
|
171
|
+
select_until_with_index(inclusive) do |*args|
|
172
|
+
i = args.last
|
173
|
+
i == last
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def select_until_last_with_index(inclusive = true)
|
179
|
+
return self unless block_given?
|
180
|
+
|
181
|
+
# Find the index of the last-matching element
|
182
|
+
last = nil
|
183
|
+
each_with_index do |*args|
|
184
|
+
#p args
|
185
|
+
i = args.last
|
186
|
+
last = i if yield(*args)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Select all elements up to last-matching element
|
190
|
+
if last.nil?
|
191
|
+
select do |*args|
|
192
|
+
false
|
193
|
+
end
|
194
|
+
else
|
195
|
+
select_until_with_index(inclusive) do |*args|
|
196
|
+
i = args.last
|
197
|
+
i == last
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
50
202
|
|
51
203
|
|
52
204
|
|
@@ -59,50 +211,183 @@ end
|
|
59
211
|
#
|
60
212
|
=begin test
|
61
213
|
require 'test/unit'
|
214
|
+
require 'facets/string/indent'
|
215
|
+
|
216
|
+
class SelectWhileAndUntilTest < Test::Unit::TestCase
|
217
|
+
def test_basic_usage
|
218
|
+
assert_equal [0, 1], (0..3).select {|v| v <= 1}
|
219
|
+
assert_equal [0, 1], (0..3).select_while {|v| v <= 1}
|
220
|
+
assert_equal [0, 1], (0..3).select_until {|v| v == 1}
|
221
|
+
assert_equal [0], (0..3).select_until(false) {|v| v == 1}
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_basic_usage_with_index
|
225
|
+
assert_equal %w[a b], %w[a b c].select_with_index {|v, i| i <= 1}
|
226
|
+
assert_equal %w[a b], %w[a b c].select_while_with_index {|v, i| i <= 1}
|
227
|
+
assert_equal %w[a b], %w[a b c].select_until_with_index {|v, i| i == 1}
|
228
|
+
assert_equal %w[a], %w[a b c].select_until_with_index(false) {|v, i| i == 1}
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_when_no_matches_found
|
232
|
+
assert_equal [], (0..3).select {|v| false}
|
233
|
+
assert_equal [], (0..3).select_while {|v| false}
|
234
|
+
assert_equal [0], (0..3).select_until {|v| true}
|
235
|
+
assert_equal [], (0..3).select_until(false) {|v| true}
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_with_hashes_basic_usage
|
239
|
+
if RUBY_VERSION < '1.9'
|
240
|
+
# Yuck! Hash#select returns an array instead of returning a hash like reject.
|
241
|
+
assert_equal [["a", 1], ["b", 2], ["d", 1]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select {|k, v| v <= 2}
|
242
|
+
assert_equal [["a", 1], ["b", 2] ], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_while {|k, v| v <= 2}
|
243
|
+
assert_equal [["a", 1], ["b", 2] ], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until {|k, v| v == 2}
|
244
|
+
assert_equal [["a", 1] ], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until(false) {|k, v| v == 2}
|
245
|
+
else
|
246
|
+
assert_equal( {"a"=>1, "b"=>2, "d"=>1}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select {|k, v| v <= 2})
|
247
|
+
assert_equal( {"a"=>1, "b"=>2}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_while {|k, v| v <= 2} )
|
248
|
+
assert_equal( {"a"=>1, "b"=>2}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until {|k, v| v == 2} )
|
249
|
+
assert_equal( {"a"=>1}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until(false) {|k, v| v == 2} )
|
250
|
+
end
|
251
|
+
end
|
62
252
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
253
|
+
def test_with_hashes_basic_usage_with_index
|
254
|
+
if RUBY_VERSION < '1.9'
|
255
|
+
assert_equal [["a", 1], ["b", 2]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_with_index {|k, v, i| i <= 1}
|
256
|
+
assert_equal [["a", 1], ["b", 2]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_while_with_index {|k, v, i| i <= 1}
|
257
|
+
assert_equal [["a", 1], ["b", 2]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_with_index {|k, v, i| i == 1}
|
258
|
+
assert_equal [["a", 1] ], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_with_index(false) {|k, v, i| i == 1}
|
259
|
+
else
|
260
|
+
assert_equal( {"a"=>1, "b"=>2}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_with_index {|k, v, i| i <= 1} )
|
261
|
+
assert_equal( {"a"=>1, "b"=>2}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_while_with_index {|k, v, i| i <= 1} )
|
262
|
+
assert_equal( {"a"=>1, "b"=>2}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_with_index {|k, v, i| i == 1} )
|
263
|
+
assert_equal( {"a"=>1}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_with_index(false) {|k, v, i| i == 1} )
|
264
|
+
end
|
67
265
|
end
|
68
266
|
|
69
|
-
def
|
267
|
+
def test_with_hashes_when_no_matches_found
|
268
|
+
if RUBY_VERSION < '1.9'
|
269
|
+
assert_equal [], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select {|k, v| false}
|
270
|
+
assert_equal [], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_while {|k, v| false}
|
271
|
+
assert_equal [["a", 1]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until {|k, v| true}
|
272
|
+
assert_equal [], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until(false) {|k, v| true}
|
273
|
+
else
|
274
|
+
assert_equal( {}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select {|k, v| false})
|
275
|
+
assert_equal( {}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_while {|k, v| false} )
|
276
|
+
assert_equal( {"a"=>1}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until {|k, v| true} )
|
277
|
+
assert_equal( {}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until(false) {|k, v| true} )
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
def test_show_how_it_differs_from_plain_old_select
|
70
283
|
# Ah, yes, it behaves the same as select in *this* simple case:
|
71
|
-
assert_equal [1, 2], (1..4).select {|
|
284
|
+
assert_equal [1, 2], (1..4).select {|v| v <= 2}
|
72
285
|
|
73
286
|
# But what about _this_ one... hmm?
|
74
|
-
assert_equal [1, 2], [1, 2, 3, 2, 1].select_while {|
|
75
|
-
assert_equal [1, 2, 2, 1], [1, 2, 3, 2, 1].select
|
287
|
+
assert_equal [1, 2], [1, 2, 3, 2, 1].select_while {|v| v <= 2}
|
288
|
+
assert_equal [1, 2, 2, 1], [1, 2, 3, 2, 1].select {|v| v <= 2} # Not the same! Keyword: _consecutive_.
|
76
289
|
|
77
290
|
# Or _this_ one...
|
78
|
-
assert_equal [1, 2, 1], [1, 2, 1, 99, 2].select_while {|
|
79
|
-
assert_equal [1, 2], [1, 2, 1, 99, 2].select {|
|
291
|
+
assert_equal [1, 2, 1], [1, 2, 1, 99, 2].select_while {|v| v <= 2}
|
292
|
+
assert_equal [1, 2], [1, 2, 1, 99, 2].select {|v| v <= 2}.uniq # Even this isn't the same.
|
80
293
|
end
|
81
294
|
|
82
|
-
def
|
295
|
+
def test_example_use_of_inclusive_option
|
296
|
+
# Let's say we have an array with these lines of code:
|
297
|
+
lines_of_code = <<-End.indent(-6).lines.map(&:chomp)
|
298
|
+
def a
|
299
|
+
:a
|
300
|
+
end
|
301
|
+
def b
|
302
|
+
:b
|
303
|
+
end
|
304
|
+
End
|
305
|
+
#puts lines_of_code.to_a
|
306
|
+
# ... and we want to match up to and including the first line that matches /end/.
|
307
|
+
|
308
|
+
assert_equal [
|
309
|
+
'def a',
|
310
|
+
' :a',
|
311
|
+
],
|
312
|
+
lines_of_code.select_until(false) {|line| line =~ /end/}
|
313
|
+
# It didn't go far enough. We actually want to *include* that last element. This is when we'd want to use inclusive=true.
|
314
|
+
|
83
315
|
assert_equal [
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
'end',
|
90
|
-
].select_until {|line| line =~ /end/}
|
91
|
-
# Not far enough. We actually want to *include* that last element.
|
316
|
+
'def a',
|
317
|
+
' :a',
|
318
|
+
'end',
|
319
|
+
],
|
320
|
+
lines_of_code.select_until(true) {|line| line =~ /end/}
|
92
321
|
|
93
322
|
assert_equal [
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
323
|
+
'def a',
|
324
|
+
' :a',
|
325
|
+
],
|
326
|
+
lines_of_code.select_while(false) {|line| line !~ /end/}
|
327
|
+
|
328
|
+
# Although a bit contrived, this is an example of when you might want to use include_first_false_element = true
|
329
|
+
# In practice, you'd probably seldom have a use for it, but I thought I should include it just to be consistent with select_until. Disagree?
|
330
|
+
assert_equal [
|
331
|
+
'def a',
|
332
|
+
' :a',
|
333
|
+
'end',
|
334
|
+
],
|
335
|
+
lines_of_code.select_while(true) {|line| line !~ /end/}
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
class SelectUntilLastTest < Test::Unit::TestCase
|
340
|
+
def test_simplest_case
|
341
|
+
assert_equal [1], [1].select_until_last {|v| v == 1}
|
342
|
+
assert_equal [], [1].select_until_last(false) {|v| v == 1} # if exclusive, we won't even return the one and only element
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_basic_usage
|
346
|
+
assert_equal [1, 2, 1], [1, 2, 1, 2].select_until_last {|v| v == 1}
|
347
|
+
assert_equal [1, 2], [1, 2, 1, 2].select_until_last(false) {|v| v == 1}
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_basic_usage_with_index
|
351
|
+
assert_equal %w[a b], %w[a b c].select_until_last_with_index {|v, i| i == 1}
|
352
|
+
assert_equal %w[a], %w[a b c].select_until_last_with_index(false) {|v, i| i == 1}
|
353
|
+
end
|
354
|
+
|
355
|
+
def test_when_no_matches_found
|
356
|
+
assert_equal [], [1, 2, 1, 2].select_until_last {|v| v == 3}
|
357
|
+
assert_equal [], [1, 2, 1, 2].select_until_last(false) {|v| v == 3}
|
358
|
+
assert_equal [], [1, 2, 1, 2].select_until_last_with_index(false) {|v, i| v == 3}
|
359
|
+
# It should be the same as doing this:
|
360
|
+
assert_equal [], [1, 2, 1, 2].select {|v| false}
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_with_hashes_basic_usage
|
364
|
+
if RUBY_VERSION < '1.9'
|
365
|
+
assert_equal [["a", 1]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until {|k, v| v == 1}
|
366
|
+
assert_equal [ ], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until(false) {|k, v| v == 1}
|
367
|
+
|
368
|
+
# See the difference:
|
369
|
+
assert_equal [["a", 1], ["b", 2], ["c", 3], ["d", 1]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last {|k, v| v == 1}
|
370
|
+
assert_equal [["a", 1], ["b", 2], ["c", 3] ], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last(false) {|k, v| v == 1}
|
371
|
+
else
|
372
|
+
assert_equal( {"a"=>1}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until {|k, v| v == 1} )
|
373
|
+
assert_equal( {}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until(false) {|k, v| v == 1} )
|
374
|
+
|
375
|
+
# See the difference:
|
376
|
+
assert_equal( {"a"=>1, "b"=>2, "c"=>3, "d"=>1}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last {|k, v| v == 1} )
|
377
|
+
assert_equal( {"a"=>1, "b"=>2, "c"=>3 }, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last(false) {|k, v| v == 1} )
|
378
|
+
end
|
105
379
|
end
|
380
|
+
|
381
|
+
def test_with_hashes_basic_usage_with_index
|
382
|
+
if RUBY_VERSION < '1.9'
|
383
|
+
assert_equal [["a", 1], ["b", 2]], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last_with_index {|(k, v), i| p=[k,v,i]; i <= 1}
|
384
|
+
assert_equal [["a", 1] ], {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last_with_index(false) {|(k, v), i| i == 1}
|
385
|
+
else
|
386
|
+
assert_equal( {"a"=>1, "b"=>2}, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last_with_index {|(k, v), i| p=[k,v,i]; i <= 1} )
|
387
|
+
assert_equal( {"a"=>1 }, {'a'=>1, 'b'=>2, 'c'=>3, 'd'=>1}.select_until_last_with_index(false) {|(k, v), i| i == 1} )
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
106
391
|
end
|
107
392
|
=end
|
108
393
|
|