jinx 2.1.3 → 2.1.4
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/Gemfile.lock +27 -0
- data/History.md +4 -0
- data/lib/jinx/helpers/class.rb +16 -12
- data/lib/jinx/helpers/collection.rb +277 -29
- data/lib/jinx/helpers/collections.rb +35 -2
- data/lib/jinx/helpers/conditional_enumerator.rb +2 -2
- data/lib/jinx/helpers/filter.rb +8 -2
- data/lib/jinx/helpers/flattener.rb +2 -2
- data/lib/jinx/helpers/hash.rb +3 -2
- data/lib/jinx/helpers/{hashable.rb → hasher.rb} +125 -77
- data/lib/jinx/helpers/module.rb +1 -1
- data/lib/jinx/helpers/multi_enumerator.rb +25 -9
- data/lib/jinx/helpers/options.rb +4 -3
- data/lib/jinx/helpers/partial_order.rb +16 -8
- data/lib/jinx/helpers/pretty_print.rb +14 -4
- data/lib/jinx/helpers/transformer.rb +3 -1
- data/lib/jinx/helpers/transitive_closure.rb +3 -3
- data/lib/jinx/helpers/visitor.rb +33 -42
- data/lib/jinx/import/java.rb +40 -27
- data/lib/jinx/importer.rb +86 -33
- data/lib/jinx/metadata/attribute_enumerator.rb +5 -11
- data/lib/jinx/metadata/dependency.rb +65 -30
- data/lib/jinx/metadata/id_alias.rb +1 -0
- data/lib/jinx/metadata/introspector.rb +21 -9
- data/lib/jinx/metadata/inverse.rb +14 -11
- data/lib/jinx/metadata/java_property.rb +15 -26
- data/lib/jinx/metadata/propertied.rb +80 -19
- data/lib/jinx/metadata/property.rb +13 -8
- data/lib/jinx/metadata/property_characteristics.rb +2 -2
- data/lib/jinx/resource.rb +62 -32
- data/lib/jinx/resource/inversible.rb +4 -0
- data/lib/jinx/resource/match_visitor.rb +0 -1
- data/lib/jinx/resource/mergeable.rb +16 -6
- data/lib/jinx/resource/reference_enumerator.rb +1 -2
- data/lib/jinx/version.rb +1 -1
- data/test/lib/jinx/helpers/collections_test.rb +29 -14
- data/test/lib/jinx/helpers/visitor_test.rb +7 -20
- data/test/lib/jinx/import/mixed_case_test.rb +17 -3
- metadata +4 -4
- data/lib/jinx/helpers/enumerable.rb +0 -245
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
jinx (2.1.3)
|
5
|
+
bundler
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
diff-lcs (1.1.3)
|
11
|
+
rake (0.9.2.2)
|
12
|
+
rspec (2.10.0)
|
13
|
+
rspec-core (~> 2.10.0)
|
14
|
+
rspec-expectations (~> 2.10.0)
|
15
|
+
rspec-mocks (~> 2.10.0)
|
16
|
+
rspec-core (2.10.1)
|
17
|
+
rspec-expectations (2.10.0)
|
18
|
+
diff-lcs (~> 1.1.3)
|
19
|
+
rspec-mocks (2.10.1)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
java
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
jinx!
|
26
|
+
rake
|
27
|
+
rspec (>= 2.6)
|
data/History.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
This history lists major release themes. See the GitHub commits (https://github.com/jinx/core)
|
2
2
|
for change details.
|
3
3
|
|
4
|
+
2.1.4 / 2012-10-31
|
5
|
+
------------------
|
6
|
+
* Push Enumerable helper methods to Jinx::Collection.
|
7
|
+
|
4
8
|
2.1.3 / 2012-08-18
|
5
9
|
------------------
|
6
10
|
* Pull UID out of uniquifier.
|
data/lib/jinx/helpers/class.rb
CHANGED
@@ -95,7 +95,7 @@ class Class
|
|
95
95
|
attr_writer(symbol)
|
96
96
|
wtr = "#{symbol}=".to_sym
|
97
97
|
iv = "@#{symbol}".to_sym
|
98
|
-
# the attribute reader creates a new
|
98
|
+
# the attribute reader creates a new value on demand
|
99
99
|
define_method(symbol) do
|
100
100
|
instance_variable_defined?(iv) ? instance_variable_get(iv) : send(wtr, yield(self))
|
101
101
|
end
|
@@ -123,10 +123,12 @@ class Class
|
|
123
123
|
# @yieldparam old_method [Symbol] the method being redefined
|
124
124
|
# @return [Symbol] an alias to the old method implementation
|
125
125
|
def redefine_method(method)
|
126
|
-
#
|
127
|
-
#
|
126
|
+
# Make a new alias id method__base for the existing method.
|
127
|
+
# Disambiguate with a counter suffix if necessary.
|
128
128
|
counter = 2
|
129
|
-
#
|
129
|
+
# Make a valid alias base. The base includes this class's object id in order
|
130
|
+
# to ensure uniqueness within the class hierarchy. This alias uniqueness
|
131
|
+
# guards against a superclass occluding a subclass redefinition.
|
130
132
|
old, eq = /^([^=]*)(=)?$/.match(method.to_s).captures
|
131
133
|
old.tr!('|', 'or')
|
132
134
|
old.tr!('&', 'and')
|
@@ -134,16 +136,18 @@ class Class
|
|
134
136
|
old.tr!('*', 'mult')
|
135
137
|
old.tr!('/', 'div')
|
136
138
|
old.gsub!(/[^\w]/, 'op')
|
137
|
-
base = "redefined__#{old}"
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
base = "redefined__#{object_id}_#{old}"
|
140
|
+
# Make a unique method alias for the old method.
|
141
|
+
old_sym = "#{base}#{eq}".to_sym
|
142
|
+
while method_defined?(old_sym)
|
143
|
+
old_sym = "#{base}#{counter}#{eq}".to_sym
|
142
144
|
counter = counter + 1
|
143
145
|
end
|
144
|
-
|
145
|
-
|
146
|
+
# Alias the old method before it is replaced.
|
147
|
+
alias_method(old_sym, method)
|
148
|
+
# The body defines the new method given the old method.
|
149
|
+
body = yield old_sym
|
146
150
|
define_method(method, body)
|
147
|
-
|
151
|
+
old_sym
|
148
152
|
end
|
149
153
|
end
|
@@ -1,33 +1,281 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
module Jinx
|
2
|
+
# This Collection mix-in augments Enumerable with utility methods.
|
3
|
+
module Collection
|
4
|
+
# Returns a new Hash generated from this Collection and an optional value generator block.
|
5
|
+
# This Enumerable contains the Hash keys. If the value generator block is given to this
|
6
|
+
# method then the block is called with each enumerated element as an argument to
|
7
|
+
# generate the associated hash value. If no block is given, then the values are nil.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# [1, 2, 3].hashify { |item| item.modulo(2) } #=> { 1 => 1, 2 => 0, 3 => 1 }
|
11
|
+
# [:a].hashify #=> { :a => nil }
|
12
|
+
# @return [Hash]
|
13
|
+
def hashify
|
14
|
+
hash = {}
|
15
|
+
each { |item| hash[item] = yield item if block_given? }
|
16
|
+
hash
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a new Hash generated from this Collection and a required value generator block.
|
20
|
+
# This Enumerable contains the Hash keys. The block is called with each enumerated
|
21
|
+
# element as an argument to generate the associated hash value.
|
22
|
+
# Only non-nil, non-empty values are included in the hash.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# [1, 2, 3].to_compact_hash { |item| item.modulo(2) } #=> { 1 => 1, 2 => 0, 3 => 1 }
|
26
|
+
# [1, 2, 3].to_compact_hash { |n| n.modulo(2) unless item > 2 } #=> {1 => 1, 2 => 0}
|
27
|
+
# [1, 2, 3].to_compact_hash { |n| n > 2 } #=> {1 => false, 2 => false, 3 => true}
|
28
|
+
# [1, 2, 3].to_compact_hash { |n| Array.new(n - 1, n) } #=> {2 => [2], 3 => [2, 3]}
|
29
|
+
# @return [Hash]
|
30
|
+
# @raise [ArgumentError] if the generator block is not given
|
31
|
+
# @see #hashify
|
32
|
+
def to_compact_hash
|
33
|
+
raise ArgumentError.new("Compact hash builder is missing the value generator block") unless block_given?
|
34
|
+
to_compact_hash_with_index { |item, index| yield item }
|
35
|
+
end
|
8
36
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
37
|
+
# Returns a new Hash generated from this Collection with a block whose arguments include the enumerated item
|
38
|
+
# and its index. Every value which is nil or empty is excluded.
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# [1, 2, 3].to_compact_hash_with_index { |item, index| item + index } #=> { 1 => 1, 2 => 3, 3 => 5 }
|
42
|
+
# @yield [item, index] the hash value
|
43
|
+
# @yieldparam item the enumerated value
|
44
|
+
# @yieldparam index the enumeration index
|
45
|
+
# @return [Hash] this {Enumerable} converted to a hash by the given block
|
46
|
+
def to_compact_hash_with_index
|
47
|
+
hash = {}
|
48
|
+
self.each_with_index do |item, index|
|
49
|
+
next if item.nil?
|
50
|
+
value = yield(item, index)
|
51
|
+
next if value.nil_or_empty?
|
52
|
+
hash[item] = value
|
53
|
+
end
|
54
|
+
hash
|
55
|
+
end
|
16
56
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
57
|
+
# This method is functionally equivalent to +to_a.empty+ but is more concise and efficient.
|
58
|
+
#
|
59
|
+
# @return [Boolean] whether this Collection iterates over at least one item
|
60
|
+
def empty?
|
61
|
+
not any? { true }
|
62
|
+
end
|
24
63
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
64
|
+
# This method is functionally equivalent to +to_a.first+ but is more concise and efficient.
|
65
|
+
#
|
66
|
+
# @return the first enumerated item in this Collection, or nil if this Collection is empty
|
67
|
+
def first
|
68
|
+
detect { true }
|
69
|
+
end
|
70
|
+
|
71
|
+
# This method is functionally equivalent to +to_a.last+ but is more concise and efficient.
|
72
|
+
#
|
73
|
+
# @return the last enumerated item in this Collection, or nil if this Collection is empty
|
74
|
+
def last
|
75
|
+
detect { true }
|
76
|
+
end
|
77
|
+
|
78
|
+
# This method is functionally equivalent to +to_a.size+ but is more concise and efficient
|
79
|
+
# for an Enumerable which does not implement the {#size} method.
|
80
|
+
#
|
81
|
+
# @return [Integer] the count of items enumerated in this Collection
|
82
|
+
def size
|
83
|
+
inject(0) { |size, item| size + 1 }
|
84
|
+
end
|
85
|
+
|
86
|
+
alias :length :size
|
87
|
+
|
88
|
+
# @return [String] the content of this Collection as a series using {Array#to_series}
|
89
|
+
def to_series(conjunction=nil)
|
90
|
+
to_a.to_series
|
91
|
+
end
|
30
92
|
|
31
|
-
|
32
|
-
|
33
|
-
|
93
|
+
# Returns the first non-nil, non-false enumerated value resulting from a call to the block given to this method,
|
94
|
+
# or nil if no value detected.
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# [1, 2].detect_value { |item| item / 2 if item % 2 == 0 } #=> 1
|
98
|
+
# @return [Object] the detected block result
|
99
|
+
# @see #detect_with_value
|
100
|
+
def detect_value
|
101
|
+
each do |*item|
|
102
|
+
value = yield(*item)
|
103
|
+
return value if value
|
104
|
+
end
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns the first item and value for which an enumeration on the block given to this method returns
|
109
|
+
# a non-nil, non-false value.
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# [1, 2].detect_with_value { |item| item / 2 if item % 2 == 0 } #=> [2, 1]
|
113
|
+
# @return [(Object, Object)] the detected [item, value] pair
|
114
|
+
# @see #detect_value
|
115
|
+
def detect_with_value
|
116
|
+
value = nil
|
117
|
+
match = detect do |*item|
|
118
|
+
value = yield(*item)
|
119
|
+
end
|
120
|
+
[match, value]
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns a new Enumerable that iterates over the base Enumerable items for which filter evaluates to a non-nil,
|
124
|
+
# non-false value, e.g.:
|
125
|
+
# [1, 2, 3].filter { |n| n != 2 }.to_a #=> [1, 3]
|
126
|
+
#
|
127
|
+
# Unlike select, filter reflects changes to the base Enumerable, e.g.:
|
128
|
+
# a = [1, 2, 3]
|
129
|
+
# filter = a.filter { |n| n != 2 }
|
130
|
+
# a << 4
|
131
|
+
# filter.to_a #=> [1, 3, 4]
|
132
|
+
#
|
133
|
+
# In addition, filter has a small, fixed storage requirement, making it preferable to select for large collections.
|
134
|
+
# Note, however, that unlike select, filter does not return an Array.
|
135
|
+
# The default filter block returns the passed item.
|
136
|
+
#
|
137
|
+
# @example
|
138
|
+
# [1, nil, 3].filter.to_a #=> [1, 3]
|
139
|
+
# @yield [item] filter the selection filter
|
140
|
+
# @yieldparam item the collection member to filter
|
141
|
+
# @return [Enumerable] the filtered result
|
142
|
+
def filter(&filter)
|
143
|
+
Jinx::Filter.new(self, &filter)
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [Enumerable] an iterator over the non-nil items in this Collection
|
147
|
+
def compact
|
148
|
+
filter { |item| not item.nil? }
|
149
|
+
end
|
150
|
+
|
151
|
+
# @example
|
152
|
+
# {:a => {:b => :c}, :d => [:e]}.enum_values.flatten.to_a #=> [:b, :c, :e]
|
153
|
+
# @return [Enumerable] the flattened result
|
154
|
+
def flatten
|
155
|
+
Jinx::Flattener.new(self).to_a
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns an Enumerable which iterates over items in this Collection and the other Enumerable in sequence.
|
159
|
+
# Unlike the Array plus (+) operator, {#union} reflects changes to the underlying enumerators.
|
160
|
+
#
|
161
|
+
# @quirk Cucumber Cucumber defines it's own Enumerable union monkey-patch. Work around this in the short
|
162
|
+
# term by trying to call the super first.
|
163
|
+
#
|
164
|
+
# @example
|
165
|
+
# a = [1, 2]
|
166
|
+
# b = [4, 5]
|
167
|
+
# ab = a.union(b)
|
168
|
+
# ab #=> [1, 2, 4, 5]
|
169
|
+
# a << 3
|
170
|
+
# a + b #=> [1, 2, 4, 5]
|
171
|
+
# ab #=> [1, 2, 3, 4, 5]
|
172
|
+
# @param [Enumerable] other the Enumerable to compose with this Collection
|
173
|
+
# @return [Enumerable] an enumerator over self followed by other
|
174
|
+
# @yield (see Jinx::MultiEnumerator#intializer)
|
175
|
+
def union(other, &appender)
|
176
|
+
Jinx::MultiEnumerator.new(self, other, &appender)
|
177
|
+
end
|
178
|
+
|
179
|
+
alias :+ :union
|
180
|
+
|
181
|
+
# @return an Enumerable which iterates over items in this Collection but not the other Enumerable
|
182
|
+
def difference(other)
|
183
|
+
filter { |item| not other.include?(item) }
|
184
|
+
end
|
185
|
+
|
186
|
+
alias :- :difference
|
187
|
+
|
188
|
+
# @return an Enumerable which iterates over items in this Collection which are also in the other
|
189
|
+
# Enumerable
|
190
|
+
def intersect(other)
|
191
|
+
filter { |item| other.include?(item) }
|
192
|
+
end
|
193
|
+
|
194
|
+
alias :& :intersect
|
195
|
+
|
196
|
+
# Returns a new Enumerable that iterates over the base Enumerable applying the transformer block
|
197
|
+
# to each item, e.g.:
|
198
|
+
# [1, 2, 3].transform_value { |n| n * 2 }.to_a #=> [2, 4, 6]
|
199
|
+
#
|
200
|
+
# Unlike Array.map, {#wrap} reflects changes to the base Enumerable, e.g.:
|
201
|
+
# a = [2, 4, 6]
|
202
|
+
``# transformed = a.wrap { |n| n * 2 }
|
203
|
+
# a << 4
|
204
|
+
# transformed.to_a #=> [2, 4, 6, 8]
|
205
|
+
#
|
206
|
+
# In addition, transform has a small, fixed storage requirement, making it preferable to select
|
207
|
+
# for large collections. Note, however, that unlike map, transform does not return an Array.
|
208
|
+
#
|
209
|
+
# @yield [item] the transformer on the enumerated items
|
210
|
+
# @yieldparam item an enumerated item
|
211
|
+
# @return [Enumerable] an enumeration on the transformed values
|
212
|
+
def transform(&mapper)
|
213
|
+
Jinx::Transformer.new(self, &mapper)
|
214
|
+
end
|
215
|
+
|
216
|
+
alias :wrap :transform
|
217
|
+
|
218
|
+
def join(sep = $,)
|
219
|
+
to_a.join(sep)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Sorts this collection's members with a partial comparator block. A partial
|
223
|
+
# comparator block returns -1, 0, 1 or nil. The resulting sorted order places
|
224
|
+
# comparable items in their relative sort order. If two items are not
|
225
|
+
# directly comparable, then the relative order of those items is
|
226
|
+
# indeterminate. In all cases the relative order is transitive, i.e.:
|
227
|
+
# * a < b and b < c => a occurs before c in the sort result
|
228
|
+
# * a > b and b > c => a occurs after c in the sort result
|
229
|
+
#
|
230
|
+
# @example
|
231
|
+
# sorted = [Enumerable, Array, String].partial_sort
|
232
|
+
# sorted.index(Array) < sorted.index(Enumerable) #=> true
|
233
|
+
# sorted.index(String) < sorted.index(Enumerable) #=> true
|
234
|
+
#
|
235
|
+
# @yield [item1, item2] the partial comparison result (-1, 0, 1 or nil)
|
236
|
+
# @yieldparam item1 an item to compare
|
237
|
+
# @yieldparam item2 another item to compare
|
238
|
+
# @return [Enumerable] a new collection consisting of the items in this collection
|
239
|
+
# in partial sort order
|
240
|
+
def partial_sort(&block)
|
241
|
+
copy = dup.to_a
|
242
|
+
copy.partial_sort!(&block)
|
243
|
+
copy
|
244
|
+
end
|
245
|
+
|
246
|
+
# Sorts this collection in-place with a partial sort operator block
|
247
|
+
#
|
248
|
+
# @see #partial_sort
|
249
|
+
# @yield (see #partial_sort)
|
250
|
+
# @yieldparam (see #partial_sort)
|
251
|
+
# @raise [NoMethodError] if this Collection does not support the +sort!+ sort in-place method
|
252
|
+
def partial_sort!
|
253
|
+
unless block_given? then return partial_sort! { |item1, item2| item1 <=> item2 } end
|
254
|
+
# The comparison hash
|
255
|
+
h = Hash.new { |h, k| h[k] = Hash.new }
|
256
|
+
sort! do |a, b|
|
257
|
+
# * If a and b are comparable, then use the comparison result.
|
258
|
+
# * Otherwise, if there is a member c such that (a <=> c) == (c <=> b),
|
259
|
+
# then a <=> b has the transitive comparison result.
|
260
|
+
# * Otherwise, a <=> b is arbitrarily set to 1.
|
261
|
+
yield(a, b) || h[a][b] ||= -h[b][a] ||= h[a].detect_value { |c, v| v if v == yield(c, b) } || 1
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Sorts this collection's members with a partial sort operator on the results of applying the block.
|
266
|
+
#
|
267
|
+
# @yield [item] transform the item to a Comparable value
|
268
|
+
# @yieldparam item an enumerated item
|
269
|
+
# @return [Enumerable] the items in this collection in partial sort order
|
270
|
+
def partial_sort_by
|
271
|
+
partial_sort { |item1, item2| yield(item1) <=> yield(item2) }
|
272
|
+
end
|
273
|
+
|
274
|
+
# @yield [item] the transformer on the enumerated items
|
275
|
+
# @yieldparam item an enumerated item
|
276
|
+
# @return [Enumerable] the mapped values excluding null values
|
277
|
+
def compact_map(&mapper)
|
278
|
+
wrap(&mapper).compact
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
@@ -1,10 +1,43 @@
|
|
1
1
|
# This file loads the definitions of useful collection mix-ins and utility classes.
|
2
|
+
require 'set'
|
3
|
+
require 'enumerator'
|
2
4
|
require 'jinx/helpers/collection'
|
3
5
|
require 'jinx/helpers/array'
|
4
|
-
require 'jinx/helpers/
|
6
|
+
require 'jinx/helpers/hasher'
|
5
7
|
require 'jinx/helpers/hash'
|
6
8
|
require 'jinx/helpers/set'
|
7
|
-
require 'jinx/helpers/enumerable'
|
8
9
|
require 'jinx/helpers/enumerate'
|
9
10
|
require 'jinx/helpers/filter'
|
11
|
+
require 'jinx/helpers/transformer'
|
10
12
|
require 'jinx/helpers/flattener'
|
13
|
+
require 'jinx/helpers/multi_enumerator'
|
14
|
+
require 'jinx/helpers/hasher'
|
15
|
+
|
16
|
+
class Object
|
17
|
+
# @return [Boolean] whether this object is a {Jinx::Collection}
|
18
|
+
def collection?
|
19
|
+
Jinx::Collection === self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
### Extend common non-String Enumerable classes and interfaces with Jinx::Collection. ###
|
24
|
+
|
25
|
+
class Enumerable::Enumerator
|
26
|
+
include Jinx::Collection
|
27
|
+
end
|
28
|
+
|
29
|
+
class Array
|
30
|
+
include Jinx::Collection
|
31
|
+
end
|
32
|
+
|
33
|
+
class Set
|
34
|
+
include Jinx::Collection
|
35
|
+
end
|
36
|
+
|
37
|
+
class File
|
38
|
+
include Jinx::Collection
|
39
|
+
end
|
40
|
+
|
41
|
+
module Java::JavaUtil::Collection
|
42
|
+
include Jinx::Collection
|
43
|
+
end
|
@@ -4,7 +4,7 @@ module Jinx
|
|
4
4
|
# @example
|
5
5
|
# ConditionalEnumerator.new([1, 2, 3]) { |i| i < 3 }.to_a #=> [1, 2]
|
6
6
|
class ConditionalEnumerator
|
7
|
-
include Collection
|
7
|
+
include Enumerable, Collection
|
8
8
|
|
9
9
|
# Creates a ConditionalEnumerator which wraps the base Enumerator with a conditional filter.
|
10
10
|
def initialize(base, &filter)
|
@@ -18,4 +18,4 @@ module Jinx
|
|
18
18
|
@base.each { |item| (yield item) if @filter.call(item) }
|
19
19
|
end
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|