rails-annotate-solargraph 0.1.1 → 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/CHANGELOG.md +10 -0
- data/Gemfile.lock +1 -1
- data/lib/generators/annotate/solargraph/templates/rails_annotate_solargraph.rake +8 -2
- data/lib/rails/annotate/solargraph/model.rb +93 -12
- data/lib/rails/annotate/solargraph/terminal_colors.rb +75 -0
- data/lib/rails/annotate/solargraph/version.rb +1 -1
- data/lib/rails/annotate/solargraph.rb +12 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 744b5deaf3bfdd5fdf4b81b54abd8f4672336402bce178af67b04ff704b6ceab
|
4
|
+
data.tar.gz: 062d49842f237ddb38202975c0c88733fb3a825ebcb4c7cbd7641b45b58ee993
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35eb981e6a0b52331164d80fd7238aadae0403cd9f4d93c7dc9a6c00e31714f6b731c23e961542ee5eac64a48c2820de926fcacaea1e6b8ff9b34c501781c05b
|
7
|
+
data.tar.gz: 6d0f472969a50ed833398216789d0000b8c288685946ab90621f48edca85f57034350df39a5006ae5ddb6b4a30623658c529584e6eca504b0202ff6b633b3379
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.2.0] - 2022-04-16
|
4
|
+
|
5
|
+
- Associations get fully documented
|
6
|
+
|
7
|
+
## [0.1.1] - 2022-04-15
|
8
|
+
|
9
|
+
- Minor bug fix after the initial release
|
10
|
+
|
3
11
|
## [0.1.0] - 2022-04-15
|
4
12
|
|
5
13
|
- Initial release
|
14
|
+
- Automatic generation of annotations after migrations
|
15
|
+
- Manual rake tasks `annotate:solargraph:generate`, `annotate:solargraph:remove`
|
data/Gemfile.lock
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
include ::Rails::Annotate::Solargraph::TerminalColors
|
4
|
+
|
3
5
|
if ::Rails.env.development?
|
4
6
|
namespace :annotate do
|
5
7
|
namespace :solargraph do
|
6
8
|
desc "Add YARD comments documenting the models' schemas"
|
7
9
|
task generate: :environment do
|
8
|
-
system 'rails runner "
|
10
|
+
system! 'bundle exec bin/rails runner "::Rails::Annotate::Solargraph.generate"'
|
9
11
|
end
|
10
12
|
|
11
13
|
desc "Remove YARD comments documenting the models' schemas"
|
12
14
|
task remove: :environment do
|
13
|
-
system 'rails runner "
|
15
|
+
system! 'bundle exec bin/rails runner "::Rails::Annotate::Solargraph.remove"'
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
@@ -23,4 +25,8 @@ if ::Rails.env.development?
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
28
|
+
|
29
|
+
def system!(val)
|
30
|
+
system(val) || abort(error_string("Command `#{val}` failed"))
|
31
|
+
end
|
26
32
|
end
|
@@ -4,9 +4,15 @@ module Rails
|
|
4
4
|
module Annotate
|
5
5
|
module Solargraph
|
6
6
|
class Model
|
7
|
+
using TerminalColors::Refinement
|
8
|
+
|
9
|
+
# @return [String]
|
7
10
|
ANNOTATION_START = "\n# %%<RailsAnnotateSolargraph:Start>%%"
|
11
|
+
# @return [String]
|
8
12
|
ANNOTATION_END = "%%<RailsAnnotateSolargraph:End>%%\n\n"
|
13
|
+
# @return [Regexp]
|
9
14
|
ANNOTATION_REGEXP = /#{ANNOTATION_START}.*#{ANNOTATION_END}/m.freeze
|
15
|
+
# @return [Regexp]
|
10
16
|
MAGIC_COMMENT_REGEXP = /(^#\s*encoding:.*(?:\n|r\n))|(^# coding:.*(?:\n|\r\n))|(^# -\*- coding:.*(?:\n|\r\n))|(^# -\*- encoding\s?:.*(?:\n|\r\n))|(^#\s*frozen_string_literal:.+(?:\n|\r\n))|(^# -\*- frozen_string_literal\s*:.+-\*-(?:\n|\r\n))/.freeze
|
11
17
|
|
12
18
|
class << self
|
@@ -51,7 +57,7 @@ module Rails
|
|
51
57
|
# @param :write [Boolean]
|
52
58
|
# @return [String] New file content.
|
53
59
|
def annotate(write: true)
|
54
|
-
file_content = remove_annotation write: false
|
60
|
+
old_content, file_content = remove_annotation write: false
|
55
61
|
|
56
62
|
if CONFIG.annotation_position == :top
|
57
63
|
magic_comments = file_content.scan(MAGIC_COMMENT_REGEXP).flatten.compact.join
|
@@ -63,35 +69,43 @@ module Rails
|
|
63
69
|
end
|
64
70
|
|
65
71
|
return new_file_content unless write
|
66
|
-
|
72
|
+
# debugger
|
73
|
+
return new_file_content if old_content == new_file_content
|
67
74
|
|
68
|
-
|
75
|
+
write_file @file_name, new_file_content
|
69
76
|
new_file_content
|
70
77
|
end
|
71
78
|
|
72
79
|
# @param :write [Boolean]
|
73
|
-
# @return [String]
|
80
|
+
# @return [Array<String>] Old file content followed by new content.
|
74
81
|
def remove_annotation(write: true)
|
75
82
|
file_content = ::File.read(@file_name)
|
76
83
|
new_file_content = file_content.sub(ANNOTATION_REGEXP, '')
|
77
|
-
|
78
|
-
return
|
84
|
+
result = [file_content, new_file_content]
|
85
|
+
return result unless write
|
86
|
+
return result if file_content == new_file_content
|
79
87
|
|
80
|
-
|
81
|
-
|
88
|
+
write_file @file_name, new_file_content
|
89
|
+
result
|
82
90
|
end
|
83
91
|
|
84
92
|
# @return [String]
|
85
93
|
def annotation
|
86
|
-
|
87
|
-
|
94
|
+
doc_string = ::String.new
|
95
|
+
doc_string << <<~DOC
|
88
96
|
#{ANNOTATION_START}
|
89
97
|
# @!parse
|
90
98
|
# class #{@klass} < #{@klass.superclass}
|
91
99
|
DOC
|
92
100
|
|
101
|
+
@klass.reflections.sort.each do |attr_name, reflection|
|
102
|
+
next document_polymorphic_relation(doc_string, attr_name, reflection) if reflection.polymorphic?
|
103
|
+
|
104
|
+
document_relation(doc_string, attr_name, reflection)
|
105
|
+
end
|
106
|
+
|
93
107
|
@klass.attribute_types.each do |name, attr_type|
|
94
|
-
|
108
|
+
doc_string << <<~DOC
|
95
109
|
# # Database column `#{@klass.table_name}.#{name}`, type: `#{attr_type.type}`.
|
96
110
|
# # @param val [#{yard_type attr_type}, nil]
|
97
111
|
# def #{name}=(val); end
|
@@ -101,7 +115,7 @@ module Rails
|
|
101
115
|
DOC
|
102
116
|
end
|
103
117
|
|
104
|
-
|
118
|
+
doc_string << <<~DOC.chomp
|
105
119
|
# end
|
106
120
|
# #{ANNOTATION_END}
|
107
121
|
DOC
|
@@ -109,6 +123,73 @@ module Rails
|
|
109
123
|
|
110
124
|
private
|
111
125
|
|
126
|
+
# @param file_name [String]
|
127
|
+
# @return [String]
|
128
|
+
def relative_file_name(file_name)
|
129
|
+
file_name.delete_prefix("#{::Rails.root}/")
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param file_name [String]
|
133
|
+
# @param content [String]
|
134
|
+
# @return [void]
|
135
|
+
def write_file(file_name, content)
|
136
|
+
::File.write(file_name, content)
|
137
|
+
puts "modify".rjust(12).with_styles(:bold, :green) + " #{relative_file_name(file_name)}"
|
138
|
+
end
|
139
|
+
|
140
|
+
# @return [String]
|
141
|
+
def klass_relation_name
|
142
|
+
@klass.table_name[..-2]
|
143
|
+
end
|
144
|
+
|
145
|
+
# @param doc_string [String]
|
146
|
+
# @param attr_name [String]
|
147
|
+
# @param reflection [ActiveRecord::Reflection::AbstractReflection]
|
148
|
+
# @return [void]
|
149
|
+
def document_relation(doc_string, attr_name, reflection)
|
150
|
+
db_description = \
|
151
|
+
case reflection
|
152
|
+
when ::ActiveRecord::Reflection::BelongsToReflection
|
153
|
+
type_docstring = reflection.klass
|
154
|
+
"`belongs_to` relation with `#{reflection.klass}`. Database column `#{@klass.table_name}.#{reflection.foreign_key}`."
|
155
|
+
when ::ActiveRecord::Reflection::HasOneReflection
|
156
|
+
type_docstring = reflection.klass
|
157
|
+
"`has_one` relation with `#{reflection.klass}`. Database column `#{reflection.klass.table_name}.#{reflection.foreign_key}`."
|
158
|
+
when ::ActiveRecord::Reflection::HasManyReflection
|
159
|
+
type_docstring = "Array<#{reflection.klass}>"
|
160
|
+
"`has_many` relation with `#{reflection.klass}`. Database column `#{reflection.klass.table_name}.#{reflection.foreign_key}`."
|
161
|
+
end
|
162
|
+
|
163
|
+
doc_string << <<~DOC
|
164
|
+
# # #{db_description}
|
165
|
+
# # @param val [#{type_docstring}, nil]
|
166
|
+
# def #{attr_name}=(val); end
|
167
|
+
# # #{db_description}
|
168
|
+
# # @return [#{type_docstring}, nil]
|
169
|
+
# def #{attr_name}; end
|
170
|
+
DOC
|
171
|
+
end
|
172
|
+
|
173
|
+
# @param doc_string [String]
|
174
|
+
# @param attr_name [String]
|
175
|
+
# @param reflection [ActiveRecord::Reflection::AbstractReflection]
|
176
|
+
# @return [void]
|
177
|
+
def document_polymorphic_relation(doc_string, attr_name, reflection)
|
178
|
+
classes = Solargraph.model_classes.select do |model_class|
|
179
|
+
model_class.reflections[klass_relation_name]&.options&.[](:as)&.to_sym == attr_name.to_sym
|
180
|
+
end
|
181
|
+
|
182
|
+
classes_string = classes.join(', ')
|
183
|
+
doc_string << <<~DOC
|
184
|
+
# # Polymorphic relation. Database columns `#{@klass.table_name}.#{attr_name}_id` and `#{@klass.table_name}.#{attr_name}_type`.
|
185
|
+
# # @param val [#{classes_string}, nil]
|
186
|
+
# def #{attr_name}=(val); end
|
187
|
+
# # Polymorphic relation. Database columns `#{@klass.table_name}.#{attr_name}_id` and `#{@klass.table_name}.#{attr_name}_type`.
|
188
|
+
# # @return [#{classes_string}, nil]
|
189
|
+
# def #{attr_name}; end
|
190
|
+
DOC
|
191
|
+
end
|
192
|
+
|
112
193
|
# @param attr_type [ActiveModel::Type::Value]
|
113
194
|
# @return [String]
|
114
195
|
def yard_type(attr_type)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module Annotate
|
5
|
+
module Solargraph
|
6
|
+
module TerminalColors
|
7
|
+
extend self
|
8
|
+
|
9
|
+
# @return [Hash{Symbol => String}]
|
10
|
+
MAP = {
|
11
|
+
blue: (BLUE = "\033[94m"),
|
12
|
+
cyan: (CYAN = "\033[96m"),
|
13
|
+
green: (GREEN = "\033[92m"),
|
14
|
+
yellow: (YELLOW = "\033[93m"),
|
15
|
+
red: (RED = "\033[91m"),
|
16
|
+
terminate: (TERMINATE = "\033[0m"),
|
17
|
+
bold: (BOLD = "\033[1m"),
|
18
|
+
italic: (ITALIC = "\033[3m"),
|
19
|
+
underline: (UNDERLINE = "\033[4m")
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# Style a string with an ASCII escape code
|
24
|
+
#
|
25
|
+
# @param string [String]
|
26
|
+
# @param style [Symbol]
|
27
|
+
# @return [String]
|
28
|
+
def with_style(string, style)
|
29
|
+
"#{MAP[style]}#{string}#{TERMINATE}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Style a string with multiple ASCII escape codes
|
33
|
+
#
|
34
|
+
# @param string [String]
|
35
|
+
# @param styles [Array<Symbol>]
|
36
|
+
# @return [String]
|
37
|
+
def with_styles(string, *styles)
|
38
|
+
result = ::String.new
|
39
|
+
styles.each do |style|
|
40
|
+
result << MAP[style]
|
41
|
+
end
|
42
|
+
|
43
|
+
result << "#{string}#{TERMINATE}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def title_string(string)
|
48
|
+
TerminalColors.with_styles "== #{string} ==", :cyan, :underline, :italic
|
49
|
+
end
|
50
|
+
|
51
|
+
def error_string(string)
|
52
|
+
TerminalColors.with_styles "!! #{string} !!", :bold, :red
|
53
|
+
end
|
54
|
+
|
55
|
+
def title(string)
|
56
|
+
puts "\n", title_string(string)
|
57
|
+
end
|
58
|
+
|
59
|
+
def error(string)
|
60
|
+
puts "\n", error_string(string)
|
61
|
+
end
|
62
|
+
|
63
|
+
module Refinement
|
64
|
+
refine ::String do
|
65
|
+
# @param styles [Array<Symbol]>
|
66
|
+
# @return [self] Colored string
|
67
|
+
def with_styles(*styles)
|
68
|
+
::Rails::Annotate::Solargraph::TerminalColors.with_styles(self, *styles)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -4,6 +4,7 @@ require 'set'
|
|
4
4
|
|
5
5
|
require_relative "solargraph/version"
|
6
6
|
require_relative "solargraph/configuration"
|
7
|
+
require_relative "solargraph/terminal_colors"
|
7
8
|
require_relative "solargraph/model"
|
8
9
|
|
9
10
|
module Rails
|
@@ -16,15 +17,19 @@ module Rails
|
|
16
17
|
RAKEFILE_NAME = 'rails_annotate_solargraph.rake'
|
17
18
|
# @return [Configuration]
|
18
19
|
CONFIG = Configuration.new
|
20
|
+
# @return [Set<Symbol>]
|
21
|
+
VALID_MODIFICATION_METHODS = ::Set[:annotate, :remove_annotation].freeze
|
19
22
|
|
20
23
|
class << self
|
21
24
|
# @return [Array<String>] Array of changed files.
|
22
25
|
def generate
|
26
|
+
title 'Generating model schema annotations'
|
23
27
|
modify_models :annotate
|
24
28
|
end
|
25
29
|
|
26
30
|
# @return [Array<String>] Array of changed files.
|
27
31
|
def remove
|
32
|
+
title 'Removing model schema annotations'
|
28
33
|
modify_models :remove_annotation
|
29
34
|
end
|
30
35
|
|
@@ -35,10 +40,15 @@ module Rails
|
|
35
40
|
|
36
41
|
alias call generate
|
37
42
|
|
38
|
-
|
43
|
+
# @return [Array<ActiveRecord::Base>]
|
44
|
+
def model_classes
|
45
|
+
@model_classes ||= (::ApplicationRecord rescue ::ActiveRecord::Base).subclasses.sort_by(&:name)
|
46
|
+
end
|
39
47
|
|
40
48
|
private
|
41
49
|
|
50
|
+
include TerminalColors
|
51
|
+
|
42
52
|
# @param method [Symbol] Name of the method that will be called on every loaded Model
|
43
53
|
# @return [Array<String>] Array of changed files.
|
44
54
|
def modify_models(method)
|
@@ -49,7 +59,7 @@ module Rails
|
|
49
59
|
model_files = ::Dir[::File.join(::Rails.root, MODEL_DIR, '**/*.rb')].map { |file| file.sub("#{::Rails.root}/", '') }.to_set
|
50
60
|
|
51
61
|
::Rails.application.eager_load!
|
52
|
-
|
62
|
+
model_classes.each do |subclass|
|
53
63
|
subclass_file = ::File.join MODEL_DIR, "#{subclass.to_s.underscore}.rb"
|
54
64
|
next unless model_files.include? subclass_file
|
55
65
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-annotate-solargraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mateusz Drewniak
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- lib/rails/annotate/solargraph.rb
|
58
58
|
- lib/rails/annotate/solargraph/configuration.rb
|
59
59
|
- lib/rails/annotate/solargraph/model.rb
|
60
|
+
- lib/rails/annotate/solargraph/terminal_colors.rb
|
60
61
|
- lib/rails/annotate/solargraph/version.rb
|
61
62
|
- rails-annotate-solargraph.gemspec
|
62
63
|
- sig/rails/annotate/solargraph.rbs
|