rtype-legacy 0.0.2 → 0.0.4

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