taipo 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/lib/taipo/check.rb +2 -0
- data/lib/taipo/parser.rb +2 -2
- data/lib/taipo/parser/validater.rb +12 -0
- data/lib/taipo/type_element.rb +23 -5
- data/lib/taipo/type_element/child_type.rb +6 -1
- data/lib/taipo/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ae496b6a69d19aceb9f158a587cb7c2f7d0faa1
|
4
|
+
data.tar.gz: ec0096547e644b51f8759529a246b273ff5354e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb51c506c37aaaca6232488649b8cf59246ea2a3f69e7efb5230b677e1c8d32e276949126202325ebea6c9e8f4d5f652287a47e0a6aa6afd08c23da0f4cd86eb
|
7
|
+
data.tar.gz: 6c1b5b0bb7512d4829167bb5d8400f204fb114cedf16350a0099f71a43a54139a5908c16f08d9a513f9ce23c6c4bbc80b0f4a29c1cd2289411f048bd295006c6
|
data/README.md
CHANGED
@@ -102,6 +102,14 @@ It's possible to specify a duck type by writing the instance method (or methods)
|
|
102
102
|
check types, a: '#to_s', b: '(#foo, #bar)'
|
103
103
|
```
|
104
104
|
|
105
|
+
#### Optional Types
|
106
|
+
|
107
|
+
If `nil` is permitted as a value, the optional shorthand `?` can be appended to the end of a class name to form an optional type. Collections and constraints can follow as usual.
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
check types, a: 'String?', b: 'Array?<Integer>', c: 'Integer?(min: 0)'
|
111
|
+
```
|
112
|
+
|
105
113
|
### Collections
|
106
114
|
|
107
115
|
Taipo can also check whether a variable has a collection of elements of the specified child type. A child type can consist of the same components as any other type (ie. a name, collection, constraint, sum).
|
data/lib/taipo/check.rb
CHANGED
@@ -88,6 +88,8 @@ module Taipo
|
|
88
88
|
unless collect_invalids || is_match
|
89
89
|
if Taipo::instance_method? v
|
90
90
|
msg = "Object '#{k}' does not respond to #{v}."
|
91
|
+
elsif Taipo::symbol? v
|
92
|
+
msg = "Object '#{k}' is not equal to #{v}."
|
91
93
|
elsif arg.is_a? Enumerable
|
92
94
|
type_def = Taipo.object_to_type_def arg
|
93
95
|
msg = "Object '#{k}' is #{type_def} but expected #{v}."
|
data/lib/taipo/parser.rb
CHANGED
@@ -35,7 +35,7 @@ module Taipo
|
|
35
35
|
|
36
36
|
case c
|
37
37
|
when '|'
|
38
|
-
unless attached? previous #
|
38
|
+
unless attached? previous # Previous character must have been '>' or ')'.
|
39
39
|
el = Taipo::TypeElement.new name: content
|
40
40
|
content = ''
|
41
41
|
elements = stack.pop
|
@@ -51,7 +51,7 @@ module Taipo
|
|
51
51
|
first_component = Array.new
|
52
52
|
stack.push first_component
|
53
53
|
when '>'
|
54
|
-
if attached? previous #
|
54
|
+
if attached? previous # Previous character must have been '>' or ')'.
|
55
55
|
last_component = stack.pop
|
56
56
|
else
|
57
57
|
el = Taipo::TypeElement.new name: content.strip
|
@@ -36,6 +36,18 @@ module Taipo
|
|
36
36
|
# parentheses can be omitted. For defining duck types that respond to
|
37
37
|
# multiple methods, the parentheses are required.
|
38
38
|
#
|
39
|
+
# ==== Optional Types
|
40
|
+
#
|
41
|
+
# 'String?', 'Array<Integer?>', 'Symbol?|String?'
|
42
|
+
#
|
43
|
+
# It is possible to specify an 'optional' type by appending a question mark
|
44
|
+
# to the name of the type. This shorthand functions similarly to defining a
|
45
|
+
# sum type with NilClass (the implementation of how optional types are
|
46
|
+
# checked is slightly different, however; see {Taipo::TypeElement#match?}).
|
47
|
+
# It is not possible to define an optional duck type. For that, either the
|
48
|
+
# implicit Object class should be specified (and then made optional), or a
|
49
|
+
# sum type should be used.
|
50
|
+
#
|
39
51
|
# === Collections
|
40
52
|
#
|
41
53
|
# 'Array<Integer>', 'Hash<Symbol, String>', 'Array<Array<Float>>'
|
data/lib/taipo/type_element.rb
CHANGED
@@ -136,6 +136,7 @@ module Taipo
|
|
136
136
|
# @since 1.0.0
|
137
137
|
# @api private
|
138
138
|
def match?(arg)
|
139
|
+
return true if optional? && arg.nil?
|
139
140
|
match_class?(arg) && match_constraints?(arg) && match_child_type?(arg)
|
140
141
|
end
|
141
142
|
|
@@ -150,12 +151,13 @@ module Taipo
|
|
150
151
|
# @since 1.0.0
|
151
152
|
# @api private
|
152
153
|
def match_class?(arg)
|
153
|
-
|
154
|
+
actual_name = (optional?) ? @name[0..-2] : @name
|
155
|
+
if actual_name == 'Boolean'
|
154
156
|
arg.is_a?(TrueClass) || arg.is_a?(FalseClass)
|
155
157
|
else
|
156
|
-
msg = "Class to match #{
|
157
|
-
raise Taipo::SyntaxError, msg unless Object.const_defined?(
|
158
|
-
arg.is_a? Object.const_get(
|
158
|
+
msg = "Class to match #{actual_name} is not defined"
|
159
|
+
raise Taipo::SyntaxError, msg unless Object.const_defined?(actual_name)
|
160
|
+
arg.is_a? Object.const_get(actual_name)
|
159
161
|
end
|
160
162
|
end
|
161
163
|
|
@@ -174,7 +176,7 @@ module Taipo
|
|
174
176
|
return false if !self_childless && arg_childless
|
175
177
|
|
176
178
|
arg.all? do |a|
|
177
|
-
if
|
179
|
+
if !arg.is_a?(Array) && a.is_a?(Array)
|
178
180
|
a.each.with_index.reduce(nil) do |memo,(component,index)|
|
179
181
|
result = @child_type[index].any? { |c| c.match? component }
|
180
182
|
(memo.nil?) ? result : memo && result
|
@@ -201,6 +203,22 @@ module Taipo
|
|
201
203
|
end
|
202
204
|
end
|
203
205
|
|
206
|
+
# Check whether this element is an optional
|
207
|
+
#
|
208
|
+
# An optional type is a variation on a normal type that also matches +nil+.
|
209
|
+
# Taipo borrows the syntax used in some other languages of denoting
|
210
|
+
# optional types by appending a question mark to the end of the class name.
|
211
|
+
#
|
212
|
+
# @note This merely checks whether +@name+ ends in a question mark.
|
213
|
+
#
|
214
|
+
# @return [Boolean] the result
|
215
|
+
#
|
216
|
+
# @since 1.3.0
|
217
|
+
# @api private
|
218
|
+
def optional?
|
219
|
+
@name[-1] == '?'
|
220
|
+
end
|
221
|
+
|
204
222
|
# Return the String representation of this TypeElement
|
205
223
|
#
|
206
224
|
# @since 1.1.0
|
@@ -8,7 +8,12 @@ module Taipo
|
|
8
8
|
|
9
9
|
# Initialize a new collection
|
10
10
|
#
|
11
|
-
# @
|
11
|
+
# @note The +components+ argument is two-dimensional array because the
|
12
|
+
# element returned by an enumerator for a collection can consist of
|
13
|
+
# multiple elements (eg. a Hash, where it consists of two elements).
|
14
|
+
#
|
15
|
+
# @param components [Array<Array<Taipo::TypeElement>>] the components that
|
16
|
+
# will make up the ChildType
|
12
17
|
#
|
13
18
|
# @since 1.0.0
|
14
19
|
# @api private
|
data/lib/taipo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: taipo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Camilleri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-01-
|
11
|
+
date: 2018-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|