rtype 0.6.6 → 0.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a159edd67900a539b8feea9186d429667af1a160
4
- data.tar.gz: 7cb75c0716d949ffce2e312032d613051a57c138
3
+ metadata.gz: 76040d28b4eee5b56fe0d5c6ebf51d462cc0200b
4
+ data.tar.gz: 7f35c3429e6be7f79856fdc43d629deafa4d7187
5
5
  SHA512:
6
- metadata.gz: f057cb5fb3bf0c21f6efecae853342f85617f823ef55060fb186bb74474c337fd741cdeeead59ac9fe81552d3c4d675fe9e2f19e9f9ad8292d24f15083b1d098
7
- data.tar.gz: 47e53f18661b3817f18259caf52b158a65f2d3912ec89072ef166f452b8573e2da00e349beba64c41668047d9a0f6b9eba025dc67ffa32cf128e3b7b96941249
6
+ metadata.gz: 5503c276531313629463a523b3589e91d6baf024f3c8bd22e126e4c57c9e0e9be5521c66435edcb6a209bc4f633c60be9a9b3f4705b2cbf57f9b123378823795
7
+ data.tar.gz: 1645c3bf900ddb43a6ade511583a5dab0c4bcadfb7884c7d5c8b46bf0e6a4b61f0391eea347771ed6acc2984099a916917f892ee9bf005d9c60b4476c1ab1d27
data/README.md CHANGED
@@ -12,17 +12,27 @@ class Test
12
12
  a.to_i + b
13
13
  end
14
14
 
15
- rtype {state: Boolean} => Boolean
15
+ rtype [{state: Boolean}] => Boolean
16
16
  def self.invert(state:)
17
17
  !state
18
18
  end
19
+
20
+ # Hashes of hashes params require () to prevent invalid syntax
21
+ rtype({state: Boolean} => Boolean)
22
+ def self.invert2(state:)
23
+ !state
24
+ end
19
25
  end
20
26
 
21
27
  Test.new.sum(123, "asd")
22
28
  # (Rtype::ArgumentTypeError) for 2nd argument:
23
29
  # Expected "asd" to be a Numeric
24
30
 
25
- Test::invert(state: 0)
31
+ Test.invert(state: 0)
32
+ # (Rtype::ArgumentTypeError) for 'state' argument:
33
+ # Expected 0 to be a Boolean
34
+
35
+ Test.invert2(state: 0)
26
36
  # (Rtype::ArgumentTypeError) for 'state' argument:
27
37
  # Expected 0 to be a Boolean
28
38
  ```
@@ -40,8 +50,10 @@ Test::invert(state: 0)
40
50
  - Provides type checking for [Keyword Argument](#keyword-argument)
41
51
  - [Type checking for hash elements](#hash)
42
52
  - [Duck Typing](#duck-typing)
43
- - [Typed Array](#typed-array)
53
+ - [Typed Array](#typed-array), Typed Set, Typed Hash
44
54
  - [Numeric check](#special-behaviors). e.g. `Int >= 0`
55
+ - [Type checking for getter and setter](#attr_accessor-with-rtype)
56
+ - [float_accessor](#float_accessor), [bool_accessor](#bool_accessor)
45
57
  - Custom type behavior
46
58
  - ...
47
59
 
@@ -67,16 +79,8 @@ gem 'rtype-native'
67
79
  ```
68
80
  then, Rtype uses it. (**Do not** `require 'rtype-native'`)
69
81
 
70
- #### Java extension for JRuby
71
- Run
72
- ```ruby
73
- gem install rtype-java
74
- ```
75
- or add to your `Gemfile`:
76
- ```ruby
77
- gem 'rtype-java'
78
- ```
79
- then, Rtype uses it. (**Do not** `require 'rtype-java'`)
82
+ #### Java extension for JRuby is automatic
83
+ **Do not** `require 'rtype-java'`
80
84
 
81
85
  ## Usage
82
86
 
