taipo 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c4f4c74c97181b0db2c4555454d0a4ae4d9af758
4
- data.tar.gz: 97107b60d9e683fbc0a3ca53c6e27ae98c2fe62a
3
+ metadata.gz: 4be2ae174cd1d29fb2d7e4088ca69c9da0aecfb3
4
+ data.tar.gz: ac87cf9977ef502fe802459da7ea0855587fecc2
5
5
  SHA512:
6
- metadata.gz: 67e4ab2d84f29b578f15668788edbef1eae23a5cc31962ebb5184667288bfa27e934c7679be11425ee7a051cc75a7d4edd778a3c6e57a65486f10491777fe062
7
- data.tar.gz: 0ac0f1d1f47ecbee80543f27ec8b9c50107eddba5445e0dfa00a17c59aae180b9f00b69186b5497c00ad0634b3c52104e52b79cbf203ba19a6189e6ad5682de8
6
+ metadata.gz: bafc5ce5e262afe6a17ca0bb06476ba4f2120d337de2e44b9bef5d0814ce556466d70a0efbe99c9df7095e0588cba45db874328d1d0dab73a03e140887f5a85c
7
+ data.tar.gz: b67fcb77105810336e8616b83a188115ddcde6ecc202221960a5c7e299be3a61a49e7b03e85a22cd998301a15c6cf456c7f0ba374b2986f2c2d2744db5db77d3
data/README.md CHANGED
@@ -12,9 +12,9 @@ Taipo is a simple library for checking the types of variables.
12
12
 
13
13
  ## Overview
14
14
 
15
- When we deal with variables in our code, we have certain expectations about what those variables can and cant do.
15
+ When we deal with variables in our code, we have certain expectations about what those variables can and can't do.
16
16
 
17
- Taipo provides a simple way to make those expectations explicit. If an expectation isnt met, Taipo can either raise an exception or return the problematic variables for us to handle.
17
+ Taipo provides a simple way to make those expectations explicit. If an expectation isn't met, Taipo can either raise an exception or return the problematic variables for us to handle.
18
18
 
19
19
  ## Installation
20
20
 
@@ -27,23 +27,23 @@ Taipo provides two methods in the `Taipo::Check` module that we can mix into our
27
27
  ### #check
28
28
 
29
29
  ```ruby
30
- require taipo
30
+ require 'taipo'
31
31
 
32
32
  class Foo
33
33
  include Taipo::Check
34
34
 
35
35
  def double(val)
36
- check types, val: Integer
36
+ check types, val: 'Integer'
37
37
  val * 2
38
38
  end
39
39
  end
40
40
 
41
41
  foo = Foo.new
42
42
  foo.double 5 #=> 10
43
- foo.double Oops #=> Taipo::TypeError
43
+ foo.double 'Oops' #=> Taipo::TypeError
44
44
  ```
45
45
 
46
- The method `#check` will raise an exception as soon as one of its arguments doesnt match its type definition.
46
+ The method `#check` will raise an exception as soon as one of its arguments doesn't match its type definition.
47
47
 
48
48
  [More information about `#check`][rdc] is available in the documentation.
49
49
 
@@ -52,24 +52,24 @@ The method `#check` will raise an exception as soon as one of its arguments does
52
52
  ### #review
53
53
 
54
54
  ```ruby
55
- require taipo
55
+ require 'taipo'
56
56
 
57
57
  class Foo
58
58
  include Taipo::Check
59
59
 
60
60
  def add(x, y)
61
- errors = review types, x: Integer’, y: Integer
61
+ errors = review types, x: 'Integer', y: 'Integer'
62
62
  if errors.empty?
63
63
  x + y
64
64
  else
65
- Oops
65
+ 'Oops'
66
66
  end
67
67
  end
68
68
  end
69
69
 
70
70
  foo = Foo.new
71
71
  foo.add 4, 5 #=> 9
72
- foo.add 2, OK #=> Oops
72
+ foo.add 2, 'OK' #=> 'Oops'
73
73
  ```
74
74
 
