rubype 0.2.0 → 0.2.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/README.md +50 -34
- data/lib/rubype.rb +14 -4
- data/lib/rubype/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a1d6b7168106e0de86c7111cfe41bfe191a4217
|
4
|
+
data.tar.gz: 2663b2cfef26e3eb90ee0c0932be7d34bb562ddb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0dce04b7c97e12030468f044af562c51c04446ed033d17acd27da10355dae3751a0fd8bc74dc8c15e8cdde31d0c6d9710d420a2cf106c6a36495636ac4a9a20e
|
7
|
+
data.tar.gz: 85d34a6e01587cab72001f08f13ca372c39a72efdb52b6b3506b10b12b7de0582f4087a60b8d23929ecb6454921a74e26edf1b0760607493083f40906b355e0f
|
data/README.md
CHANGED
@@ -1,9 +1,56 @@
|
|
1
|
-
# Ruby
|
1
|
+
# Ruby + Type = Rubype
|
2
|
+
|
3
|
+
```rb
|
4
|
+
def sum(x, y)
|
5
|
+
x + y
|
6
|
+
end
|
7
|
+
typesig sum: [Numeric, Numeric => Numeric]
|
8
|
+
```
|
9
|
+
|
10
|
+
This gem brings you advantage of type without changing existing code's behavior.
|
2
11
|
|
3
12
|
Matz has mentioned Ruby3.0 with static type at some confluences. But almost all rubyists(include me) are not sure how typed Ruby is.
|
4
13
|
|
5
14
|
But it's worth thinking more. This gem is kind of trial without so much side-effect.
|
6
15
|
|
16
|
+
# Feature
|
17
|
+
### Typed method can coexist with non-typed method
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
# It's totally OK!!
|
21
|
+
class MyClass
|
22
|
+
def method_with_type(x, y)
|
23
|
+
x + y
|
24
|
+
end
|
25
|
+
typesig sum: [Numeric, Numeric => Numeric]
|
26
|
+
|
27
|
+
def method_without_type(x, y)
|
28
|
+
'string'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
### Duck typing
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
|
37
|
+
class MyClass
|
38
|
+
def foo(any_obj)
|
39
|
+
1
|
40
|
+
end
|
41
|
+
typesig sum: [Any => Numeric]
|
42
|
+
end
|
43
|
+
|
44
|
+
# It's totally OK!!
|
45
|
+
MyClass.new.foo(1)
|
46
|
+
# It's totally OK!!
|
47
|
+
MyClass.new.foo('str')
|
48
|
+
```
|
49
|
+
|
50
|
+
### Advantage of type
|
51
|
+
* Meaningful error
|
52
|
+
* Executable documentation
|
53
|
+
|
7
54
|
```rb
|
8
55
|
require 'rubype'
|
9
56
|
|
@@ -45,39 +92,7 @@ People.new.marry('non people')
|
|
45
92
|
#=> ArgumentError: Wrong type of argument, type of "non people" should be People
|
46
93
|
```
|
47
94
|
|
48
|
-
## Feature
|
49
|
-
### Typed method can coexist with non-typed method
|
50
|
-
|
51
|
-
```ruby
|
52
|
-
# It's totally OK!!
|
53
|
-
class MyClass
|
54
|
-
def sum(x, y)
|
55
|
-
x + y
|
56
|
-
end
|
57
|
-
typesig sum: [Numeric, Numeric => Numeric]
|
58
|
-
|
59
|
-
def sum_without_type(x, y)
|
60
|
-
'string'
|
61
|
-
end
|
62
|
-
end
|
63
|
-
```
|
64
|
-
|
65
|
-
### Duck typing
|
66
95
|
|
67
|
-
```ruby
|
68
|
-
|
69
|
-
class MyClass
|
70
|
-
def foo(any_obj)
|
71
|
-
1
|
72
|
-
end
|
73
|
-
typesig sum: [Any => Numeric]
|
74
|
-
end
|
75
|
-
|
76
|
-
# It's totally OK!!
|
77
|
-
MyClass.new.foo(1)
|
78
|
-
# It's totally OK!!
|
79
|
-
MyClass.new.foo('str')
|
80
|
-
```
|
81
96
|
|
82
97
|
## Installation
|
83
98
|
|
@@ -104,4 +119,5 @@ Push to the branch (`git push origin my-new-feature`)
|
|
104
119
|
Create a new Pull Request
|
105
120
|
|
106
121
|
## Credits
|
107
|
-
[@chancancode](https://github.com/chancancode) first brought this to my attention. I've stolen some idea from
|
122
|
+
[@chancancode](https://github.com/chancancode) and [This article](http://blog.codeclimate.com/blog/2014/05/06/gradual-type-checking-for-ruby/) first brought this to my attention. I've stolen some idea from them.
|
123
|
+
|
data/lib/rubype.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "rubype/rubype"
|
2
|
-
|
3
1
|
# Builtin Contracts
|
4
2
|
class Any; end
|
5
3
|
module Boolean; end
|
@@ -13,14 +11,15 @@ class Module
|
|
13
11
|
@__rubype__
|
14
12
|
end
|
15
13
|
|
14
|
+
# @param hash [Hash] {method_name: [ArgClass1, ArgClass2, ... ArgClassn => RtnClass]}
|
16
15
|
def typesig(hash)
|
17
16
|
meth = hash.keys.first
|
18
17
|
*arg_types, type_pair = hash.values.first
|
19
18
|
|
20
19
|
__rubype__.send(:define_method, meth) do |*args, &block|
|
21
|
-
::Rubype.assert_arg_type
|
20
|
+
::Rubype.send(:assert_arg_type, meth, args, arg_types << type_pair.keys.first)
|
22
21
|
rtn = super(*args, &block)
|
23
|
-
::Rubype.assert_trn_type
|
22
|
+
::Rubype.send(:assert_trn_type, meth, rtn, type_pair.values.first)
|
24
23
|
rtn
|
25
24
|
end
|
26
25
|
self
|
@@ -29,6 +28,11 @@ end
|
|
29
28
|
|
30
29
|
module Rubype
|
31
30
|
class << self
|
31
|
+
private
|
32
|
+
|
33
|
+
# @param meth [Symbol]
|
34
|
+
# @param args [Array<Object>]
|
35
|
+
# @param klasses [Array<Class>]
|
32
36
|
def assert_arg_type(meth, args, klasses)
|
33
37
|
args.each_with_index do |arg, i|
|
34
38
|
if wrong_type?(arg, klasses[i])
|
@@ -37,12 +41,18 @@ module Rubype
|
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
44
|
+
# @param meth [Symbol]
|
45
|
+
# @param rtn [Object]
|
46
|
+
# @param klass [Class]
|
40
47
|
def assert_trn_type(meth, rtn, klass)
|
41
48
|
if wrong_type?(rtn, klass)
|
42
49
|
raise TypeError, "Expected #{meth} to return #{klass} but got #{rtn.inspect} instead"
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
53
|
+
# @param obj [Object]
|
54
|
+
# @param klass [Class]
|
55
|
+
# @return [Boolean]
|
46
56
|
def wrong_type?(obj, klass)
|
47
57
|
!(obj.is_a?(klass) || klass == Any)
|
48
58
|
end
|
data/lib/rubype/version.rb
CHANGED