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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ae0b6a1e018a6dc49298c7333333f5b780395c08d6050696d466e67071bdaf5
4
- data.tar.gz: e796b18cc593dc6ac014185e45a86a8b3f17f7de9764ee5da465ced12e445c10
3
+ metadata.gz: daa6e411ef5ed471ff9ece81500cb7ba07197141f8b031b2870636953c634b6a
4
+ data.tar.gz: e7cff143d64a4bf06213def2ffacfee00286e1b7a82be2479fc695714500a749
5
5
  SHA512:
6
- metadata.gz: d7287ffa69f2c273324acd514fa011f5a4834a16ee970310e452adec5a206325b43a8c3a213332b7046826ff075791e34e2e8ab7391c47c12452842834d4222d
7
- data.tar.gz: 0c11df4506fdcf596a5be17f5a067759f513c6ed32bb19b711b564c5a0a66fc0f4091ba85a866e2a6e590777fca6f9897eb68aabb4030d3ed4736f1c9c00b3c2
6
+ metadata.gz: 85da59bc8d15f1fa5497d65a0d03b2a525f1123e037aff1b122d50a81772f9ea84c0ad2384e869e8101ee4e69b0aebaa968bac25cc82df06b9b587e05945a590
7
+ data.tar.gz: '019a49943d9ede03c0dbc3679b1c0d90160601f72d377171b80e39d1487796fc8e3c6b94fe7af008c4baf2fb74a2fc2038dce79f73f01cce4973467640eecd54'
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/ruby-signature"]
2
+ path = vendor/ruby-signature
3
+ url = https://github.com/ruby/ruby-signature.git
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.6.5
4
+ - 2.7.0
5
+ - ruby-head
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in overloader.gemspec
4
4
  gemspec
5
+
6
+ gem 'ruby-signature', path: 'vendor/ruby-signature'
7
+ gem 'ruby2_keywords'
8
+ gem 'racc'
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'
@@ -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
@@ -3,7 +3,7 @@ module Overloader
3
3
  using AstExt
4
4
 
5
5
  def self.define_overload(klass, proc)
6
- self.new(klass, proc).define_overload
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
- true
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
@@ -1,3 +1,3 @@
1
1
  module Overloader
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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", "~> 2.1.a"
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.1.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: 2019-04-27 00:00:00.000000000 Z
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: 2.1.a
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: 2.1.a
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