rails-annotate-solargraph 0.2.2 → 0.4.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/.vscode/settings.json +1 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +1 -1
- data/README.md +22 -2
- data/lib/rails/annotate/solargraph/configuration.rb +6 -2
- data/lib/rails/annotate/solargraph/model.rb +168 -38
- data/lib/rails/annotate/solargraph/version.rb +1 -1
- data/lib/rails/annotate/solargraph.rb +16 -0
- data/rails-annotate-solargraph.gemspec +1 -1
- 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: 80d2fcb8fc2090d6a1eabc8f510b3b9fec1608da1870c7d88b301ce64907920a
|
4
|
+
data.tar.gz: 9553090d359f8f829e955349cac6c527c43335433e38d91152862780cce3ab63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b2415d929d939454a4f65277d85baa03935219226c6ad5b35c35264cd2de94bb1b1d55a55a55ee8cc737523210e3653c648bea50798dd53b580767fbb6a2eec
|
7
|
+
data.tar.gz: 9436e870a6cbc28e636151b76717cde5bf4186f44bc8af4293ada785f1c50e039895fcf5cb38dd27868c5e88027df9f52be8ee070591e0635de30fdba7437aef
|
data/.vscode/settings.json
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.4.0] - 2022-04-17
|
4
|
+
|
5
|
+
- Annotations get saved to a schema file by default `app/models/annotate_solargraph_schema.rb`
|
6
|
+
|
7
|
+
## [0.3.0] - 2022-04-17
|
8
|
+
|
9
|
+
- `has_many :through` and `has_one :through` relations get documented
|
10
|
+
|
11
|
+
## [0.2.3] - 2022-04-16
|
12
|
+
|
13
|
+
- A nicer fix for the previous problem
|
14
|
+
|
3
15
|
## [0.2.2] - 2022-04-16
|
4
16
|
|
5
17
|
- Inexistent class loading error has been resolved
|
@@ -11,6 +23,7 @@
|
|
11
23
|
## [0.2.0] - 2022-04-16
|
12
24
|
|
13
25
|
- Associations get fully documented
|
26
|
+
- `has_many`, `has_one` and `belongs_to` relations get documented
|
14
27
|
|
15
28
|
## [0.1.1] - 2022-04-15
|
16
29
|
|
@@ -20,4 +33,5 @@
|
|
20
33
|
|
21
34
|
- Initial release
|
22
35
|
- Automatic generation of annotations after migrations
|
36
|
+
- Database fields get documented
|
23
37
|
- Manual rake tasks `annotate:solargraph:generate`, `annotate:solargraph:remove`
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -63,11 +63,31 @@ You can change the gem's default configuration like so:
|
|
63
63
|
```ruby
|
64
64
|
# config/initializers/rails_annotate_solargraph.rb
|
65
65
|
|
66
|
-
Rails
|
67
|
-
|
66
|
+
if ::Rails.env.development?
|
67
|
+
::Rails::Annotate::Solargraph.configure do |conf|
|
68
|
+
conf.annotation_position = :top # `:schema_file` by default
|
69
|
+
end
|
68
70
|
end
|
69
71
|
```
|
70
72
|
|
73
|
+
#### annotation_position
|
74
|
+
|
75
|
+
There are a few values for this option:
|
76
|
+
|
77
|
+
- `:schema_file` -- default value, annotations get saved to a special file `app/models/annotate_solargraph_schema.rb`
|
78
|
+
- `:bottom` -- annotations are appended to the model files
|
79
|
+
- `:top` -- annotations are prepended to the model files
|
80
|
+
|
81
|
+
### Update
|
82
|
+
|
83
|
+
To update this gem you should generate the rakefiles once again. Overwrite them.
|
84
|
+
|
85
|
+
```sh
|
86
|
+
$ rails g annotate:solargraph:install
|
87
|
+
$ rake annotate:solargraph:remove
|
88
|
+
$ rake annotate:solargraph:generate
|
89
|
+
```
|
90
|
+
|
71
91
|
## Development
|
72
92
|
|
73
93
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -9,10 +9,10 @@ module Rails
|
|
9
9
|
# @return [Symbol]
|
10
10
|
attr_reader :annotation_position
|
11
11
|
|
12
|
-
ANNOTATION_POSITIONS = ::Set[:bottom, :top].freeze
|
12
|
+
ANNOTATION_POSITIONS = ::Set[:bottom, :top, :schema_file].freeze
|
13
13
|
|
14
14
|
def initialize
|
15
|
-
@annotation_position = :
|
15
|
+
@annotation_position = :schema_file
|
16
16
|
end
|
17
17
|
|
18
18
|
# @param val [Symbol]
|
@@ -22,6 +22,10 @@ module Rails
|
|
22
22
|
|
23
23
|
@annotation_position = val
|
24
24
|
end
|
25
|
+
|
26
|
+
def schema_file?
|
27
|
+
@annotation_position == :schema_file
|
28
|
+
end
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
@@ -1,32 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'fileutils'
|
4
|
+
|
3
5
|
module Rails
|
4
6
|
module Annotate
|
5
7
|
module Solargraph
|
6
8
|
class Model
|
7
9
|
using TerminalColors::Refinement
|
8
10
|
|
9
|
-
# @return [String]
|
10
|
-
ANNOTATION_START = "\n# %%<RailsAnnotateSolargraph:Start>%%"
|
11
|
-
# @return [String]
|
12
|
-
ANNOTATION_END = "%%<RailsAnnotateSolargraph:End>%%\n\n"
|
13
|
-
# @return [Regexp]
|
14
|
-
ANNOTATION_REGEXP = /#{ANNOTATION_START}.*#{ANNOTATION_END}/m.freeze
|
15
11
|
# @return [Regexp]
|
16
12
|
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
|
17
13
|
|
18
|
-
class << (FAKE_MODEL_CLASS = Object.new)
|
19
|
-
def to_s
|
20
|
-
::Object.to_s
|
21
|
-
end
|
22
|
-
|
23
|
-
alias name to_s
|
24
|
-
|
25
|
-
def table_name
|
26
|
-
'<unknown>'
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
14
|
class << self
|
31
15
|
# @param type [Symbol, String, nil]
|
32
16
|
# @return [String]
|
@@ -52,6 +36,26 @@ module Rails
|
|
52
36
|
::Object.to_s
|
53
37
|
end
|
54
38
|
end
|
39
|
+
|
40
|
+
# @param klass [Class]
|
41
|
+
# @return [String]
|
42
|
+
def annotation_start(klass = nil)
|
43
|
+
table_name = klass && CONFIG.schema_file? ? ":#{klass.table_name}" : ''
|
44
|
+
"\n# %%<RailsAnnotateSolargraph:Start#{table_name}>%%"
|
45
|
+
end
|
46
|
+
|
47
|
+
# @param klass [Class]
|
48
|
+
# @return [String]
|
49
|
+
def annotation_end(klass = nil)
|
50
|
+
table_name = klass && CONFIG.schema_file? ? ":#{klass.table_name}" : ''
|
51
|
+
"%%<RailsAnnotateSolargraph:End#{table_name}>%%\n\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param klass [Class]
|
55
|
+
# @return [Regexp]
|
56
|
+
def annotation_regexp(klass = nil)
|
57
|
+
/#{annotation_start(klass)}.*#{annotation_end(klass)}/m
|
58
|
+
end
|
55
59
|
end
|
56
60
|
|
57
61
|
# @return [String]
|
@@ -63,7 +67,23 @@ module Rails
|
|
63
67
|
# @param klass [Class]
|
64
68
|
def initialize(klass)
|
65
69
|
@klass = klass
|
66
|
-
|
70
|
+
base_file_name = CONFIG.schema_file? ? SCHEMA_FILE_NAME : "#{klass.to_s.underscore}.rb"
|
71
|
+
@file_name = ::File.join(::Rails.root, MODEL_DIR, base_file_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [String]
|
75
|
+
def annotation_start
|
76
|
+
self.class.annotation_start(@klass)
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [String]
|
80
|
+
def annotation_end
|
81
|
+
self.class.annotation_end(@klass)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Regexp]
|
85
|
+
def annotation_regexp
|
86
|
+
self.class.annotation_regexp(@klass)
|
67
87
|
end
|
68
88
|
|
69
89
|
# @param :write [Boolean]
|
@@ -91,8 +111,10 @@ module Rails
|
|
91
111
|
# @param :write [Boolean]
|
92
112
|
# @return [Array<String>] Old file content followed by new content.
|
93
113
|
def remove_annotation(write: true)
|
114
|
+
return ['', ''] unless ::File.exist?(@file_name)
|
115
|
+
|
94
116
|
file_content = ::File.read(@file_name)
|
95
|
-
new_file_content = file_content.sub(
|
117
|
+
new_file_content = file_content.sub(annotation_regexp, '')
|
96
118
|
result = [file_content, new_file_content]
|
97
119
|
return result unless write
|
98
120
|
return result if file_content == new_file_content
|
@@ -105,7 +127,7 @@ module Rails
|
|
105
127
|
def annotation
|
106
128
|
doc_string = ::String.new
|
107
129
|
doc_string << <<~DOC
|
108
|
-
#{
|
130
|
+
#{annotation_start}
|
109
131
|
# @!parse
|
110
132
|
# class #{@klass} < #{@klass.superclass}
|
111
133
|
DOC
|
@@ -129,7 +151,7 @@ module Rails
|
|
129
151
|
|
130
152
|
doc_string << <<~DOC.chomp
|
131
153
|
# end
|
132
|
-
# #{
|
154
|
+
# #{annotation_end}
|
133
155
|
DOC
|
134
156
|
end
|
135
157
|
|
@@ -145,6 +167,7 @@ module Rails
|
|
145
167
|
# @param content [String]
|
146
168
|
# @return [void]
|
147
169
|
def write_file(file_name, content)
|
170
|
+
::FileUtils.touch(file_name) unless ::File.exists?(file_name)
|
148
171
|
::File.write(file_name, content)
|
149
172
|
puts "modify".rjust(12).with_styles(:bold, :green) + " #{relative_file_name(file_name)}"
|
150
173
|
end
|
@@ -154,35 +177,57 @@ module Rails
|
|
154
177
|
@klass.table_name[..-2]
|
155
178
|
end
|
156
179
|
|
180
|
+
# @param reflection [ActiveRecord::Reflection::AbstractReflection]
|
181
|
+
# @return [Class]
|
182
|
+
def reflection_class(reflection)
|
183
|
+
reflection.klass
|
184
|
+
rescue ::NameError
|
185
|
+
Object
|
186
|
+
end
|
187
|
+
|
188
|
+
# @param reflection [ActiveRecord::Reflection::AbstractReflection]
|
189
|
+
# @return [String]
|
190
|
+
def reflection_foreign_key(reflection)
|
191
|
+
reflection.try(:foreign_key) || '<unknown>'
|
192
|
+
end
|
193
|
+
|
194
|
+
# @param klass [Class]
|
195
|
+
# @return [String]
|
196
|
+
def class_table_name(klass)
|
197
|
+
klass.try(:table_name) || '<unknown>'
|
198
|
+
end
|
199
|
+
|
157
200
|
# @param doc_string [String]
|
158
201
|
# @param attr_name [String]
|
159
202
|
# @param reflection [ActiveRecord::Reflection::AbstractReflection]
|
160
203
|
# @return [void]
|
161
204
|
def document_relation(doc_string, attr_name, reflection)
|
162
|
-
|
163
|
-
|
164
|
-
rescue ::NameError
|
165
|
-
FAKE_MODEL_CLASS
|
166
|
-
end
|
167
|
-
|
168
|
-
db_description = \
|
205
|
+
reflection_klass = reflection_class(reflection)
|
206
|
+
type_docstring, db_description = \
|
169
207
|
case reflection
|
170
208
|
when ::ActiveRecord::Reflection::BelongsToReflection
|
171
|
-
|
172
|
-
|
209
|
+
belongs_to_description(reflection_klass,
|
210
|
+
class_table_name(@klass),
|
211
|
+
reflection_foreign_key(reflection))
|
173
212
|
when ::ActiveRecord::Reflection::HasOneReflection
|
174
|
-
|
175
|
-
|
213
|
+
has_one_description(reflection_klass,
|
214
|
+
class_table_name(reflection_klass),
|
215
|
+
reflection_foreign_key(reflection))
|
176
216
|
when ::ActiveRecord::Reflection::HasManyReflection
|
177
|
-
|
178
|
-
|
217
|
+
has_many_description(reflection_klass,
|
218
|
+
class_table_name(reflection_klass),
|
219
|
+
reflection_foreign_key(reflection))
|
220
|
+
when ::ActiveRecord::Reflection::ThroughReflection
|
221
|
+
through_description(reflection)
|
222
|
+
else
|
223
|
+
[::Object.to_s, '']
|
179
224
|
end
|
180
225
|
|
181
226
|
doc_string << <<~DOC
|
182
|
-
#
|
227
|
+
# ##{db_description}
|
183
228
|
# # @param val [#{type_docstring}, nil]
|
184
229
|
# def #{attr_name}=(val); end
|
185
|
-
#
|
230
|
+
# ##{db_description}
|
186
231
|
# # @return [#{type_docstring}, nil]
|
187
232
|
# def #{attr_name}; end
|
188
233
|
DOC
|
@@ -197,7 +242,7 @@ module Rails
|
|
197
242
|
model_class.reflections[klass_relation_name]&.options&.[](:as)&.to_sym == attr_name.to_sym
|
198
243
|
end
|
199
244
|
|
200
|
-
classes_string = classes.join(', ')
|
245
|
+
classes_string = classes.empty? ? ::Object.to_s : classes.join(', ')
|
201
246
|
doc_string << <<~DOC
|
202
247
|
# # Polymorphic relation. Database columns `#{@klass.table_name}.#{attr_name}_id` and `#{@klass.table_name}.#{attr_name}_type`.
|
203
248
|
# # @param val [#{classes_string}, nil]
|
@@ -208,6 +253,91 @@ module Rails
|
|
208
253
|
DOC
|
209
254
|
end
|
210
255
|
|
256
|
+
# @param reflection [ActiveRecord::Reflection::AbstractReflection]
|
257
|
+
# @return [Array<String>]
|
258
|
+
def through_description(reflection)
|
259
|
+
through_klass = reflection_class(reflection.through_reflection)
|
260
|
+
|
261
|
+
case (reflection.__send__(:delegate_reflection) rescue nil)
|
262
|
+
when ::ActiveRecord::Reflection::HasOneReflection
|
263
|
+
has_one_description(reflection_class(reflection.source_reflection),
|
264
|
+
class_table_name(through_klass),
|
265
|
+
reflection_foreign_key(reflection.source_reflection),
|
266
|
+
through: through_klass)
|
267
|
+
when ::ActiveRecord::Reflection::HasManyReflection
|
268
|
+
has_many_description(reflection_class(reflection.source_reflection),
|
269
|
+
class_table_name(through_klass),
|
270
|
+
reflection_foreign_key(reflection.source_reflection),
|
271
|
+
through: through_klass)
|
272
|
+
else
|
273
|
+
[::Object.to_s, '']
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# @param through [Class, nil]
|
278
|
+
# @return [String]
|
279
|
+
def through_sentence(through = nil)
|
280
|
+
return '' unless through
|
281
|
+
|
282
|
+
" through `#{through}`"
|
283
|
+
end
|
284
|
+
|
285
|
+
# @param table_name [String]
|
286
|
+
# @param foreign_key [String]
|
287
|
+
# @param through [Class, nil]
|
288
|
+
# @return [String]
|
289
|
+
def column_description(table_name, foreign_key, through = nil)
|
290
|
+
return '' if through
|
291
|
+
|
292
|
+
" Database column `#{table_name}.#{foreign_key}`."
|
293
|
+
end
|
294
|
+
|
295
|
+
# @param relation [Symbol, String]
|
296
|
+
# @param klass [Class]
|
297
|
+
# @param table_name [String]
|
298
|
+
# @param foreign_key [String]
|
299
|
+
# @param through [Class, nil]
|
300
|
+
# @return [String]
|
301
|
+
def relation_description(relation, klass, table_name, foreign_key, through = nil)
|
302
|
+
" `#{relation}` relation with `#{klass}`#{through_sentence(through)}.#{column_description(table_name, foreign_key, through)}"
|
303
|
+
end
|
304
|
+
|
305
|
+
|
306
|
+
# @param klass [Class]
|
307
|
+
# @param table_name [String]
|
308
|
+
# @param foreign_key [String]
|
309
|
+
# @param :through [Class, nil]
|
310
|
+
# @return [Array<String>] Type docstring followed by the description of the method.
|
311
|
+
def has_many_description(klass, table_name, foreign_key, through: nil)
|
312
|
+
type_docstring = "Array<#{klass}>"
|
313
|
+
desc = relation_description(:has_many, klass, table_name, foreign_key, through)
|
314
|
+
|
315
|
+
[type_docstring, desc]
|
316
|
+
end
|
317
|
+
|
318
|
+
# @param klass [Class]
|
319
|
+
# @param table_name [String]
|
320
|
+
# @param foreign_key [String]
|
321
|
+
# @param :through [Class, nil]
|
322
|
+
# @return [Array<String>] Type docstring followed by the description of the method.
|
323
|
+
def has_one_description(klass, table_name, foreign_key, through: nil)
|
324
|
+
type_docstring = klass
|
325
|
+
desc = relation_description(:has_one, klass, table_name, foreign_key, through)
|
326
|
+
|
327
|
+
[type_docstring, desc]
|
328
|
+
end
|
329
|
+
|
330
|
+
# @param klass [Class]
|
331
|
+
# @param table_name [String]
|
332
|
+
# @param foreign_key [String]
|
333
|
+
# @return [Array<String>] Type docstring followed by the description of the method.
|
334
|
+
def belongs_to_description(klass, table_name, foreign_key)
|
335
|
+
type_docstring = klass
|
336
|
+
desc = relation_description(:belongs_to, klass, table_name, foreign_key)
|
337
|
+
|
338
|
+
[type_docstring, desc]
|
339
|
+
end
|
340
|
+
|
211
341
|
# @param attr_type [ActiveModel::Type::Value]
|
212
342
|
# @return [String]
|
213
343
|
def yard_type(attr_type)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'set'
|
4
|
+
require 'fileutils'
|
4
5
|
|
5
6
|
require_relative "solargraph/version"
|
6
7
|
require_relative "solargraph/configuration"
|
@@ -19,11 +20,16 @@ module Rails
|
|
19
20
|
CONFIG = Configuration.new
|
20
21
|
# @return [Set<Symbol>]
|
21
22
|
VALID_MODIFICATION_METHODS = ::Set[:annotate, :remove_annotation].freeze
|
23
|
+
# @return [String]
|
24
|
+
SCHEMA_CLASS_NAME = 'AnnotateSolargraphSchema'
|
25
|
+
# @return [String]
|
26
|
+
SCHEMA_FILE_NAME = "annotate_solargraph_schema.rb"
|
22
27
|
|
23
28
|
class << self
|
24
29
|
# @return [Array<String>] Array of changed files.
|
25
30
|
def generate
|
26
31
|
title 'Generating model schema annotations'
|
32
|
+
create_schema_file
|
27
33
|
modify_models :annotate
|
28
34
|
end
|
29
35
|
|
@@ -49,6 +55,16 @@ module Rails
|
|
49
55
|
|
50
56
|
include TerminalColors
|
51
57
|
|
58
|
+
def create_schema_file
|
59
|
+
schema_file = ::File.join(::Rails.root, MODEL_DIR, SCHEMA_FILE_NAME)
|
60
|
+
return unless CONFIG.schema_file? && !::File.exist?(schema_file)
|
61
|
+
|
62
|
+
::FileUtils.touch(schema_file)
|
63
|
+
::File.write schema_file, <<~SCHEMA
|
64
|
+
module AnnotateSolargraphSchema; end
|
65
|
+
SCHEMA
|
66
|
+
end
|
67
|
+
|
52
68
|
# @param method [Symbol] Name of the method that will be called on every loaded Model
|
53
69
|
# @return [Array<String>] Array of changed files.
|
54
70
|
def modify_models(method)
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
18
18
|
spec.metadata["source_code_uri"] = "https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph"
|
19
|
-
|
19
|
+
spec.metadata["changelog_uri"] = "https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph/-/raw/main/CHANGELOG.md"
|
20
20
|
|
21
21
|
# Specify which files should be added to the gem when it is released.
|
22
22
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
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.4.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-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -67,6 +67,7 @@ licenses:
|
|
67
67
|
metadata:
|
68
68
|
homepage_uri: https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph
|
69
69
|
source_code_uri: https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph
|
70
|
+
changelog_uri: https://gitlab.com/mateuszdrewniak/rails-annotate-solargraph/-/raw/main/CHANGELOG.md
|
70
71
|
post_install_message:
|
71
72
|
rdoc_options: []
|
72
73
|
require_paths:
|