Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added WithEnum#but and with_range #1649

Merged
merged 1 commit into from
Nov 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions test/stdlib/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,20 @@ def and_nil(&block)
self.and(nil, &block)
end

def but(*cases)
return WithEnum.new to_enum(__method__, *args) unless block_given?

each do |arg|
yield arg unless cases.any? { _1 === arg }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow! we can use numbered parameter now!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah! :-)

end
end

def and(*args, &block)
return WithEnum.new to_enum(__method__, args) unless block_given?
return WithEnum.new to_enum(__method__, *args) unless block_given?

each(&block)
args.each do |arg|
if WithEnum === arg
if WithEnum === arg # use `===` as `arg` might not have `.is_a?` on it
arg.each(&block)
else
block.call(arg)
Expand All @@ -192,6 +201,11 @@ def and(*args, &block)
end
end

def with(*args, &block)
return WithEnum.new to_enum(__method__, *args) unless block_given?
args.each(&block)
end

def with_int(value = 3)
return WithEnum.new to_enum(__method__, value) unless block_given?
yield value
Expand Down Expand Up @@ -264,7 +278,31 @@ def with_boolish(&block)
end

alias with_untyped with_boolish

def with_range(start, stop, exclude_end = false)
# If you need fixed starting and stopping points, you can just do `with_range with(1), with(2)`.
raise ArgumentError, '`start` must be from a `with` method' unless start.is_a? WithEnum
raise ArgumentError, '`stop` must be from a `with` method' unless stop.is_a? WithEnum

start.each do |lower|
stop.each do |upper|
yield CustomRange.new(lower, upper, exclude_end)

# `Range` requires `begin <=> end` to return non-nil, but doesn't actually
# end up using the return value of it. This is to add that in when needed.
def lower.<=>(rhs) = :not_nil unless defined? lower.<=>

# If `lower <=> rhs` is defined but nil, then that means we're going to be constructing
# an illegal range (eg `3..ToInt.new(4)`). So, we need to skip yielding an invalid range
# in that case.
next if defined?(lower.<=>) && nil == (lower <=> upper)

yield Range.new(lower, upper, exclude_end)
end
end
end
end

module TypeAssertions
module ClassMethods
attr_reader :target
Expand Down Expand Up @@ -689,6 +727,18 @@ def to_path
end
end

class CustomRange < BlankSlate
attr_reader :begin, :end

def initialize(begin_, end_, exclude_end = false)
@begin = begin_
@end = end_
@exclude_end = exclude_end
end

def exclude_end? = @exclude_end
end

class Each < BlankSlate
def initialize(*args)
@args = args
Expand Down