chusaku 0.1.3 → 0.3.2
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/.codeclimate.yml +4 -0
- data/.rubocop.yml +13 -19
- data/README.md +42 -11
- data/bin/chusaku +3 -6
- data/chusaku.gemspec +4 -3
- data/lib/chusaku.rb +110 -69
- data/lib/chusaku/cli.rb +120 -0
- data/lib/chusaku/parser.rb +35 -22
- data/lib/chusaku/routes.rb +88 -47
- data/lib/chusaku/version.rb +1 -1
- metadata +31 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2976318f89e26e31f77c54e1cc338812ac6a107ec033d53c077fd4eb1759be6
|
4
|
+
data.tar.gz: 8413d9353d6115929985f3d6275396abeb25d7b9df834ccd0d4e19fd834ef574
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44c12d0f6c0f970cd3a0e5c76cd14b18d8bfbf16f7d39e8789e4c09c87a8273a8b3e288de865533c7a39b81fe1dd51088a1ddc7c33edb0325e12a676153d5563
|
7
|
+
data.tar.gz: 5e01aeaa4eea9099c47445c88db326ff4ceb5d028088bbd6c2a328f21673c17d80c93bc8fda0c4135e76956f1439a26df758985a23bfe895d5f3f2ff14eb3982
|
data/.codeclimate.yml
ADDED
data/.rubocop.yml
CHANGED
@@ -1,27 +1,21 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
3
|
+
|
1
4
|
AllCops:
|
2
5
|
Exclude:
|
3
6
|
- 'bin/**/*'
|
4
|
-
|
5
|
-
|
6
|
-
EnforcedStyle: rails
|
7
|
+
- 'test/mock/app/**/*'
|
8
|
+
- 'test/mock/examples/**/*'
|
7
9
|
|
8
10
|
Metrics/AbcSize:
|
9
|
-
|
11
|
+
Exclude:
|
12
|
+
- 'test/**/*'
|
10
13
|
|
11
14
|
Metrics/MethodLength:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Enabled: false
|
16
|
-
|
17
|
-
Style/ClassVars:
|
18
|
-
Enabled: false
|
19
|
-
|
20
|
-
Style/CommentedKeyword:
|
21
|
-
Enabled: false
|
22
|
-
|
23
|
-
Style/Documentation:
|
24
|
-
Enabled: false
|
15
|
+
Max: 25
|
16
|
+
Exclude:
|
17
|
+
- 'test/**/*'
|
25
18
|
|
26
|
-
Style/
|
27
|
-
|
19
|
+
Style/ClassAndModuleChildren:
|
20
|
+
Exclude:
|
21
|
+
- 'test/**/*'
|
data/README.md
CHANGED
@@ -1,16 +1,22 @@
|
|
1
1
|
# Chusaku
|
2
2
|
|
3
|
-
|
|
4
|
-
|
5
|
-
|[](https://circleci.com/gh/nshki/chusaku)|[](https://badge.fury.io/rb/chusaku)|[](https://circleci.com/gh/nshki/chusaku)|[](https://codeclimate.com/github/nshki/chusaku/maintainability)
|
6
6
|
|
7
7
|
Add comments above your Rails actions that look like:
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
# @route
|
10
|
+
# @route GET /waterlilies/:id (waterlily)
|
11
11
|
def show
|
12
12
|
# ...
|
13
13
|
end
|
14
|
+
|
15
|
+
# @route PATCH /waterlilies/:id (waterlily)
|
16
|
+
# @route PUT /waterlilies/:id (waterlily)
|
17
|
+
def update
|
18
|
+
# ...
|
19
|
+
end
|
14
20
|
```
|
15
21
|
|
16
22
|
Based on your `routes.rb` file!
|
@@ -43,19 +49,44 @@ From the root of your Rails application, run:
|
|
43
49
|
$ bundle exec chusaku
|
44
50
|
```
|
45
51
|
|
52
|
+
Chusaku has some flags available for use as well:
|
53
|
+
|
54
|
+
```
|
55
|
+
$ bundle exec chusaku --help
|
56
|
+
Usage: chusaku [options]
|
57
|
+
--exit-with-error-on-annotation
|
58
|
+
Fail if any file was annotated
|
59
|
+
--dry-run Run without file modifications
|
60
|
+
-v, --version Show Chusaku version number and quit
|
61
|
+
-h, --help Show this help message and quit
|
62
|
+
```
|
46
63
|
|
47
|
-
## Development
|
48
64
|
|
49
|
-
|
65
|
+
## Pre-commit Hook
|
50
66
|
|
51
|
-
|
67
|
+
Here's an example setup that you could use for automating Chusaku as a Git hook
|
68
|
+
with the [Lefthook](https://github.com/Arkweid/lefthook) gem.
|
52
69
|
|
70
|
+
```yaml
|
71
|
+
pre-commit:
|
72
|
+
commands:
|
73
|
+
chusaku:
|
74
|
+
run: eval "! git diff --staged --name-only | grep -q 'routes.rb' && exit 0 || bundle exec chusaku --exit-with-error-on-annotation"
|
75
|
+
```
|
53
76
|
|
54
|
-
|
77
|
+
This example config only runs Chusaku if `routes.rb` was modified.
|
55
78
|
|
56
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/nshki/chusaku.
|
57
79
|
|
80
|
+
## Development
|
81
|
+
|
82
|
+
Read the blog post explaining how the gem works at a high level:
|
83
|
+
https://nshki.com/chusaku-a-controller-annotation-gem/.
|
58
84
|
|
59
|
-
|
85
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
86
|
+
`bundle exec rake test` to run the tests. You can also run `bin/console` for an
|
87
|
+
interactive prompt that will allow you to experiment.
|
60
88
|
|
61
|
-
|
89
|
+
To release a new version, update the version number in `version.rb`, and then
|
90
|
+
run `bundle exec rake release`, which will create a git tag for the version,
|
91
|
+
git commits and tags, and push the `.gem` file to
|
92
|
+
[rubygems.org](https://rubygems.org).
|
data/bin/chusaku
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
unless File.directory?('./app/controllers') && File.exist?('./Rakefile')
|
4
|
-
abort 'Please run chusaku from the root of your project.'
|
5
|
-
end
|
6
|
-
|
7
3
|
require 'rubygems'
|
8
4
|
|
9
5
|
begin
|
@@ -18,5 +14,6 @@ begin
|
|
18
14
|
rescue StandardError
|
19
15
|
end
|
20
16
|
|
21
|
-
require 'chusaku'
|
22
|
-
|
17
|
+
require 'chusaku/cli'
|
18
|
+
|
19
|
+
exit Chusaku::CLI.new.call
|
data/chusaku.gemspec
CHANGED
@@ -43,8 +43,9 @@ Gem::Specification.new do |spec|
|
|
43
43
|
|
44
44
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
45
45
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
46
|
-
spec.add_development_dependency 'rake', '~>
|
46
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
47
|
+
spec.add_development_dependency 'rubocop', '~> 0.77'
|
48
|
+
spec.add_development_dependency 'rubocop-performance', '~> 1.5'
|
47
49
|
|
48
|
-
spec.add_dependency 'rails', '>
|
49
|
-
spec.add_dependency 'ruby-progressbar', '~> 1.10.1'
|
50
|
+
spec.add_dependency 'rails', '> 2.0'
|
50
51
|
end
|
data/lib/chusaku.rb
CHANGED
@@ -1,89 +1,130 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'ruby-progressbar'
|
4
3
|
require 'chusaku/version'
|
5
4
|
require 'chusaku/parser'
|
6
5
|
require 'chusaku/routes'
|
7
6
|
|
7
|
+
# Handles core functionality of annotating projects.
|
8
8
|
module Chusaku
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
parsed_file.each_cons(2) do |prev, curr|
|
37
|
-
# Remove all @route comments in the previous group.
|
38
|
-
if prev[:type] == :comment
|
39
|
-
prev[:body] = prev[:body].gsub(/^\s*#\s*@route.*$\n/, '')
|
40
|
-
end
|
9
|
+
class << self
|
10
|
+
# The main method to run Chusaku. Annotate all actions in a Rails project as
|
11
|
+
# follows:
|
12
|
+
#
|
13
|
+
# # @route GET /waterlilies/:id (waterlilies)
|
14
|
+
# def show
|
15
|
+
# # ...
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# @param {Hash} flags - CLI flags
|
19
|
+
# @return {Integer} - 0 on success, 1 on error
|
20
|
+
def call(flags = {})
|
21
|
+
@flags = flags
|
22
|
+
@routes = Chusaku::Routes.call
|
23
|
+
@annotated_paths = []
|
24
|
+
controllers_pattern = 'app/controllers/**/*_controller.rb'
|
25
|
+
|
26
|
+
Dir.glob(Rails.root.join(controllers_pattern)).each do |path|
|
27
|
+
controller = %r{controllers\/(.*)_controller\.rb}.match(path)[1]
|
28
|
+
actions = @routes[controller]
|
29
|
+
next if actions.nil?
|
30
|
+
|
31
|
+
annotate_file(path: path, controller: controller, actions: actions.keys)
|
32
|
+
end
|
33
|
+
|
34
|
+
output_results
|
35
|
+
end
|
41
36
|
|
42
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
# Adds annotations to the given file.
|
40
|
+
#
|
41
|
+
# @param {String} path - Path to file
|
42
|
+
# @param {String} controller - Controller name
|
43
|
+
# @param {Array<String>} actions - List of valid actions for the controller
|
44
|
+
# @return {void}
|
45
|
+
def annotate_file(path:, controller:, actions:)
|
46
|
+
parsed_file = Chusaku::Parser.call(path: path, actions: actions)
|
47
|
+
parsed_file[:groups].each_cons(2) do |prev, curr|
|
48
|
+
clean_group(prev)
|
43
49
|
next unless curr[:type] == :action
|
44
50
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
51
|
+
route_data = @routes[controller][curr[:action]]
|
52
|
+
next unless route_data.any?
|
53
|
+
|
54
|
+
annotate_group(group: curr, route_data: route_data)
|
55
|
+
end
|
56
|
+
|
57
|
+
write_to_file(path: path, parsed_file: parsed_file)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Given a parsed group, clean out its contents.
|
61
|
+
#
|
62
|
+
# @param {Hash} group - { type: Symbol, body: String }
|
63
|
+
# @return {void}
|
64
|
+
def clean_group(group)
|
65
|
+
return unless group[:type] == :comment
|
66
|
+
|
67
|
+
group[:body] = group[:body].gsub(/^\s*#\s*@route.*$\n/, '')
|
68
|
+
group[:body] =
|
69
|
+
group[:body].gsub(%r{^\s*# (GET|POST|PATCH\/PUT|DELETE) \/\S+$\n}, '')
|
70
|
+
end
|
71
|
+
|
72
|
+
# Add an annotation to the given group given by Chusaku::Parser that looks
|
73
|
+
# like:
|
74
|
+
#
|
75
|
+
# @route GET /waterlilies/:id (waterlilies)
|
76
|
+
#
|
77
|
+
# @param {Hash} group - Parsed content given by Chusaku::Parser
|
78
|
+
# @param {Hash} route_data - Individual route data given by Chusaku::Routes
|
79
|
+
# @return {void}
|
80
|
+
def annotate_group(group:, route_data:)
|
81
|
+
whitespace = /^(\s*).*$/.match(group[:body])[1]
|
82
|
+
route_data.reverse_each do |datum|
|
83
|
+
name = datum[:name]
|
84
|
+
annotation = "@route #{datum[:verb]} #{datum[:path]}"
|
85
|
+
annotation += " (#{name})" unless name.nil?
|
49
86
|
comment = "#{whitespace}# #{annotation}\n"
|
50
|
-
|
87
|
+
group[:body] = comment + group[:body]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Write annotated content to a file if it differs from the original.
|
92
|
+
#
|
93
|
+
# @param {String} path - File path to write to
|
94
|
+
# @param {Hash} parsed_file - Hash mutated by `annotate_group`
|
95
|
+
# @return {void}
|
96
|
+
def write_to_file(path:, parsed_file:)
|
97
|
+
content = parsed_file[:groups].map { |pf| pf[:body] }.join
|
98
|
+
return unless parsed_file[:content] != content
|
99
|
+
|
100
|
+
unless @flags.include?(:dry)
|
101
|
+
# When running the test suite, we want to make sure we're not
|
102
|
+
# overwriting any files. `r` mode ensures that.
|
103
|
+
mode = File.instance_methods.include?(:test_write) ? 'r' : 'w'
|
104
|
+
|
105
|
+
File.open(path, mode) do |file|
|
106
|
+
if file.respond_to?(:test_write)
|
107
|
+
file.test_write(content, path)
|
108
|
+
else
|
109
|
+
file.write(content)
|
110
|
+
end
|
111
|
+
end
|
51
112
|
end
|
52
113
|
|
53
|
-
|
54
|
-
parsed_content = parsed_file.map { |pf| pf[:body] }
|
55
|
-
write(path, parsed_content.join)
|
114
|
+
@annotated_paths.push(path)
|
56
115
|
end
|
57
|
-
end
|
58
116
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
File.open(path, 'r+') do |file|
|
67
|
-
if file.respond_to?(:test_write)
|
68
|
-
file.test_write(content, path)
|
117
|
+
# Output results to user.
|
118
|
+
#
|
119
|
+
# @return {Integer} - 0 for success, 1 for error
|
120
|
+
def output_results
|
121
|
+
if @annotated_paths.any?
|
122
|
+
puts("Annotated #{@annotated_paths.join(', ')}")
|
123
|
+
@flags.include?(:error_on_annotation) ? 1 : 0
|
69
124
|
else
|
70
|
-
|
125
|
+
puts('Nothing to annotate')
|
126
|
+
0
|
71
127
|
end
|
72
128
|
end
|
73
129
|
end
|
74
|
-
|
75
|
-
# Given a hash describing an action, generate an annotation in the form:
|
76
|
-
#
|
77
|
-
# @route [GET] /waterlilies/:id (waterlilies)
|
78
|
-
#
|
79
|
-
# @param {Hash} action_info
|
80
|
-
# @return {String}
|
81
|
-
def self.annotate(action_info)
|
82
|
-
verbs = action_info[:verbs]
|
83
|
-
path = action_info[:path]
|
84
|
-
name = action_info[:name]
|
85
|
-
annotation = "@route [#{verbs.join(', ')}] #{path}"
|
86
|
-
annotation += " (#{name})" unless name.nil?
|
87
|
-
annotation
|
88
|
-
end
|
89
130
|
end
|
data/lib/chusaku/cli.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'chusaku'
|
5
|
+
|
6
|
+
module Chusaku
|
7
|
+
# Enables flags for the `chusaku` executable.
|
8
|
+
class CLI
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
STATUS_SUCCESS = 0
|
12
|
+
STATUS_ERROR = 1
|
13
|
+
|
14
|
+
Finished = Class.new(RuntimeError)
|
15
|
+
NotARailsProject = Class.new(RuntimeError)
|
16
|
+
|
17
|
+
# Initializes a new instance of Chusaku::CLI.
|
18
|
+
#
|
19
|
+
# @return {Chusaku::CLI} - Instance of this class
|
20
|
+
def initialize
|
21
|
+
@options = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse CLI flags, if any, and handle applicable behaviors.
|
25
|
+
#
|
26
|
+
# @param {Array<String>} args - CLI arguments
|
27
|
+
# @return {Integer} - 0 on success, 1 on error
|
28
|
+
def call(args = ARGV)
|
29
|
+
optparser.parse!(args)
|
30
|
+
check_for_rails_project
|
31
|
+
Chusaku.call(options)
|
32
|
+
rescue NotARailsProject
|
33
|
+
warn('Please run chusaku from the root of your project.')
|
34
|
+
STATUS_ERROR
|
35
|
+
rescue Finished
|
36
|
+
STATUS_SUCCESS
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Raises exception if Rails project cannot be detected.
|
42
|
+
#
|
43
|
+
# @raise {Chusaku::CLI::NotARailsProject} - Exception if not Rails project
|
44
|
+
# @return {void}
|
45
|
+
def check_for_rails_project
|
46
|
+
has_controllers = File.directory?('./app/controllers')
|
47
|
+
has_rakefile = File.exist?('./Rakefile')
|
48
|
+
raise NotARailsProject unless has_controllers && has_rakefile
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns an instance of OptionParser with supported flags.
|
52
|
+
#
|
53
|
+
# @return {OptionParser} - Preconfigured OptionParser instance
|
54
|
+
def optparser
|
55
|
+
OptionParser.new do |opts|
|
56
|
+
opts.banner = 'Usage: chusaku [options]'
|
57
|
+
add_error_on_annotation_flag(opts)
|
58
|
+
add_dry_run_flag(opts)
|
59
|
+
add_version_flag(opts)
|
60
|
+
add_help_flag(opts)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Adds `--exit-with-error-on-annotation` flag.
|
65
|
+
#
|
66
|
+
# @param {OptionParser} opts - OptionParser instance
|
67
|
+
# @return {void}
|
68
|
+
def add_error_on_annotation_flag(opts)
|
69
|
+
opts.on(
|
70
|
+
'--exit-with-error-on-annotation',
|
71
|
+
'Fail if any file was annotated'
|
72
|
+
) do
|
73
|
+
@options[:error_on_annotation] = true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Adds `--dry-run` flag.
|
78
|
+
#
|
79
|
+
# @param {OptionParser} opts - OptionParser instance
|
80
|
+
# @return {void}
|
81
|
+
def add_dry_run_flag(opts)
|
82
|
+
opts.on(
|
83
|
+
'--dry-run',
|
84
|
+
'Run without file modifications'
|
85
|
+
) do
|
86
|
+
@options[:dry] = true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Adds `--version` flag.
|
91
|
+
#
|
92
|
+
# @param {OptionParser} opts - OptionParser instance
|
93
|
+
# @return {void}
|
94
|
+
def add_version_flag(opts)
|
95
|
+
opts.on(
|
96
|
+
'-v',
|
97
|
+
'--version',
|
98
|
+
'Show Chusaku version number and quit'
|
99
|
+
) do
|
100
|
+
puts(Chusaku::VERSION)
|
101
|
+
raise Finished
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Adds `--help` flag.
|
106
|
+
#
|
107
|
+
# @param {OptionParser} opts - OptionParser instance
|
108
|
+
# @return {void}
|
109
|
+
def add_help_flag(opts)
|
110
|
+
opts.on(
|
111
|
+
'-h',
|
112
|
+
'--help',
|
113
|
+
'Show this help message and quit'
|
114
|
+
) do
|
115
|
+
puts(opts)
|
116
|
+
raise Finished
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/chusaku/parser.rb
CHANGED
@@ -1,32 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Chusaku
|
4
|
+
# Handles parsing a file and groups its lines into categories.
|
4
5
|
module Parser
|
5
|
-
# Parses a file and groups its lines into categories:
|
6
|
-
#
|
7
6
|
# Example output:
|
8
7
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
8
|
+
# {
|
9
|
+
# content: <Original file content>,
|
10
|
+
# groups: [
|
11
|
+
# {
|
12
|
+
# type: :code,
|
13
|
+
# body: 'class Foo\n',
|
14
|
+
# action: nil
|
15
|
+
# },
|
16
|
+
# {
|
17
|
+
# type: :comment,
|
18
|
+
# body: ' # Bar\n # Baz\n',
|
19
|
+
# action: nil
|
20
|
+
# },
|
21
|
+
# {
|
22
|
+
# type: :action,
|
23
|
+
# body: ' def action_name; end\n',
|
24
|
+
# action: 'action_name'
|
25
|
+
# }
|
26
|
+
# {
|
27
|
+
# type: :code,
|
28
|
+
# body: 'end # vanilla is the best flavor\n',
|
29
|
+
# action: nil
|
30
|
+
# }
|
31
|
+
# ]
|
32
|
+
# }
|
21
33
|
#
|
22
|
-
# @param {String} path
|
23
|
-
# @param {Array<String>} actions
|
24
|
-
# @return {Array<Hash>}
|
34
|
+
# @param {String} path - File path to parse
|
35
|
+
# @param {Array<String>} actions - List of valid actions for this route
|
36
|
+
# @return {Hash} - { content: String, groups: Array<Hash> }
|
25
37
|
def self.call(path:, actions:)
|
26
38
|
groups = []
|
27
39
|
group = {}
|
40
|
+
content = IO.read(path)
|
28
41
|
|
29
|
-
|
42
|
+
content.each_line do |line|
|
30
43
|
parsed_line = parse_line(line: line, actions: actions)
|
31
44
|
|
32
45
|
if group[:type] != parsed_line[:type]
|
@@ -42,7 +55,7 @@ module Chusaku
|
|
42
55
|
|
43
56
|
# Push the last group onto the array and return.
|
44
57
|
groups.push(group)
|
45
|
-
groups
|
58
|
+
{ content: content, groups: groups }
|
46
59
|
end
|
47
60
|
|
48
61
|
# Given a line and actions, returns the line's type:
|
@@ -56,9 +69,9 @@ module Chusaku
|
|
56
69
|
#
|
57
70
|
# { type: :action, body: 'def foo', action: 'foo' }
|
58
71
|
#
|
59
|
-
# @param {String} line
|
60
|
-
# @param {Array<String>} actions
|
61
|
-
# @return {Hash}
|
72
|
+
# @param {String} line - A line of a file
|
73
|
+
# @param {Array<String>} actions - List of valid actions for this route
|
74
|
+
# @return {Hash} - { type: Symbol, body: String, action: String }
|
62
75
|
def self.parse_line(line:, actions:)
|
63
76
|
comment_match = /^\s*#.*$/.match(line)
|
64
77
|
def_match = /^\s*def\s+(\w*)\s*\w*.*$/.match(line)
|
data/lib/chusaku/routes.rb
CHANGED
@@ -1,65 +1,106 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Chusaku
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# }
|
30
|
-
#
|
31
|
-
# @return {Hash}
|
32
|
-
def self.call
|
33
|
-
routes = {}
|
4
|
+
# Handles extracting information about the Rails project's routes.
|
5
|
+
class Routes
|
6
|
+
class << self
|
7
|
+
# Example output:
|
8
|
+
#
|
9
|
+
# {
|
10
|
+
# 'users' => {
|
11
|
+
# 'edit' => [
|
12
|
+
# { verb: 'GET', path: '/users/:id', name: 'edit_user' }
|
13
|
+
# ],
|
14
|
+
# 'update' => [
|
15
|
+
# { verb: 'PATCH', path: '/users', name: 'edit_user' },
|
16
|
+
# { verb: 'PUT', path: '/users', name: 'edit_user' }
|
17
|
+
# ]
|
18
|
+
# },
|
19
|
+
# 'empanadas' => {
|
20
|
+
# 'create' => [
|
21
|
+
# { verb: 'POST', path: '/empanadas', name: nil }
|
22
|
+
# ]
|
23
|
+
# }
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# @return {Hash} - Routes hash
|
27
|
+
def call
|
28
|
+
routes = {}
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
Rails.application.routes.routes.each do |route|
|
31
|
+
controller, action = extract_controller_and_action_from(route)
|
32
|
+
routes[controller] ||= {}
|
33
|
+
routes[controller][action] ||= []
|
39
34
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
routes[controller][action][:verbs].push(route.verb)
|
35
|
+
verbs_for(route).each do |verb|
|
36
|
+
routes[controller][action].push(format(route: route, verb: verb))
|
37
|
+
routes[controller][action].uniq!
|
38
|
+
end
|
45
39
|
end
|
40
|
+
|
41
|
+
backfill_routes(routes)
|
46
42
|
end
|
47
43
|
|
48
|
-
|
49
|
-
end
|
44
|
+
private
|
50
45
|
|
51
|
-
|
46
|
+
# Extract the HTTP verbs for a Rails route. Required for older versions of
|
47
|
+
# Rails that return regular expressions for a route verb which sometimes
|
48
|
+
# contains multiple verbs.
|
49
|
+
#
|
50
|
+
# @param {ActionDispatch::Journey::Route} route - Route given by Rails
|
51
|
+
# @return {Array<String>} - List of HTTP verbs for the given route
|
52
|
+
def verbs_for(route)
|
53
|
+
route_verb = route.verb.to_s
|
54
|
+
|
55
|
+
['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].select do |verb|
|
56
|
+
route_verb.include?(verb)
|
57
|
+
end
|
58
|
+
end
|
52
59
|
|
53
|
-
#
|
60
|
+
# Formats information for a given route.
|
54
61
|
#
|
55
|
-
# @param {ActionDispatch::Journey::Route} route
|
56
|
-
# @
|
57
|
-
|
62
|
+
# @param {ActionDispatch::Journey::Route} route - Route given by Rails
|
63
|
+
# @param {String} verb - HTTP verb
|
64
|
+
# @return {Hash} - { verb: String, path: String, name: String }
|
65
|
+
def format(route:, verb:)
|
58
66
|
{
|
59
|
-
|
67
|
+
verb: verb,
|
60
68
|
path: route.path.spec.to_s.gsub('(.:format)', ''),
|
61
69
|
name: route.name
|
62
70
|
}
|
63
71
|
end
|
72
|
+
|
73
|
+
# Given a routes hash, backfill entries that aren't already filled by
|
74
|
+
# `Rails.application.routes`.
|
75
|
+
#
|
76
|
+
# @param {Hash} routes - Routes hash generated by this class
|
77
|
+
# @return {Hash} - Backfilled routes hash
|
78
|
+
def backfill_routes(routes)
|
79
|
+
paths = {}
|
80
|
+
|
81
|
+
routes.each do |_controller, actions|
|
82
|
+
actions.each do |_action, data|
|
83
|
+
data.each do |datum|
|
84
|
+
paths[datum[:path]] ||= datum[:name]
|
85
|
+
datum[:name] ||= paths[datum[:path]]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
routes
|
91
|
+
end
|
92
|
+
|
93
|
+
# Given a route, extract the controller and action strings.
|
94
|
+
#
|
95
|
+
# @param {ActionDispatch::Journey::Route} route - Route instance
|
96
|
+
# @return {Array<String>} - [String, String]
|
97
|
+
def extract_controller_and_action_from(route)
|
98
|
+
defaults = route.defaults
|
99
|
+
controller = defaults[:controller]
|
100
|
+
action = defaults[:action]
|
101
|
+
|
102
|
+
[controller, action]
|
103
|
+
end
|
104
|
+
end
|
64
105
|
end
|
65
106
|
end
|
data/lib/chusaku/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chusaku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nishiki Liu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -44,42 +44,56 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '12.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '12.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
62
|
-
type: :
|
61
|
+
version: '0.77'
|
62
|
+
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0.77'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rubocop-performance
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 1.
|
76
|
-
type: :
|
75
|
+
version: '1.5'
|
76
|
+
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1.
|
82
|
+
version: '1.5'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.0'
|
83
97
|
description: Annotate your Rails controllers with route info.
|
84
98
|
email:
|
85
99
|
- nishiki.liu@gmail.com
|
@@ -89,6 +103,7 @@ extensions: []
|
|
89
103
|
extra_rdoc_files: []
|
90
104
|
files:
|
91
105
|
- ".circleci/config.yml"
|
106
|
+
- ".codeclimate.yml"
|
92
107
|
- ".gitignore"
|
93
108
|
- ".rubocop.yml"
|
94
109
|
- Gemfile
|
@@ -100,6 +115,7 @@ files:
|
|
100
115
|
- bin/setup
|
101
116
|
- chusaku.gemspec
|
102
117
|
- lib/chusaku.rb
|
118
|
+
- lib/chusaku/cli.rb
|
103
119
|
- lib/chusaku/parser.rb
|
104
120
|
- lib/chusaku/routes.rb
|
105
121
|
- lib/chusaku/version.rb
|
@@ -126,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
142
|
- !ruby/object:Gem::Version
|
127
143
|
version: '0'
|
128
144
|
requirements: []
|
129
|
-
rubygems_version: 3.
|
145
|
+
rubygems_version: 3.1.2
|
130
146
|
signing_key:
|
131
147
|
specification_version: 4
|
132
148
|
summary: Annotate your Rails controllers with route info.
|