rtype 0.6.6 → 0.6.8

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: 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