overloader 0.1.0 → 0.2.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/.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
|