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 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