rtype-legacy 0.0.2 → 0.0.4

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: d83a1b9bdda46b928d39f78417ffdd1c6e2d29c1
4
- data.tar.gz: db294d682cfc81e9e3fb85ad27ebc0a5dd721ad7
3
+ metadata.gz: 1cfd6d899191a80db171d581dcf6c4cf324e0fe3
4
+ data.tar.gz: 4fec96dfa193388fef8478984625d5cc30d02f9e
5
5
  SHA512:
6
- metadata.gz: 00b1755b7d8d35d541064556e4eac6ad6ed45511b106fbcde14778f8aa60c7f2901e60a67ef38b7486e1e4b680d052027991bf7f577b96566deb6162b1d1a8da
7
- data.tar.gz: ae8294f653096d7b145c5e5747af364cf302219f6d00fc1c30940a4332a27dc82ad1e9a600a650b7f36c99748f66d4bf17fc570131d0b248c17371eef7058dbe
6
+ metadata.gz: 602834cd3859a45248ead08fdda5ea34dd7a633c764319fdb8c5e6ce8427c438226293784ca2dc5de335514bfd22f01ee170d4a6c18d2a4bf75dae30d7e7ba42
7
+ data.tar.gz: 5891fbb28f6a11bc849d9487fe034f4581125ba14c383cf85b6b530495ca7d30d1ef354cb2520e7e9d9cea696af307c5c3a4ba66d66fcb65fdf170c422b61664
data/README.md CHANGED
@@ -12,7 +12,9 @@ class Test
12
12
  a.to_i + b
13
13
  end
14
14
 
15
- rtype [{state: Boolean}. {}] => Boolean
15
+ # Second hash is keyword argument signature
16
+ # (syntax compatibility with 'rtype' gem)
17
+ rtype [{state: Boolean}, {}] => Boolean
16
18
  def self.invert(opts)
17
19
  !opts[:state]
18
20
  end
@@ -22,7 +24,7 @@ Test.new.sum(123, "asd")
22
24
  # (Rtype::ArgumentTypeError) for 2nd argument:
23
25
  # Expected "asd" to be a Numeric
24
26
 
25
- Test::invert(state: 0)
27
+ Test.invert(state: 0)
26
28
  # (Rtype::ArgumentTypeError) for 1st argument:
27
29
  # Expected {:state=>0} to be a hash with 1 elements:
28
30
  # - state : Expected 0 to be a Boolean
@@ -47,8 +49,10 @@ Test::invert(state: 0)
47
49
  - Provides type checking for arguments and return