75
75
  The method `#review` will put the invalid arguments into an array and return that to the user. If there are no errors, the array is empty.
@@ -88,7 +88,7 @@ The information in this README is only meant as an introduction. [More informati
88
88
 
89
89
  ### Names
90
90
 
91
- The simplest case is to write the name of a class. For example, `’String’`. Inherited class names can also be used.
91
+ The simplest case is to write the name of a class. For example, `'String'`. Inherited class names can also be used.
92
92
 
93
93
  ```ruby
94
94
  check types, a: 'String', b: 'Numeric'
@@ -126,19 +126,27 @@ Type definitions can be combined to form sum types. Sum types consist of two or
126
126
  check types, a: 'String|Float', b: 'Boolean|Array<String|Hash<Symbol,Point>|Array<String>>', c: 'Integer(max: 100)|Float(max: 100)'
127
127
  ```
128
128
 
129
+ #### Enums
130
+
131
+ It's possible to approximate an enum by writing a sum type consisting of Symbols.
132
+
133
+ ```ruby
134
+ check types, a: ':foo|:bar', b: ':one|:two|:three'
135
+ ```
136
+
129
137
  ## Requirements
130
138
 
131
139
  Taipo has been tested with Ruby version 2.4.2.
132
140
 
133
141
  ## Bugs
134
142
 
135
- Found a bug? Id love to know about it. The best way is to report them in the [Issues section][ghi] on GitHub.
143
+ Found a bug? I'd love to know about it. The best way is to report them in the [Issues section][ghi] on GitHub.
136
144
 
137
145
  [ghi]: https://github.com/pyrmont/taipo/issues
138
146
 
139
147
  ## Contributing
140
148
 
141
- If youre interested in contributing to Taipo, feel free to fork and submit a pull request.
149
+ If you're interested in contributing to Taipo, feel free to fork and submit a pull request.
142
150
 
143
151
  ## Versioning
144
152
 
@@ -159,4 +167,4 @@ Taipo began as, and remains primarily, an exercise to improve my programming ski
159
167
 
160
168
  Taipo is released into the public domain. See [LICENSE.md][lc] for more details.
161
169
 
162
- [lc]: https://github.com/pyrmont/taipo/blob/master/LICENSE.md
170
+ [lc]: https://github.com/pyrmont/taipo/blob/master/LICENSE.md
data/lib/taipo.rb CHANGED
@@ -70,7 +70,7 @@ module Taipo
70
70
  # @note All this does is check whether the given string begins with a hash
71
71
  # symbol.
72
72
  #
73
- # @param str [String] the method name to check
73
+ # @param str [String] the string to check
74
74
  #
75
75
  # @return [Boolean] the result
76
76
  #
@@ -85,7 +85,7 @@ module Taipo
85
85
  # @note This assume that each element returned by Enumerator#each has the same
86
86
  # number of components.
87
87
  #
88
- # @param arg [Object] the object
88
+ # @param obj [Object] the object
89
89
  #
90
90
  # @return [String] a type definition of the object
91
91
  #
@@ -123,9 +123,23 @@ module Taipo
123
123
  end
124
124
  end
125
125
 
126
+ # Check if a string is the name of a symbol
127
+ #
128
+ # @note All this does is check whether the given string begins with a colon.
129
+ #
130
+ # @param str [String] the string to check
131
+ #
132
+ # @return [Boolean] the result
133
+ #
134
+ # @since 1.2.0
135
+ # @api private
136
+ def self.symbol?(str)
137
+ str[0] == ':'
138
+ end
139
+
126
140
  # Return a String representation of an array of {Taipo::TypeElement}
127
141
  #
128
- # @param arg [Array<Taipo::TypeElement>] the array of {Taipo::TypeElement}
142
+ # @param types [Array<Taipo::TypeElement>] the array of {Taipo::TypeElement}
129
143
  #
130
144
  # @return [String] the String representation
131
145
  #
data/lib/taipo/parser.rb CHANGED
@@ -22,6 +22,7 @@ module Taipo
22
22
  Taipo::Parser::Validater.validate str
23
23
 
24
24
  content = ''
25
+ previous = ''
25
26
  is_fallthrough = false
26
27
  fallthroughs = [ '/', '"' ]
27
28
  closing_symbol = ''
@@ -34,12 +35,13 @@ module Taipo
34
35
 
35
36
  case c
36
37
  when '|'
37
- next if content.empty? # Previous character must have been '>' or ')'.
38
- el = Taipo::TypeElement.new name: content
39
- content = ''
40
- elements = stack.pop
41
- elements.push el
42
- stack.push elements
38
+ unless attached? previous # content.empty? # Previous character must have been '>' or ')'.
39
+ el = Taipo::TypeElement.new name: content
40
+ content = ''
41
+ elements = stack.pop
42
+ elements.push el
43
+ stack.push elements
44
+ end
43
45
  when '<'
44
46
  el = Taipo::TypeElement.new name: content
45
47
  content = ''
@@ -49,7 +51,7 @@ module Taipo
49
51
  first_component = Array.new
50
52
  stack.push first_component
51
53
  when '>'
52
- if content.empty? # Previous character must have been '>' or ')'.
54
+ if attached? previous # content.empty? # Previous character must have been '>' or ')'.
53
55
  last_component = stack.pop
54
56
  else
55
57
  el = Taipo::TypeElement.new name: content.strip
@@ -65,7 +67,10 @@ module Taipo
65
67
  elements.push parent_el
66
68
  stack.push elements
67
69
  when '('
68
- if content.empty? # Previous character must have been '>'.
70
+ if unattached? previous
71
+ el = Taipo::TypeElement.new name: 'Object'
72
+ content = ''
73
+ elsif attached_collection? previous # Previous character must have been '>'.
69
74
  elements = stack.pop
70
75
  el = elements.pop
71
76
  stack.push elements
@@ -77,8 +82,8 @@ module Taipo
77
82
  cst_collection = Array.new
78
83
  stack.push cst_collection
79
84
  when '#'
80
- if bare_method_constraint? stack
81
- content = content + '#'
85
+ if unattached? previous
86
+ content = '#'
82
87
  else
83
88
  cst = Taipo::TypeElement::Constraint.new
84
89
  content = ''
@@ -87,11 +92,18 @@ module Taipo
87
92
  stack.push cst_collection
88
93
  end
89
94
  when ':'
90
- cst = Taipo::TypeElement::Constraint.new name: content.strip
91
- content = ''
92
- cst_collection = stack.pop
93
- cst_collection.push cst
94
- stack.push cst_collection
95
+ if unattached? previous
96
+ content = ':'
97
+ elsif content.strip.empty?
98
+ content = ':'
99
+ else
100
+ content = content
101
+ cst = Taipo::TypeElement::Constraint.new name: content.strip
102
+ content = ''
103
+ cst_collection = stack.pop
104
+ cst_collection.push cst
105
+ stack.push cst_collection
106
+ end
95
107
  when ',' # We could be inside a collection or a set of constraints
96
108
  if inside_collection? stack
97
109
  previous_component = stack.pop
@@ -132,6 +144,7 @@ module Taipo
132
144
  end
133
145
  content = content + c
134
146
  end
147
+ previous = c
135
148
  end
136
149
 
137
150
  unless content.empty?
@@ -143,6 +156,37 @@ module Taipo
143
156
 
144
157
  stack.pop
145
158
  end
159
+
160
+ # Check whether the current element is 'attached' to anything
161
+ #
162
+ # This check is performed by checking whether +char+ is the final character
163
+ # in a collection or constraint.
164
+ #
165
+ # @param char [String] the character to use in the test
166
+ #
167
+ # @return [Boolean] the result
168
+ #
169
+ # @since 1.2.0
170
+ # @api private
171
+ def self.attached?(char)
172
+ char == '>' || char == ')'
173
+ end
174
+
175
+ # Check whether the current element is 'attached' to a collection
176
+ #
177
+ # Like {self.attached?}, this check is performed by checking +char+. In
178
+ # this case, the check is whether +char+ is the final character in a
179
+ # collection.
180
+ #
181
+ # @param char [String] the character to use in the test
182
+ #
183
+ # @return [Boolean] the result
184
+ #
185
+ # @since 1.2.0
186
+ # @api private
187
+ def self.attached_collection?(char)
188
+ char == '>'
189
+ end
146
190
 
147
191
  # Check if the parser is inside a collection
148
192
  #
@@ -156,16 +200,19 @@ module Taipo
156
200
  stack[-2]&.class == Taipo::TypeElement::ChildType
157
201
  end
158
202
 
159
- # Check if this constraint is only a method
203
+ # Check whether the current element is 'unattached' to anything
160
204
  #
161
- # @param stack [Array] the stack of parsed elements
205
+ # This check checks whether +char+ represents the beginning of a discrete
206
+ # type definition.
207
+ #
208
+ # @param char [String] the character to use in the test
162
209
  #
163
210
  # @return [Boolean] the result
164
211
  #
165
- # @since 1.0.0
212
+ # @since 1.2.0
166
213
  # @api private
167
- def self.bare_method_constraint?(stack)
168
- stack[-2]&.class != Taipo::TypeElement
214
+ def self.unattached?(char)
215
+ char.empty? || char == '|' || char == '<'
169
216
  end
170
217
  end
171
218
  end
@@ -103,6 +103,15 @@ module Taipo
103
103
  # The sum comprises two or more type definitions, each separated by a bar
104
104
  # (ie. +|+).
105
105
  #
106
+ # ==== Enums
107
+ #
108
+ # ':foo|:bar', ':one|:two|:three'
109
+ #
110
+ # It's possible to approximate the enum idiom available in many languages
111
+ # by creating a sum type consisting of Symbols. As a convenience, Taipo
112
+ # parses these values as constraints on the Object class. In other words,
113
+ # +':foo|:bar'+ is really +'Object(val: :foo)|Object(val: :bar)'+.
114
+ #
106
115
  # @since 1.0.0
107
116
  module Validater
108
117
 
@@ -132,7 +141,7 @@ module Taipo
132
141
  chars = str.chars
133
142
  str_length = chars.size
134
143
 
135
- state.prohibit_all except: [ :hsh, :oth ]
144
+ state.prohibit_all except: [ :lpr, :hsh, :cln, :oth ]
136
145
 
137
146
  while (i < str_length)
138
147
  msg = "The string '#{str}' has an error here: #{str[0, i+1]}"
@@ -142,11 +151,11 @@ module Taipo
142
151
  raise Taipo::SyntaxError, msg unless conditions.all?
143
152
  state.enable :lab
144
153
  state.enable :lpr
145
- state.prohibit_all except: [ :hsh, :oth ]
154
+ state.prohibit_all except: [ :lpr, :hsh, :cln, :oth ]
146
155
  when '<' # lab
147
156
  conditions = [ state.allowed?(:lab) ]
148
157
  raise Taipo::SyntaxError, msg unless conditions.all?
149
- state.prohibit_all except: [ :hsh, :oth ]
158
+ state.prohibit_all except: [ :lpr, :hsh, :cln, :oth ]
150
159
  state.increment :angle
151
160
  when '>' # rab
152
161
  conditions = [ state.allowed?(:rab), state.inside?(:angle) ]
@@ -176,10 +185,20 @@ module Taipo
176
185
  state.decrement :const
177
186
  end
178
187
  when ':' # cln
179
- conditions = [ state.allowed?(:cln), state.inside?(:paren) ]
188
+ conditions = [ state.allowed?(:cln) ]
180
189
  raise Taipo::SyntaxError, msg unless conditions.all?
181
- state.prohibit_all except: [ :sls, :qut, :spc, :oth ]
182
- state.decrement :const
190
+ if state.outside? :paren
191
+ state.disable :lab
192
+ state.disable :lpr
193
+ state.prohibit_all except: [ :oth ]
194
+ else
195
+ if state.count(:const) == 0 # This is a symbol.
196
+ state.prohibit_all except: [ :qut, :oth ]
197
+ else
198
+ state.prohibit_all except: [ :cln, :sls, :qut, :spc, :oth ]
199
+ state.decrement :const
200
+ end
201
+ end
183
202
  when '/' #sls
184
203
  conditions = [ state.allowed?(:sls), state.inside?(:paren),
185
204
  state.outside?(:const) ]
@@ -201,11 +220,15 @@ module Taipo
201
220
  when ' ' # spc
202
221
  conditions = [ state.allowed?(:spc) ]
203
222
  raise Taipo::SyntaxError, msg unless conditions.all?
204
- state.prohibit_all except: [ :hsh, :sls, :qut, :oth ]
223
+ state.prohibit_all except: [ :hsh, :cln, :sls, :qut, :oth ]
205
224
  else # oth
206
225
  conditions = [ state.allowed?(:oth) ]
207
226
  raise Taipo::SyntaxError, msg unless conditions.all?
208
- state.allow_all except: [ :hsh, :spc ]
227
+ if state.inside? :paren
228
+ state.allow_all except: [ :hsh, :spc ]
229
+ else
230
+ state.allow_all except: [ :hsh, :cln, :spc ]
231
+ end
209
232
  end
210
233
  i += 1
211
234
  end
@@ -40,7 +40,7 @@ module Taipo
40
40
  # wrong type
41
41
  # @raise [::ArgumentError] if +name+, +child_type+ or +constraints+ was
42
42
  # blank or empty, or +child_type+ or +constraints+ was non-nil and this
43
- # is a duck type (ie. a method the type responds to)
43
+ # is a duck type (ie. a method the type responds to) or a symbol
44
44
  #
45
45
  # @since 1.0.0
46
46
  # @api private
@@ -61,15 +61,19 @@ module Taipo
61
61
  msg = 'Argument constraints was empty.'
62
62
  raise ::ArgumentError, msg if constraints&.empty?
63
63
 
64
- if Taipo.instance_method? name
64
+ if Taipo.instance_method?(name) || Taipo.symbol?(name)
65
65
  msg = 'Argument child_type should have been nil.'
66
66
  raise ::ArgumentError, msg unless child_type.nil?
67
67
  msg = 'Argument constraints should have been nil.'
68
68
  raise ::ArgumentError, msg unless constraints.nil?
69
69
 
70
- constraints = [
71
- Taipo::TypeElement::Constraint.new(name: nil, value: name[1..-1])
72
- ]
70
+ constraints = if Taipo.instance_method? name
71
+ [Taipo::TypeElement::Constraint.new(name: nil,
72
+ value: name[1..-1])]
73
+ elsif Taipo.symbol? name
74
+ [Taipo::TypeElement::Constraint.new(name: 'val',
75
+ value: name)]
76
+ end
73
77
  name = 'Object'
74
78
  end
75
79
  @name = name
@@ -214,6 +218,5 @@ module Taipo
214
218
  end
215
219
  name_str + child_type_str + constraints_str
216
220
  end
217
-
218
221
  end
219
222
  end
@@ -44,7 +44,13 @@ module Taipo
44
44
  msg = 'Argument name was an empty string.'
45
45
  raise ::ArgumentError, msg if name&.empty?
46
46
 
47
- @name = (name.nil?) ? Constraint::METHOD : name
47
+ @name = if name.nil?
48
+ Constraint::METHOD
49
+ elsif name == ':'
50
+ 'val'
51
+ else
52
+ name
53
+ end
48
54
  @value = self.parse_value value
49
55
  end
50
56
 
@@ -79,6 +85,8 @@ module Taipo
79
85
  when 'val'
80
86
  if @value[0] == '"' && @value[-1] == '"'
81
87
  arg.to_s == @value.slice(1..-2)
88
+ elsif arg.is_a? Symbol
89
+ ":" + arg.to_s == @value
82
90
  else
83
91
  arg.to_s == @value
84
92
  end
data/lib/taipo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Taipo
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
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.1.1
4
+ version: 1.2.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-21 00:00:00.000000000 Z
11
+ date: 2018-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler