rtype-legacy-java 0.0.4-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 78d88663795698815c19fe35507f697dfb2ebd0f
4
+ data.tar.gz: e9d2e61a7a944a248c48786635d18fec18995d2f
5
+ SHA512:
6
+ metadata.gz: fae5879fc185a5d7de087492e2230729c326bbbeee950c371c7448b74b9e863daa8402e0cc42a940e92f672c4e74d3d5656e751cb7fdeb4d21b2689105a3800e
7
+ data.tar.gz: 750ad92ad7a462ccba10250091b2f7c75474d8642810daf92f0176c6a6f3fd8af2742dce3cdebc8de973cac5704c18e4a66d40574b16230d5d9f5ffa1ce87af2
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec :name => 'rtype-legacy'
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Sputnik Gugja
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,475 @@
1
+ # Rtype Legacy: ruby with type (rtype for ruby 1.9+)
2
+ [![Gem Version](https://badge.fury.io/rb/rtype-legacy.svg)](https://badge.fury.io/rb/rtype-legacy)
3
+ [![Build Status](https://travis-ci.org/sputnikgugja/rtype-legacy.svg?branch=master)](https://travis-ci.org/sputnikgugja/rtype-legacy)
4
+ [![Coverage Status](https://coveralls.io/repos/github/sputnikgugja/rtype-legacy/badge.svg?branch=master)](https://coveralls.io/github/sputnikgugja/rtype-legacy?branch=master)
5
+
6
+ ```ruby
7
+ require 'rtype/legacy'
8
+
9
+ class Test
10
+ rtype [:to_i, Numeric] => Numeric
11
+ def sum(a, b)
12
+ a.to_i + b
13
+ end
14
+
15
+ # Second hash is keyword argument signature
16
+ # (syntax compatibility with 'rtype' gem)
17
+ rtype [{state: Boolean}, {}] => Boolean
18
+ def self.invert(opts)
19
+ !opts[: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 1st argument:
29
+ # Expected {:state=>0} to be a hash with 1 elements:
30
+ # - state : Expected 0 to be a Boolean
31
+ ```
32
+
33
+ ## Requirements
34
+ - Ruby >= 1.9
35
+ - If you are using ruby 2.1+, see [rtype](https://github.com/sputnikgugja/rtype)
36
+ - MRI
37
+ - If C native extension is used. otherwise it is not required
38
+ - JRuby (JRuby 1.7+)
39
+ - If Java extension is used. otherwise it is not required
40
+
41
+ ## Difference between rtype and rtype-legacy
42
+ - The two are separate gem
43
+ - Rtype requires ruby 2.1+. Rtype Legacy requires ruby 1.9+
44
+ - Rtype supports 'type checking for keyword argument'. Rtype Legacy doesn't
45
+ - Rtype uses `Module#prepend`. Rtype Legacy redefines method
46
+ - Rtype can be used outside of module (with specifying method name). Rtype Legacy can't be used outside of module
47
+
48
+ ## Features
49
+ - Provides type checking for arguments and return
50
+ - [Type checking for hash elements](#hash)
51
+ - [Duck Typing](#duck-typing)
52
+ - [Typed Array](#typed-array), Typed Set, Typed Hash
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)
56
+ - Custom type behavior
57
+ - ...
58
+
59
+ ## Installation
60
+ Run `gem install rtype-legacy` or add `gem 'rtype-legacy'` to your `Gemfile`
61
+
62
+ And add to your `.rb` source file:
63
+ ```ruby
64
+ require 'rtype/legacy'
65
+ ```
66
+
67
+ ### Native extension
68
+ Rtype itself is pure-ruby gem. but you can make it more faster by using native extension.
69
+
70
+ #### Native extension for MRI
71
+ Run
72
+ ```ruby
73
+ gem install rtype-legacy-native
74
+ ```
75
+ or add to your `Gemfile`:
76
+ ```ruby
77
+ gem 'rtype-legacy-native'
78
+ ```
79
+ then, Rtype Legacy uses it. (**Do not** `require 'rtype-legacy-native'`)
80
+
81
+ #### Java extension for JRuby is automatic
82
+ **Do not** `require 'rtype-java'`
83
+
84
+ ## Usage
85
+
86
+ ### Supported Type Behaviors
87
+ - `Module` : Value must be of this module (`is_a?`)
88
+ - `Any` : Alias for `BasicObject` (means Any Object)
89
+ - `Boolean` : `true` or `false`
90
+ - `Symbol` : Value must respond to a method with this name
91
+ - `Regexp` : Value must match this regexp pattern
92
+ - `Range` : Value must be included in this range
93
+ - `Array` : Value can be any type in this array
94
+ - `Proc` : Value must return a truthy value for this proc
95
+ - `true` : Value must be truthy
96
+ - `false` : Value must be falsy
97
+ - `nil` : Value must be nil
98
+ - `Hash`
99
+ - Value must be a hash
100
+ - Each of elements must be valid
101
+ - Keys of the value must be equal to keys of this hash
102
+ - **String** key is **different** from **symbol** key
103
+ - vs. Keyword arguments (e.g.)
104
+ - `[{}]` is **not** hash argument. it is keyword argument, because its position is last
105
+ - `[{}, {}]` is hash argument (first) and keyword argument (second)
106
+ - `[{}, {}, {}]` is two hash argument (first, second) and keyword argument (last)
107
+ - `{}` is keyword argument. non-keyword arguments must be in array.
108
+ - Of course, nested hash works
109
+ - Example: [Hash](#hash)
110
+
111
+ - [Special Behaviors](#special-behaviors)
112
+ - `TypedArray, TypedSet, TypedHash`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
113
+
114
+ ### Examples
115
+
116
+ #### Basic
117
+ ```ruby
118
+ require 'rtype'
119
+
120
+ class Example
121
+ rtype [Integer] => nil
122
+ def test(i)
123
+ end
124
+
125
+ rtype [Any] => nil
126
+ def any_type_arg(arg)
127
+ end
128
+
129
+ rtype [] => Integer
130
+ def return_type_test
131
+ "not integer"
132
+ end
133
+ end
134
+
135
+ e = Example.new
136
+ e.test("not integer")
137
+ # (Rtype::ArgumentTypeError) for 1st argument:
138
+ # Expected "not integer" to be a Integer
139
+
140
+ e.any_type_arg("Any argument!") # Works
141
+
142
+ e.return_type_test
143
+ # (Rtype::ReturnTypeError) for return:
144
+ # Expected "not integer" to be a Integer
145
+ ```
146
+
147
+ #### Duck typing
148
+ ```ruby
149
+ require 'rtype'
150
+
151
+ class Duck
152
+ rtype [:to_i] => Any
153
+ def says(i)
154
+ puts "duck:" + " quack"*i.to_i
155
+ end
156
+ end
157
+
158
+ Duck.new.says("2") # duck: quack quack
159
+ ```
160
+
161
+ #### Array
162
+ ```ruby
163
+ rtype :ruby!, [[String, Integer]] => Any
164
+ def ruby!(arg)
165
+ puts "ruby!"
166
+ end
167
+
168
+ func("str") # ruby!
169
+ func(123) # ruby!
170
+
171
+ func(nil)
172
+ # (Rtype::ArgumentTypeError) for 1st argument:
173
+ # Expected nil to be a String
174
+ # OR Expected nil to be a Integer
175
+ ```
176
+
177
+ #### Hash
178
+ ```ruby
179
+ # last hash element is keyword arguments
180
+ rtype :func, [{msg: String}, {}] => Any
181
+ def func(hash)
182
+ puts hash[:msg]
183
+ end
184
+
185
+ func({})
186
+ # (Rtype::ArgumentTypeError) for 1st argument:
187
+ # Expected {} to be a hash with 1 elements:
188
+ # - msg : Expected nil to be a String
189
+
190
+ func({msg: 123})
191
+ # (Rtype::ArgumentTypeError) for 1st argument:
192
+ # Expected {:msg=>123} to be a hash with 1 elements:
193
+ # - msg : Expected 123 to be a String
194
+
195
+ func({msg: "hello", key: 'value'})
196
+ # (Rtype::ArgumentTypeError) for 1st argument:
197
+ # Expected {:msg=>"hello", :key=>"value"} to be a hash with 1 elements:
198
+ # - msg : Expected "hello" to be a String
199
+
200
+ func({"msg" => "hello hash"})
201
+ # (Rtype::ArgumentTypeError) for 1st argument:
202
+ # Expected {"msg"=>"hello hash"} to be a hash with 1 elements:
203
+ # - msg : Expected nil to be a String
204
+
205
+ func({msg: "hello hash"}) # hello hash
206
+ ```
207
+
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
212
+
213
+ You can use `rtype_accessor_self` for static accessor. (`rtype_reader_self`, `rtype_writer_self` also exist)
214
+
215
+ ```ruby
216
+ require 'rtype'
217
+
218
+ class Example
219
+ rtype_accessor :value, String
220
+
221
+ def initialize
222
+ @value = 456
223
+ end
224
+ end
225
+
226
+ Example.new.value = 123
227
+ # (Rtype::ArgumentTypeError) for 1st argument:
228
+ # Expected 123 to be a String
229
+
230
+ Example.new.value
231
+ # (Rtype::ReturnTypeError) for return:
232
+ # Expected 456 to be a String
233
+ ```
234
+
235
+ #### Typed Array
236
+ ```ruby
237
+ ### TEST 1 ###
238
+ class Test
239
+ rtype [Array.of(Integer)] => Any
240
+ def sum(args)
241
+ num = 0
242
+ args.each { |e| num += e }
243
+ end
244
+ end
245
+
246
+ sum([1, 2, 3]) # => 6
247
+
248
+ sum([1.0, 2, 3])
249
+ # (Rtype::ArgumentTypeError) for 1st argument:
250
+ # Expected [1.0, 2, 3] to be an array with type Integer"
251
+ ```
252
+
253
+ ```ruby
254
+ ### TEST 2 ###
255
+ class Test
256
+ rtype [ Array.of([Integer, Float]) ] => Any
257
+ def sum(args)
258
+ num = 0
259
+ args.each { |e| num += e }
260
+ end
261
+ end
262
+
263
+ sum([1, 2, 3]) # => 6
264
+ sum([1.0, 2, 3]) # => 6.0
265
+ ```
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
+
290
+ #### `rtype`
291
+ ```ruby
292
+ require 'rtype'
293
+
294
+ class Example
295
+ # Recommended. With annotation mode (no method name required)
296
+ rtype [Integer, String] => String
297
+ def hello_world(i, str)
298
+ puts "Hello? #{i} #{st
299
+ end
300
+
301
+ # Works (with specifying method name)
302
+ rtype :hello_world, [Integer, String] => String
303
+ def hello_world(i, str)
304
+ puts "Hello? #{i} #{st
305
+ end
306
+
307
+ # Works
308
+ def hello_world_two(i, str)
309
+ puts "Hello? #{i} #{str}"
310
+ end
311
+ rtype :hello_world_two, [Integer, String] => String
312
+
313
+ # Also works (String will be converted to Symbol)
314
+ rtype 'hello_world_three', [Integer, String] => String
315
+ def hello_world_three(i, str)
316
+ puts "Hello? #{i} #{str}"
317
+ end
318
+
319
+ # Doesn't work. annotation mode works for following (next) method
320
+ def hello_world_four(i, str)
321
+ puts "Hello? #{i} #{str}"
322
+ end
323
+ rtype [Integer, String] => String
324
+ end
325
+ ```
326
+
327
+ #### Class method
328
+ Annotation mode works for both instance method and class method
329
+
330
+ ```ruby
331
+ require 'rtype'
332
+
333
+ class Example
334
+ rtype [:to_i] => Any
335
+ def self.say_ya(i)
336
+ puts "say" + " ya"*i.to_i
337
+ end
338
+ end
339
+
340
+ Example::say_ya(3) #say ya ya ya
341
+ ```
342
+
343
+ if you specify method name, however, you must use `rtype_self` instead of `rtype`
344
+
345
+ ```ruby
346
+ require 'rtype'
347
+
348
+ class Example
349
+ rtype_self :say_ya, [:to_i] => Any
350
+ def self.say_ya(i)
351
+ puts "say" + " ya"*i.to_i
352
+ end
353
+ end
354
+
355
+ Example::say_ya(3) #say ya ya ya
356
+ ```
357
+
358
+ #### Type information
359
+ This is just 'information'
360
+
361
+ Any change of this doesn't affect type checking
362
+
363
+ ```ruby
364
+ require 'rtype'
365
+
366
+ class Example
367
+ rtype [:to_i] => Any
368
+ def test(i)
369
+ end
370
+ end
371
+
372
+ Example.new.method(:test).type_info
373
+ # => [:to_i] => Any
374
+ Example.new.method(:test).argument_type
375
+ # => [:to_i]
376
+ Example.new.method(:test).return_type
377
+ # => Any
378
+ ```
379
+
380
+ #### Special Behaviors
381
+ - `TypedArray` : Ensures value is an array with the type (type signature)
382
+ - `Array.of(type)` (recommended)
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)
390
+
391
+ - `Num, Int, Flo` : Numeric check
392
+ - `Num/Int/Flo >/>=/</<=/== x`
393
+ - e.g. `Num >= 2` means value must be a `Numeric` and >= 2
394
+ - e.g. `Int >= 2` means value must be a `Integer` and >= 2
395
+ - e.g. `Flo >= 2` means value must be a `Float` and >= 2
396
+
397
+ - `And` : Ensures value is valid for all given types
398
+ - `Rtype.and(*types)`, `Rtype::Behavior::And[*types]`
399
+ - or `Array#comb`, `Object#and(*others)`
400
+
401
+ - `Xor` : Ensures value is valid for only one of given types
402
+ - `Rtype.xor(*types)`, `Rtype::Behavior::Xor[*types]`
403
+ - or `Object#xor(*others)`
404
+
405
+ - `Not` : Ensures value is not valid for all given types
406
+ - `Rtype.not(*types)`, `Rtype::Behavior::Not[*types]`
407
+ - or `Object#not`
408
+
409
+ - `Nilable` : Value can be nil
410
+ - `Rtype.nilable(type)`, `Rtype::Behavior::Nilable[type]`
411
+ - or `Object#nilable`, `Object#or_nil`
412
+
413
+ - You can create custom behaviors by extending `Rtype::Behavior::Base`
414
+
415
+ ## Documentation
416
+ [RubyDoc.info](http://www.rubydoc.info/gems/rtype-legacy)
417
+
418
+ ## Benchmarks
419
+ Result of `rake benchmark` ([source](https://github.com/sputnikgugja/rtype-legacy/tree/master/benchmark/benchmark.rb))
420
+
421
+ Rubype and Sig don't support 1.9 ruby. Typecheck raises an error in my environment
422
+
423
+ ### MRI
424
+ ```
425
+ Ruby version: 1.9.3
426
+ Ruby engine: ruby
427
+ Ruby description: ruby 1.9.3p551 (2014-11-13 revision 48407) [i686-linux]
428
+ Rtype Legacy version: 0.0.1
429
+ Contracts version: 0.14.0
430
+ Rtype Legacy with native extension
431
+ Warming up --------------------------------------
432
+ pure 49.620k i/100ms
433
+ rtype-legacy 13.038k i/100ms
434
+ contracts 2.765k i/100ms
435
+ Calculating -------------------------------------
436
+ pure 2.037M (± 1.9%) i/s - 10.222M
437
+ rtype-legacy 179.155k (± 2.3%) i/s - 899.622k
438
+ contracts 30.576k (± 0.9%) i/s - 154.840k
439
+
440
+ Comparison:
441
+ pure: 2036909.8 i/s
442
+ rtype-legacy: 179155.3 i/s - 11.37x slower
443
+ contracts: 30575.8 i/s - 66.62x slower
444
+ ```
445
+
446
+ ### JRuby
447
+ ```
448
+ Ruby version: 1.9.3
449
+ Ruby engine: jruby
450
+ Ruby description: jruby 1.7.23 (1.9.3p551) 2015-11-24 f496dd5 on Java HotSpot(TM) Server VM 1.8.0_91-b14 +jit [linux-i386]
451
+ Rtype Legacy version: 0.0.1
452
+ Contracts version: 0.14.0
453
+ Rtype Legacy with java extension
454
+ Warming up --------------------------------------
455
+ pure 76.140k i/100ms
456
+ rtype-legacy 5.123k i/100ms
457
+ contracts 1.422k i/100ms
458
+ Calculating -------------------------------------
459
+ pure 6.330M (± 9.7%) i/s - 30.913M
460
+ rtype-legacy 293.793k (± 4.4%) i/s - 1.465M
461
+ contracts 33.924k (± 2.3%) i/s - 170.640k
462
+
463
+ Comparison:
464
+ pure: 6329735.2 i/s
465
+ rtype-legacy: 293793.2 i/s - 21.54x slower
466
+ contracts: 33924.0 i/s - 186.59x slower
467
+ ```
468
+
469
+ ## Author
470
+ Sputnik Gugja (sputnikgugja@gmail.com)
471
+
472
+ ## License
473
+ MIT license (@ Sputnik Gugja)
474
+
475
+ See `LICENSE` file.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ # Default pattern is 'spec/**{,/*/**}/*_spec.rb'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => [:spec]
7
+
8
+ # Benchmark
9
+ desc "Compare with pure ruby and other gems"
10
+ task :benchmark do
11
+ ruby "benchmark/benchmark.rb"
12
+ end
@@ -0,0 +1,104 @@
1
+ require 'benchmark/ips'
2
+
3
+ require "rtype/legacy"
4
+ require "contracts"
5
+ require "contracts/version"
6
+
7
+ puts "Ruby version: #{RUBY_VERSION}"
8
+ puts "Ruby engine: #{RUBY_ENGINE}"
9
+ puts "Ruby description: #{RUBY_DESCRIPTION}"
10
+
11
+ puts "Rtype Legacy version: #{Rtype::Legacy::VERSION}"
12
+ puts "Contracts version: #{Contracts::VERSION}"
13
+
14
+ if !Rtype::Legacy::NATIVE_EXT_VERSION.nil?
15
+ puts "Rtype Legacy with native extension"
16
+ elsif !Rtype::Legacy::JAVA_EXT_VERSION.nil?
17
+ puts "Rtype Legacy with java extension"
18
+ else
19
+ puts "Rtype Legacy without native extension"
20
+ end
21
+
22
+ class PureTest
23
+ def sum(x, y)
24
+ x + y
25
+ end
26
+
27
+ def mul(x, y)
28
+ x * y
29
+ end
30
+
31
+ def args(a, b, c, d)
32
+ end
33
+ end
34
+ pure_obj = PureTest.new
35
+
36
+ class RtypeTest
37
+ rtype [Numeric, Numeric] => Numeric
38
+ def sum(x, y)
39
+ x + y
40
+ end
41
+
42
+ rtype [:to_i, :to_i] => Numeric
43
+ def mul(x, y)
44
+ x * y
45
+ end
46
+
47
+ rtype [Integer, Numeric, String, :to_i] => Any
48
+ def args(a, b, c, d)
49
+ end
50
+ end
51
+ rtype_obj = RtypeTest.new
52
+
53
+ class ContractsTest
54
+ include Contracts
55
+
56
+ Contract Num, Num => Num
57
+ def sum(x, y)
58
+ x + y
59
+ end
60
+
61
+ Contract RespondTo[:to_i], RespondTo[:to_i] => Num
62
+ def mul(x, y)
63
+ x * y
64
+ end
65
+
66
+ Contract Int, Num, String, RespondTo[:to_i] => Any
67
+ def args(a, b, c, d)
68
+ end
69
+ end
70
+ contracts_obj = ContractsTest.new
71
+
72
+ Benchmark.ips do |x|
73
+ x.report("pure") do |times|
74
+ i = 0
75
+ while i < times
76
+ pure_obj.sum(1, 2)
77
+ pure_obj.mul(1, 2)
78
+ pure_obj.args(1, 2, "c", 4)
79
+ i += 1
80
+ end
81
+ end
82
+
83
+ x.report("rtype-legacy") do |times|
84
+ i = 0
85
+ while i < times
86
+ rtype_obj.sum(1, 2)
87
+ rtype_obj.mul(1, 2)
88
+ rtype_obj.args(1, 2, "c", 4)
89
+ i += 1
90
+ end
91
+ end
92
+
93
+ x.report("contracts") do |times|
94
+ i = 0
95
+ while i < times
96
+ contracts_obj.sum(1, 2)
97
+ contracts_obj.mul(1, 2)
98
+ contracts_obj.args(1, 2, "c", 4)
99
+ i += 1
100
+ end
101
+ end
102
+
103
+ x.compare!
104
+ end