sord 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/exe/sord +3 -1
- data/lib/sord/rbi_generator.rb +156 -80
- data/lib/sord/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14900bd9ce64eda2373d0844e42032ea041b44dd10a6ca6a82bd66c31b2b0c9b
|
4
|
+
data.tar.gz: 983e467e872f0e455da6ca618b2a2ffb159d81f6cc1456e8370e33ecd42179bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a63ef228f6763653b2be68d46c16f20793118a67adec93d6cc2ec016ed9df254803e3b1fb1bc5c5b26a248020715ee72836c3b4fab6bb07e2d1223e685af97b
|
7
|
+
data.tar.gz: b9a86b1af67cdfd6d73eb28f2b6b46d10b5e61418d2118693e2103da1d5e9d506c8046b069922b908d1d4ecd908abf832ad4a480868b6720650a386fb010d766
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file.
|
|
3
3
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
5
5
|
|
6
|
+
## [2.0.0] - 2020-03-16
|
7
|
+
### Added
|
8
|
+
- Sord now supports generating `attr_accessor`, `attr_reader` and `attr_writer`
|
9
|
+
and will do so automatically when these are used in your code.
|
10
|
+
- Depending on what you're doing with Sord, this is **potentially breaking**,
|
11
|
+
as for example attributes which would previously generate two `foo` and `foo=`
|
12
|
+
methods in Sord will now just generate an `attr_accessor`.
|
13
|
+
- `#initialize` is now always typed as returning `void`, which is
|
14
|
+
**potentially breaking** if you directly call `#initialize` in code.
|
15
|
+
- The `--use-original-initialize-return` flag restores the old behaviour of
|
16
|
+
using whatever return type is provided, like any other method.
|
17
|
+
|
6
18
|
## [1.0.0] - 2020-02-16
|
7
19
|
### Added
|
8
20
|
- Added the `--skip-constants` flag to avoid generating RBIs for constants.
|
data/exe/sord
CHANGED
@@ -20,6 +20,7 @@ command :gen do |c|
|
|
20
20
|
c.option '--include-messages STRING', String, 'Whitelists a comma-separated string of log message types'
|
21
21
|
c.option '--keep-original-comments', 'Retains original YARD comments rather than converting them to Markdown'
|
22
22
|
c.option '--skip-constants', 'Excludes constants from generated RBI'
|
23
|
+
c.option '--use-original-initialize-return', 'Uses the specified return type for #initialize rather than void'
|
23
24
|
|
24
25
|
c.action do |args, options|
|
25
26
|
options.default(
|
@@ -31,7 +32,8 @@ command :gen do |c|
|
|
31
32
|
exclude_messages: nil,
|
32
33
|
include_messages: nil,
|
33
34
|
keep_original_comments: false,
|
34
|
-
skip_constants: false
|
35
|
+
skip_constants: false,
|
36
|
+
use_original_initialize_return: false,
|
35
37
|
)
|
36
38
|
|
37
39
|
if args.length != 1
|
data/lib/sord/rbi_generator.rb
CHANGED
@@ -40,6 +40,7 @@ module Sord
|
|
40
40
|
@replace_unresolved_with_untyped = options[:replace_unresolved_with_untyped]
|
41
41
|
@keep_original_comments = options[:keep_original_comments]
|
42
42
|
@skip_constants = options[:skip_constants]
|
43
|
+
@use_original_initialize_return = options[:use_original_initialize_return]
|
43
44
|
|
44
45
|
# Hook the logger so that messages are added as comments to the RBI file
|
45
46
|
Logging.add_hook do |type, msg, item|
|
@@ -96,6 +97,97 @@ module Sord
|
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
100
|
+
# Adds comments to an RBI object based on a docstring.
|
101
|
+
# @param [YARD::CodeObjects::NamespaceObject] item
|
102
|
+
# @param [Parlour::RbiGenerator::RbiObject] rbi_object
|
103
|
+
# @return [void]
|
104
|
+
def add_comments(item, rbi_object)
|
105
|
+
if @keep_original_comments
|
106
|
+
rbi_object.add_comments(item.docstring.all.split("\n"))
|
107
|
+
else
|
108
|
+
parser = YARD::Docstring.parser
|
109
|
+
parser.parse(item.docstring.all)
|
110
|
+
|
111
|
+
docs_array = parser.text.split("\n")
|
112
|
+
|
113
|
+
# Add @param tags if there are any with names and descriptions.
|
114
|
+
params = parser.tags.select { |tag| tag.tag_name == 'param' && tag.is_a?(YARD::Tags::Tag) && !tag.name.nil? }
|
115
|
+
# Add a blank line if there's anything before the params.
|
116
|
+
docs_array << '' if docs_array.length.positive? && params.length.positive?
|
117
|
+
params.each do |param|
|
118
|
+
docs_array << '' if docs_array.last != '' && docs_array.length.positive?
|
119
|
+
# Output params in the form of:
|
120
|
+
# _@param_ `foo` — Lorem ipsum.
|
121
|
+
# _@param_ `foo`
|
122
|
+
if param.text.nil? || param.text == ''
|
123
|
+
docs_array << "_@param_ `#{param.name}`"
|
124
|
+
else
|
125
|
+
docs_array << "_@param_ `#{param.name}` — #{param.text.gsub("\n", " ")}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Add @return tags (there could possibly be more than one, despite this not being supported)
|
130
|
+
returns = parser.tags.select { |tag| tag.tag_name == 'return' && tag.is_a?(YARD::Tags::Tag) && !tag.text.nil? && tag.text.strip != '' }
|
131
|
+
# Add a blank line if there's anything before the returns.
|
132
|
+
docs_array << '' if docs_array.length.positive? && returns.length.positive?
|
133
|
+
returns.each do |retn|
|
134
|
+
docs_array << '' if docs_array.last != '' && docs_array.length.positive?
|
135
|
+
# Output returns in the form of:
|
136
|
+
# _@return_ — Lorem ipsum.
|
137
|
+
docs_array << "_@return_ — #{retn.text}"
|
138
|
+
end
|
139
|
+
|
140
|
+
# Iterate through the @example tags for a given YARD doc and output them in Markdown codeblocks.
|
141
|
+
examples = parser.tags.select { |tag| tag.tag_name == 'example' && tag.is_a?(YARD::Tags::Tag) }
|
142
|
+
examples.each do |example|
|
143
|
+
# Only add a blank line if there's anything before the example.
|
144
|
+
docs_array << '' if docs_array.length.positive?
|
145
|
+
# Include the example's 'name' if there is one.
|
146
|
+
docs_array << example.name unless example.name.nil? || example.name == ""
|
147
|
+
docs_array << "```ruby"
|
148
|
+
docs_array.concat(example.text.split("\n"))
|
149
|
+
docs_array << "```"
|
150
|
+
end if examples.length.positive?
|
151
|
+
|
152
|
+
# Add @note and @deprecated tags.
|
153
|
+
notice_tags = parser.tags.select { |tag| ['note', 'deprecated'].include?(tag.tag_name) && tag.is_a?(YARD::Tags::Tag) }
|
154
|
+
# Add a blank line if there's anything before the params.
|
155
|
+
docs_array << '' if docs_array.last != '' && docs_array.length.positive? && notice_tags.length.positive?
|
156
|
+
notice_tags.each do |notice_tag|
|
157
|
+
docs_array << '' if docs_array.last != ''
|
158
|
+
# Output note/deprecated/see in the form of:
|
159
|
+
# _@note_ — Lorem ipsum.
|
160
|
+
# _@note_
|
161
|
+
if notice_tag.text.nil?
|
162
|
+
docs_array << "_@#{notice_tag.tag_name}_"
|
163
|
+
else
|
164
|
+
docs_array << "_@#{notice_tag.tag_name}_ — #{notice_tag.text}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Add @see tags.
|
169
|
+
see_tags = parser.tags.select { |tag| tag.tag_name == 'see' && tag.is_a?(YARD::Tags::Tag) }
|
170
|
+
# Add a blank line if there's anything before the params.
|
171
|
+
docs_array << '' if docs_array.last != '' && docs_array.length.positive? && see_tags.length.positive?
|
172
|
+
see_tags.each do |see_tag|
|
173
|
+
docs_array << '' if docs_array.last != ''
|
174
|
+
# Output note/deprecated/see in the form of:
|
175
|
+
# _@see_ `B` — Lorem ipsum.
|
176
|
+
# _@see_ `B`
|
177
|
+
if see_tag.text.nil?
|
178
|
+
docs_array << "_@see_ `#{see_tag.name}`"
|
179
|
+
else
|
180
|
+
docs_array << "_@see_ `#{see_tag.name}` — #{see_tag.text}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# fix: yard text may contains multiple line. should deal \n.
|
185
|
+
# else generate text will be multiple line and only first line is commented
|
186
|
+
docs_array = docs_array.flat_map {|line| line.empty? ? [""] : line.split("\n")}
|
187
|
+
rbi_object.add_comments(docs_array)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
99
191
|
# Given a YARD NamespaceObject, add lines defining its methods and their
|
100
192
|
# signatures to the current RBI file.
|
101
193
|
# @param [YARD::CodeObjects::NamespaceObject] item
|
@@ -110,6 +202,11 @@ module Sord
|
|
110
202
|
next
|
111
203
|
end
|
112
204
|
|
205
|
+
# If the method is an attribute, it'll be handled by add_attributes
|
206
|
+
if meth.is_attribute?
|
207
|
+
next
|
208
|
+
end
|
209
|
+
|
113
210
|
# Sort parameters
|
114
211
|
meth.parameters.reverse.sort! { |pair1, pair2| sort_params(pair1, pair2) }
|
115
212
|
# This is better than iterating over YARD's "@param" tags directly
|
@@ -191,7 +288,9 @@ module Sord
|
|
191
288
|
end
|
192
289
|
|
193
290
|
return_tags = meth.tags('return')
|
194
|
-
returns = if
|
291
|
+
returns = if meth.name == :initialize && !@use_original_initialize_return
|
292
|
+
nil
|
293
|
+
elsif return_tags.length == 0
|
195
294
|
Logging.omit("no YARD return type given, using T.untyped", meth)
|
196
295
|
'T.untyped'
|
197
296
|
elsif return_tags.length == 1 && return_tags&.first&.types&.first&.downcase == "void"
|
@@ -221,89 +320,65 @@ module Sord
|
|
221
320
|
returns: returns,
|
222
321
|
class_method: meth.scope == :class
|
223
322
|
) do |m|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
parser.parse(meth.docstring.all)
|
229
|
-
|
230
|
-
docs_array = parser.text.split("\n")
|
231
|
-
|
232
|
-
# Add @param tags if there are any with names and descriptions.
|
233
|
-
params = parser.tags.select { |tag| tag.tag_name == 'param' && tag.is_a?(YARD::Tags::Tag) && !tag.name.nil? }
|
234
|
-
# Add a blank line if there's anything before the params.
|
235
|
-
docs_array << '' if docs_array.length.positive? && params.length.positive?
|
236
|
-
params.each do |param|
|
237
|
-
docs_array << '' if docs_array.last != '' && docs_array.length.positive?
|
238
|
-
# Output params in the form of:
|
239
|
-
# _@param_ `foo` — Lorem ipsum.
|
240
|
-
# _@param_ `foo`
|
241
|
-
if param.text.nil? || param.text == ''
|
242
|
-
docs_array << "_@param_ `#{param.name}`"
|
243
|
-
else
|
244
|
-
docs_array << "_@param_ `#{param.name}` — #{param.text.gsub("\n", " ")}"
|
245
|
-
end
|
246
|
-
end
|
323
|
+
add_comments(meth, m)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
247
327
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
328
|
+
# Given a YARD NamespaceObject, add lines defining either its class
|
329
|
+
# and instance attributes and their signatures to the current RBI file.
|
330
|
+
# @param [YARD::CodeObjects::NamespaceObject] item
|
331
|
+
# @return [void]
|
332
|
+
def add_attributes(item)
|
333
|
+
[:class, :instance].each do |attr_loc|
|
334
|
+
# Grab attributes for the current location (class or instance)
|
335
|
+
attrs = item.attributes[attr_loc]
|
336
|
+
attrs.each do |name, attribute|
|
337
|
+
reader = attribute[:read]
|
338
|
+
writer = attribute[:write]
|
339
|
+
|
340
|
+
unless reader || writer
|
341
|
+
Logging.warn("attribute is not readable or writable somehow, skipping", attribute)
|
342
|
+
next
|
343
|
+
end
|
258
344
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
end if examples.length.positive?
|
270
|
-
|
271
|
-
# Add @note and @deprecated tags.
|
272
|
-
notice_tags = parser.tags.select { |tag| ['note', 'deprecated'].include?(tag.tag_name) && tag.is_a?(YARD::Tags::Tag) }
|
273
|
-
# Add a blank line if there's anything before the params.
|
274
|
-
docs_array << '' if docs_array.last != '' && docs_array.length.positive? && notice_tags.length.positive?
|
275
|
-
notice_tags.each do |notice_tag|
|
276
|
-
docs_array << '' if docs_array.last != ''
|
277
|
-
# Output note/deprecated/see in the form of:
|
278
|
-
# _@note_ — Lorem ipsum.
|
279
|
-
# _@note_
|
280
|
-
if notice_tag.text.nil?
|
281
|
-
docs_array << "_@#{notice_tag.tag_name}_"
|
282
|
-
else
|
283
|
-
docs_array << "_@#{notice_tag.tag_name}_ — #{notice_tag.text}"
|
284
|
-
end
|
285
|
-
end
|
345
|
+
# Get all given types
|
346
|
+
yard_types = []
|
347
|
+
if reader
|
348
|
+
yard_types += reader.tags('return').flat_map(&:types).compact.reject { |x| x.downcase == 'void' } +
|
349
|
+
reader.tags('param').flat_map(&:types)
|
350
|
+
end
|
351
|
+
if writer
|
352
|
+
yard_types += writer.tags('return').flat_map(&:types).compact.reject { |x| x.downcase == 'void' } +
|
353
|
+
writer.tags('param').flat_map(&:types)
|
354
|
+
end
|
286
355
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
356
|
+
# Use T.untyped if not types specified anywhere, otherwise try to
|
357
|
+
# compute Sorbet type given all these types
|
358
|
+
if yard_types.empty?
|
359
|
+
Logging.omit("no YARD type given for #{name.inspect}, using T.untyped", reader || writer)
|
360
|
+
sorbet_type = 'T.untyped'
|
361
|
+
else
|
362
|
+
sorbet_type = TypeConverter.yard_to_sorbet(
|
363
|
+
yard_types, reader || writer, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
|
364
|
+
end
|
365
|
+
|
366
|
+
# Generate attribute
|
367
|
+
if reader && writer
|
368
|
+
kind = :accessor
|
369
|
+
elsif reader
|
370
|
+
kind = :reader
|
371
|
+
elsif writer
|
372
|
+
kind = :writer
|
373
|
+
end
|
302
374
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
375
|
+
@current_object.create_attribute(
|
376
|
+
name.to_s,
|
377
|
+
kind: kind,
|
378
|
+
type: sorbet_type,
|
379
|
+
class_attribute: (attr_loc == :class)
|
380
|
+
) do |m|
|
381
|
+
add_comments(reader || writer, m)
|
307
382
|
end
|
308
383
|
end
|
309
384
|
end
|
@@ -327,6 +402,7 @@ module Sord
|
|
327
402
|
|
328
403
|
add_mixins(item)
|
329
404
|
add_methods(item)
|
405
|
+
add_attributes(item)
|
330
406
|
add_constants(item) unless @skip_constants
|
331
407
|
|
332
408
|
item.children.select { |x| [:class, :module].include?(x.type) }
|
data/lib/sord/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Christiansen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: yard
|
@@ -185,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: '0'
|
187
187
|
requirements: []
|
188
|
-
rubygems_version: 3.
|
188
|
+
rubygems_version: 3.0.3
|
189
189
|
signing_key:
|
190
190
|
specification_version: 4
|
191
191
|
summary: Generate Sorbet RBI files from YARD documentation
|