overloader 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +41 -0
- data/Rakefile +6 -1
- data/lib/overloader/ast_ext.rb +14 -0
- data/lib/overloader/core.rb +13 -2
- data/lib/overloader/type/checker.rb +46 -0
- data/lib/overloader/type.rb +23 -0
- data/lib/overloader/version.rb +1 -1
- data/overloader.gemspec +1 -1
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: daa6e411ef5ed471ff9ece81500cb7ba07197141f8b031b2870636953c634b6a
|
4
|
+
data.tar.gz: e7cff143d64a4bf06213def2ffacfee00286e1b7a82be2479fc695714500a749
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85da59bc8d15f1fa5497d65a0d03b2a525f1123e037aff1b122d50a81772f9ea84c0ad2384e869e8101ee4e69b0aebaa968bac25cc82df06b9b587e05945a590
|
7
|
+
data.tar.gz: '019a49943d9ede03c0dbc3679b1c0d90160601f72d377171b80e39d1487796fc8e3c6b94fe7af008c4baf2fb74a2fc2038dce79f73f01cce4973467640eecd54'
|
data/.gitmodules
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
Overload for Ruby
|
4
4
|
|
5
|
+
# DO NOT USE THIS LIBRARY FOR PRODUCTION
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
Add this line to your application's Gemfile:
|
@@ -38,6 +40,45 @@ p a.foo(1) # => "one args"
|
|
38
40
|
p a.foo(1, 2) # => "two args"
|
39
41
|
```
|
40
42
|
|
43
|
+
## Advanced Usage: types
|
44
|
+
|
45
|
+
You can define overload with types.
|
46
|
+
|
47
|
+
This feature requires the following things.
|
48
|
+
|
49
|
+
* Ruby 2.7 or greater
|
50
|
+
* [ruby-signature](https://github.com/ruby/ruby-signature) gem
|
51
|
+
* This gem has not been published to RubyGems.org. So you need to install it manually.
|
52
|
+
|
53
|
+
First, add `require 'overloader/type'`.
|
54
|
+
Then, define the method type with RBS syntax. https://github.com/ruby/ruby-signature
|
55
|
+
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
require 'overloader'
|
59
|
+
require 'overloader/type'
|
60
|
+
|
61
|
+
class A
|
62
|
+
extend Overloader
|
63
|
+
overload do
|
64
|
+
# (String, Integer) -> untyped
|
65
|
+
def foo(x, y) 'str int' end
|
66
|
+
|
67
|
+
# (Integer, String) -> untyped
|
68
|
+
def foo(x, y) 'int str' end
|
69
|
+
|
70
|
+
# (Symbol, Symbol) -> untyped
|
71
|
+
def foo(x, y) 'sym sym' end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
a = A.new
|
76
|
+
p a.foo('bar', 42) # => "str int"
|
77
|
+
p a.foo(42, 'baz') # => "int str"
|
78
|
+
p a.foo(:a, :b) # => "sym sym"
|
79
|
+
p a.foo(:a, 42) # => ArgumentError
|
80
|
+
```
|
81
|
+
|
41
82
|
## Development
|
42
83
|
|
43
84
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/Rakefile
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require 'rake/testtask'
|
3
|
-
task :default => :test
|
3
|
+
task :default => [:build_deps, :test]
|
4
|
+
|
5
|
+
task :build_deps do
|
6
|
+
sh 'bundle check || bundle install', chdir: 'vendor/ruby-signature'
|
7
|
+
sh 'bundle exec rake parser', chdir: 'vendor/ruby-signature'
|
8
|
+
end
|
4
9
|
|
5
10
|
Rake::TestTask.new do |test|
|
6
11
|
test.libs << 'test'
|
data/lib/overloader/ast_ext.rb
CHANGED
@@ -20,6 +20,20 @@ module Overloader
|
|
20
20
|
file_content(path)[first_index(path)..last_index(path)]
|
21
21
|
end
|
22
22
|
|
23
|
+
def comment(content: nil, path: nil)
|
24
|
+
raise ArgumentError.new("content or path is required") unless content || path
|
25
|
+
|
26
|
+
content ||= file_content(path)
|
27
|
+
l = first_lineno - 2
|
28
|
+
|
29
|
+
res = []
|
30
|
+
while (comment = content.lines[l])&.match?(/^\s*#/)
|
31
|
+
res.unshift comment
|
32
|
+
l -= 1
|
33
|
+
end
|
34
|
+
res.empty? ? nil : res.join
|
35
|
+
end
|
36
|
+
|
23
37
|
# method node ext
|
24
38
|
|
25
39
|
def method_body
|
data/lib/overloader/core.rb
CHANGED
@@ -3,7 +3,7 @@ module Overloader
|
|
3
3
|
using AstExt
|
4
4
|
|
5
5
|
def self.define_overload(klass, proc)
|
6
|
-
|
6
|
+
new(klass, proc).define_overload
|
7
7
|
end
|
8
8
|
|
9
9
|
def initialize(klass, proc)
|
@@ -25,7 +25,7 @@ module Overloader
|
|
25
25
|
def __#{name}_#{index}_checker_inner(#{args_source}) end
|
26
26
|
def __#{name}_#{index}_checker(*args)
|
27
27
|
__#{name}_#{index}_checker_inner(*args)
|
28
|
-
|
28
|
+
#{type_check_code(def_node, name)}
|
29
29
|
rescue ArgumentError
|
30
30
|
false
|
31
31
|
end
|
@@ -51,6 +51,17 @@ module Overloader
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
def type_check_code(def_node, method_name)
|
55
|
+
return 'true' unless defined?(::Overloader::Type)
|
56
|
+
|
57
|
+
comment = def_node.comment(path: absolute_path)
|
58
|
+
return 'true' unless comment
|
59
|
+
|
60
|
+
type = comment.sub(/^\s*#/, '')
|
61
|
+
|
62
|
+
"::Overloader::Type.callable?(#{type.dump}, self.class, #{method_name.inspect}, *args)"
|
63
|
+
end
|
64
|
+
|
54
65
|
private def absolute_path
|
55
66
|
@proc.source_location[0]
|
56
67
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Overloader
|
2
|
+
module Type
|
3
|
+
class Checker
|
4
|
+
def initialize(type:, klass:)
|
5
|
+
@type = type
|
6
|
+
@klass = klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.env
|
10
|
+
@env ||= begin
|
11
|
+
loader = Ruby::Signature::EnvironmentLoader.new
|
12
|
+
Ruby::Signature::Environment.new.tap do |env|
|
13
|
+
loader.load(env: env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.builder
|
19
|
+
Ruby::Signature::DefinitionBuilder.new(env: env)
|
20
|
+
end
|
21
|
+
|
22
|
+
ruby2_keywords def errors(method_name, *args)
|
23
|
+
call = Ruby::Signature::Test::CallTrace.new(
|
24
|
+
method_call: Ruby::Signature::Test::ArgumentsReturn.new(arguments: args, return_value: nil, exception: nil),
|
25
|
+
block_calls: [],
|
26
|
+
block_given: false,
|
27
|
+
)
|
28
|
+
errors = type_check.method_call(method_name, method_type, call, errors: [])
|
29
|
+
|
30
|
+
errors.reject { |e| e.is_a?(Ruby::Signature::Test::Errors::ReturnTypeError) }
|
31
|
+
end
|
32
|
+
|
33
|
+
private def method_type
|
34
|
+
Ruby::Signature::Parser.parse_method_type(type)
|
35
|
+
end
|
36
|
+
|
37
|
+
private def type_check
|
38
|
+
Ruby::Signature::Test::TypeCheck.new(self_class: klass, builder: self.class.builder)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
private
|
43
|
+
attr_reader :type, :klass
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
gem 'ruby-signature'
|
2
|
+
gem 'ruby2_keywords'
|
3
|
+
require 'ruby/signature'
|
4
|
+
require 'ruby/signature/test'
|
5
|
+
require 'ruby2_keywords'
|
6
|
+
|
7
|
+
require_relative 'type/checker'
|
8
|
+
|
9
|
+
module Overloader
|
10
|
+
module Type
|
11
|
+
CHECKERS = {}
|
12
|
+
extend self
|
13
|
+
|
14
|
+
ruby2_keywords def callable?(type, klass, method_name, *args)
|
15
|
+
checker = checker(klass: klass, type: type)
|
16
|
+
checker.errors(method_name, *args).empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
private def checker(klass:, type:)
|
20
|
+
CHECKERS[[klass, type]] ||= Checker.new(type: type, klass: klass)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/overloader/version.rb
CHANGED
data/overloader.gemspec
CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
-
spec.add_development_dependency "bundler", "
|
30
|
+
spec.add_development_dependency "bundler", "< 3"
|
31
31
|
spec.add_development_dependency "rake", "~> 12.0"
|
32
32
|
spec.add_development_dependency "minitest", "> 5"
|
33
33
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: overloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masataka Pocke Kuwabara
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-25 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: '3'
|
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: '3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +60,8 @@ extensions: []
|
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
62
|
- ".gitignore"
|
63
|
+
- ".gitmodules"
|
64
|
+
- ".travis.yml"
|
63
65
|
- Gemfile
|
64
66
|
- README.md
|
65
67
|
- Rakefile
|
@@ -68,6 +70,8 @@ files:
|
|
68
70
|
- lib/overloader.rb
|
69
71
|
- lib/overloader/ast_ext.rb
|
70
72
|
- lib/overloader/core.rb
|
73
|
+
- lib/overloader/type.rb
|
74
|
+
- lib/overloader/type/checker.rb
|
71
75
|
- lib/overloader/version.rb
|
72
76
|
- overloader.gemspec
|
73
77
|
homepage: https://github.com/pocke/overloader
|