48
50
  - [Type checking for hash elements](#hash)
49
51
  - [Duck Typing](#duck-typing)
50
- - [Typed Array](#typed-array)
52
+ - [Typed Array](#typed-array), Typed Set, Typed Hash
51
53
  - [Numeric check](#special-behaviors). e.g. `Int >= 0`
54
+ - [Type checking for getter and setter](#attr_accessor-with-rtype)
55
+ - [float_accessor](#float_accessor), [bool_accessor](#bool_accessor)
52
56
  - Custom type behavior
53
57
  - ...
54
58
 
@@ -74,16 +78,8 @@ gem 'rtype-legacy-native'
74
78
  ```
75
79
  then, Rtype Legacy uses it. (**Do not** `require 'rtype-legacy-native'`)
76
80
 
77
- #### Java extension for JRuby
78
- Run
79
- ```ruby
80
- gem install rtype-legacy-java
81
- ```
82
- or add to your `Gemfile`:
83
- ```ruby
84
- gem 'rtype-legacy-java'
85
- ```
86
- then, Rtype Legacy uses it. (**Do not** `require 'rtype-legacy-java'`)
81
+ #### Java extension for JRuby is automatic
82
+ **Do not** `require 'rtype-java'`
87
83
 
88
84
  ## Usage
89
85
 
@@ -113,7 +109,7 @@ then, Rtype Legacy uses it. (**Do not** `require 'rtype-legacy-java'`)
113
109
  - Example: [Hash](#hash)
114
110
 
115
111
  - [Special Behaviors](#special-behaviors)
116
- - `TypedArray`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
112
+ - `TypedArray, TypedSet, TypedHash`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
117
113
 
118
114
  ### Examples
119
115
 
@@ -209,10 +205,12 @@ func({"msg" => "hello hash"})
209
205
  func({msg: "hello hash"}) # hello hash
210
206
  ```
211
207
 
212
- #### rtype with attr_accessor
213
- `rtype_accessor` : calls `attr_accessor` if the accessor method(getter/setter) is not defined. and makes it typed
208
+ #### attr_accessor with rtype
209
+ - `rtype_accessor(*names, type)` : calls `attr_accessor` if the accessor methods(getter/setter) are not defined. and makes it typed
210
+ - `rtype_reader(*names, type)` : calls `attr_reader` if the getters are not defined. and makes it typed
211
+ - `rtype_writer(*names, type)` : calls `attr_writer` if the setters are not defined. and makes it typed
214
212
 
215
- You can use `rtype_accessor_self` for static accessor.
213
+ You can use `rtype_accessor_self` for static accessor. (`rtype_reader_self`, `rtype_writer_self` also exist)
216
214
 
217
215
  ```ruby
218
216
  require 'rtype'
@@ -266,6 +264,29 @@ sum([1, 2, 3]) # => 6
266
264
  sum([1.0, 2, 3]) # => 6.0
267
265
  ```
268
266
 
267
+ #### float_accessor
268
+ ```ruby
269
+ class Point
270
+ float_accessor :x, :y
271
+ end
272
+
273
+ v = Point.new
274
+ v.x = 1
275
+ v.x # => 1.0 (always Float)
276
+ ```
277
+
278
+ #### bool_accessor
279
+ ```ruby
280
+ class Human
281
+ bool_accessor :hungry
282
+ end
283
+
284
+ a = Human.new
285
+ a.hungry = true
286
+ a.hungry? # => true
287
+ a.hungry # NoMethodError
288
+ ```
289
+
269
290
  #### `rtype`
270
291
  ```ruby
271
292
  require 'rtype'
@@ -358,9 +379,14 @@ Example.new.method(:test).return_type
358
379
 
359
380
  #### Special Behaviors
360
381
  - `TypedArray` : Ensures value is an array with the type (type signature)
361
- - `Array::of(type)` (recommended)
362
- - or `Rtype::Behavior::TypedArray[type]`
382
+ - `Array.of(type)` (recommended)
363
383
  - Example: [TypedArray](#typed-array)
384
+
385
+ - `TypedSet` : Ensures value is a set with the type (type signature)
386
+ - `Set.of(type)` (recommended)
387
+
388
+ - `TypedHash` : Ensures value is a hash with the type (type signature)
389
+ - `Hash.of(key_type, value_type)` (recommended)
364
390
 
365
391
  - `Num, Int, Flo` : Numeric check
366
392
  - `Num/Int/Flo >/>=/</<=/== x`
@@ -369,19 +395,19 @@ Example.new.method(:test).return_type
369
395
  - e.g. `Flo >= 2` means value must be a `Float` and >= 2
370
396
 
371
397
  - `And` : Ensures value is valid for all given types
372
- - `Rtype::and(*types)`, `Rtype::Behavior::And[*types]`
398
+ - `Rtype.and(*types)`, `Rtype::Behavior::And[*types]`
373
399
  - or `Array#comb`, `Object#and(*others)`
374
400
 
375
401
  - `Xor` : Ensures value is valid for only one of given types
376
- - `Rtype::xor(*types)`, `Rtype::Behavior::Xor[*types]`
402
+ - `Rtype.xor(*types)`, `Rtype::Behavior::Xor[*types]`
377
403
  - or `Object#xor(*others)`
378
404
 
379
405
  - `Not` : Ensures value is not valid for all given types
380
- - `Rtype::not(*types)`, `Rtype::Behavior::Not[*types]`
406
+ - `Rtype.not(*types)`, `Rtype::Behavior::Not[*types]`
381
407
  - or `Object#not`
382
408
 
383
409
  - `Nilable` : Value can be nil
384
- - `Rtype::nilable(type)`, `Rtype::Behavior::Nilable[type]`
410
+ - `Rtype.nilable(type)`, `Rtype::Behavior::Nilable[type]`
385
411
  - or `Object#nilable`, `Object#or_nil`
386
412
 
387
413
  - You can create custom behaviors by extending `Rtype::Behavior::Base`
@@ -392,7 +418,7 @@ Example.new.method(:test).return_type
392
418
  ## Benchmarks
393
419
  Result of `rake benchmark` ([source](https://github.com/sputnikgugja/rtype-legacy/tree/master/benchmark/benchmark.rb))
394
420
 
395
- Rubype and Sig don't support 1.9 ruby. Typecheck raise an error in my environment
421
+ Rubype and Sig don't support 1.9 ruby. Typecheck raises an error in my environment
396
422
 
397
423
  ### MRI
398
424
  ```
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
@@ -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
@@ -59,50 +59,179 @@ private
59
59
 
60
60
  # Makes the accessor methods (getter and setter) typed
61
61
  #
62
- # @param [Array<#to_sym>] accessor_names
62
+ # @param [Array<#to_sym>] names
63
63
  # @param type_behavior A type behavior
64
64
  # @return [void]
65
65
  #
66
- # @raise [ArgumentError] If accessor_names contains nil
66
+ # @raise [ArgumentError] If names contains nil
67
67
  # @raise [TypeSignatureError] If type_behavior is invalid
68
68
  # @raise [RuntimeError] If called outside of module
69
69
  # @see #rtype
70
- def rtype_accessor(*accessor_names, type_behavior)
71
- accessor_names.each do |accessor_name|
72
- raise ArgumentError, "accessor_names contains nil" if accessor_name.nil?
70
+ def rtype_accessor(*names, type_behavior)
71
+ rtype_reader(*names, type_behavior)
72
+ rtype_writer(*names, type_behavior)
73
+ end
74
+
75
+ # Makes the accessor methods (getter and setter) typed
76
+ #
77
+ # @param [Array<#to_sym>] names
78
+ # @param type_behavior A type behavior
79
+ # @return [void]
80
+ #
81
+ # @raise [ArgumentError] If names contains nil
82
+ # @raise [TypeSignatureError] If type_behavior is invalid
83
+ # @see #rtype_self
84
+ def rtype_accessor_self(*names, type_behavior)
85
+ rtype_reader_self(*names, type_behavior)
86
+ rtype_writer_self(*names, type_behavior)
87
+ end
88
+
89
+ # Makes the getter methods typed
90
+ #
91
+ # @param [Array<#to_sym>] names
92
+ # @param type_behavior A type behavior
93
+ # @return [void]
94
+ #
95
+ # @raise [ArgumentError] If names contains nil
96
+ # @raise [TypeSignatureError] If type_behavior is invalid
97
+ # @raise [RuntimeError] If called outside of module
98
+ # @see #rtype
99
+ def rtype_reader(*names, type_behavior)
100
+ names.each do |name|
101
+ raise ArgumentError, "names contains nil" if name.nil?
73
102
 
74
- accessor_name = accessor_name.to_sym
75
- if !respond_to?(accessor_name) || !respond_to?(:"#{accessor_name}=")
76
- attr_accessor accessor_name
103
+ name = name.to_sym
104
+ if !respond_to?(name)
105
+ attr_reader name
77
106
  end
78
107
 
79
108
  if is_a?(Module)
80
- ::Rtype::define_typed_accessor(self, accessor_name, type_behavior, false)
109
+ ::Rtype::define_typed_reader(self, name, type_behavior, false)
81
110
  else
82
- raise "rtype_accessor doesn't work in the outside of module"
111
+ raise "rtype_reader doesn't work in the outside of module"
83
112
  end
84
113
  end
85
114
  nil
86
115
  end
87
116
 
88
- # Makes the accessor methods (getter and setter) typed
117
+ # Makes the getter methods typed
89
118
  #
90
- # @param [Array<#to_sym>] accessor_names
119
+ # @param [Array<#to_sym>] names
91
120
  # @param type_behavior A type behavior
92
121
  # @return [void]
93
122
  #
94
- # @raise [ArgumentError] If accessor_names contains nil
123
+ # @raise [ArgumentError] If names contains nil
95
124
  # @raise [TypeSignatureError] If type_behavior is invalid
96
125
  # @see #rtype_self
97
- def rtype_accessor_self(*accessor_names, type_behavior)
98
- accessor_names.each do |accessor_name|
99
- raise ArgumentError, "accessor_names contains nil" if accessor_name.nil?
126
+ def rtype_reader_self(*names, type_behavior)
127
+ names.each do |name|
128
+ raise ArgumentError, "names contains nil" if name.nil?
129
+
130
+ name = name.to_sym
131
+ if !respond_to?(name)
132
+ singleton_class.send(:attr_reader, name)
133
+ end
134
+ ::Rtype::define_typed_reader(self, name, type_behavior, true)
135
+ end
136
+ nil
137
+ end
138
+
139
+ # Makes the setter methods typed
140
+ #
141
+ # @param [Array<#to_sym>] names
142
+ # @param type_behavior A type behavior
143
+ # @return [void]
144
+ #
145
+ # @raise [ArgumentError] If names contains nil
146
+ # @raise [TypeSignatureError] If type_behavior is invalid
147
+ # @raise [RuntimeError] If called outside of module
148
+ # @see #rtype
149
+ def rtype_writer(*names, type_behavior)
150
+ names.each do |name|
151
+ raise ArgumentError, "names contains nil" if name.nil?
152
+
153
+ name = name.to_sym
154
+ if !respond_to?(:"#{name}=")
155
+ attr_writer name
156
+ end
157
+
158
+ if is_a?(Module)
159
+ ::Rtype::define_typed_writer(self, name, type_behavior, false)
160
+ else
161
+ raise "rtype_writer doesn't work in the outside of module"
162
+ end
163
+ end
164
+ nil
165
+ end
166
+
167
+ # Makes the setter methods typed
168
+ #
169
+ # @param [Array<#to_sym>] names
170
+ # @param type_behavior A type behavior
171
+ # @return [void]
172
+ #
173
+ # @raise [ArgumentError] If names contains nil
174
+ # @raise [TypeSignatureError] If type_behavior is invalid
175
+ # @see #rtype_self
176
+ def rtype_writer_self(*names, type_behavior)
177
+ names.each do |name|
178
+ raise ArgumentError, "names contains nil" if name.nil?
179
+
180
+ name = name.to_sym
181
+ if !respond_to?(:"#{name}=")
182
+ singleton_class.send(:attr_writer, name)
183
+ end
184
+ ::Rtype::define_typed_writer(self, name, type_behavior, true)
185
+ end
186
+ nil
187
+ end
188
+
189
+ # Creates getter, setter methods.
190
+ # The getter method is typed with Float
191
+ # and the setter method is typed with Numeric.
192
+ #
193
+ # If the setter is called with a numeric given,
194
+ # the setter convert the numeric to a float, and store it.
195
+ #
196
+ # As a result, setter can accept a Numeric(Integer/Float), and getter always returns a Float
197
+ #
198
+ # @param [Array<#to_sym>] names
199
+ # @return [void]
200
+ #
201
+ # @raise [ArgumentError] If names contains nil
202
+ def float_accessor(*names)
203
+ names.each do |name|
204
+ raise ArgumentError, "names contains nil" if name.nil?
205
+
206
+ name = name.to_sym
207
+ rtype_reader name, Float
208
+ define_method(:"#{name}=") do |val|
209
+ instance_variable_set(:"@#{name}", val.to_f)
210
+ end
211
+ ::Rtype::define_typed_writer(self, name, Numeric, false)
212
+ end
213
+ nil
214
+ end
215
+
216
+ # Creates getter, setter methods. And makes it typed with Boolean.
217
+ # The name of the getter ends with `?`.
218
+ #
219
+ # e.g. `bool_accessor :closed` will create `closed=` and `closed?` methods
220
+ #
221
+ # @param [Array<#to_sym>] names
222
+ # @return [void]
223
+ #
224
+ # @raise [ArgumentError] If names contains nil
225
+ def bool_accessor(*names)
226
+ names.each do |name|
227
+ raise ArgumentError, "names contains nil" if name.nil?
100
228
 
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)
229
+ name = name.to_sym
230
+ rtype_writer name, Boolean
231
+ define_method(:"#{name}?") do
232
+ instance_variable_get(:"@#{name}")
104
233
  end
105
- ::Rtype::define_typed_accessor(self, accessor_name, type_behavior, true)
234
+ ::Rtype::define_typed_reader(self, :"#{name}?", Boolean, false)
106
235
  end
107
236
  nil
108
237
  end
@@ -77,27 +77,46 @@ module Rtype
77
77
 
78
78
  redefine_method_to_typed(owner, method_name, expected_args, return_sig, singleton)
79
79
  end
80
-
81
- # Calls `attr_accessor` if the accessor method(getter/setter) is not defined.
82
- # and makes it typed.
80
+
81
+ # @param owner Owner of the accessor
82
+ # @param [#to_sym] name
83
+ # @param type_behavior A type behavior. e.g. Integer
84
+ # @param [Boolean] singleton Whether the method is singleton method
85
+ # @return [void]
83
86
  #
84
- # this method uses `define_typed_method` for getter and setter.
87
+ # @raise [ArgumentError] If name is nil
88
+ # @raise [TypeSignatureError]
89
+ def define_typed_accessor(owner, name, type_behavior, singleton)
90
+ define_typed_reader(owner, name, type_behavior, singleton)
91
+ define_typed_writer(owner, name, type_behavior, singleton)
92
+ end
93
+
94
+ # @param owner Owner of the getter
95
+ # @param [#to_sym] name
96
+ # @param type_behavior A type behavior. e.g. Integer
97
+ # @param [Boolean] singleton Whether the method is singleton method
98
+ # @return [void]
85
99
  #
86
- # @param owner Owner of the accessor
87
- # @param [#to_sym] accessor_name
100
+ # @raise [ArgumentError] If name is nil
101
+ # @raise [TypeSignatureError]
102
+ def define_typed_reader(owner, name, type_behavior, singleton)
103
+ raise ArgumentError, "name is nil" if name.nil?
104
+ valid?(type_behavior, nil)
105
+ define_typed_method owner, name.to_sym, {[] => type_behavior}, singleton
106
+ end
107
+
108
+ # @param owner Owner of the setter
109
+ # @param [#to_sym] name
88
110
  # @param type_behavior A type behavior. e.g. Integer
89
111
  # @param [Boolean] singleton Whether the method is singleton method
90
112
  # @return [void]
91
113
  #
92
- # @raise [ArgumentError] If accessor_name is nil or singleton is not a boolean
114
+ # @raise [ArgumentError] If name is nil
93
115
  # @raise [TypeSignatureError]
94
- def define_typed_accessor(owner, accessor_name, type_behavior, singleton)
95
- raise ArgumentError, "accessor_name is nil" if accessor_name.nil?
96
- getter = accessor_name.to_sym
97
- setter = :"#{accessor_name}="
116
+ def define_typed_writer(owner, name, type_behavior, singleton)
117
+ raise ArgumentError, "name is nil" if name.nil?
98
118
  valid?(type_behavior, nil)
99
- define_typed_method owner, getter, {[] => type_behavior}, singleton
100
- define_typed_method owner, setter, {[type_behavior] => Any}, singleton
119
+ define_typed_method owner, :"#{name.to_sym}=", {[type_behavior] => Any}, singleton
101
120
  end
102
121
 
103
122
  # This is just 'information'
@@ -1,6 +1,6 @@
1
1
  module Rtype
2
2
  module Legacy
3
- VERSION = "0.0.2".freeze
3
+ VERSION = "0.0.4".freeze
4
4
  # rtype java extension version. nil If the extension is not used
5
5
  JAVA_EXT_VERSION = nil unless const_defined?(:JAVA_EXT_VERSION, false)
6
6
  # rtype c extension version. nil If the extension is not used
@@ -152,6 +152,93 @@ describe Rtype::Legacy do
152
152
  expect {TestClass::value2}.to raise_error Rtype::ReturnTypeError
153
153
  end
154
154
 
155
+ it 'Kernel#rtype_reader' do
156
+ class ReaderTestClass
157
+ rtype_reader :value, :value2, String
158
+
159
+ def initialize
160
+ @value = 123
161
+ @value2 = 123
162
+ end
163
+ end
164
+ expect {ReaderTestClass.new.value}.to raise_error Rtype::ReturnTypeError
165
+ expect {ReaderTestClass.new.value2}.to raise_error Rtype::ReturnTypeError
166
+ end
167
+
168
+ it 'Kernel#rtype_reader_self' do
169
+ class ReaderTestClass
170
+ @@value = 123
171
+ @@value2 = 123
172
+ rtype_reader_self :value, :value2, String
173
+ end
174
+ expect {ReaderTestClass::value}.to raise_error Rtype::ReturnTypeError
175
+ expect {ReaderTestClass::value2}.to raise_error Rtype::ReturnTypeError
176
+ end
177
+
178
+ it 'Kernel#rtype_writer' do
179
+ class WriterTestClass
180
+ rtype_writer :value, :value2, String
181
+
182
+ def initialize
183
+ @value = 123
184
+ @value2 = 123
185
+ end
186
+ end
187
+ expect {WriterTestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
188
+ expect {WriterTestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
189
+ end
190
+
191
+ it 'Kernel#rtype_writer_self' do
192
+ class WriterTestClass
193
+ @@value = 123
194
+ @@value2 = 123
195
+ rtype_writer_self :value, :value2, String
196
+ end
197
+ expect {WriterTestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
198
+ expect {WriterTestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
199
+ end
200
+
201
+ it 'Kernel#float_accessor' do
202
+ class FloatAccessorTestClass
203
+ float_accessor :float, :int
204
+
205
+ def initialize
206
+ @float = 10.0
207
+ @int = 10
208
+ end
209
+ end
210
+
211
+ float_accessor_test = FloatAccessorTestClass.new
212
+
213
+ float_accessor_test.float
214
+ expect {float_accessor_test.int}.to raise_error Rtype::ReturnTypeError
215
+ float_accessor_test.float = 5.0
216
+ float_accessor_test.float = 5
217
+ expect(float_accessor_test.float).to eql(5.0) # be(expected) => passes if actual.eql?(expected)
218
+ expect(float_accessor_test.float).not_to eql(5)
219
+ end
220
+
221
+ it 'Kernel#bool_accessor' do
222
+ class BoolAccessorTestClass
223
+ bool_accessor :state, :invalid_var
224
+
225
+ def initialize
226
+ @state = false
227
+ @invalid_var = 123
228
+ end
229
+ end
230
+
231
+ bool_accessor_test = BoolAccessorTestClass.new
232
+
233
+ bool_accessor_test.state?
234
+ expect {bool_accessor_test.state}.to raise_error NoMethodError
235
+ expect(bool_accessor_test.state?).to eql(false)
236
+ bool_accessor_test.state = true
237
+ expect(bool_accessor_test.state?).to eql(true)
238
+ expect {bool_accessor_test.state = 123}.to raise_error Rtype::ArgumentTypeError
239
+ expect {bool_accessor_test.invalid_var?}.to raise_error Rtype::ReturnTypeError
240
+ end
241
+
155
242
  describe 'Test type behaviors' do
156
243
  describe 'Module' do
157
244
  it "is right" do
@@ -451,6 +538,65 @@ describe Rtype::Legacy do
451
538
  end
452
539
  end
453
540
 
541
+ describe 'Rtype::Behavior::TypedSet' do
542
+ it 'class singleton [] method' do
543
+ klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedSet[Integer] ] => nil
544
+ instance.return_nil( Set.new([123]) )
545
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
546
+ expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
547
+ end
548
+
549
+ it 'core extension method (Set::of)' do
550
+ klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
551
+ instance.return_nil( Set.new([123]) )
552
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
553
+ expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
554
+ end
555
+
556
+ it 'complicated type sig' do
557
+ klass.send :rtype, :return_nil, [ Set.of(:to_i.and(:chars)) ] => nil
558
+ instance.return_nil( Set.new(["hello"]) )
559
+ expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
560
+ expect { instance.return_nil(Set.new([123])) }.to raise_error Rtype::ArgumentTypeError
561
+ end
562
+
563
+ it 'allows empty set' do
564
+ klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
565
+ instance.return_nil(Set.new)
566
+ end
567
+ end
568
+
569
+ describe 'Rtype::Behavior::TypedHash' do
570
+ it 'class singleton [] method' do
571
+ klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedHash[Symbol, Integer] ] => nil
572
+ instance.return_nil( {key: 123} )
573
+ expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
574
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
575
+ expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
576
+ end
577
+
578
+ it 'core extension method (Hash::of)' do
579
+ klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
580
+ instance.return_nil( {key: 123} )
581
+ expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
582
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
583
+ expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
584
+ end
585
+
586
+ it 'complicated type sig' do
587
+ klass.send :rtype, :return_nil, [ Hash.of(:to_i.and(:chars), :to_i.and(:chars)) ] => nil
588
+ instance.return_nil( {"key" => "val"} )
589
+ expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
590
+ expect {instance.return_nil( {key: "val"} )}.to raise_error Rtype::ArgumentTypeError
591
+ expect {instance.return_nil( {"key" => :val} )}.to raise_error Rtype::ArgumentTypeError
592
+ end
593
+
594
+ it 'allows empty hash' do
595
+ klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
596
+ instance.return_nil({})
597
+ end
598
+ end
599
+
454
600
  describe 'Numeric check' do
455
601
  it 'Num (Numeric)' do
456
602
  klass.send :rtype, :return_nil, [Num >= 0] => Any
@@ -3,6 +3,7 @@ Coveralls.wear!
3
3
 
4
4
  require 'rtype/legacy'
5
5
  require 'rspec'
6
+ require 'set'
6
7
 
7
8
  if !Rtype::Legacy::NATIVE_EXT_VERSION.nil?
8
9
  puts "Rtype Legacy with native extension"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rtype-legacy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
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-03 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
@@ -68,9 +68,14 @@ files:
68
68
  - lib/rtype/behavior/and.rb
69
69
  - lib/rtype/behavior/base.rb
70
70
  - lib/rtype/behavior/core_ext.rb
71
+ - lib/rtype/behavior/float_check.rb
72
+ - lib/rtype/behavior/integer_check.rb
71
73
  - lib/rtype/behavior/nilable.rb
72
74
  - lib/rtype/behavior/not.rb
75
+ - lib/rtype/behavior/numeric_check.rb
73
76
  - lib/rtype/behavior/typed_array.rb
77
+ - lib/rtype/behavior/typed_hash.rb
78
+ - lib/rtype/behavior/typed_set.rb
74
79
  - lib/rtype/behavior/xor.rb
75
80
  - lib/rtype/core_ext.rb
76
81
  - lib/rtype/legacy.rb