solargraph-rails 0.3.1 → 1.0.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- data/.github/workflows/ruby.yml +36 -0
- data/.gitignore +7 -0
- data/.solargraph.yml +19 -0
- data/CHANGELOG.md +15 -0
- data/DEVELOPMENT.md +83 -0
- data/lib/solargraph/rails/annotate.rb +44 -0
- data/lib/solargraph/rails/annotations.rb +50 -0
- data/lib/solargraph/rails/autoload.rb +53 -0
- data/lib/solargraph/rails/debug.rb +30 -0
- data/lib/solargraph/rails/delegate.rb +42 -0
- data/lib/solargraph/rails/devise.rb +48 -0
- data/lib/solargraph/rails/model.rb +100 -0
- data/lib/solargraph/rails/rails_api.rb +98 -0
- data/lib/solargraph/rails/schema.rb +100 -0
- data/lib/solargraph/rails/storage.rb +48 -0
- data/lib/solargraph/rails/types.yml +24 -0
- data/lib/solargraph/rails/util.rb +68 -0
- data/lib/solargraph/rails/version.rb +1 -1
- data/lib/solargraph/rails/walker.rb +89 -0
- data/lib/solargraph-rails.rb +57 -22
- data/script/generate_definitions.rb +134 -0
- data/solargraph-rails.gemspec +24 -22
- metadata +28 -17
- data/lib/solargraph/rails/files_loader.rb +0 -16
- data/lib/solargraph/rails/meta_source/association/belongs_to_matcher.rb +0 -24
- data/lib/solargraph/rails/meta_source/association/has_and_belongs_to_many_matcher.rb +0 -24
- data/lib/solargraph/rails/meta_source/association/has_many_matcher.rb +0 -24
- data/lib/solargraph/rails/meta_source/association/has_one_matcher.rb +0 -24
- data/lib/solargraph/rails/pin_creator.rb +0 -118
- data/lib/solargraph/rails/ruby_parser.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 134394397585a1df968b364e98d20b8e38a2fb6294833bfe8bbcfb81b13c545f
|
4
|
+
data.tar.gz: cb4e7fe2906a0769c95e8a3e7de08b6d0188b4dd8d509db2e001006e9367e6db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7acc8b51be9a665bcca385a67bcee5eed0ffd9e697c155bfab4e5e94dcd691cb4ccab4f04c09306166c99e9802e3276e9895374540d3df7b3c979c59be582d4
|
7
|
+
data.tar.gz: 4de5589904080422ed72fec8d76e4679a53df812f551c7e99d5d0e6fc7a6cabefe5256a6403dab04ae96e0fd79ec85c92f7a171502202afdb7403e30b266ee04
|
@@ -0,0 +1,33 @@
|
|
1
|
+
---
|
2
|
+
name: Bug report
|
3
|
+
about: Create a report to help us improve
|
4
|
+
title: ''
|
5
|
+
labels: ''
|
6
|
+
assignees: ''
|
7
|
+
|
8
|
+
---
|
9
|
+
|
10
|
+
**Describe the bug**
|
11
|
+
A clear and concise description of what the bug is.
|
12
|
+
|
13
|
+
**To Reproduce**
|
14
|
+
Steps to reproduce the behavior:
|
15
|
+
1. Go to '...'
|
16
|
+
2. Click on '....'
|
17
|
+
3. Scroll down to '....'
|
18
|
+
4. See error
|
19
|
+
|
20
|
+
**Expected behavior**
|
21
|
+
A clear and concise description of what you expected to happen.
|
22
|
+
|
23
|
+
**Screenshots**
|
24
|
+
If applicable, add screenshots to help explain your problem.
|
25
|
+
|
26
|
+
**Debug log**
|
27
|
+
|
28
|
+
Run the following command in the project you are having problems:
|
29
|
+
```
|
30
|
+
ruby -r'solargraph-rails' -e 'Solargraph::Rails::Debug.run()'
|
31
|
+
```
|
32
|
+
|
33
|
+
and paste the output here
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
workflow_dispatch: {}
|
12
|
+
pull_request:
|
13
|
+
branches: [master]
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
test:
|
17
|
+
runs-on: ubuntu-latest
|
18
|
+
strategy:
|
19
|
+
matrix:
|
20
|
+
ruby-version:
|
21
|
+
- "2.7"
|
22
|
+
- "3.0"
|
23
|
+
- "3.1"
|
24
|
+
|
25
|
+
steps:
|
26
|
+
- uses: actions/checkout@v2
|
27
|
+
- uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: ${{ matrix.ruby-version }}
|
30
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
31
|
+
- name: Install Rails 5 deps
|
32
|
+
run: (cd spec/rails5; bundle install; yard gems)
|
33
|
+
- name: Install Rails 6 deps
|
34
|
+
run: (cd spec/rails6; bundle install; yard gems)
|
35
|
+
- name: Run tests
|
36
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/.solargraph.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
include:
|
3
|
+
- "**/*.rb"
|
4
|
+
exclude:
|
5
|
+
- test/**/*
|
6
|
+
- vendor/**/*
|
7
|
+
- ".bundle/**/*"
|
8
|
+
require: []
|
9
|
+
domains: []
|
10
|
+
reporters: []
|
11
|
+
formatter:
|
12
|
+
rubocop:
|
13
|
+
cops: safe
|
14
|
+
except: []
|
15
|
+
only: []
|
16
|
+
extra_args: []
|
17
|
+
require_paths: []
|
18
|
+
plugins: []
|
19
|
+
max_files: 5000
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
## Changes
|
4
4
|
|
5
|
+
### v1.0.0.pre.1
|
6
|
+
|
7
|
+
https://github.com/alisnic/solargraph-arc was merged, with the following features:
|
8
|
+
- fixes autocompletion for multi-level classes defined in 1 line `class Foo::Bar::Baz`. See https://github.com/castwide/solargraph/issues/506
|
9
|
+
- autocomplete database columns by parsing db/schema.rb
|
10
|
+
- autocomplete of model relations
|
11
|
+
- parsing of `delegate` calls
|
12
|
+
- completions for methods generated by Devise
|
13
|
+
- better support for running solargraph outside bundle
|
14
|
+
- better completion inside controllers. `request`, `response`, `params`, etc.
|
15
|
+
- autocomplete inside routes.rb
|
16
|
+
- autocomplete inside migrations
|
17
|
+
- completions for methods generated by ActiveStorage
|
18
|
+
- better ActiveRecord completions
|
19
|
+
|
5
20
|
### v0.3.0
|
6
21
|
* Require String inflection monkeypatches directly to avoid error from ActiveSupport v7
|
7
22
|
* Remove Gemfile.lock from version control
|
data/DEVELOPMENT.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Solargraph-Rails development guide
|
2
|
+
|
3
|
+
## Contributing
|
4
|
+
|
5
|
+
1. create fork and clone the repo
|
6
|
+
2. install gem deps `bundle install`
|
7
|
+
3. install dummy rails5 app deps and build its yard cache
|
8
|
+
|
9
|
+
```
|
10
|
+
$ cd spec/rails5
|
11
|
+
$ bundle install && yard gems
|
12
|
+
$ cd ../../
|
13
|
+
```
|
14
|
+
|
15
|
+
3. install dummy rails6 app deps and build its yard cache
|
16
|
+
|
17
|
+
```
|
18
|
+
$ cd spec/rails6
|
19
|
+
$ bundle install && yard gems
|
20
|
+
$ cd ../../
|
21
|
+
```
|
22
|
+
4. now tests should pass locally and you can try different changes
|
23
|
+
5. sumbit PR
|
24
|
+
|
25
|
+
## Completion coverage tracking
|
26
|
+
|
27
|
+
Solargraph-Rails uses a [set of yaml files](https://github.com/iftheshoefritz/solargraph-rails/tree/master/spec/definitions) to track coverage of found completions.
|
28
|
+
Those yaml files are generated at runtime from a dummy [rails5](https://github.com/iftheshoefritz/solargraph-rails/tree/master/spec/rails5) or [rails6](https://github.com/iftheshoefritz/solargraph-rails/tree/master/spec/rails6) app.
|
29
|
+
|
30
|
+
The main goal is to catch any regressions in case of any change. In case a method completion is marked completed and it is not found in solargraph completions, the tests will fail.
|
31
|
+
|
32
|
+
### Checking coverage
|
33
|
+
|
34
|
+
To see what is completion coverage for solargraph-rails, run the tests with the `PRINT_STATS=true` environment variable:
|
35
|
+
|
36
|
+
```
|
37
|
+
$ PRINT_STATS=true bundle exec rspec
|
38
|
+
```
|
39
|
+
|
40
|
+
What you will see in test output is reported coverage for classes that are tracked:
|
41
|
+
|
42
|
+
```
|
43
|
+
{:class_name=>"ActiveRecord::Base", :total=>800, :covered=>321, :typed=>10, :percent_covered=>40.1, :percent_typed=>1.3}
|
44
|
+
provides completions for ActiveRecord::Base
|
45
|
+
```
|
46
|
+
|
47
|
+
### Updating assertions
|
48
|
+
|
49
|
+
In case an improvement is made, and more completions are found then being asserted, tests will throw a warning:
|
50
|
+
|
51
|
+
```
|
52
|
+
ActionDispatch::Routing::Mapper.try! is marked as skipped in spec/definitions/rails5/routes.yml, but is actually present.
|
53
|
+
Consider setting skip=false
|
54
|
+
provides completions for ActionDispatch::Routing::Mapper
|
55
|
+
```
|
56
|
+
|
57
|
+
In this case there are 2 options:
|
58
|
+
1. Manually updating yml file and setting `skip: false` for that method
|
59
|
+
2. Updating yml file in place by passing `update: true` to assertion:
|
60
|
+
|
61
|
+
```diff
|
62
|
+
assert_matches_definition(
|
63
|
+
map,
|
64
|
+
'ActionDispatch::Routing::Mapper',
|
65
|
+
'rails5/routes',
|
66
|
+
+ update: true
|
67
|
+
)
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
In case of option 2, don't forget to remove the flag after yml file has been updated. Also review git diff, to make sure that no regressions have been set (skip=true was set for entries which previously had skip=false)
|
72
|
+
|
73
|
+
### Generating assertions
|
74
|
+
|
75
|
+
In case a new set of assertion files has to be created (for a new Rails version for example), a script can be used - https://github.com/iftheshoefritz/solargraph-rails/blob/master/script/generate_definitions.rb.
|
76
|
+
|
77
|
+
All you have to do is to go to the same Rails app root, and execute the script:
|
78
|
+
|
79
|
+
```
|
80
|
+
ruby path/to/generate_definitions.rb
|
81
|
+
```
|
82
|
+
|
83
|
+
Make sure to review the script and uncomment relevant parts
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Rails
|
3
|
+
class Annotate
|
4
|
+
def self.instance
|
5
|
+
@instance ||= self.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.reset
|
9
|
+
@instance = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@schema_present = File.exist?('db/schema.rb')
|
14
|
+
end
|
15
|
+
|
16
|
+
def process(source_map, ns)
|
17
|
+
return [] if @schema_present
|
18
|
+
return [] unless source_map.filename.include?('app/models')
|
19
|
+
|
20
|
+
pins = []
|
21
|
+
walker = Walker.from_source(source_map.source)
|
22
|
+
walker.comments.each do |_, snip|
|
23
|
+
name, type = snip.text.gsub(/[\(\),:\d]/, '').split[1..2]
|
24
|
+
|
25
|
+
next unless name && type
|
26
|
+
|
27
|
+
ruby_type = Schema::RUBY_TYPES[type.to_sym]
|
28
|
+
next unless ruby_type
|
29
|
+
|
30
|
+
pins <<
|
31
|
+
Util.build_public_method(
|
32
|
+
ns,
|
33
|
+
name,
|
34
|
+
types: [ruby_type],
|
35
|
+
location:
|
36
|
+
Solargraph::Location.new(source_map.filename, snip.range)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
pins
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# The following comments fill some of the gaps in Solargraph's understanding of
|
2
|
+
# Rails apps. Since they're all in YARD, they get mapped in Solargraph but
|
3
|
+
# ignored at runtime.
|
4
|
+
#
|
5
|
+
# You can put this file anywhere in the project, as long as it gets included in
|
6
|
+
# the workspace maps. It's recommended that you keep it in a standalone file
|
7
|
+
# instead of pasting it into an existing one.
|
8
|
+
#
|
9
|
+
# @!parse
|
10
|
+
# class ActionController::Base
|
11
|
+
# include ActionController::MimeResponds
|
12
|
+
# include ActionController::Redirecting
|
13
|
+
# include ActionController::Cookies
|
14
|
+
# include AbstractController::Rendering
|
15
|
+
# extend ActiveSupport::Callbacks::ClassMethods
|
16
|
+
# extend ActiveSupport::Rescuable::ClassMethods
|
17
|
+
# extend AbstractController::Callbacks::ClassMethods
|
18
|
+
# extend ActionController::RequestForgeryProtection::ClassMethods
|
19
|
+
# end
|
20
|
+
# class ActionDispatch::Routing::Mapper
|
21
|
+
# include ActionDispatch::Routing::Mapper::Base
|
22
|
+
# include ActionDispatch::Routing::Mapper::HttpHelpers
|
23
|
+
# include ActionDispatch::Routing::Mapper::Redirection
|
24
|
+
# include ActionDispatch::Routing::Mapper::Scoping
|
25
|
+
# include ActionDispatch::Routing::Mapper::Concerns
|
26
|
+
# include ActionDispatch::Routing::Mapper::Resources
|
27
|
+
# include ActionDispatch::Routing::Mapper::CustomUrls
|
28
|
+
# end
|
29
|
+
# class Rails
|
30
|
+
# # @return [Rails::Application]
|
31
|
+
# def self.application; end
|
32
|
+
# end
|
33
|
+
# class Rails::Application
|
34
|
+
# # @return [ActionDispatch::Routing::RouteSet]
|
35
|
+
# def routes; end
|
36
|
+
# end
|
37
|
+
# class ActionDispatch::Routing::RouteSet
|
38
|
+
# # @yieldself [ActionDispatch::Routing::Mapper]
|
39
|
+
# def draw; end
|
40
|
+
# end
|
41
|
+
# class ActiveRecord::Base
|
42
|
+
# extend ActiveRecord::QueryMethods
|
43
|
+
# extend ActiveRecord::FinderMethods
|
44
|
+
# extend ActiveRecord::Associations::ClassMethods
|
45
|
+
# extend ActiveRecord::Inheritance::ClassMethods
|
46
|
+
# extend ActiveRecord::ModelSchema::ClassMethods
|
47
|
+
# extend ActiveRecord::Transactions::ClassMethods
|
48
|
+
# extend ActiveRecord::Scoping::Named::ClassMethods
|
49
|
+
# include ActiveRecord::Persistence
|
50
|
+
# end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Rails
|
3
|
+
class Autoload
|
4
|
+
def self.instance
|
5
|
+
@instance ||= self.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def process(source_map, ns, ds)
|
9
|
+
return [] unless ds.size == 1 && ns.path.include?('::')
|
10
|
+
Solargraph.logger.debug(
|
11
|
+
"[Rails][Autoload] seeding class tree for #{ns.path}"
|
12
|
+
)
|
13
|
+
|
14
|
+
root_ns = source_map.pins.find { |p| p.path == '' }
|
15
|
+
namespace_stubs(root_ns, ns)
|
16
|
+
end
|
17
|
+
|
18
|
+
def namespace_stubs(root_ns, ns)
|
19
|
+
parts = ns.path.split('::')
|
20
|
+
|
21
|
+
candidates =
|
22
|
+
parts
|
23
|
+
.each_with_index
|
24
|
+
.reduce([]) { |acc, (_, i)| acc + [parts[0..i].join('::')] }
|
25
|
+
.reject { |el| el == ns.path }
|
26
|
+
|
27
|
+
previous_ns = root_ns
|
28
|
+
pins = []
|
29
|
+
|
30
|
+
parts[0..-2].each_with_index do |name, i|
|
31
|
+
gates = candidates[0..i].reverse + ['']
|
32
|
+
path = gates.first
|
33
|
+
next if path == ns.path
|
34
|
+
|
35
|
+
previous_ns =
|
36
|
+
Solargraph::Pin::Namespace.new(
|
37
|
+
type: :class,
|
38
|
+
location: ns.location,
|
39
|
+
closure: previous_ns,
|
40
|
+
name: name,
|
41
|
+
comments: ns.comments,
|
42
|
+
visibility: :public,
|
43
|
+
gates: gates[1..-1]
|
44
|
+
)
|
45
|
+
|
46
|
+
pins << previous_ns
|
47
|
+
end
|
48
|
+
|
49
|
+
pins
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Rails
|
3
|
+
class Debug
|
4
|
+
def self.run(query = nil)
|
5
|
+
self.new.run(query)
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(query)
|
9
|
+
Solargraph.logger.level = Logger::DEBUG
|
10
|
+
|
11
|
+
api_map = Solargraph::ApiMap.load('./')
|
12
|
+
|
13
|
+
puts "Ruby version: #{RUBY_VERSION}"
|
14
|
+
puts "Solargraph version: #{Solargraph::VERSION}"
|
15
|
+
puts "Solargraph Rails version: #{Solargraph::Rails::VERSION}"
|
16
|
+
|
17
|
+
return unless query
|
18
|
+
|
19
|
+
puts "Known methods for #{query}"
|
20
|
+
|
21
|
+
pin = api_map.pins.find { |p| p.path == query }
|
22
|
+
return unless pin
|
23
|
+
|
24
|
+
api_map
|
25
|
+
.get_complex_type_methods(pin.return_type)
|
26
|
+
.each { |pin| puts "- #{pin.path}" }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Rails
|
3
|
+
class Delegate
|
4
|
+
def self.instance
|
5
|
+
@instance ||= self.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def process(source_map, ns)
|
9
|
+
return [] unless source_map.code.include?('delegate')
|
10
|
+
|
11
|
+
walker = Walker.from_source(source_map.source)
|
12
|
+
pins = []
|
13
|
+
|
14
|
+
walker.on :send, [nil, :delegate] do |ast|
|
15
|
+
methods =
|
16
|
+
ast.children[2..-1]
|
17
|
+
.map { |c| c.children.first }
|
18
|
+
.select { |s| s.is_a?(Symbol) }
|
19
|
+
|
20
|
+
methods.each do |meth|
|
21
|
+
pins <<
|
22
|
+
Util.build_public_method(
|
23
|
+
ns,
|
24
|
+
meth.to_s,
|
25
|
+
location: Util.build_location(ast, ns.filename)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
walker.walk
|
31
|
+
|
32
|
+
if pins.any?
|
33
|
+
Solargraph.logger.debug(
|
34
|
+
"[Rails][Delegate] added #{pins.map(&:name)} to #{ns.path}"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
pins
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Rails
|
3
|
+
class Devise
|
4
|
+
def self.instance
|
5
|
+
@instance ||= self.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def process(source_map, ns)
|
9
|
+
if source_map.filename.include?('app/models')
|
10
|
+
process_model(source_map.source, ns)
|
11
|
+
else
|
12
|
+
[]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def process_model(source, ns)
|
19
|
+
walker = Walker.from_source(source)
|
20
|
+
pins = []
|
21
|
+
|
22
|
+
walker.on :send, [nil, :devise] do |ast|
|
23
|
+
modules =
|
24
|
+
ast.children[2..-1]
|
25
|
+
.map { |c| c.children.first }
|
26
|
+
.select { |s| s.is_a?(Symbol) }
|
27
|
+
|
28
|
+
modules.each do |mod|
|
29
|
+
pins <<
|
30
|
+
Util.build_module_include(
|
31
|
+
ns,
|
32
|
+
"Devise::Models::#{mod.to_s.capitalize}",
|
33
|
+
Util.build_location(ast, ns.filename)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
walker.walk
|
39
|
+
if pins.any?
|
40
|
+
Solargraph.logger.debug(
|
41
|
+
"[Rails][Devise] added #{pins.map(&:name)} to #{ns.path}"
|
42
|
+
)
|
43
|
+
end
|
44
|
+
pins
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Rails
|
3
|
+
class Model
|
4
|
+
def self.instance
|
5
|
+
@instance ||= self.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def process(source_map, ns)
|
9
|
+
return [] unless source_map.filename.include?('app/models')
|
10
|
+
|
11
|
+
walker = Walker.from_source(source_map.source)
|
12
|
+
pins = []
|
13
|
+
|
14
|
+
walker.on :send, [nil, :belongs_to] do |ast|
|
15
|
+
pins << singular_association(ns, ast)
|
16
|
+
end
|
17
|
+
|
18
|
+
walker.on :send, [nil, :has_one] do |ast|
|
19
|
+
pins << singular_association(ns, ast)
|
20
|
+
end
|
21
|
+
|
22
|
+
walker.on :send, [nil, :has_many] do |ast|
|
23
|
+
pins << plural_association(ns, ast)
|
24
|
+
end
|
25
|
+
|
26
|
+
walker.on :send, [nil, :has_and_belongs_to_many] do |ast|
|
27
|
+
pins << plural_association(ns, ast)
|
28
|
+
end
|
29
|
+
|
30
|
+
walker.on :send, [nil, :scope] do |ast|
|
31
|
+
name = ast.children[2].children.last
|
32
|
+
|
33
|
+
method_pin =
|
34
|
+
Util.build_public_method(
|
35
|
+
ns,
|
36
|
+
name.to_s,
|
37
|
+
types: ns.return_type.map(&:tag),
|
38
|
+
scope: :class,
|
39
|
+
location: Util.build_location(ast, ns.filename)
|
40
|
+
)
|
41
|
+
|
42
|
+
if ast.children.last.type == :block
|
43
|
+
location = ast.children.last.location
|
44
|
+
block_pin =
|
45
|
+
source_map.locate_block_pin(location.line, location.column)
|
46
|
+
method_pin.parameters.concat(block_pin.parameters.clone)
|
47
|
+
end
|
48
|
+
pins << method_pin
|
49
|
+
end
|
50
|
+
|
51
|
+
walker.walk
|
52
|
+
if pins.any?
|
53
|
+
Solargraph.logger.debug(
|
54
|
+
"[Rails][Model] added #{pins.map(&:name)} to #{ns.path}"
|
55
|
+
)
|
56
|
+
end
|
57
|
+
pins
|
58
|
+
end
|
59
|
+
|
60
|
+
def plural_association(ns, ast)
|
61
|
+
relation_name = ast.children[2].children.first
|
62
|
+
class_name =
|
63
|
+
extract_custom_class_name(ast) ||
|
64
|
+
relation_name.to_s.singularize.camelize
|
65
|
+
|
66
|
+
Util.build_public_method(
|
67
|
+
ns,
|
68
|
+
relation_name.to_s,
|
69
|
+
types: ["ActiveRecord::Associations::CollectionProxy<#{class_name}>"],
|
70
|
+
location: Util.build_location(ast, ns.filename)
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def singular_association(ns, ast)
|
75
|
+
relation_name = ast.children[2].children.first
|
76
|
+
class_name =
|
77
|
+
extract_custom_class_name(ast) || relation_name.to_s.camelize
|
78
|
+
|
79
|
+
Util.build_public_method(
|
80
|
+
ns,
|
81
|
+
relation_name.to_s,
|
82
|
+
types: [class_name],
|
83
|
+
location: Util.build_location(ast, ns.filename)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def extract_custom_class_name(ast)
|
88
|
+
options = ast.children[3..-1].find { |n| n.type == :hash }
|
89
|
+
return unless options
|
90
|
+
|
91
|
+
class_name_pair =
|
92
|
+
options.children.find do |n|
|
93
|
+
n.children[0].deconstruct == %i[sym class_name] &&
|
94
|
+
n.children[1].type == :str
|
95
|
+
end
|
96
|
+
class_name_pair && class_name_pair.children.last.children.last
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module Rails
|
3
|
+
class RailsApi
|
4
|
+
def self.instance
|
5
|
+
@instance ||= self.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def global(yard_map)
|
9
|
+
return [] if yard_map.required.empty?
|
10
|
+
|
11
|
+
ann = File.read(File.dirname(__FILE__) + '/annotations.rb')
|
12
|
+
source = Solargraph::Source.load_string(ann, 'annotations.rb')
|
13
|
+
map = Solargraph::SourceMap.map(source)
|
14
|
+
|
15
|
+
Solargraph.logger.debug(
|
16
|
+
"[Rails][Rails] found #{map.pins.size} pins in annotations"
|
17
|
+
)
|
18
|
+
|
19
|
+
overrides =
|
20
|
+
YAML
|
21
|
+
.load_file(File.dirname(__FILE__) + '/types.yml')
|
22
|
+
.map do |meth, data|
|
23
|
+
if data['return']
|
24
|
+
Util.method_return(meth, data['return'])
|
25
|
+
elsif data['yieldself']
|
26
|
+
Solargraph::Pin::Reference::Override.from_comment(
|
27
|
+
meth,
|
28
|
+
"@yieldself [#{data['yieldself'].join(',')}]"
|
29
|
+
)
|
30
|
+
elsif data['yieldparam']
|
31
|
+
Solargraph::Pin::Reference::Override.from_comment(
|
32
|
+
meth,
|
33
|
+
"@yieldparam [#{data['yieldparam'].join(',')}]"
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
ns =
|
39
|
+
Solargraph::Pin::Namespace.new(
|
40
|
+
name: 'ActionController::Base',
|
41
|
+
gates: ['ActionController::Base']
|
42
|
+
)
|
43
|
+
|
44
|
+
definitions = [
|
45
|
+
Util.build_public_method(
|
46
|
+
ns,
|
47
|
+
'response',
|
48
|
+
types: ['ActionDispatch::Response'],
|
49
|
+
location: Util.dummy_location('whatever.rb')
|
50
|
+
),
|
51
|
+
Util.build_public_method(
|
52
|
+
ns,
|
53
|
+
'request',
|
54
|
+
types: ['ActionDispatch::Request'],
|
55
|
+
location: Util.dummy_location('whatever.rb')
|
56
|
+
),
|
57
|
+
Util.build_public_method(
|
58
|
+
ns,
|
59
|
+
'session',
|
60
|
+
types: ['ActionDispatch::Request::Session'],
|
61
|
+
location: Util.dummy_location('whatever.rb')
|
62
|
+
),
|
63
|
+
Util.build_public_method(
|
64
|
+
ns,
|
65
|
+
'flash',
|
66
|
+
types: ['ActionDispatch::Flash::FlashHash'],
|
67
|
+
location: Util.dummy_location('whatever.rb')
|
68
|
+
)
|
69
|
+
]
|
70
|
+
|
71
|
+
map.pins + definitions + overrides
|
72
|
+
end
|
73
|
+
|
74
|
+
def local(source_map, ns)
|
75
|
+
return [] unless source_map.filename.include?('db/migrate')
|
76
|
+
node, _ = Walker.normalize_ast(source_map.source)
|
77
|
+
|
78
|
+
pins = [
|
79
|
+
Util.build_module_include(
|
80
|
+
ns,
|
81
|
+
'ActiveRecord::ConnectionAdapters::SchemaStatements',
|
82
|
+
Util.build_location(node, ns.filename)
|
83
|
+
),
|
84
|
+
Util.build_module_extend(
|
85
|
+
ns,
|
86
|
+
'ActiveRecord::ConnectionAdapters::SchemaStatements',
|
87
|
+
Util.build_location(node, ns.filename)
|
88
|
+
)
|
89
|
+
]
|
90
|
+
|
91
|
+
Solargraph.logger.debug(
|
92
|
+
"[Rails][RailsApi] added #{pins.map(&:name)} to #{ns.path}"
|
93
|
+
)
|
94
|
+
pins
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|