rtype-native 0.5.0 → 0.5.1
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 +4 -4
- data/Gemfile +2 -2
- data/LICENSE +8 -8
- data/README.md +567 -567
- data/Rakefile +11 -11
- data/benchmark/benchmark.rb +191 -191
- data/ext/rtype/c/extconf.rb +2 -2
- data/ext/rtype/c/rtype.c +148 -148
- data/ext/rtype/c/rtype.h +4 -4
- data/spec/rtype_spec.rb +822 -822
- data/spec/spec_helper.rb +4 -4
- metadata +6 -5
data/README.md
CHANGED
@@ -1,568 +1,568 @@
|
|
1
|
-
# Rtype: ruby with type
|
2
|
-
[](https://badge.fury.io/rb/rtype)
|
3
|
-
[](https://travis-ci.org/sputnikgugja/rtype)
|
4
|
-
[](https://coveralls.io/github/sputnikgugja/rtype?branch=master)
|
5
|
-
|
6
|
-
You can do the type checking in Ruby with this gem!
|
7
|
-
|
8
|
-
```ruby
|
9
|
-
require 'rtype'
|
10
|
-
|
11
|
-
class Test
|
12
|
-
rtype [:to_i, Numeric] => Numeric
|
13
|
-
def sum(a, b)
|
14
|
-
a.to_i + b
|
15
|
-
end
|
16
|
-
|
17
|
-
rtype {state: Boolean} => Boolean
|
18
|
-
def self.invert(state:)
|
19
|
-
!state
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
Test.new.sum(123, "asd")
|
24
|
-
# (Rtype::ArgumentTypeError) for 2nd argument:
|
25
|
-
# Expected "asd" to be a Numeric
|
26
|
-
|
27
|
-
Test::invert(state: 0)
|
28
|
-
# (Rtype::ArgumentTypeError) for 'state' argument:
|
29
|
-
# Expected 0 to be a Boolean
|
30
|
-
```
|
31
|
-
|
32
|
-
## Requirements
|
33
|
-
- Ruby >= 2.1
|
34
|
-
- MRI
|
35
|
-
- If C native extension is used, otherwise it is not required
|
36
|
-
- JRuby
|
37
|
-
- If Java extension is used, otherwise it is not required
|
38
|
-
|
39
|
-
## Features
|
40
|
-
- Provide type checking for arguments and return
|
41
|
-
- Support type checking for [keyword argument](#keyword-argument)
|
42
|
-
- [Type checking for array elements](#array)
|
43
|
-
- [Type checking for hash elements](#hash)
|
44
|
-
- [Duck typing](#duck-typing)
|
45
|
-
- Custom type behavior
|
46
|
-
|
47
|
-
## Installation
|
48
|
-
Run `gem install rtype` or add `gem 'rtype'` to your `Gemfile`
|
49
|
-
|
50
|
-
And add to your `.rb` source file:
|
51
|
-
```ruby
|
52
|
-
require 'rtype'
|
53
|
-
```
|
54
|
-
|
55
|
-
### Native extension
|
56
|
-
Rtype itself is pure-ruby gem. but you can make it more faster by using native extension.
|
57
|
-
|
58
|
-
#### Native extension for MRI
|
59
|
-
Just run
|
60
|
-
```ruby
|
61
|
-
gem install rtype-native
|
62
|
-
```
|
63
|
-
or add to your `Gemfile`:
|
64
|
-
```ruby
|
65
|
-
gem 'rtype-native'
|
66
|
-
```
|
67
|
-
then, Rtype use it. (Do not `require 'rtype-native'`)
|
68
|
-
|
69
|
-
#### Java extension for JRuby
|
70
|
-
Just run
|
71
|
-
```ruby
|
72
|
-
gem install rtype-java
|
73
|
-
```
|
74
|
-
or add to your `Gemfile`:
|
75
|
-
```ruby
|
76
|
-
gem 'rtype-java'
|
77
|
-
```
|
78
|
-
then, Rtype use it. (Do not `require 'rtype-java'`)
|
79
|
-
|
80
|
-
## Usage
|
81
|
-
|
82
|
-
### Supported Type Behaviors
|
83
|
-
- `Module`
|
84
|
-
- Value must be an instance of this module/class or one of its superclasses
|
85
|
-
- `Any` : An alias for `BasicObject` (means Any Object)
|
86
|
-
- `Boolean` : `true` or `false`
|
87
|
-
- `Symbol`
|
88
|
-
- Value must have(respond to) a method with this name
|
89
|
-
- `Regexp`
|
90
|
-
- Value must match this regexp pattern
|
91
|
-
- `Range`
|
92
|
-
- Value must be included in this range
|
93
|
-
- `Array` (tuple)
|
94
|
-
- Value must be an array
|
95
|
-
- Each of value's elements must be valid
|
96
|
-
- Value's length must be equal to the array's length
|
97
|
-
- Of course, nested array works
|
98
|
-
- Example: [Array](#array)
|
99
|
-
- This can be used as a tuple
|
100
|
-
- `Hash`
|
101
|
-
- Value must be an hash
|
102
|
-
- Each of value’s elements must be valid
|
103
|
-
- Value's key list must be equal to the hash's key list
|
104
|
-
- **String** key is **different** from **symbol** key
|
105
|
-
- vs Keyword arguments
|
106
|
-
- `[{}]` is **not** hash type argument. it is keyword argument because its position is last
|
107
|
-
- `[{}, {}]` is empty hash type argument (first) and one empty keyword argument (second)
|
108
|
-
- `[{}, {}, {}]` is two empty hash type argument (first, second) and empty keyword argument (last)
|
109
|
-
- `{}` is keyword argument. non-keyword arguments must be in array.
|
110
|
-
- Of course, nested hash works
|
111
|
-
- Example: [Hash](#hash)
|
112
|
-
- `Proc`
|
113
|
-
- Value must return a truthy value for this proc
|
114
|
-
- `true`
|
115
|
-
- Value must be **truthy**
|
116
|
-
- `false`
|
117
|
-
- Value must be **falsy**
|
118
|
-
- `nil`
|
119
|
-
- Only available for **return type**. void return type in other languages
|
120
|
-
- Special Behaviors
|
121
|
-
- `Rtype::and(*types)` : Ensure value is valid for all the types
|
122
|
-
- `Rtype::and(*types)`
|
123
|
-
- `Rtype::Behavior::And[*types]`
|
124
|
-
- `include Rtype::Behavior; And[...]`
|
125
|
-
- `obj.and(*others)` (core extension)
|
126
|
-
|
127
|
-
- `Rtype::or(*types)` : Ensure value is valid for at least one of the types
|
128
|
-
- `Rtype::or(*types)`
|
129
|
-
- `Rtype::Behavior::Or[*types]`
|
130
|
-
- `include Rtype::Behavior; Or[...]`
|
131
|
-
- `obj.or(*others)` (core extension)
|
132
|
-
|
133
|
-
- `Rtype::xor(*types)` : Ensure value is valid for only one of the types
|
134
|
-
- `Rtype::xor(*types)`
|
135
|
-
- `Rtype::Behavior::Xor[*types]`
|
136
|
-
- `include Rtype::Behavior; Xor[...]`
|
137
|
-
- `obj.xor(*others)` (core extension)
|
138
|
-
|
139
|
-
- `Rtype::not(*types)` : Ensure value is not valid for all the types
|
140
|
-
- `Rtype::not(*types)`
|
141
|
-
- `Rtype::Behavior::Not[*types]`
|
142
|
-
- `include Rtype::Behavior; Not[...]`
|
143
|
-
- `obj.not` (core extension)
|
144
|
-
|
145
|
-
- `Rtype::nilable(type)` : Ensure value can be nil
|
146
|
-
- `Rtype::nilable(type)`
|
147
|
-
- `Rtype::Behavior::Nilable[type]`
|
148
|
-
- `include Rtype::Behavior; Nilable[...]`
|
149
|
-
- `obj.nilable` (core extension)
|
150
|
-
- `obj.or_nil` (core extension)
|
151
|
-
|
152
|
-
- You can create custom behavior by extending `Rtype::Behavior::Base`
|
153
|
-
|
154
|
-
### Examples
|
155
|
-
|
156
|
-
#### Basic
|
157
|
-
```ruby
|
158
|
-
require 'rtype'
|
159
|
-
|
160
|
-
class Example
|
161
|
-
rtype [Integer] => nil
|
162
|
-
def test(i)
|
163
|
-
end
|
164
|
-
|
165
|
-
rtype [Any] => nil
|
166
|
-
def any_type_arg(arg)
|
167
|
-
end
|
168
|
-
|
169
|
-
rtype [] => Integer
|
170
|
-
def return_type_test
|
171
|
-
"not integer"
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
e = Example.new
|
176
|
-
e.test("not integer")
|
177
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
178
|
-
# Expected "not integer" to be a Integer
|
179
|
-
|
180
|
-
e.any_type_arg("Any argument!") # Works
|
181
|
-
|
182
|
-
e.return_type_test
|
183
|
-
# (Rtype::ReturnTypeError) for return:
|
184
|
-
# Expected "not integer" to be a Integer
|
185
|
-
```
|
186
|
-
|
187
|
-
#### Keyword argument
|
188
|
-
```ruby
|
189
|
-
require 'rtype'
|
190
|
-
|
191
|
-
class Example
|
192
|
-
rtype {name: String} => Any
|
193
|
-
def say_your_name(name:)
|
194
|
-
puts "My name is #{name}"
|
195
|
-
end
|
196
|
-
|
197
|
-
# Mixing positional arguments and keyword arguments
|
198
|
-
rtype [String, {age: Integer}] => Any
|
199
|
-
def name_and_age(name, age:)
|
200
|
-
puts "Name: #{name}, Age: #{age}"
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
Example.new.say_your_name(name: "Babo") # My name is Babo
|
205
|
-
Example.new.name_and_age("Bamboo", age: 100) # Name: Bamboo, Age: 100
|
206
|
-
|
207
|
-
Example.new.say_your_name(name: 12345)
|
208
|
-
# (Rtype::ArgumentTypeError) for 'name' argument:
|
209
|
-
# Expected 12345 to be a String
|
210
|
-
```
|
211
|
-
|
212
|
-
#### Duck typing
|
213
|
-
```ruby
|
214
|
-
require 'rtype'
|
215
|
-
|
216
|
-
class Duck
|
217
|
-
rtype [:to_i] => Any
|
218
|
-
def says(i)
|
219
|
-
puts "duck:" + " quack"*i.to_i
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
Duck.new.says("2") # duck: quack quack
|
224
|
-
```
|
225
|
-
|
226
|
-
#### Array
|
227
|
-
This can be used as a tuple.
|
228
|
-
|
229
|
-
```ruby
|
230
|
-
rtype :func, [[Numeric, Numeric]] => Any
|
231
|
-
def func(arr)
|
232
|
-
puts "Your location is (#{arr[0]}, #{arr[1]}). I will look for you. I will find you"
|
233
|
-
end
|
234
|
-
|
235
|
-
func [1, "str"]
|
236
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
237
|
-
# Expected [1, "str"] to be an array with 2 elements:
|
238
|
-
# - [0] index : Expected 1 to be a Numeric
|
239
|
-
# - [1] index : Expected "str" to be a Numeric
|
240
|
-
|
241
|
-
func [1, 2, 3]
|
242
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
243
|
-
# Expected [1, 2, 3] to be an array with 2 elements:
|
244
|
-
# - [0] index : Expected 1 to be a Numeric
|
245
|
-
# - [1] index : Expected 2 to be a Numeric
|
246
|
-
|
247
|
-
func [1]
|
248
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
249
|
-
# Expected [1] to be an array with 2 elements:
|
250
|
-
# - [0] index : Expected 1 to be a Numeric
|
251
|
-
# - [1] index : Expected nil to be a Numeric
|
252
|
-
|
253
|
-
func [1, 2] # Your location is (1, 2). I will look for you. I will find you
|
254
|
-
```
|
255
|
-
|
256
|
-
#### Hash
|
257
|
-
```ruby
|
258
|
-
# last hash element is keyword arguments
|
259
|
-
rtype :func, [{msg: String}, {}] => Any
|
260
|
-
def func(hash)
|
261
|
-
puts hash[:msg]
|
262
|
-
end
|
263
|
-
|
264
|
-
# last hash is keyword arguments
|
265
|
-
func({}, {})
|
266
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
267
|
-
# Expected {} to be an hash with 1 elements:
|
268
|
-
# - msg : Expected nil to be a String
|
269
|
-
|
270
|
-
func({msg: 123}, {})
|
271
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
272
|
-
# Expected {:msg=>123} to be an hash with 1 elements:
|
273
|
-
# - msg : Expected 123 to be a String
|
274
|
-
|
275
|
-
func({msg: "hello", key: 'value'}, {})
|
276
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
277
|
-
# Expected {:msg=>"hello", :key=>"value"} to be an hash with 1 elements:
|
278
|
-
# - msg : Expected "hello" to be a String
|
279
|
-
|
280
|
-
func({"msg" => "hello hash"}, {})
|
281
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
282
|
-
# Expected {"msg"=>"hello hash"} to be an hash with 1 elements:
|
283
|
-
# - msg : Expected nil to be a String
|
284
|
-
|
285
|
-
func({msg: "hello hash"}, {}) # hello hash
|
286
|
-
```
|
287
|
-
|
288
|
-
#### rtype with attr_accessor
|
289
|
-
`rtype_accessor` :
|
290
|
-
|
291
|
-
You can use `rtype_accessor_self` for static accessor.
|
292
|
-
|
293
|
-
```ruby
|
294
|
-
require 'rtype'
|
295
|
-
|
296
|
-
class Example
|
297
|
-
rtype_accessor :value, String
|
298
|
-
|
299
|
-
def initialize
|
300
|
-
@value = 456
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
Example.new.value = 123
|
305
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
306
|
-
# Expected 123 to be a String
|
307
|
-
|
308
|
-
Example.new.value
|
309
|
-
# (Rtype::ReturnTypeError) for return:
|
310
|
-
# Expected 456 to be a String
|
311
|
-
```
|
312
|
-
|
313
|
-
#### Combined type
|
314
|
-
```ruby
|
315
|
-
### TEST 1 ###
|
316
|
-
require 'rtype'
|
317
|
-
|
318
|
-
class Example
|
319
|
-
rtype [String.and(:func)] => Any
|
320
|
-
# also works:
|
321
|
-
# rtype [Rtype::and(String, :func)] => Any
|
322
|
-
def and_test(arg)
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
Example.new.and_test("A string")
|
327
|
-
# (Rtype::ArgumentTypeError) for 1st argument:
|
328
|
-
# Expected "A string" to be a String
|
329
|
-
# AND Expected "A string" to respond to :func
|
330
|
-
```
|
331
|
-
```ruby
|
332
|
-
### TEST 2 ###
|
333
|
-
# ... require rtype and define Example the same as above ...
|
334
|
-
|
335
|
-
class String
|
336
|
-
def func; end
|
337
|
-
end
|
338
|
-
|
339
|
-
Example.new.and_test("A string") # Works!
|
340
|
-
```
|
341
|
-
|
342
|
-
#### Combined duck type
|
343
|
-
Application of duck typing and combined type
|
344
|
-
|
345
|
-
```ruby
|
346
|
-
require 'rtype'
|
347
|
-
|
348
|
-
module Game
|
349
|
-
ENEMY = [
|
350
|
-
:name,
|
351
|
-
:level
|
352
|
-
]
|
353
|
-
|
354
|
-
class Player < Entity
|
355
|
-
include Rtype::Behavior
|
356
|
-
|
357
|
-
rtype [And[*ENEMY]] => Any
|
358
|
-
def attacks(enemy)
|
359
|
-
"Player attacks '#{enemy.name}' (level #{enemy.level})!"
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
class Slime < Entity
|
364
|
-
def name
|
365
|
-
"Powerful Slime"
|
366
|
-
end
|
367
|
-
|
368
|
-
def level
|
369
|
-
123
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
Game::Player.new.attacks Game::Slime.new
|
375
|
-
# Player attacks 'Powerful Slime' (level 123)!
|
376
|
-
```
|
377
|
-
|
378
|
-
#### Position of `rtype` && (Specify method name || annotation mode) && (Symbol || String)
|
379
|
-
```ruby
|
380
|
-
require 'rtype'
|
381
|
-
|
382
|
-
class Example
|
383
|
-
# Recommended. Annotation mode (no method name required)
|
384
|
-
rtype [Integer, String] => String
|
385
|
-
def hello_world(i, str)
|
386
|
-
puts "Hello? #{i} #{st
|
387
|
-
end
|
388
|
-
|
389
|
-
# Works (specifying method name)
|
390
|
-
rtype :hello_world, [Integer, String] => String
|
391
|
-
def hello_world(i, str)
|
392
|
-
puts "Hello? #{i} #{st
|
393
|
-
end
|
394
|
-
|
395
|
-
# Works
|
396
|
-
def hello_world_two(i, str)
|
397
|
-
puts "Hello? #{i} #{str}"
|
398
|
-
end
|
399
|
-
rtype :hello_world_two, [Integer, String] => String
|
400
|
-
|
401
|
-
# Also works (String will be converted to Symbol)
|
402
|
-
rtype 'hello_world_three', [Integer, String] => String
|
403
|
-
def hello_world_three(i, str)
|
404
|
-
puts "Hello? #{i} #{str}"
|
405
|
-
end
|
406
|
-
|
407
|
-
# Don't works. `rtype` works for next method
|
408
|
-
def hello_world_four(i, str)
|
409
|
-
puts "Hello? #{i} #{str}"
|
410
|
-
end
|
411
|
-
rtype [Integer, String] => String
|
412
|
-
end
|
413
|
-
```
|
414
|
-
|
415
|
-
#### Outside of module (root)
|
416
|
-
Outside of module, annotation mode don't works. You must specify method name.
|
417
|
-
|
418
|
-
```ruby
|
419
|
-
rtype :say, [String] => Any
|
420
|
-
def say(message)
|
421
|
-
puts message
|
422
|
-
end
|
423
|
-
|
424
|
-
Test.new.say "Hello" # Hello
|
425
|
-
|
426
|
-
rtype [String] => Any
|
427
|
-
# (ArgumentError) Annotation mode not working out of module
|
428
|
-
```
|
429
|
-
|
430
|
-
#### Static(singleton) method
|
431
|
-
rtype annotation mode works both instance and class method
|
432
|
-
|
433
|
-
```ruby
|
434
|
-
require 'rtype'
|
435
|
-
|
436
|
-
class Example
|
437
|
-
rtype [:to_i] => Any
|
438
|
-
def self.say_ya(i)
|
439
|
-
puts "say" + " ya"*i.to_i
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
|
-
Example::say_ya(3) #say ya ya ya
|
444
|
-
```
|
445
|
-
|
446
|
-
however, if you specify method name, you must use `rtype_self` instead of `rtype`
|
447
|
-
|
448
|
-
```ruby
|
449
|
-
require 'rtype'
|
450
|
-
|
451
|
-
class Example
|
452
|
-
rtype_self :say_ya, [:to_i] => Any
|
453
|
-
def self.say_ya(i)
|
454
|
-
puts "say" + " ya"*i.to_i
|
455
|
-
end
|
456
|
-
end
|
457
|
-
|
458
|
-
Example::say_ya(3) #say ya ya ya
|
459
|
-
```
|
460
|
-
|
461
|
-
#### Check type information
|
462
|
-
This is just the 'information'
|
463
|
-
|
464
|
-
Any change of this doesn't affect type checking
|
465
|
-
|
466
|
-
```ruby
|
467
|
-
require 'rtype'
|
468
|
-
|
469
|
-
class Example
|
470
|
-
rtype [:to_i] => Any
|
471
|
-
def test(i)
|
472
|
-
end
|
473
|
-
end
|
474
|
-
|
475
|
-
Example.new.method(:test).type_info
|
476
|
-
# => [:to_i] => Any
|
477
|
-
Example.new.method(:test).argument_type
|
478
|
-
# => [:to_i]
|
479
|
-
Example.new.method(:test).return_type
|
480
|
-
# => Any
|
481
|
-
```
|
482
|
-
|
483
|
-
## Documentation
|
484
|
-
[RubyDoc.info](http://www.rubydoc.info/gems/rtype)
|
485
|
-
|
486
|
-
## Benchmarks
|
487
|
-
Result of `rake benchmark` ([source](https://github.com/sputnikgugja/rtype/tree/master/benchmark/benchmark.rb))
|
488
|
-
|
489
|
-
### MRI
|
490
|
-
```
|
491
|
-
Rtype with C native extension
|
492
|
-
Ruby version: 2.1.7
|
493
|
-
Ruby engine: ruby
|
494
|
-
Ruby description: ruby 2.1.7p400 (2015-08-18 revision 51632) [x64-mingw32]
|
495
|
-
Rtype version: 0.3.0
|
496
|
-
Rubype version: 0.3.1
|
497
|
-
Sig version: 1.0.1
|
498
|
-
Contracts version: 0.13.0
|
499
|
-
Typecheck version: 0.1.2
|
500
|
-
Warming up --------------------------------------
|
501
|
-
pure 85.328k i/100ms
|
502
|
-
rtype 25.665k i/100ms
|
503
|
-
rubype 21.414k i/100ms
|
504
|
-
sig 8.921k i/100ms
|
505
|
-
contracts 4.638k i/100ms
|
506
|
-
typecheck 1.110k i/100ms
|
507
|
-
Calculating -------------------------------------
|
508
|
-
pure 3.282M (± 2.7%) i/s - 16.468M
|
509
|
-
rtype 339.065k (± 2.6%) i/s - 1.720M
|
510
|
-
rubype 266.893k (± 5.9%) i/s - 1.349M
|
511
|
-
sig 99.952k (± 2.1%) i/s - 499.576k
|
512
|
-
contracts 49.693k (± 1.5%) i/s - 250.452k
|
513
|
-
typecheck 11.356k (± 1.6%) i/s - 57.720k
|
514
|
-
|
515
|
-
Comparison:
|
516
|
-
pure: 3282431.9 i/s
|
517
|
-
rtype: 339064.9 i/s - 9.68x slower
|
518
|
-
rubype: 266892.9 i/s - 12.30x slower
|
519
|
-
sig: 99952.2 i/s - 32.84x slower
|
520
|
-
contracts: 49693.0 i/s - 66.05x slower
|
521
|
-
typecheck: 11355.9 i/s - 289.05x slower
|
522
|
-
```
|
523
|
-
|
524
|
-
### JRuby
|
525
|
-
Without Rubype that doesn't support JRuby
|
526
|
-
|
527
|
-
```
|
528
|
-
Rtype with Java extension
|
529
|
-
Ruby version: 2.2.3
|
530
|
-
Ruby engine: jruby
|
531
|
-
Ruby description: jruby 9.0.5.0 (2.2.3) 2016-01-26 7bee00d Java HotSpot(TM) 64-Bit Server VM 25.60-b23 on 1.8.0_60-b27 +jit [Windows 10-amd64]
|
532
|
-
Rtype version: 0.3.0
|
533
|
-
Sig version: 1.0.1
|
534
|
-
Contracts version: 0.13.0
|
535
|
-
Typecheck version: 0.1.2
|
536
|
-
Warming up --------------------------------------
|
537
|
-
pure 9.994k i/100ms
|
538
|
-
rtype 6.181k i/100ms
|
539
|
-
sig 4.041k i/100ms
|
540
|
-
contracts 951.000 i/100ms
|
541
|
-
typecheck 970.000 i/100ms
|
542
|
-
Calculating -------------------------------------
|
543
|
-
pure 7.128M (?±35.6%) i/s - 30.831M
|
544
|
-
rtype 121.556k (?± 6.2%) i/s - 605.738k
|
545
|
-
sig 72.187k (?± 6.4%) i/s - 359.649k
|
546
|
-
contracts 24.984k (?± 3.9%) i/s - 125.532k
|
547
|
-
typecheck 12.041k (?± 9.5%) i/s - 60.140k
|
548
|
-
|
549
|
-
Comparison:
|
550
|
-
pure: 7128373.0 i/s
|
551
|
-
rtype: 121555.8 i/s - 58.64x slower
|
552
|
-
sig: 72186.8 i/s - 98.75x slower
|
553
|
-
contracts: 24984.5 i/s - 285.31x slower
|
554
|
-
typecheck: 12041.0 i/s - 592.01x slower
|
555
|
-
```
|
556
|
-
|
557
|
-
## Rubype, Sig
|
558
|
-
Rtype is influenced by [Rubype](https://github.com/gogotanaka/Rubype) and [Sig](https://github.com/janlelis/sig).
|
559
|
-
|
560
|
-
If you don't like Rtype, You can use other type checking gem such as Contracts, Rubype, Rtc, Typecheck, Sig.
|
561
|
-
|
562
|
-
## Author
|
563
|
-
Sputnik Gugja (sputnikgugja@gmail.com)
|
564
|
-
|
565
|
-
## License
|
566
|
-
MIT license (@ Sputnik Gugja)
|
567
|
-
|
1
|
+
# Rtype: ruby with type
|
2
|
+
[](https://badge.fury.io/rb/rtype)
|
3
|
+
[](https://travis-ci.org/sputnikgugja/rtype)
|
4
|
+
[](https://coveralls.io/github/sputnikgugja/rtype?branch=master)
|
5
|
+
|
6
|
+
You can do the type checking in Ruby with this gem!
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
require 'rtype'
|
10
|
+
|
11
|
+
class Test
|
12
|
+
rtype [:to_i, Numeric] => Numeric
|
13
|
+
def sum(a, b)
|
14
|
+
a.to_i + b
|
15
|
+
end
|
16
|
+
|
17
|
+
rtype {state: Boolean} => Boolean
|
18
|
+
def self.invert(state:)
|
19
|
+
!state
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Test.new.sum(123, "asd")
|
24
|
+
# (Rtype::ArgumentTypeError) for 2nd argument:
|
25
|
+
# Expected "asd" to be a Numeric
|
26
|
+
|
27
|
+
Test::invert(state: 0)
|
28
|
+
# (Rtype::ArgumentTypeError) for 'state' argument:
|
29
|
+
# Expected 0 to be a Boolean
|
30
|
+
```
|
31
|
+
|
32
|
+
## Requirements
|
33
|
+
- Ruby >= 2.1
|
34
|
+
- MRI
|
35
|
+
- If C native extension is used, otherwise it is not required
|
36
|
+
- JRuby
|
37
|
+
- If Java extension is used, otherwise it is not required
|
38
|
+
|
39
|
+
## Features
|
40
|
+
- Provide type checking for arguments and return
|
41
|
+
- Support type checking for [keyword argument](#keyword-argument)
|
42
|
+
- [Type checking for array elements](#array)
|
43
|
+
- [Type checking for hash elements](#hash)
|
44
|
+
- [Duck typing](#duck-typing)
|
45
|
+
- Custom type behavior
|
46
|
+
|
47
|
+
## Installation
|
48
|
+
Run `gem install rtype` or add `gem 'rtype'` to your `Gemfile`
|
49
|
+
|
50
|
+
And add to your `.rb` source file:
|
51
|
+
```ruby
|
52
|
+
require 'rtype'
|
53
|
+
```
|
54
|
+
|
55
|
+
### Native extension
|
56
|
+
Rtype itself is pure-ruby gem. but you can make it more faster by using native extension.
|
57
|
+
|
58
|
+
#### Native extension for MRI
|
59
|
+
Just run
|
60
|
+
```ruby
|
61
|
+
gem install rtype-native
|
62
|
+
```
|
63
|
+
or add to your `Gemfile`:
|
64
|
+
```ruby
|
65
|
+
gem 'rtype-native'
|
66
|
+
```
|
67
|
+
then, Rtype use it. (Do not `require 'rtype-native'`)
|
68
|
+
|
69
|
+
#### Java extension for JRuby
|
70
|
+
Just run
|
71
|
+
```ruby
|
72
|
+
gem install rtype-java
|
73
|
+
```
|
74
|
+
or add to your `Gemfile`:
|
75
|
+
```ruby
|
76
|
+
gem 'rtype-java'
|
77
|
+
```
|
78
|
+
then, Rtype use it. (Do not `require 'rtype-java'`)
|
79
|
+
|
80
|
+
## Usage
|
81
|
+
|
82
|
+
### Supported Type Behaviors
|
83
|
+
- `Module`
|
84
|
+
- Value must be an instance of this module/class or one of its superclasses
|
85
|
+
- `Any` : An alias for `BasicObject` (means Any Object)
|
86
|
+
- `Boolean` : `true` or `false`
|
87
|
+
- `Symbol`
|
88
|
+
- Value must have(respond to) a method with this name
|
89
|
+
- `Regexp`
|
90
|
+
- Value must match this regexp pattern
|
91
|
+
- `Range`
|
92
|
+
- Value must be included in this range
|
93
|
+
- `Array` (tuple)
|
94
|
+
- Value must be an array
|
95
|
+
- Each of value's elements must be valid
|
96
|
+
- Value's length must be equal to the array's length
|
97
|
+
- Of course, nested array works
|
98
|
+
- Example: [Array](#array)
|
99
|
+
- This can be used as a tuple
|
100
|
+
- `Hash`
|
101
|
+
- Value must be an hash
|
102
|
+
- Each of value’s elements must be valid
|
103
|
+
- Value's key list must be equal to the hash's key list
|
104
|
+
- **String** key is **different** from **symbol** key
|
105
|
+
- vs Keyword arguments
|
106
|
+
- `[{}]` is **not** hash type argument. it is keyword argument because its position is last
|
107
|
+
- `[{}, {}]` is empty hash type argument (first) and one empty keyword argument (second)
|
108
|
+
- `[{}, {}, {}]` is two empty hash type argument (first, second) and empty keyword argument (last)
|
109
|
+
- `{}` is keyword argument. non-keyword arguments must be in array.
|
110
|
+
- Of course, nested hash works
|
111
|
+
- Example: [Hash](#hash)
|
112
|
+
- `Proc`
|
113
|
+
- Value must return a truthy value for this proc
|
114
|
+
- `true`
|
115
|
+
- Value must be **truthy**
|
116
|
+
- `false`
|
117
|
+
- Value must be **falsy**
|
118
|
+
- `nil`
|
119
|
+
- Only available for **return type**. void return type in other languages
|
120
|
+
- Special Behaviors
|
121
|
+
- `Rtype::and(*types)` : Ensure value is valid for all the types
|
122
|
+
- `Rtype::and(*types)`
|
123
|
+
- `Rtype::Behavior::And[*types]`
|
124
|
+
- `include Rtype::Behavior; And[...]`
|
125
|
+
- `obj.and(*others)` (core extension)
|
126
|
+
|
127
|
+
- `Rtype::or(*types)` : Ensure value is valid for at least one of the types
|
128
|
+
- `Rtype::or(*types)`
|
129
|
+
- `Rtype::Behavior::Or[*types]`
|
130
|
+
- `include Rtype::Behavior; Or[...]`
|
131
|
+
- `obj.or(*others)` (core extension)
|
132
|
+
|
133
|
+
- `Rtype::xor(*types)` : Ensure value is valid for only one of the types
|
134
|
+
- `Rtype::xor(*types)`
|
135
|
+
- `Rtype::Behavior::Xor[*types]`
|
136
|
+
- `include Rtype::Behavior; Xor[...]`
|
137
|
+
- `obj.xor(*others)` (core extension)
|
138
|
+
|
139
|
+
- `Rtype::not(*types)` : Ensure value is not valid for all the types
|
140
|
+
- `Rtype::not(*types)`
|
141
|
+
- `Rtype::Behavior::Not[*types]`
|
142
|
+
- `include Rtype::Behavior; Not[...]`
|
143
|
+
- `obj.not` (core extension)
|
144
|
+
|
145
|
+
- `Rtype::nilable(type)` : Ensure value can be nil
|
146
|
+
- `Rtype::nilable(type)`
|
147
|
+
- `Rtype::Behavior::Nilable[type]`
|
148
|
+
- `include Rtype::Behavior; Nilable[...]`
|
149
|
+
- `obj.nilable` (core extension)
|
150
|
+
- `obj.or_nil` (core extension)
|
151
|
+
|
152
|
+
- You can create custom behavior by extending `Rtype::Behavior::Base`
|
153
|
+
|
154
|
+
### Examples
|
155
|
+
|
156
|
+
#### Basic
|
157
|
+
```ruby
|
158
|
+
require 'rtype'
|
159
|
+
|
160
|
+
class Example
|
161
|
+
rtype [Integer] => nil
|
162
|
+
def test(i)
|
163
|
+
end
|
164
|
+
|
165
|
+
rtype [Any] => nil
|
166
|
+
def any_type_arg(arg)
|
167
|
+
end
|
168
|
+
|
169
|
+
rtype [] => Integer
|
170
|
+
def return_type_test
|
171
|
+
"not integer"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
e = Example.new
|
176
|
+
e.test("not integer")
|
177
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
178
|
+
# Expected "not integer" to be a Integer
|
179
|
+
|
180
|
+
e.any_type_arg("Any argument!") # Works
|
181
|
+
|
182
|
+
e.return_type_test
|
183
|
+
# (Rtype::ReturnTypeError) for return:
|
184
|
+
# Expected "not integer" to be a Integer
|
185
|
+
```
|
186
|
+
|
187
|
+
#### Keyword argument
|
188
|
+
```ruby
|
189
|
+
require 'rtype'
|
190
|
+
|
191
|
+
class Example
|
192
|
+
rtype {name: String} => Any
|
193
|
+
def say_your_name(name:)
|
194
|
+
puts "My name is #{name}"
|
195
|
+
end
|
196
|
+
|
197
|
+
# Mixing positional arguments and keyword arguments
|
198
|
+
rtype [String, {age: Integer}] => Any
|
199
|
+
def name_and_age(name, age:)
|
200
|
+
puts "Name: #{name}, Age: #{age}"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
Example.new.say_your_name(name: "Babo") # My name is Babo
|
205
|
+
Example.new.name_and_age("Bamboo", age: 100) # Name: Bamboo, Age: 100
|
206
|
+
|
207
|
+
Example.new.say_your_name(name: 12345)
|
208
|
+
# (Rtype::ArgumentTypeError) for 'name' argument:
|
209
|
+
# Expected 12345 to be a String
|
210
|
+
```
|
211
|
+
|
212
|
+
#### Duck typing
|
213
|
+
```ruby
|
214
|
+
require 'rtype'
|
215
|
+
|
216
|
+
class Duck
|
217
|
+
rtype [:to_i] => Any
|
218
|
+
def says(i)
|
219
|
+
puts "duck:" + " quack"*i.to_i
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
Duck.new.says("2") # duck: quack quack
|
224
|
+
```
|
225
|
+
|
226
|
+
#### Array
|
227
|
+
This can be used as a tuple.
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
rtype :func, [[Numeric, Numeric]] => Any
|
231
|
+
def func(arr)
|
232
|
+
puts "Your location is (#{arr[0]}, #{arr[1]}). I will look for you. I will find you"
|
233
|
+
end
|
234
|
+
|
235
|
+
func [1, "str"]
|
236
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
237
|
+
# Expected [1, "str"] to be an array with 2 elements:
|
238
|
+
# - [0] index : Expected 1 to be a Numeric
|
239
|
+
# - [1] index : Expected "str" to be a Numeric
|
240
|
+
|
241
|
+
func [1, 2, 3]
|
242
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
243
|
+
# Expected [1, 2, 3] to be an array with 2 elements:
|
244
|
+
# - [0] index : Expected 1 to be a Numeric
|
245
|
+
# - [1] index : Expected 2 to be a Numeric
|
246
|
+
|
247
|
+
func [1]
|
248
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
249
|
+
# Expected [1] to be an array with 2 elements:
|
250
|
+
# - [0] index : Expected 1 to be a Numeric
|
251
|
+
# - [1] index : Expected nil to be a Numeric
|
252
|
+
|
253
|
+
func [1, 2] # Your location is (1, 2). I will look for you. I will find you
|
254
|
+
```
|
255
|
+
|
256
|
+
#### Hash
|
257
|
+
```ruby
|
258
|
+
# last hash element is keyword arguments
|
259
|
+
rtype :func, [{msg: String}, {}] => Any
|
260
|
+
def func(hash)
|
261
|
+
puts hash[:msg]
|
262
|
+
end
|
263
|
+
|
264
|
+
# last hash is keyword arguments
|
265
|
+
func({}, {})
|
266
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
267
|
+
# Expected {} to be an hash with 1 elements:
|
268
|
+
# - msg : Expected nil to be a String
|
269
|
+
|
270
|
+
func({msg: 123}, {})
|
271
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
272
|
+
# Expected {:msg=>123} to be an hash with 1 elements:
|
273
|
+
# - msg : Expected 123 to be a String
|
274
|
+
|
275
|
+
func({msg: "hello", key: 'value'}, {})
|
276
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
277
|
+
# Expected {:msg=>"hello", :key=>"value"} to be an hash with 1 elements:
|
278
|
+
# - msg : Expected "hello" to be a String
|
279
|
+
|
280
|
+
func({"msg" => "hello hash"}, {})
|
281
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
282
|
+
# Expected {"msg"=>"hello hash"} to be an hash with 1 elements:
|
283
|
+
# - msg : Expected nil to be a String
|
284
|
+
|
285
|
+
func({msg: "hello hash"}, {}) # hello hash
|
286
|
+
```
|
287
|
+
|
288
|
+
#### rtype with attr_accessor
|
289
|
+
`rtype_accessor` : calls `attr_accessor` if the accessor method(getter/setter) is not defined, and makes it typed method
|
290
|
+
|
291
|
+
You can use `rtype_accessor_self` for static accessor.
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
require 'rtype'
|
295
|
+
|
296
|
+
class Example
|
297
|
+
rtype_accessor :value, String
|
298
|
+
|
299
|
+
def initialize
|
300
|
+
@value = 456
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
Example.new.value = 123
|
305
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
306
|
+
# Expected 123 to be a String
|
307
|
+
|
308
|
+
Example.new.value
|
309
|
+
# (Rtype::ReturnTypeError) for return:
|
310
|
+
# Expected 456 to be a String
|
311
|
+
```
|
312
|
+
|
313
|
+
#### Combined type
|
314
|
+
```ruby
|
315
|
+
### TEST 1 ###
|
316
|
+
require 'rtype'
|
317
|
+
|
318
|
+
class Example
|
319
|
+
rtype [String.and(:func)] => Any
|
320
|
+
# also works:
|
321
|
+
# rtype [Rtype::and(String, :func)] => Any
|
322
|
+
def and_test(arg)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
Example.new.and_test("A string")
|
327
|
+
# (Rtype::ArgumentTypeError) for 1st argument:
|
328
|
+
# Expected "A string" to be a String
|
329
|
+
# AND Expected "A string" to respond to :func
|
330
|
+
```
|
331
|
+
```ruby
|
332
|
+
### TEST 2 ###
|
333
|
+
# ... require rtype and define Example the same as above ...
|
334
|
+
|
335
|
+
class String
|
336
|
+
def func; end
|
337
|
+
end
|
338
|
+
|
339
|
+
Example.new.and_test("A string") # Works!
|
340
|
+
```
|
341
|
+
|
342
|
+
#### Combined duck type
|
343
|
+
Application of duck typing and combined type
|
344
|
+
|
345
|
+
```ruby
|
346
|
+
require 'rtype'
|
347
|
+
|
348
|
+
module Game
|
349
|
+
ENEMY = [
|
350
|
+
:name,
|
351
|
+
:level
|
352
|
+
]
|
353
|
+
|
354
|
+
class Player < Entity
|
355
|
+
include Rtype::Behavior
|
356
|
+
|
357
|
+
rtype [And[*ENEMY]] => Any
|
358
|
+
def attacks(enemy)
|
359
|
+
"Player attacks '#{enemy.name}' (level #{enemy.level})!"
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
class Slime < Entity
|
364
|
+
def name
|
365
|
+
"Powerful Slime"
|
366
|
+
end
|
367
|
+
|
368
|
+
def level
|
369
|
+
123
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
Game::Player.new.attacks Game::Slime.new
|
375
|
+
# Player attacks 'Powerful Slime' (level 123)!
|
376
|
+
```
|
377
|
+
|
378
|
+
#### Position of `rtype` && (Specify method name || annotation mode) && (Symbol || String)
|
379
|
+
```ruby
|
380
|
+
require 'rtype'
|
381
|
+
|
382
|
+
class Example
|
383
|
+
# Recommended. Annotation mode (no method name required)
|
384
|
+
rtype [Integer, String] => String
|
385
|
+
def hello_world(i, str)
|
386
|
+
puts "Hello? #{i} #{st
|
387
|
+
end
|
388
|
+
|
389
|
+
# Works (specifying method name)
|
390
|
+
rtype :hello_world, [Integer, String] => String
|
391
|
+
def hello_world(i, str)
|
392
|
+
puts "Hello? #{i} #{st
|
393
|
+
end
|
394
|
+
|
395
|
+
# Works
|
396
|
+
def hello_world_two(i, str)
|
397
|
+
puts "Hello? #{i} #{str}"
|
398
|
+
end
|
399
|
+
rtype :hello_world_two, [Integer, String] => String
|
400
|
+
|
401
|
+
# Also works (String will be converted to Symbol)
|
402
|
+
rtype 'hello_world_three', [Integer, String] => String
|
403
|
+
def hello_world_three(i, str)
|
404
|
+
puts "Hello? #{i} #{str}"
|
405
|
+
end
|
406
|
+
|
407
|
+
# Don't works. `rtype` works for next method
|
408
|
+
def hello_world_four(i, str)
|
409
|
+
puts "Hello? #{i} #{str}"
|
410
|
+
end
|
411
|
+
rtype [Integer, String] => String
|
412
|
+
end
|
413
|
+
```
|
414
|
+
|
415
|
+
#### Outside of module (root)
|
416
|
+
Outside of module, annotation mode don't works. You must specify method name.
|
417
|
+
|
418
|
+
```ruby
|
419
|
+
rtype :say, [String] => Any
|
420
|
+
def say(message)
|
421
|
+
puts message
|
422
|
+
end
|
423
|
+
|
424
|
+
Test.new.say "Hello" # Hello
|
425
|
+
|
426
|
+
rtype [String] => Any
|
427
|
+
# (ArgumentError) Annotation mode not working out of module
|
428
|
+
```
|
429
|
+
|
430
|
+
#### Static(singleton) method
|
431
|
+
rtype annotation mode works both instance and class method
|
432
|
+
|
433
|
+
```ruby
|
434
|
+
require 'rtype'
|
435
|
+
|
436
|
+
class Example
|
437
|
+
rtype [:to_i] => Any
|
438
|
+
def self.say_ya(i)
|
439
|
+
puts "say" + " ya"*i.to_i
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
Example::say_ya(3) #say ya ya ya
|
444
|
+
```
|
445
|
+
|
446
|
+
however, if you specify method name, you must use `rtype_self` instead of `rtype`
|
447
|
+
|
448
|
+
```ruby
|
449
|
+
require 'rtype'
|
450
|
+
|
451
|
+
class Example
|
452
|
+
rtype_self :say_ya, [:to_i] => Any
|
453
|
+
def self.say_ya(i)
|
454
|
+
puts "say" + " ya"*i.to_i
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
Example::say_ya(3) #say ya ya ya
|
459
|
+
```
|
460
|
+
|
461
|
+
#### Check type information
|
462
|
+
This is just the 'information'
|
463
|
+
|
464
|
+
Any change of this doesn't affect type checking
|
465
|
+
|
466
|
+
```ruby
|
467
|
+
require 'rtype'
|
468
|
+
|
469
|
+
class Example
|
470
|
+
rtype [:to_i] => Any
|
471
|
+
def test(i)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
Example.new.method(:test).type_info
|
476
|
+
# => [:to_i] => Any
|
477
|
+
Example.new.method(:test).argument_type
|
478
|
+
# => [:to_i]
|
479
|
+
Example.new.method(:test).return_type
|
480
|
+
# => Any
|
481
|
+
```
|
482
|
+
|
483
|
+
## Documentation
|
484
|
+
[RubyDoc.info](http://www.rubydoc.info/gems/rtype)
|
485
|
+
|
486
|
+
## Benchmarks
|
487
|
+
Result of `rake benchmark` ([source](https://github.com/sputnikgugja/rtype/tree/master/benchmark/benchmark.rb))
|
488
|
+
|
489
|
+
### MRI
|
490
|
+
```
|
491
|
+
Rtype with C native extension
|
492
|
+
Ruby version: 2.1.7
|
493
|
+
Ruby engine: ruby
|
494
|
+
Ruby description: ruby 2.1.7p400 (2015-08-18 revision 51632) [x64-mingw32]
|
495
|
+
Rtype version: 0.3.0
|
496
|
+
Rubype version: 0.3.1
|
497
|
+
Sig version: 1.0.1
|
498
|
+
Contracts version: 0.13.0
|
499
|
+
Typecheck version: 0.1.2
|
500
|
+
Warming up --------------------------------------
|
501
|
+
pure 85.328k i/100ms
|
502
|
+
rtype 25.665k i/100ms
|
503
|
+
rubype 21.414k i/100ms
|
504
|
+
sig 8.921k i/100ms
|
505
|
+
contracts 4.638k i/100ms
|
506
|
+
typecheck 1.110k i/100ms
|
507
|
+
Calculating -------------------------------------
|
508
|
+
pure 3.282M (± 2.7%) i/s - 16.468M
|
509
|
+
rtype 339.065k (± 2.6%) i/s - 1.720M
|
510
|
+
rubype 266.893k (± 5.9%) i/s - 1.349M
|
511
|
+
sig 99.952k (± 2.1%) i/s - 499.576k
|
512
|
+
contracts 49.693k (± 1.5%) i/s - 250.452k
|
513
|
+
typecheck 11.356k (± 1.6%) i/s - 57.720k
|
514
|
+
|
515
|
+
Comparison:
|
516
|
+
pure: 3282431.9 i/s
|
517
|
+
rtype: 339064.9 i/s - 9.68x slower
|
518
|
+
rubype: 266892.9 i/s - 12.30x slower
|
519
|
+
sig: 99952.2 i/s - 32.84x slower
|
520
|
+
contracts: 49693.0 i/s - 66.05x slower
|
521
|
+
typecheck: 11355.9 i/s - 289.05x slower
|
522
|
+
```
|
523
|
+
|
524
|
+
### JRuby
|
525
|
+
Without Rubype that doesn't support JRuby
|
526
|
+
|
527
|
+
```
|
528
|
+
Rtype with Java extension
|
529
|
+
Ruby version: 2.2.3
|
530
|
+
Ruby engine: jruby
|
531
|
+
Ruby description: jruby 9.0.5.0 (2.2.3) 2016-01-26 7bee00d Java HotSpot(TM) 64-Bit Server VM 25.60-b23 on 1.8.0_60-b27 +jit [Windows 10-amd64]
|
532
|
+
Rtype version: 0.3.0
|
533
|
+
Sig version: 1.0.1
|
534
|
+
Contracts version: 0.13.0
|
535
|
+
Typecheck version: 0.1.2
|
536
|
+
Warming up --------------------------------------
|
537
|
+
pure 9.994k i/100ms
|
538
|
+
rtype 6.181k i/100ms
|
539
|
+
sig 4.041k i/100ms
|
540
|
+
contracts 951.000 i/100ms
|
541
|
+
typecheck 970.000 i/100ms
|
542
|
+
Calculating -------------------------------------
|
543
|
+
pure 7.128M (?±35.6%) i/s - 30.831M
|
544
|
+
rtype 121.556k (?± 6.2%) i/s - 605.738k
|
545
|
+
sig 72.187k (?± 6.4%) i/s - 359.649k
|
546
|
+
contracts 24.984k (?± 3.9%) i/s - 125.532k
|
547
|
+
typecheck 12.041k (?± 9.5%) i/s - 60.140k
|
548
|
+
|
549
|
+
Comparison:
|
550
|
+
pure: 7128373.0 i/s
|
551
|
+
rtype: 121555.8 i/s - 58.64x slower
|
552
|
+
sig: 72186.8 i/s - 98.75x slower
|
553
|
+
contracts: 24984.5 i/s - 285.31x slower
|
554
|
+
typecheck: 12041.0 i/s - 592.01x slower
|
555
|
+
```
|
556
|
+
|
557
|
+
## Rubype, Sig
|
558
|
+
Rtype is influenced by [Rubype](https://github.com/gogotanaka/Rubype) and [Sig](https://github.com/janlelis/sig).
|
559
|
+
|
560
|
+
If you don't like Rtype, You can use other type checking gem such as Contracts, Rubype, Rtc, Typecheck, Sig.
|
561
|
+
|
562
|
+
## Author
|
563
|
+
Sputnik Gugja (sputnikgugja@gmail.com)
|
564
|
+
|
565
|
+
## License
|
566
|
+
MIT license (@ Sputnik Gugja)
|
567
|
+
|
568
568
|
See `LICENSE` file.
|