Skip to content

Commit 42ba313

Browse files
committed
add find and find! methods to indexable
1 parent a1b2d3b commit 42ba313

File tree

2 files changed

+73
-0
lines changed

2 files changed

+73
-0
lines changed

spec/std/indexable_spec.cr

+44
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,50 @@ describe Indexable do
143143
end
144144
end
145145

146+
describe "#find" do
147+
it "finds the element matching the block" do
148+
indexable = SafeIndexable.new(4)
149+
indexable.find { |i| i > 2 }.should eq 3
150+
end
151+
152+
it "finds the element matching the block after given offset" do
153+
indexable = SafeIndexable.new(8)
154+
indexable.find(5) { |i| i.even? }.should eq 6
155+
end
156+
157+
it "does not find the element matching the block" do
158+
indexable = SafeIndexable.new(4)
159+
indexable.find { |i| i > 7 }.should be_nil
160+
end
161+
162+
it "does not find the element matching the block, returns custom if_none value" do
163+
indexable = SafeIndexable.new(4)
164+
indexable.find(if_none: -1) { |i| i > 7 }.should eq -1
165+
end
166+
167+
it "does not find the element matching the block after given offset, returns custom if_none value" do
168+
indexable = SafeIndexable.new(5)
169+
indexable.find(3, -3) { |i| i > 15 }.should eq -3
170+
end
171+
end
172+
173+
describe "#find!" do
174+
it "finds the element matching the block" do
175+
indexable = SafeIndexable.new(4)
176+
indexable.find! { |i| i > 2 }.should eq 3
177+
end
178+
179+
it "finds the element matching the block after given offset" do
180+
indexable = SafeIndexable.new(8)
181+
indexable.find!(5) { |i| i.even? }.should eq 6
182+
end
183+
184+
it "does not find the element matching the block, raises not found" do
185+
indexable = SafeIndexable.new(4)
186+
expect_raises(Enumerable::NotFoundError) { indexable.find! { |i| i > 7 } }
187+
end
188+
end
189+
146190
describe "#rindex" do
147191
it "does rindex with big negative offset" do
148192
indexable = SafeIndexable.new(3)

src/indexable.cr

+29
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,35 @@ module Indexable(T)
809809
index(offset) { |e| yield e } || raise Enumerable::NotFoundError.new
810810
end
811811

812+
# Returns the first element in the indexable for which the passed block
813+
# is truthy, starting from the given *offset*.
814+
#
815+
# Accepts an optional parameter *if_none*, to set what gets returned if
816+
# no element is found (defaults to `nil`).
817+
#
818+
# ```
819+
# [1, 2, 3, 4].find { |i| i > 2 } # => 3
820+
# [1, 2, 3, 4].find(-1, 2) { |i| i < 2 } # => -1
821+
# [1, 2, 3, 4].find(-1) { |i| i > 8 } # => -1
822+
# ```
823+
def find(offset : Int = 0, if_none = nil, & : T ->)
824+
offset += size if offset < 0
825+
return nil if offset < 0
826+
return (index(offset) { |i| yield i }).try { |i| unsafe_fetch(i) } || if_none
827+
end
828+
829+
# Returns the first element in the indexable for which the passed block is truthy.
830+
# Raises `Enumerable::NotFoundError` if there is no element for which the block is truthy.
831+
#
832+
# ```
833+
# [1, 2, 3, 4].find! { |i| i > 2 } # => 3
834+
# [1, 2, 3, 4].find! { |i| i > 8 } # => raises Enumerable::NotFoundError
835+
def find!(offset : Int = 0, & : T ->)
836+
offset += size if offset < 0
837+
return nil if offset < 0
838+
return (index(offset) { |i| yield i }).try { |i| unsafe_fetch(i) } || raise Enumerable::NotFoundError.new
839+
end
840+
812841
# Returns the last element of `self` if it's not empty, or raises `IndexError`.
813842
#
814843
# ```

0 commit comments

Comments
 (0)