Skip to content

Commit

Permalink
feat: add RespondTo type
Browse files Browse the repository at this point in the history
  • Loading branch information
joelmoss committed May 17, 2024
1 parent 835efc7 commit 6ccfc2c
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ sig validate: T.Boolean
def create(validate:); end
```
#### `RespondTo`
Value **MUST** be respond to the given method(s).
```ruby
sig name: T.RespondTo(:to_s)
def create(name:); end
```
#### `Any`
Value **MUST** be any of the given list of values, that is, the value must be one of the given list.
Expand Down
9 changes: 5 additions & 4 deletions lib/delivered/signature.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def sig(*sig_args, **sig_kwargs, &return_blk)
args[i] => ^arg
rescue NoMatchingPatternError => e
raise Delivered::ArgumentError,
"`#{cname}` expected `#{arg}` as positional arg #{i}, but received " \
"`#{cname}` expected #{arg.inspect} as argument #{i}, but received " \
"`#{args[i].inspect}`",
caller, cause: e
end
Expand All @@ -43,8 +43,8 @@ def sig(*sig_args, **sig_kwargs, &return_blk)
value => ^(sig_kwargs[key])
rescue NoMatchingPatternError => e
raise Delivered::ArgumentError,
"`#{cname}` expected `#{sig_kwargs[key]}` as keyword arg :#{key}, but received " \
"`#{value.inspect}`",
"`#{cname}` expected #{sig_kwargs[key].inspect} as keyword argument :#{key}, " \
"but received `#{value.inspect}`",
caller, cause: e
end

Expand All @@ -58,7 +58,8 @@ def sig(*sig_args, **sig_kwargs, &return_blk)
result => ^returns unless returns.nil?
rescue NoMatchingPatternError => e
raise Delivered::ArgumentError,
"`#{cname}` expected to return `#{returns}`, but returned `#{result.inspect}`",
"`#{cname}` expected to return #{returns.inspect}, " \
"but returned `#{result.inspect}`",
caller, cause: e
end

Expand Down
19 changes: 19 additions & 0 deletions lib/delivered/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,32 @@ def initialize(*types)
@types = types
end

def inspect = "Any(#{@types.map(&:inspect).join(', ')})"

def ===(value)
@types.empty? ? true : @types.any? { |type| type === value }
end
end

class RespondToType
def initialize(*methods)
@methods = methods
end

def inspect = "RespondTo(#{@methods.map(&:inspect).join(', ')})"

def ===(value)
@methods.all? { |m| value.respond_to?(m) }
end
end

class NilableType
def initialize(type = nil)
@type = type
end

def inspect = "Nilable(#{@type&.inspect || 'Any'})"

def ===(value)
(@type.nil? ? true : nil === value) || @type === value
end
Expand All @@ -26,6 +42,8 @@ def initialize
freeze
end

def inspect = 'Boolean'

def ===(value)
[true, false].include?(value)
end
Expand All @@ -35,6 +53,7 @@ module Types
module_function

def Nilable(type = nil) = NilableType.new(type)
def RespondTo(*methods) = RespondToType.new(*methods)
def Any(*types) = AnyType.new(*types)
def Boolean = BooleanType.new
end
Expand Down
13 changes: 12 additions & 1 deletion test/delivered/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
end

with 'arguments' do
it 'one of given arg' do
it 'is one of given arg' do
assert T.Any(:one, :two) === :one
assert T.Any(String, Integer) === 'one'
assert T.Any(String, Integer) === 1
Expand All @@ -32,6 +32,17 @@
end
end

describe 'RespondTo' do
it 'should respond to given method' do
assert T.RespondTo(:to_s) === 'foo'
assert T.RespondTo(:to_s, :to_i) === 'foo'
end

it 'raises when not respond to' do
expect { :foo => ^(T.RespondTo(:bar)) }.to raise_exception NoMatchingPatternError
end
end

describe 'Boolean' do
it 'should be true or false' do
assert T.Boolean === true
Expand Down

0 comments on commit 6ccfc2c

Please sign in to comment.