rubype 0.0.1 → 0.1.0
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/.travis.yml +4 -0
- data/Gemfile +1 -1
- data/README.md +102 -17
- data/lib/rubype/type_pair.rb +7 -0
- data/lib/rubype/version.rb +1 -1
- data/lib/rubype.rb +46 -3
- data/rubype.gemspec +5 -5
- data/test/test_rubype.rb +107 -5
- metadata +14 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d3acd50cc84b3a88ae2270111796825a1d7b916
|
4
|
+
data.tar.gz: 53745d33a11a70db20b39199df8cd54115cf3e6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28374048f7e03c8611d69d1cc6ee842ed93e0cda775968f0e9f4d1e7da31f29a6694fd136445d8c93864403fa0ed97001bc08cdbeb14d85447326c81070829e8
|
7
|
+
data.tar.gz: b0faae01aa81746ca428efd63993969b6f4c4d4f8437b5a4fd76051b7bd7ecf48f1cd78bed70bb2470a140c57dcbe8dd161c0b27bc41bc023a282c799f4ccc51
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,31 +1,116 @@
|
|
1
|
-
#
|
1
|
+
# Ruby with Type.
|
2
2
|
|
3
|
-
|
3
|
+
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
4
|
|
5
|
-
|
5
|
+
But it's worth thinking more. This gem is kind of trial without so much side-effect.
|
6
|
+
|
7
|
+
```rb
|
8
|
+
require 'rubype'
|
9
|
+
|
10
|
+
# ex1
|
11
|
+
class MyClass
|
12
|
+
def sum(x, y)
|
13
|
+
x + y
|
14
|
+
end
|
15
|
+
type Numeric, Numeric >= Numeric, :sum
|
16
|
+
|
17
|
+
def wrong_sum(x, y)
|
18
|
+
'string'
|
19
|
+
end
|
20
|
+
type Numeric, Numeric >= Numeric, :sum
|
21
|
+
end
|
22
|
+
|
23
|
+
MyClass.new.sum(1, 2)
|
24
|
+
#=> 3
|
25
|
+
|
26
|
+
MyClass.new.sum(1, 'string')
|
27
|
+
#=> ArgumentError: Wrong type of argument, type of "str" should be Numeric
|
28
|
+
|
29
|
+
MyClass.new.wrong_sum(1, 2)
|
30
|
+
#=> TypeError: Expected wrong_sum to return Numeric but got "str" instead
|
31
|
+
|
32
|
+
# ex2: (Ruby 2.1.0+)
|
33
|
+
class MyClass
|
34
|
+
type Numeric, Numeric >= Numeric, def sum(x, y)
|
35
|
+
x + y
|
36
|
+
end
|
37
|
+
|
38
|
+
type Numeric, Numeric >= Numeric, def wrong_sum(x, y)
|
39
|
+
'string'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# ex3: (Ruby 2.1.0+)
|
44
|
+
class People
|
45
|
+
type People >= Any, def marry(people)
|
46
|
+
# Your Ruby code as usual
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
People.new.marry(People.new)
|
51
|
+
#=> no error
|
52
|
+
|
53
|
+
People.new.marry('non people')
|
54
|
+
#=> ArgumentError: Wrong type of argument, type of "non people" should be People
|
55
|
+
```
|
6
56
|
|
7
|
-
|
57
|
+
## Feature
|
58
|
+
### Typed method can coexist with non-typed method
|
8
59
|
|
9
60
|
```ruby
|
10
|
-
|
61
|
+
# It's totally OK!!
|
62
|
+
class MyClass
|
63
|
+
def sum(x, y)
|
64
|
+
x + y
|
65
|
+
end
|
66
|
+
type Numeric, Numeric >= Numeric, :sum
|
67
|
+
|
68
|
+
def wrong_sum(x, y)
|
69
|
+
'string'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
### Duck typing
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
|
78
|
+
class MyClass
|
79
|
+
def foo(any_obj)
|
80
|
+
1
|
81
|
+
end
|
82
|
+
type Any >= Numeric, :foo
|
83
|
+
end
|
84
|
+
|
85
|
+
# It's totally OK!!
|
86
|
+
MyClass.new.foo(1)
|
87
|
+
# It's totally OK!!
|
88
|
+
MyClass.new.foo('str')
|
11
89
|
```
|
12
90
|
|
13
|
-
|
91
|
+
## Installation
|
92
|
+
|
93
|
+
gem install rubype or add gem 'rubype' to your Gemfile.
|
94
|
+
|
95
|
+
This gem requires Ruby 2.0.0+.
|
96
|
+
|
97
|
+
### Contributing
|
98
|
+
|
99
|
+
Fork it ( https://github.com/[my-github-username]/rubype/fork )
|
100
|
+
|
101
|
+
Create your feature branch (`git checkout -b my-new-feature`)
|
14
102
|
|
15
|
-
$ bundle
|
103
|
+
$ bundle install --path vendor/bundle
|
16
104
|
|
17
|
-
|
105
|
+
Commit your changes (`git commit -am 'Add some feature'`)
|
18
106
|
|
19
|
-
$
|
107
|
+
$ bundle exec rake test
|
20
108
|
|
21
|
-
|
109
|
+
> 5 runs, 39 assertions, 0 failures, 0 errors, 0 skips
|
22
110
|
|
23
|
-
|
111
|
+
Push to the branch (`git push origin my-new-feature`)
|
24
112
|
|
25
|
-
|
113
|
+
Create a new Pull Request
|
26
114
|
|
27
|
-
|
28
|
-
|
29
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
-
5. Create a new Pull Request
|
115
|
+
## Credits
|
116
|
+
[@chancancode](https://github.com/chancancode) first brought this to my attention. I've stolen some idea from him.
|
data/lib/rubype/version.rb
CHANGED
data/lib/rubype.rb
CHANGED
@@ -1,6 +1,49 @@
|
|
1
|
-
require
|
2
|
-
|
1
|
+
require 'rubype/type_pair'
|
2
|
+
|
3
|
+
# Builtin Contracts
|
4
|
+
class Any; end
|
5
|
+
module Boolean; end
|
6
|
+
TrueClass.send(:include, Boolean)
|
7
|
+
FalseClass.send(:include, Boolean)
|
8
|
+
|
9
|
+
class Module
|
10
|
+
private
|
11
|
+
def __rubype__
|
12
|
+
prepend (@__rubype__ = Module.new) unless @__rubype__
|
13
|
+
@__rubype__
|
14
|
+
end
|
15
|
+
|
16
|
+
def type(*arguments)
|
17
|
+
*arg_types, type_pair, meth = arguments
|
18
|
+
|
19
|
+
__rubype__.send(:define_method, meth) do |*args, &block|
|
20
|
+
::Rubype.assert_arg_type(meth, args, arg_types << type_pair.last_arg_type)
|
21
|
+
rtn = super(*args, &block)
|
22
|
+
::Rubype.assert_trn_type(meth, rtn, type_pair.rtn_type)
|
23
|
+
rtn
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
end
|
3
28
|
|
4
29
|
module Rubype
|
5
|
-
|
30
|
+
class << self
|
31
|
+
def assert_arg_type(meth, args, klasses)
|
32
|
+
args.each_with_index do |arg, i|
|
33
|
+
if wrong_type?(arg, klasses[i])
|
34
|
+
raise ArgumentError, "Wrong type of argument, type of #{arg.inspect} should be #{klasses[i]}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def assert_trn_type(meth, rtn, klass)
|
40
|
+
if wrong_type?(rtn, klass)
|
41
|
+
raise TypeError, "Expected #{meth} to return #{klass} but got #{rtn.inspect} instead"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def wrong_type?(obj, klass)
|
46
|
+
!(obj.is_a?(klass) || klass == Any)
|
47
|
+
end
|
48
|
+
end
|
6
49
|
end
|
data/rubype.gemspec
CHANGED
@@ -9,9 +9,9 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["gogotanaka"]
|
10
10
|
spec.email = ["mail@tanakakazuki.com"]
|
11
11
|
spec.extensions = ["ext/rubype/extconf.rb"]
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.description = %q{
|
14
|
-
spec.homepage = ""
|
12
|
+
spec.summary = %q{Ruby with type.}
|
13
|
+
spec.description = %q{Ruby with type.}
|
14
|
+
spec.homepage = "http://azabuhs.org/"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_development_dependency "bundler"
|
23
|
-
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "bundler"
|
23
|
+
spec.add_development_dependency "rake"
|
24
24
|
spec.add_development_dependency "rake-compiler"
|
25
25
|
spec.add_development_dependency "minitest"
|
26
26
|
end
|
data/test/test_rubype.rb
CHANGED
@@ -1,11 +1,113 @@
|
|
1
1
|
require 'minitest_helper'
|
2
|
-
|
2
|
+
class TypePair
|
3
|
+
def to_s
|
4
|
+
"#{last_arg_type} >= #{rtn_type}"
|
5
|
+
end
|
6
|
+
end
|
3
7
|
class TestRubype < MiniTest::Unit::TestCase
|
4
|
-
def
|
5
|
-
|
8
|
+
def setup
|
9
|
+
@string = 'str'
|
10
|
+
@numeric = 1
|
11
|
+
@symbol = :test
|
12
|
+
@array = [1, 2, 3]
|
13
|
+
@hash = { test: :hash }
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_type_list
|
17
|
+
assert_equal_to_s "Numeric >= Numeric", Numeric >= Numeric
|
18
|
+
assert_equal_to_s "Numeric >= Array", Numeric >= Array
|
19
|
+
assert_equal_to_s "Array >= String", Array >= String
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_correct_type
|
23
|
+
assert_correct_type [Numeric >= Numeric], [@numeric], @numeric
|
24
|
+
assert_correct_type [Numeric >= Array ], [@numeric], @array
|
25
|
+
assert_correct_type [Numeric >= String ], [@numeric], @string
|
26
|
+
assert_correct_type [Numeric >= Hash ], [@numeric], @hash
|
27
|
+
assert_correct_type [Numeric >= Symbol ], [@numeric], @symbol
|
28
|
+
assert_correct_type [Numeric >= Boolean], [@numeric], true
|
29
|
+
assert_correct_type [Numeric >= Boolean], [@numeric], false
|
30
|
+
|
31
|
+
assert_correct_type [Boolean, Numeric >= Numeric], [true, @numeric], @numeric
|
32
|
+
assert_correct_type [Boolean, Array >= Array ], [true, @array ], @array
|
33
|
+
assert_correct_type [Boolean, String >= String ], [true, @string ], @string
|
34
|
+
assert_correct_type [Boolean, Hash >= Hash ], [true, @hash ], @hash
|
35
|
+
assert_correct_type [Boolean, Symbol >= Symbol ], [true, @symbol ], @symbol
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_wrong_return_type
|
39
|
+
assert_wrong_rtn [Numeric >= Numeric], [@numeric], @array
|
40
|
+
assert_wrong_rtn [Numeric >= Numeric], [@numeric], @string
|
41
|
+
assert_wrong_rtn [Numeric >= Numeric], [@numeric], @hash
|
42
|
+
assert_wrong_rtn [Numeric >= Numeric], [@numeric], @symbol
|
43
|
+
assert_wrong_rtn [Numeric >= Numeric], [@numeric], true
|
44
|
+
|
45
|
+
assert_wrong_rtn [Numeric, Numeric >= Numeric], [@numeric, @numeric], @array
|
46
|
+
assert_wrong_rtn [Numeric, Numeric >= Numeric], [@numeric, @numeric], @string
|
47
|
+
assert_wrong_rtn [Numeric, Numeric >= Numeric], [@numeric, @numeric], @hash
|
48
|
+
assert_wrong_rtn [Numeric, Numeric >= Numeric], [@numeric, @numeric], @symbol
|
49
|
+
assert_wrong_rtn [Numeric, Numeric >= Numeric], [@numeric, @numeric], true
|
6
50
|
end
|
7
51
|
|
8
|
-
def
|
9
|
-
|
52
|
+
def test_wrong_args_type
|
53
|
+
assert_wrong_arg [Numeric >= Numeric], [@array ], @numeric
|
54
|
+
assert_wrong_arg [Numeric >= Numeric], [@string], @numeric
|
55
|
+
assert_wrong_arg [Numeric >= Numeric], [@hash ], @numeric
|
56
|
+
assert_wrong_arg [Numeric >= Numeric], [@symbol], @numeric
|
57
|
+
assert_wrong_arg [Numeric >= Numeric], [true ], @numeric
|
58
|
+
|
59
|
+
assert_wrong_arg [Numeric, Numeric >= Numeric], [@numeric, @array ], @numeric
|
60
|
+
assert_wrong_arg [Numeric, Numeric >= Numeric], [@numeric, @string], @numeric
|
61
|
+
assert_wrong_arg [Numeric, Numeric >= Numeric], [@numeric, @hash ], @numeric
|
62
|
+
assert_wrong_arg [Numeric, Numeric >= Numeric], [@numeric, @symbol], @numeric
|
63
|
+
assert_wrong_arg [Numeric, Numeric >= Numeric], [@numeric, true ], @numeric
|
10
64
|
end
|
65
|
+
|
66
|
+
def test_any
|
67
|
+
assert_correct_type [Any >= Any], [@array ], @numeric
|
68
|
+
assert_correct_type [Any >= Any], [@string], @numeric
|
69
|
+
assert_correct_type [Any >= Any], [@hash ], @numeric
|
70
|
+
assert_correct_type [Any >= Any], [@symbol], @numeric
|
71
|
+
|
72
|
+
assert_correct_type [Any, Any >= Any], [@numeric, @array ], @numeric
|
73
|
+
assert_correct_type [Any, Any >= Any], [@numeric, @string], @numeric
|
74
|
+
assert_correct_type [Any, Any >= Any], [@numeric, @hash ], @numeric
|
75
|
+
assert_correct_type [Any, Any >= Any], [@numeric, @symbol], @numeric
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def assert_equal_to_s(str, val)
|
80
|
+
assert_equal str, val.to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
def assert_correct_type(type_list, args, val)
|
84
|
+
assert_equal val, define_test_method(type_list, args, val).call(*args)
|
85
|
+
end
|
86
|
+
|
87
|
+
def assert_wrong_arg(type_list, args, val)
|
88
|
+
assert_raises(ArgumentError) { define_test_method(type_list, args, val).call(*args) }
|
89
|
+
end
|
90
|
+
|
91
|
+
def assert_wrong_rtn(type_list, args, val)
|
92
|
+
assert_raises(TypeError) { define_test_method(type_list, args, val).call(*args) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def define_test_method(type_list, args, val)
|
96
|
+
klass = Class.new.class_eval <<-RUBY_CODE
|
97
|
+
def call(#{arg_literal(args.count)})
|
98
|
+
#{obj_literal(val)}
|
99
|
+
end
|
100
|
+
type #{type_list.map(&:to_s).join(',')}, :call
|
101
|
+
RUBY_CODE
|
102
|
+
|
103
|
+
klass.new
|
104
|
+
end
|
105
|
+
|
106
|
+
def obj_literal(obj)
|
107
|
+
"ObjectSpace._id2ref(#{obj.__id__})"
|
108
|
+
end
|
109
|
+
|
110
|
+
def arg_literal(count)
|
111
|
+
('a'..'z').to_a[0..count-1].join(',')
|
112
|
+
end
|
11
113
|
end
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubype
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- gogotanaka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake-compiler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
-
description:
|
69
|
+
description: Ruby with type.
|
70
70
|
email:
|
71
71
|
- mail@tanakakazuki.com
|
72
72
|
executables:
|
@@ -86,11 +86,12 @@ files:
|
|
86
86
|
- ext/rubype/rubype.c
|
87
87
|
- ext/rubype/rubype.h
|
88
88
|
- lib/rubype.rb
|
89
|
+
- lib/rubype/type_pair.rb
|
89
90
|
- lib/rubype/version.rb
|
90
91
|
- rubype.gemspec
|
91
92
|
- test/minitest_helper.rb
|
92
93
|
- test/test_rubype.rb
|
93
|
-
homepage:
|
94
|
+
homepage: http://azabuhs.org/
|
94
95
|
licenses:
|
95
96
|
- MIT
|
96
97
|
metadata: {}
|
@@ -113,7 +114,7 @@ rubyforge_project:
|
|
113
114
|
rubygems_version: 2.2.2
|
114
115
|
signing_key:
|
115
116
|
specification_version: 4
|
116
|
-
summary: Ruby with
|
117
|
+
summary: Ruby with type.
|
117
118
|
test_files:
|
118
119
|
- test/minitest_helper.rb
|
119
120
|
- test/test_rubype.rb
|