@@ -106,7 +110,7 @@ then, Rtype uses it. (**Do not** `require 'rtype-java'`)
106
110
  - Example: [Hash](#hash)
107
111
 
108
112
  - [Special Behaviors](#special-behaviors)
109
- - `TypedArray`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
113
+ - `TypedArray, TypedSet, TypedHash`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
110
114
 
111
115
  ### Examples
112
116
 
@@ -204,34 +208,35 @@ def func(hash)
204
208
  puts hash[:msg]
205
209
  end
206
210
 
207
- # last hash is not hash argument but keyword arguments
208
- func({}, {})
211
+ func({})
209
212
  # (Rtype::ArgumentTypeError) for 1st argument:
210
213
  # Expected {} to be a hash with 1 elements:
211
214
  # - msg : Expected nil to be a String
212
215
 
213
- func({msg: 123}, {})
216
+ func({msg: 123})
214
217
  # (Rtype::ArgumentTypeError) for 1st argument:
215
218
  # Expected {:msg=>123} to be a hash with 1 elements:
216
219
  # - msg : Expected 123 to be a String
217
220
 
218
- func({msg: "hello", key: 'value'}, {})
221
+ func({msg: "hello", key: 'value'})
219
222
  # (Rtype::ArgumentTypeError) for 1st argument:
220
223
  # Expected {:msg=>"hello", :key=>"value"} to be a hash with 1 elements:
221
224
  # - msg : Expected "hello" to be a String
222
225
 
223
- func({"msg" => "hello hash"}, {})
226
+ func({"msg" => "hello hash"})
224
227
  # (Rtype::ArgumentTypeError) for 1st argument:
225
228
  # Expected {"msg"=>"hello hash"} to be a hash with 1 elements:
226
229
  # - msg : Expected nil to be a String
227
230
 
228
- func({msg: "hello hash"}, {}) # hello hash
231
+ func({msg: "hello hash"}) # hello hash
229
232
  ```
230
233
 
231
- #### rtype with attr_accessor
232
- `rtype_accessor` : calls `attr_accessor` if the accessor method(getter/setter) is not defined. and makes it typed
234
+ #### attr_accessor with rtype
235
+ - `rtype_accessor(*names, type)` : calls `attr_accessor` if the accessor methods(getter/setter) are not defined. and makes it typed
236
+ - `rtype_reader(*names, type)` : calls `attr_reader` if the getters are not defined. and makes it typed
237
+ - `rtype_writer(*names, type)` : calls `attr_writer` if the setters are not defined. and makes it typed
233
238
 
234
- You can use `rtype_accessor_self` for static accessor.
239
+ You can use `rtype_accessor_self` for static accessor. (`rtype_reader_self`, `rtype_writer_self` also exist)
235
240
 
236
241
  ```ruby
237
242
  require 'rtype'
@@ -285,6 +290,29 @@ sum([1, 2, 3]) # => 6
285
290
  sum([1.0, 2, 3]) # => 6.0
286
291
  ```
287
292
 
293
+ #### float_accessor
294
+ ```ruby
295
+ class Point
296
+ float_accessor :x, :y
297
+ end
298
+
299
+ v = Point.new
300
+ v.x = 1
301
+ v.x # => 1.0 (always Float)
302
+ ```
303
+
304
+ #### bool_accessor
305
+ ```ruby
306
+ class Human
307
+ bool_accessor :hungry
308
+ end
309
+
310
+ a = Human.new
311
+ a.hungry = true
312
+ a.hungry? # => true
313
+ a.hungry # NoMethodError
314
+ ```
315
+
288
316
  #### `rtype`
289
317
  ```ruby
290
318
  require 'rtype'
@@ -392,9 +420,14 @@ Example.new.method(:test).return_type
392
420
 
393
421
  #### Special Behaviors
394
422
  - `TypedArray` : Ensures value is an array with the type (type signature)
395
- - `Array::of(type)` (recommended)
396
- - or `Rtype::Behavior::TypedArray[type]`
423
+ - `Array.of(type)` (recommended)
397
424
  - Example: [TypedArray](#typed-array)
425
+
426
+ - `TypedSet` : Ensures value is a set with the type (type signature)
427
+ - `Set.of(type)` (recommended)
428
+
429
+ - `TypedHash` : Ensures value is a hash with the type (type signature)
430
+ - `Hash.of(key_type, value_type)` (recommended)
398
431
 
399
432
  - `Num, Int, Flo` : Numeric check
400
433
  - `Num/Int/Flo >/>=/</<=/== x`
@@ -403,19 +436,19 @@ Example.new.method(:test).return_type
403
436
  - e.g. `Flo >= 2` means value must be a `Float` and >= 2
404
437
 
405
438
  - `And` : Ensures value is valid for all given types
406
- - `Rtype::and(*types)`, `Rtype::Behavior::And[*types]`
439
+ - `Rtype.and(*types)`, `Rtype::Behavior::And[*types]`
407
440
  - or `Array#comb`, `Object#and(*others)`
408
441
 
409
442
  - `Xor` : Ensures value is valid for only one of given types
410
- - `Rtype::xor(*types)`, `Rtype::Behavior::Xor[*types]`
443
+ - `Rtype.xor(*types)`, `Rtype::Behavior::Xor[*types]`
411
444
  - or `Object#xor(*others)`
412
445
 
413
446
  - `Not` : Ensures value is not valid for all given types
414
- - `Rtype::not(*types)`, `Rtype::Behavior::Not[*types]`
447
+ - `Rtype.not(*types)`, `Rtype::Behavior::Not[*types]`
415
448
  - or `Object#not`
416
449
 
417
450
  - `Nilable` : Value can be nil
418
- - `Rtype::nilable(type)`, `Rtype::Behavior::Nilable[type]`
451
+ - `Rtype.nilable(type)`, `Rtype::Behavior::Nilable[type]`
419
452
  - or `Object#nilable`, `Object#or_nil`
420
453
 
421
454
  - You can create custom behaviors by extending `Rtype::Behavior::Base`
data/Rakefile CHANGED
@@ -8,5 +8,5 @@ task :default => [:spec]
8
8
  # Benchmark
9
9
  desc "Compare with pure ruby and other gems"
10
10
  task :benchmark do
11
- ruby "benchmark/benchmark.rb"
11
+ ruby "benchmark/benchmark.rb"
12
12
  end
@@ -74,26 +74,43 @@ module Rtype
74
74
 
75
75
  define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
76
76
  end
77
-
78
- # Calls `attr_accessor` if the accessor method(getter/setter) is not defined.
79
- # and makes it typed.
77
+
78
+ # @param owner Owner of the accessor
79
+ # @param [#to_sym] name
80
+ # @param type_behavior A type behavior. e.g. Integer
81
+ # @return [void]
80
82
  #
81
- # this method uses `define_typed_method` for getter and setter.
83
+ # @raise [ArgumentError] If name is nil
84
+ # @raise [TypeSignatureError]
85
+ def define_typed_accessor(owner, name, type_behavior)
86
+ define_typed_reader(owner, name, type_behavior)
87
+ define_typed_writer(owner, name, type_behavior)
88
+ end
89
+
90
+ # @param owner Owner of the getter
91
+ # @param [#to_sym] name
92
+ # @param type_behavior A type behavior. e.g. Integer
93
+ # @return [void]
82
94
  #
83
- # @param owner Owner of the accessor
84
- # @param [#to_sym] accessor_name
95
+ # @raise [ArgumentError] If name is nil
96
+ # @raise [TypeSignatureError]
97
+ def define_typed_reader(owner, name, type_behavior)
98
+ raise ArgumentError, "name is nil" if name.nil?
99
+ valid?(type_behavior, nil)
100
+ define_typed_method owner, name.to_sym, [] => type_behavior
101
+ end
102
+
103
+ # @param owner Owner of the setter
104
+ # @param [#to_sym] name
85
105
  # @param type_behavior A type behavior. e.g. Integer
86
106
  # @return [void]
87
107
  #
88
- # @raise [ArgumentError] If accessor_name is nil
108
+ # @raise [ArgumentError] If name is nil
89
109
  # @raise [TypeSignatureError]
90
- def define_typed_accessor(owner, accessor_name, type_behavior)
91
- raise ArgumentError, "accessor_name is nil" if accessor_name.nil?
92
- getter = accessor_name.to_sym
93
- setter = :"#{accessor_name}="
110
+ def define_typed_writer(owner, name, type_behavior)
111
+ raise ArgumentError, "name is nil" if name.nil?
94
112
  valid?(type_behavior, nil)
95
- define_typed_method owner, getter, [] => type_behavior
96
- define_typed_method owner, setter, [type_behavior] => Any
113
+ define_typed_method owner, :"#{name.to_sym}=", [type_behavior] => Any
97
114
  end
98
115
 
99
116
  # This is just 'information'
@@ -9,4 +9,9 @@ require_relative 'behavior/xor'
9
9
  require_relative 'behavior/not'
10
10
  require_relative 'behavior/nilable'
11
11
  require_relative 'behavior/typed_array'
12
+ require_relative 'behavior/typed_set'
13
+ require_relative 'behavior/typed_hash'
14
+ require_relative 'behavior/numeric_check'
15
+ require_relative 'behavior/integer_check'
16
+ require_relative 'behavior/float_check'
12
17
  require_relative 'behavior/core_ext'
@@ -33,128 +33,142 @@ class Array
33
33
  end
34
34
  end
35
35
 
36
+ class Set
37
+ # @return [Rtype::Behavior::TypedSet]
38
+ def self.of(type_sig)
39
+ ::Rtype::Behavior::TypedSet.new(type_sig)
40
+ end
41
+ end
42
+
43
+ class Hash
44
+ # @return [Rtype::Behavior::TypedHash]
45
+ def self.of(key_type, value_type)
46
+ ::Rtype::Behavior::TypedHash.new(key_type, value_type)
47
+ end
48
+ end
49
+
36
50
  class Num
37
51
  # @param [Numeric] x
38
- # @return [Proc]
52
+ # @return [Rtype::Behavior::NumericCheck]
39
53
  # @example Value must be a Numeric and > 2
40
54
  # rtype [Num > 2] => Any
41
55
  def self.>(x)
42
- lambda { |obj| obj.is_a?(Numeric) && obj > x }
56
+ ::Rtype::Behavior::NumericCheck.new(:>, x)
43
57
  end
44
58
 
45
59
  # @param [Numeric] x
46
- # @return [Proc]
60
+ # @return [Rtype::Behavior::NumericCheck]
47
61
  # @example Value must be a Numeric and > 2
48
62
  # rtype [Num > 2] => Any
49
63
  def self.>=(x)
50
- lambda { |obj| obj.is_a?(Numeric) && obj >= x }
64
+ ::Rtype::Behavior::NumericCheck.new(:>=, x)
51
65
  end
52
66
 
53
67
  # @param [Numeric] x
54
- # @return [Proc]
68
+ # @return [Rtype::Behavior::NumericCheck]
55
69
  # @example Value must be a Numeric and > 2
56
70
  # rtype [Num > 2] => Any
57
71
  def self.<(x)
58
- lambda { |obj| obj.is_a?(Numeric) && obj < x }
72
+ ::Rtype::Behavior::NumericCheck.new(:<, x)
59
73
  end
60
74
 
61
75
  # @param [Numeric] x
62
- # @return [Proc]
76
+ # @return [Rtype::Behavior::NumericCheck]
63
77
  # @example Value must be a Numeric and > 2
64
78
  # rtype [Num > 2] => Any
65
79
  def self.<=(x)
66
- lambda { |obj| obj.is_a?(Numeric) && obj <= x }
80
+ ::Rtype::Behavior::NumericCheck.new(:<=, x)
67
81
  end
68
82
 
69
83
  # @param [Numeric] x
70
- # @return [Proc]
84
+ # @return [Rtype::Behavior::NumericCheck]
71
85
  # @example Value must be a Numeric and > 2
72
86
  # rtype [Num > 2] => Any
73
87
  def self.==(x)
74
- lambda { |obj| obj.is_a?(Numeric) && obj == x }
88
+ ::Rtype::Behavior::NumericCheck.new(:==, x)
75
89
  end
76
90
  end
77
91
 
78
92
  class Int
79
93
  # @param [Numeric] x
80
- # @return [Proc]
94
+ # @return [Rtype::Behavior::IntegerCheck]
81
95
  # @example Value must be a Integer and > 2
82
96
  # rtype [Int > 2] => Any
83
97
  def self.>(x)
84
- lambda { |obj| obj.is_a?(Integer) && obj > x }
98
+ ::Rtype::Behavior::IntegerCheck.new(:>, x)
85
99
  end
86
100
 
87
101
  # @param [Numeric] x
88
- # @return [Proc]
102
+ # @return [Rtype::Behavior::IntegerCheck]
89
103
  # @example Value must be a Integer and > 2
90
104
  # rtype [Int > 2] => Any
91
105
  def self.>=(x)
92
- lambda { |obj| obj.is_a?(Integer) && obj >= x }
106
+ ::Rtype::Behavior::IntegerCheck.new(:>=, x)
93
107
  end
94
108
 
95
109
  # @param [Numeric] x
96
- # @return [Proc]
110
+ # @return [Rtype::Behavior::IntegerCheck]
97
111
  # @example Value must be a Integer and > 2
98
112
  # rtype [Int > 2] => Any
99
113
  def self.<(x)
100
- lambda { |obj| obj.is_a?(Integer) && obj < x }
114
+ ::Rtype::Behavior::IntegerCheck.new(:<, x)
101
115
  end
102
116
 
103
117
  # @param [Numeric] x
104
- # @return [Proc]
118
+ # @return [Rtype::Behavior::IntegerCheck]
105
119
  # @example Value must be a Integer and > 2
106
120
  # rtype [Int > 2] => Any
107
121
  def self.<=(x)
108
- lambda { |obj| obj.is_a?(Integer) && obj <= x }
122
+ ::Rtype::Behavior::IntegerCheck.new(:<=, x)
109
123
  end
110
124
 
111
125
  # @param [Numeric] x
112
- # @return [Proc]
126
+ # @return [Rtype::Behavior::IntegerCheck]
113
127
  # @example Value must be a Integer and > 2
114
128
  # rtype [Int > 2] => Any
115
129
  def self.==(x)
116
- lambda { |obj| obj.is_a?(Integer) && obj == x }
130
+ ::Rtype::Behavior::IntegerCheck.new(:==, x)
117
131
  end
118
132
  end
119
133
 
120
134
  class Flo
121
135
  # @param [Numeric] x
122
- # @return [Proc]
136
+ # @return [Rtype::Behavior::FloatCheck]
123
137
  # @example Value must be a Float and > 2
124
138
  # rtype [Flo > 2] => Any
125
139
  def self.>(x)
126
- lambda { |obj| obj.is_a?(Float) && obj > x }
140
+ ::Rtype::Behavior::FloatCheck.new(:>, x)
127
141
  end
128
142
 
129
143
  # @param [Numeric] x
130
- # @return [Proc]
144
+ # @return [Rtype::Behavior::FloatCheck]
131
145
  # @example Value must be a Float and > 2
132
146
  # rtype [Flo > 2] => Any
133
147
  def self.>=(x)
134
- lambda { |obj| obj.is_a?(Float) && obj >= x }
148
+ ::Rtype::Behavior::FloatCheck.new(:>=, x)
135
149
  end
136
150
 
137
151
  # @param [Numeric] x
138
- # @return [Proc]
152
+ # @return [Rtype::Behavior::FloatCheck]
139
153
  # @example Value must be a Float and > 2
140
154
  # rtype [Flo > 2] => Any
141
155
  def self.<(x)
142
- lambda { |obj| obj.is_a?(Float) && obj < x }
156
+ ::Rtype::Behavior::FloatCheck.new(:<, x)
143
157
  end
144
158
 
145
159
  # @param [Numeric] x
146
- # @return [Proc]
160
+ # @return [Rtype::Behavior::FloatCheck]
147
161
  # @example Value must be a Float and > 2
148
162
  # rtype [Flo > 2] => Any
149
163
  def self.<=(x)
150
- lambda { |obj| obj.is_a?(Float) && obj <= x }
164
+ ::Rtype::Behavior::FloatCheck.new(:<=, x)
151
165
  end
152
166
 
153
167
  # @param [Numeric] x
154
- # @return [Proc]
168
+ # @return [Rtype::Behavior::FloatCheck]
155
169
  # @example Value must be a Float and > 2
156
170
  # rtype [Flo > 2] => Any
157
171
  def self.==(x)
158
- lambda { |obj| obj.is_a?(Float) && obj == x }
172
+ ::Rtype::Behavior::FloatCheck.new(:==, x)
159
173
  end
160
174
  end
@@ -0,0 +1,17 @@
1
+ module Rtype
2
+ module Behavior
3
+ class FloatCheck < NumericCheck
4
+ def valid?(value)
5
+ if value.is_a?(Float)
6
+ @lambda.call(value)
7
+ else
8
+ false
9
+ end
10
+ end
11
+
12
+ def error_message(value)
13
+ "Expected #{value.inspect} to be a float #{@condition} #{@x}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Rtype
2
+ module Behavior
3
+ class IntegerCheck < NumericCheck
4
+ def valid?(value)
5
+ if value.is_a?(Integer)
6
+ @lambda.call(value)
7
+ else
8
+ false
9
+ end
10
+ end
11
+
12
+ def error_message(value)
13
+ "Expected #{value.inspect} to be an integer #{@condition} #{@x}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ module Rtype
2
+ module Behavior
3
+ class NumericCheck < Base
4
+ @@conditions = [
5
+ :>, :<, :>=, :<=, :==
6
+ ]
7
+
8
+ # @param [Symbol] condition
9
+ # @param [Numeric] x
10
+ def initialize(condition, x)
11
+ raise ArgumentError, "Invalid condition '#{condition}'" unless @@conditions.include?(condition)
12
+ raise ArgumentError, "x is not a Numeric" unless x.is_a?(Numeric)
13
+ @condition = condition
14
+ @x = x
15
+ @lambda = case condition
16
+ when :>
17
+ lambda { |obj| obj > @x }
18
+ when :<
19
+ lambda { |obj| obj < @x }
20
+ when :>=
21
+ lambda { |obj| obj >= @x }
22
+ when :<=
23
+ lambda { |obj| obj <= @x }
24
+ when :==
25
+ lambda { |obj| obj == @x }
26
+ end
27
+ end
28
+
29
+ def valid?(value)
30
+ if value.is_a?(Numeric)
31
+ @lambda.call(value)
32
+ else
33
+ false
34
+ end
35
+ end
36
+
37
+ def error_message(value)
38
+ "Expected #{value.inspect} to be a numeric #{@condition} #{@x}"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,5 +1,6 @@
1
1
  module Rtype
2
2
  module Behavior
3
+ # Typed array behavior. empty array allowed
3
4
  class TypedArray < Base
4
5
  def initialize(type)
5
6
  @type = type
@@ -0,0 +1,29 @@
1
+ module Rtype
2
+ module Behavior
3
+ # Typed hash behavior. empty hash allowed
4
+ class TypedHash < Base
5
+ def initialize(key_type, value_type)
6
+ @ktype = key_type
7
+ @vtype = value_type
8
+ Rtype.assert_valid_argument_type_sig_element(@ktype)
9
+ Rtype.assert_valid_argument_type_sig_element(@vtype)
10
+ end
11
+
12
+ def valid?(value)
13
+ if value.is_a?(Hash)
14
+ any = value.any? do |k, v|
15
+ !Rtype::valid?(@ktype, k) ||
16
+ !Rtype::valid?(@vtype, v)
17
+ end
18
+ !any
19
+ else
20
+ false
21
+ end
22
+ end
23
+
24
+ def error_message(value)
25
+ "Expected #{value.inspect} to be a hash with key type #{@ktype.inspect} and value type #{@vtype.inspect}"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ module Rtype
2
+ module Behavior
3
+ # Typed set behavior. empty set allowed
4
+ class TypedSet < Base
5
+ def initialize(type)
6
+ @type = type
7
+ Rtype.assert_valid_argument_type_sig_element(@type)
8
+ end
9
+
10
+ def valid?(value)
11
+ if value.is_a?(Set)
12
+ any = value.any? do |e|
13
+ !Rtype::valid?(@type, e)
14
+ end
15
+ !any
16
+ else
17
+ false
18
+ end
19
+ end
20
+
21
+ def error_message(value)
22
+ "Expected #{value.inspect} to be a set with type #{@type.inspect}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -22,7 +22,7 @@ private
22
22
  # Makes the method typed
23
23
  #
24
24
  # With 'annotation mode', this method works for both instance method and singleton method (class method).
25
- # Without it (specifying method name), this method only works for instance method.
25
+ # Without it, this method only works for instance method.
26
26
  #
27
27
  # @param [#to_sym, nil] method_name The name of method. If nil, annotation mode works
28
28
  # @param [Hash] type_sig_info A type signature. e.g. [Integer] => Any
@@ -62,47 +62,184 @@ private
62
62
  ::Rtype.define_typed_method(singleton_class, method_name, type_sig_info)
63
63
  end
64
64
 
65
- # Makes the accessor methods (getter and setter) typed
65
+ # Calls `attr_accessor` if the accessor method(getter/setter) is not defined.
66
+ # and makes it typed.
66
67
  #
67
- # @param [Array<#to_sym>] accessor_names
68
+ # @param [Array<#to_sym>] names
68
69
  # @param type_behavior A type behavior
69
70
  # @return [void]
70
71
  #
71
- # @raise [ArgumentError] If accessor_names contains nil
72
+ # @raise [ArgumentError] If names contains nil
72
73
  # @raise [TypeSignatureError] If type_behavior is invalid
73
74
  # @see #rtype
74
- def rtype_accessor(*accessor_names, type_behavior)
75
- accessor_names.each do |accessor_name|
76
- accessor_name = accessor_name.to_sym
77
- if !respond_to?(accessor_name) || !respond_to?(:"#{accessor_name}=")
78
- attr_accessor accessor_name
75
+ def rtype_accessor(*names, type_behavior)
76
+ rtype_reader(*names, type_behavior)
77
+ rtype_writer(*names, type_behavior)
78
+ end
79
+
80
+ # Calls `attr_accessor` if the accessor method(getter/setter) is not defined.
81
+ # and makes it typed.
82
+ #
83
+ # @param [Array<#to_sym>] names
84
+ # @param type_behavior A type behavior
85
+ # @return [void]
86
+ #
87
+ # @raise [ArgumentError] If names contains nil
88
+ # @raise [TypeSignatureError] If type_behavior is invalid
89
+ # @see #rtype_self
90
+ def rtype_accessor_self(*names, type_behavior)
91
+ rtype_reader_self(*names, type_behavior)
92
+ rtype_writer_self(*names, type_behavior)
93
+ end
94
+
95
+ # Calls `attr_reader` if the getter method is not defined.
96
+ # and makes it typed.
97
+ #
98
+ # @param [Array<#to_sym>] names
99
+ # @param type_behavior A type behavior
100
+ # @return [void]
101
+ #
102
+ # @raise [ArgumentError] If names contains nil
103
+ # @raise [TypeSignatureError] If type_behavior is invalid
104
+ # @see #rtype
105
+ def rtype_reader(*names, type_behavior)
106
+ names.each do |name|
107
+ raise ArgumentError, "names contains nil" if name.nil?
108
+
109
+ name = name.to_sym
110
+ if !respond_to?(name)
111
+ attr_reader name
79
112
  end
80
113
 
81
114
  if is_a?(Module)
82
- ::Rtype::define_typed_accessor(self, accessor_name, type_behavior)
115
+ ::Rtype::define_typed_reader(self, name, type_behavior)
83
116
  else
84
- rtype_accessor_self(accessor_name, type_behavior)
117
+ rtype_reader_self(name, type_behavior)
85
118
  end
86
119
  end
87
120
  nil
88
121
  end
89
122
 
90
- # Makes the accessor methods (getter and setter) typed
123
+ # Calls `attr_reader` if the getter method is not defined.
124
+ # and makes it typed.
91
125
  #
92
- # @param [Array<#to_sym>] accessor_names
126
+ # @param [Array<#to_sym>] names
93
127
  # @param type_behavior A type behavior
94
128
  # @return [void]
95
129
  #
96
- # @raise [ArgumentError] If accessor_names contains nil
130
+ # @raise [ArgumentError] If names contains nil
97
131
  # @raise [TypeSignatureError] If type_behavior is invalid
98
132
  # @see #rtype_self
99
- def rtype_accessor_self(*accessor_names, type_behavior)
100
- accessor_names.each do |accessor_name|
101
- accessor_name = accessor_name.to_sym
102
- if !respond_to?(accessor_name) || !respond_to?(:"#{accessor_name}=")
103
- singleton_class.send(:attr_accessor, accessor_name)
133
+ def rtype_reader_self(*names, type_behavior)
134
+ names.each do |name|
135
+ raise ArgumentError, "names contains nil" if name.nil?
136
+
137
+ name = name.to_sym
138
+ if !respond_to?(name)
139
+ singleton_class.send(:attr_reader, name)
140
+ end
141
+ ::Rtype::define_typed_reader(singleton_class, name, type_behavior)
142
+ end
143
+ nil
144
+ end
145
+
146
+ # Calls `attr_writer` if the setter method is not defined.
147
+ # and makes it typed.
148
+ #
149
+ # @param [Array<#to_sym>] names
150
+ # @param type_behavior A type behavior
151
+ # @return [void]
152
+ #
153
+ # @raise [ArgumentError] If names contains nil
154
+ # @raise [TypeSignatureError] If type_behavior is invalid
155
+ # @see #rtype
156
+ def rtype_writer(*names, type_behavior)
157
+ names.each do |name|
158
+ raise ArgumentError, "names contains nil" if name.nil?
159
+
160
+ name = name.to_sym
161
+ if !respond_to?(:"#{name}=")
162
+ attr_writer name
163
+ end
164
+
165
+ if is_a?(Module)
166
+ ::Rtype::define_typed_writer(self, name, type_behavior)
167
+ else
168
+ rtype_reader_self(name, type_behavior)
169
+ end
170
+ end
171
+ nil
172
+ end
173
+
174
+ # Calls `attr_writer` if the setter method is not defined.
175
+ # and makes it typed.
176
+ #
177
+ # @param [Array<#to_sym>] names
178
+ # @param type_behavior A type behavior
179
+ # @return [void]
180
+ #
181
+ # @raise [ArgumentError] If names contains nil
182
+ # @raise [TypeSignatureError] If type_behavior is invalid
183
+ # @see #rtype_self
184
+ def rtype_writer_self(*names, type_behavior)
185
+ names.each do |name|
186
+ raise ArgumentError, "names contains nil" if name.nil?
187
+
188
+ name = name.to_sym
189
+ if !respond_to?(:"#{name}=")
190
+ singleton_class.send(:attr_writer, name)
191
+ end
192
+ ::Rtype::define_typed_writer(singleton_class, name, type_behavior)
193
+ end
194
+ nil
195
+ end
196
+
197
+ # Creates getter, setter methods.
198
+ # The getter method is typed with Float
199
+ # and the setter method is typed with Numeric.
200
+ #
201
+ # If the setter is called with a numeric given,
202
+ # the setter convert the numeric to a float, and store it.
203
+ #
204
+ # As a result, setter can accept a Numeric(Integer/Float), and getter always returns a Float
205
+ #
206
+ # @param [Array<#to_sym>] names
207
+ # @return [void]
208
+ #
209
+ # @raise [ArgumentError] If names contains nil
210
+ def float_accessor(*names)
211
+ names.each do |name|
212
+ raise ArgumentError, "names contains nil" if name.nil?
213
+
214
+ name = name.to_sym
215
+ rtype_reader name, Float
216
+ define_method(:"#{name}=") do |val|
217
+ instance_variable_set(:"@#{name}", val.to_f)
218
+ end
219
+ ::Rtype::define_typed_writer(self, name, Numeric)
220
+ end
221
+ nil
222
+ end
223
+
224
+ # Creates getter, setter methods. And makes it typed with Boolean.
225
+ # The name of the getter ends with `?`.
226
+ #
227
+ # e.g. `bool_accessor :closed` will create `closed=` and `closed?` methods
228
+ #
229
+ # @param [Array<#to_sym>] names
230
+ # @return [void]
231
+ #
232
+ # @raise [ArgumentError] If names contains nil
233
+ def bool_accessor(*names)
234
+ names.each do |name|
235
+ raise ArgumentError, "names contains nil" if name.nil?
236
+
237
+ name = name.to_sym
238
+ rtype_writer name, Boolean
239
+ define_method(:"#{name}?") do
240
+ instance_variable_get(:"@#{name}")
104
241
  end
105
- ::Rtype::define_typed_accessor(singleton_class, accessor_name, type_behavior)
242
+ ::Rtype::define_typed_reader(self, :"#{name}?", Boolean)
106
243
  end
107
244
  nil
108
245
  end
@@ -1,5 +1,5 @@
1
1
  module Rtype
2
- VERSION = "0.6.6".freeze
2
+ VERSION = "0.6.8".freeze
3
3
  # rtype java extension version. nil If the extension is not used
4
4
  JAVA_EXT_VERSION = nil unless const_defined?(:JAVA_EXT_VERSION, false)
5
5
  # rtype c extension version. nil If the extension is not used
@@ -46,6 +46,10 @@ describe Rtype do
46
46
 
47
47
  def args_and_kwargs(a, b, c:, d:)
48
48
  end
49
+
50
+ public
51
+ def public_func
52
+ end
49
53
 
50
54
  protected
51
55
  def protected_func
@@ -149,7 +153,7 @@ describe Rtype do
149
153
  end
150
154
 
151
155
  it 'Kernel#rtype_accessor' do
152
- class TestClass
156
+ class AccessorTestClass
153
157
  rtype_accessor :value, :value2, String
154
158
 
155
159
  def initialize
@@ -157,23 +161,109 @@ describe Rtype do
157
161
  @value2 = 123
158
162
  end
159
163
  end
160
- expect {TestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
161
- expect {TestClass.new.value}.to raise_error Rtype::ReturnTypeError
162
- expect {TestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
163
- expect {TestClass.new.value2}.to raise_error Rtype::ReturnTypeError
164
+ expect {AccessorTestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
165
+ expect {AccessorTestClass.new.value}.to raise_error Rtype::ReturnTypeError
166
+ expect {AccessorTestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
167
+ expect {AccessorTestClass.new.value2}.to raise_error Rtype::ReturnTypeError
164
168
  end
165
169
 
166
170
  it 'Kernel#rtype_accessor_self' do
167
- class TestClass
171
+ class AccessorTestClass
168
172
  @@value = 123
169
173
  @@value2 = 123
170
-
171
174
  rtype_accessor_self :value, :value2, String
172
175
  end
173
- expect {TestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
174
- expect {TestClass::value}.to raise_error Rtype::ReturnTypeError
175
- expect {TestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
176
- expect {TestClass::value2}.to raise_error Rtype::ReturnTypeError
176
+ expect {AccessorTestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
177
+ expect {AccessorTestClass::value}.to raise_error Rtype::ReturnTypeError
178
+ expect {AccessorTestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
179
+ expect {AccessorTestClass::value2}.to raise_error Rtype::ReturnTypeError
180
+ end
181
+
182
+ it 'Kernel#rtype_reader' do
183
+ class ReaderTestClass
184
+ rtype_reader :value, :value2, String
185
+
186
+ def initialize
187
+ @value = 123
188
+ @value2 = 123
189
+ end
190
+ end
191
+ expect {ReaderTestClass.new.value}.to raise_error Rtype::ReturnTypeError
192
+ expect {ReaderTestClass.new.value2}.to raise_error Rtype::ReturnTypeError
193
+ end
194
+
195
+ it 'Kernel#rtype_reader_self' do
196
+ class ReaderTestClass
197
+ @@value = 123
198
+ @@value2 = 123
199
+ rtype_reader_self :value, :value2, String
200
+ end
201
+ expect {ReaderTestClass::value}.to raise_error Rtype::ReturnTypeError
202
+ expect {ReaderTestClass::value2}.to raise_error Rtype::ReturnTypeError
203
+ end
204
+
205
+ it 'Kernel#rtype_writer' do
206
+ class WriterTestClass
207
+ rtype_writer :value, :value2, String
208
+
209
+ def initialize
210
+ @value = 123
211
+ @value2 = 123
212
+ end
213
+ end
214
+ expect {WriterTestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
215
+ expect {WriterTestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
216
+ end
217
+
218
+ it 'Kernel#rtype_writer_self' do
219
+ class WriterTestClass
220
+ @@value = 123
221
+ @@value2 = 123
222
+ rtype_writer_self :value, :value2, String
223
+ end
224
+ expect {WriterTestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
225
+ expect {WriterTestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
226
+ end
227
+
228
+ it 'Kernel#float_accessor' do
229
+ class FloatAccessorTestClass
230
+ float_accessor :float, :int
231
+
232
+ def initialize
233
+ @float = 10.0
234
+ @int = 10
235
+ end
236
+ end
237
+
238
+ float_accessor_test = FloatAccessorTestClass.new
239
+
240
+ float_accessor_test.float
241
+ expect {float_accessor_test.int}.to raise_error Rtype::ReturnTypeError
242
+ float_accessor_test.float = 5.0
243
+ float_accessor_test.float = 5
244
+ expect(float_accessor_test.float).to eql(5.0) # be(expected) => passes if actual.eql?(expected)
245
+ expect(float_accessor_test.float).not_to eql(5)
246
+ end
247
+
248
+ it 'Kernel#bool_accessor' do
249
+ class BoolAccessorTestClass
250
+ bool_accessor :state, :invalid_var
251
+
252
+ def initialize
253
+ @state = false
254
+ @invalid_var = 123
255
+ end
256
+ end
257
+
258
+ bool_accessor_test = BoolAccessorTestClass.new
259
+
260
+ bool_accessor_test.state?
261
+ expect {bool_accessor_test.state}.to raise_error NoMethodError
262
+ expect(bool_accessor_test.state?).to eql(false)
263
+ bool_accessor_test.state = true
264
+ expect(bool_accessor_test.state?).to eql(true)
265
+ expect {bool_accessor_test.state = 123}.to raise_error Rtype::ArgumentTypeError
266
+ expect {bool_accessor_test.invalid_var?}.to raise_error Rtype::ReturnTypeError
177
267
  end
178
268
 
179
269
  describe 'Test type behaviors' do
@@ -475,6 +565,65 @@ describe Rtype do
475
565
  end
476
566
  end
477
567
 
568
+ describe 'Rtype::Behavior::TypedSet' do
569
+ it 'class singleton [] method' do
570
+ klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedSet[Integer] ] => nil
571
+ instance.return_nil( Set.new([123]) )
572
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
573
+ expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
574
+ end
575
+
576
+ it 'core extension method (Set::of)' do
577
+ klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
578
+ instance.return_nil( Set.new([123]) )
579
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
580
+ expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
581
+ end
582
+
583
+ it 'complicated type sig' do
584
+ klass.send :rtype, :return_nil, [ Set.of(:to_i.and(:chars)) ] => nil
585
+ instance.return_nil( Set.new(["hello"]) )
586
+ expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
587
+ expect { instance.return_nil(Set.new([123])) }.to raise_error Rtype::ArgumentTypeError
588
+ end
589
+
590
+ it 'allows empty set' do
591
+ klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
592
+ instance.return_nil(Set.new)
593
+ end
594
+ end
595
+
596
+ describe 'Rtype::Behavior::TypedHash' do
597
+ it 'class singleton [] method' do
598
+ klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedHash[Symbol, Integer] ] => nil
599
+ instance.return_nil( {key: 123} )
600
+ expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
601
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
602
+ expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
603
+ end
604
+
605
+ it 'core extension method (Hash::of)' do
606
+ klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
607
+ instance.return_nil( {key: 123} )
608
+ expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
609
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
610
+ expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
611
+ end
612
+
613
+ it 'complicated type sig' do
614
+ klass.send :rtype, :return_nil, [ Hash.of(:to_i.and(:chars), :to_i.and(:chars)) ] => nil
615
+ instance.return_nil( {"key" => "val"} )
616
+ expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
617
+ expect {instance.return_nil( {key: "val"} )}.to raise_error Rtype::ArgumentTypeError
618
+ expect {instance.return_nil( {"key" => :val} )}.to raise_error Rtype::ArgumentTypeError
619
+ end
620
+
621
+ it 'allows empty hash' do
622
+ klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
623
+ instance.return_nil({})
624
+ end
625
+ end
626
+
478
627
  describe 'Numeric check' do
479
628
  it 'Num (Numeric)' do
480
629
  klass.send :rtype, :return_nil, [Num >= 0] => Any
@@ -751,6 +900,10 @@ describe Rtype do
751
900
  klass.send :rtype, :private_func, [] => Any
752
901
  expect {instance.private_func}.to raise_error NoMethodError
753
902
  end
903
+ it 'public' do
904
+ klass.send :rtype, :public_func, [] => Any
905
+ instance.public_func
906
+ end
754
907
  end
755
908
 
756
909
  context 'with empty argument signature' do
@@ -816,6 +969,32 @@ describe Rtype do
816
969
  AnnotationTest2.new.inst_one(123)
817
970
  AnnotationTest2::static_two(123)
818
971
  end
972
+
973
+ context 'when rtype signature duplicated' do
974
+ it 'the latest have priority' do
975
+ class PriorityTest1
976
+ rtype :test_priority, [String] => Any
977
+ def test_priority(arg)
978
+ end
979
+ rtype :test_priority, [Integer] => Any
980
+ end
981
+
982
+ PriorityTest1.new.test_priority(1)
983
+ expect { PriorityTest1.new.test_priority("str") }.to raise_error Rtype::ArgumentTypeError
984
+ end
985
+
986
+ it 'annotation mode have priority in contemporaneous signatures' do
987
+ class PriorityTest2
988
+ rtype :test_priority, [String] => Any
989
+ rtype [Integer] => Any
990
+ def test_priority(arg)
991
+ end
992
+ end
993
+
994
+ PriorityTest2.new.test_priority(1)
995
+ expect { PriorityTest2.new.test_priority("str") }.to raise_error Rtype::ArgumentTypeError
996
+ end
997
+ end
819
998
  end
820
999
 
821
1000
  describe "Call Rtype`s static method directly" do
@@ -3,6 +3,7 @@ Coveralls.wear!
3
3
 
4
4
  require 'rtype'
5
5
  require 'rspec'
6
+ require 'set'
6
7
 
7
8
  if !Rtype::NATIVE_EXT_VERSION.nil?
8
9
  puts "Rtype with native extension"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rtype
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.6
4
+ version: 0.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sputnik Gugja
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-01 00:00:00.000000000 Z
11
+ date: 2016-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -70,9 +70,14 @@ files:
70
70
  - lib/rtype/behavior/and.rb
71
71
  - lib/rtype/behavior/base.rb
72
72
  - lib/rtype/behavior/core_ext.rb
73
+ - lib/rtype/behavior/float_check.rb
74
+ - lib/rtype/behavior/integer_check.rb
73
75
  - lib/rtype/behavior/nilable.rb
74
76
  - lib/rtype/behavior/not.rb
77
+ - lib/rtype/behavior/numeric_check.rb
75
78
  - lib/rtype/behavior/typed_array.rb
79
+ - lib/rtype/behavior/typed_hash.rb
80
+ - lib/rtype/behavior/typed_set.rb
76
81
  - lib/rtype/behavior/xor.rb
77
82
  - lib/rtype/core_ext.rb
78
83
  - lib/rtype/method_annotator.rb