Skip to content

Commit d585139

Browse files
committed
feat: ArrayOf and Enumerable types
1 parent f83fcb0 commit d585139

File tree

4 files changed

+97
-1
lines changed

4 files changed

+97
-1
lines changed

README.md

+23
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,29 @@ sig name: T.RangeOf(Integer)
101101
def create(name: 1...2); end
102102
```
103103
104+
#### `ArrayOf`
105+
106+
Value **MUST** be an Array of the given type
107+
108+
```ruby
109+
sig names: T.ArrayOf(String)
110+
def create(names: ['Joel', 'Ash']); end
111+
```
112+
113+
#### `Enumerable`
114+
115+
Value **MUST** be an Enumerable of the optional given type
116+
117+
```ruby
118+
sig users: T.Enumerable
119+
def create(users: [1, 2]); end
120+
```
121+
122+
```ruby
123+
sig users: T.Enumerable(User)
124+
def create(users: User.all); end
125+
```
126+
104127
#### `Any`
105128
106129
Value **MUST** be any of the given list of values, that is, the value must be one of the given list.

lib/delivered.rb

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# frozen_string_literal: true
22

33
module Delivered
4+
EXPENSIVE_TYPE_CHECKS = ENV['DELIVERED_EXPENSIVE_TYPE_CHECKS'] != 'false'
5+
46
class ArgumentError < ArgumentError
57
end
68

lib/delivered/types.rb

+39-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,42 @@ def ===(value)
1313
end
1414
end
1515

16+
class EnumerableType
17+
def initialize(type)
18+
@type = type
19+
end
20+
21+
def inspect = "Enumerable(#{@type.inspect})"
22+
23+
if Delivered::EXPENSIVE_TYPE_CHECKS
24+
def ===(value)
25+
Enumerable === value && value.all? { |item| @type === item }
26+
end
27+
else
28+
def ===(value)
29+
Enumerable === value && (value.empty? || @type === value.first)
30+
end
31+
end
32+
end
33+
34+
class ArrayOfType
35+
def initialize(type)
36+
@type = type
37+
end
38+
39+
def inspect = "ArrayOf(#{@type.inspect})"
40+
41+
if Delivered::EXPENSIVE_TYPE_CHECKS
42+
def ===(value)
43+
Array === value && value.all? { |item| @type === item }
44+
end
45+
else
46+
def ===(value)
47+
Array === value && (value.empty? || @type === value[0])
48+
end
49+
end
50+
end
51+
1652
class RangeOfType
1753
def initialize(type)
1854
@type = type
@@ -68,7 +104,9 @@ module Types
68104
module_function
69105

70106
def Nilable(type = nil) = NilableType.new(type)
71-
def RangeOf(type = nil) = RangeOfType.new(type)
107+
def Enumerable(type = nil) = EnumerableType.new(type)
108+
def ArrayOf(type) = ArrayOfType.new(type)
109+
def RangeOf(type) = RangeOfType.new(type)
72110
def RespondTo(*methods) = RespondToType.new(*methods)
73111
def Any(*types) = AnyType.new(*types)
74112
def Boolean = BooleanType.new

test/delivered/types.rb

+33
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,39 @@
4343
end
4444
end
4545

46+
describe 'ArrayOf' do
47+
it 'should be an Array of given type' do
48+
assert T.ArrayOf(Integer) === [1, 2]
49+
assert T.ArrayOf(Integer) === []
50+
end
51+
52+
it 'raises when not an Array' do
53+
expect { 1 => ^(T.ArrayOf(Integer)) }.to raise_exception NoMatchingPatternError
54+
end
55+
56+
it 'raises when not an Array of given type' do
57+
expect { [1] => ^(T.ArrayOf(String)) }.to raise_exception NoMatchingPatternError
58+
expect { ['w', 1] => ^(T.ArrayOf(String)) }.to raise_exception NoMatchingPatternError
59+
end
60+
end
61+
62+
describe 'Enumerable' do
63+
it 'should be an Enumerable of given type' do
64+
assert T.Enumerable === []
65+
assert T.Enumerable(Integer) === [1, 2]
66+
assert T.Enumerable(Integer) === []
67+
end
68+
69+
it 'raises when not an Enumerable' do
70+
expect { 1 => ^(T.Enumerable(Integer)) }.to raise_exception NoMatchingPatternError
71+
end
72+
73+
it 'raises when not an Enumerable of given type' do
74+
expect { [1] => ^(T.Enumerable(String)) }.to raise_exception NoMatchingPatternError
75+
expect { ['w', 1] => ^(T.Enumerable(String)) }.to raise_exception NoMatchingPatternError
76+
end
77+
end
78+
4679
describe 'RangeOf' do
4780
it 'should be a Range of given type' do
4881
assert T.RangeOf(Integer) === (1..2)

0 commit comments

Comments
 (0)