sord 1.0.0 → 2.0.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 +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
|