sord 3.0.1 → 5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c04d27e18791a912df49bf20c04c3d8555c04ce7f4e9d97d566398c705b4d826
4
- data.tar.gz: c9868a430d1cace15d5c11463c7718aa768e2f4b195c9877ba0cb9a995bb8d7e
3
+ metadata.gz: 12567f3b935a14271aedb28b62acfcfef3cb1e3bfb80fd294732947490dfb765
4
+ data.tar.gz: c40c2790500508fd2e575ab01e471cf7fe0e90f0c6d255285c7474433b65952c
5
5
  SHA512:
6
- metadata.gz: 2e1266f3b0950874993fb09814431d6ccc7e379128b7146bd46865571d422676df3103ec602534d2cd2e517e1b24b098d8e1edb09cb7002226369fa41d65c127
7
- data.tar.gz: c358bd3954399bc55db8883720a40bf1452131771367eb0613637899f5c4d319af6ee3c4d261cb70cb355d83cc21339489562ec1847c47f2893cb40a9c192818
6
+ metadata.gz: 85435a86928840302557121d0deeafde94a0b70905da93403c642a303ec773f5f4503b316beed31709052839a597e671df9ac554410d4c169843e859aebf361d
7
+ data.tar.gz: 77795ca64b509b9c7e7da210fac12d2b27bb8fe9e952ab61dc1d87c92189a1d0e457a4546bce2cebac4230a643f96072559c39bd477fc7e345819c98dd0b3bdd
@@ -0,0 +1,22 @@
1
+ name: Run tests
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ matrix:
9
+ ruby: [2.7, 3.0, 3.1]
10
+ continue-on-error: false
11
+
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: bundle install
21
+ - name: Run tests
22
+ run: bundle exec rake
data/CHANGELOG.md CHANGED
@@ -3,6 +3,49 @@ 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
+ ## [5.0.0] - 2022-10-06
7
+ ### Added
8
+ - If a derived class does not provide tags for a method, but it is overridden from a base class
9
+ which does, then the base class' documentation will be used to generate types for the derived
10
+ method.
11
+ - When generating RBS, if a duck type matches one of RBS' built-in interfaces, this type will be
12
+ generated instead. (For example, `#to_s` will generate the type `_ToS`.)
13
+ - Added the `--hide-private` flag, which will omit outputting items with private visibility.
14
+ - To improve resolution, types for gems are now loaded from the RBS collection.
15
+ - If you are using custom YARD tags, Sord can now be made aware of these by passing the `--tags`
16
+ option.
17
+
18
+ ### Changed
19
+ - **Breaking change**: Support for versions of Ruby prior to 2.7 has been dropped.
20
+ - When Sord runs YARD automatically, it no longer generates HTML documentation, since this isn't
21
+ necessary for Sord's analysis. If you were relying on this as part of your workflow, then this
22
+ could be a **breaking change**.
23
+
24
+ ### Fixed
25
+ - Duck-typed methods ending with `?` or `!`, and operator methods like `#[]=`, are now correctly
26
+ recognised as duck types.
27
+ - Fixed an exception when referring to built-in types with root namespace (`::Array<Foo>`) syntax.
28
+ - `@yieldparams` without a parameter name no longer cause an exception, and instead use default
29
+ names of the pattern: `arg0`, `arg1`, ...
30
+
31
+ ## [4.0.0] - 2022-07-19
32
+ ### Added
33
+ - Constants are now assigned types when generating RBS, using `@return`.
34
+ - Class-level `attr_accessor`s are converted to methods when generating RBS.
35
+ - Added the `--exclude-untyped` flag, which skips generating type signatures for methods with
36
+ `untyped` return values.
37
+
38
+ ### Changed
39
+ - If YARD tags are present for a block, but there is no block param (such as when using `yield`),
40
+ the type signature now includes the documented block. This could be a **breaking change** leading
41
+ to type errors in existing code where such methods are called.
42
+
43
+ ### Fixed
44
+ - Added workaround for YARD syntax error when a default parameter value begins with a unary minus
45
+ - Name resolutions from the root (e.g. `::X`) now behave correctly; previously they may have
46
+ selected a class named `X` nested within another namespace. This may be a **breaking change** if
47
+ any part of your generated type signatures was relying on the old, buggy behaviour.
48
+
6
49
  ## [3.0.1] - 2020-12-28
7
50
  ### Fixed
8
51
  - Fixed `SortedSet` crash on Ruby 3
data/README.md CHANGED
@@ -12,6 +12,8 @@ type signatures you need!
12
12
  Sord is the perfect way to jump-start the adoption of types in your project,
13
13
  whether you plan to use Sorbet's RBI format or Ruby 3/Steep's RBS format.
14
14
 
15
+ **Try Sord online at: [sord.aaronc.cc](https://sord.aaronc.cc)**
16
+
15
17
  Sord has the following features:
16
18
  - Automatically generates signatures for modules, classes and methods
17
19
  - Support for multiple parameter or return types (`T.any`/`|`)
@@ -81,6 +83,10 @@ Sord also takes some flags to alter the generated file:
81
83
  take a comma-separated list of logging kinds, for example `omit,infer`.
82
84
  When using `--include-messages`, the `done` kind is included by default.
83
85
  (You cannot specify both `--include-messages` and `--exclude-messages`.)
86
+ - `--exclude-untyped`: Exclude methods and attributes with untyped return
87
+ values.
88
+ - `--tags TAGS`: Provide a list of comma-separated tags as understood by the
89
+ `yard` command. E.g. `--tags 'mytag:My Description,mytag2:My New Description'
84
90
 
85
91
  ## Example
86
92
 
data/exe/sord CHANGED
@@ -22,7 +22,10 @@ command :gen do |c|
22
22
  c.option '--include-messages STRING', String, 'Whitelists a comma-separated string of log message types'
23
23
  c.option '--keep-original-comments', 'Retains original YARD comments rather than converting them to Markdown'
24
24
  c.option '--skip-constants', 'Excludes constants from generated file'
25
+ c.option '--hide-private', 'Exclude any object marked with @!visibility private'
25
26
  c.option '--use-original-initialize-return', 'Uses the specified return type for #initialize rather than void'
27
+ c.option '--exclude-untyped', 'Exclude methods and attributes with untyped return values'
28
+ c.option '--tags TAGS', Array, 'Tag parameters for the YARD command'
26
29
 
27
30
  c.action do |args, options|
28
31
  options.default(
@@ -33,21 +36,24 @@ command :gen do |c|
33
36
  break_params: 4,
34
37
  replace_errors_with_untyped: false,
35
38
  replace_unresolved_with_untyped: false,
39
+ hide_private: false,
36
40
  exclude_messages: nil,
37
41
  include_messages: nil,
38
42
  keep_original_comments: false,
39
43
  skip_constants: false,
40
44
  use_original_initialize_return: false,
45
+ exclude_untyped: false,
46
+ tags: [],
41
47
  )
42
48
 
43
49
  if args.length != 1
44
50
  Sord::Logging.error('Must specify filename')
45
51
  exit 1
46
52
  end
47
-
53
+
48
54
  plugin_options = options.__hash__
49
- plugin_options[:exclude_options] = plugin_options[:exclude_options]&.split(',')
50
- plugin_options[:include_options] = plugin_options[:include_options]&.split(',')
55
+ plugin_options[:exclude_messages] = plugin_options[:exclude_messages]&.split(',')
56
+ plugin_options[:include_messages] = plugin_options[:include_messages]&.split(',')
51
57
 
52
58
  if !(plugin_options[:rbi] || plugin_options[:rbs])
53
59
  if args.first
@@ -84,7 +90,7 @@ command :gen do |c|
84
90
 
85
91
  plugin.parlour = klass.new(break_params: plugin_options[:break_params])
86
92
  plugin.generate(plugin.parlour.root)
87
-
93
+
88
94
  File.write(args.first, plugin.parlour.send(generator_method))
89
95
  end
90
96
  end
@@ -8,16 +8,16 @@ require 'rainbow'
8
8
  module Sord
9
9
  # Converts the current working directory's YARD registry into an type
10
10
  # signature file.
11
- class Generator
11
+ class Generator
12
12
  VALID_MODES = [:rbi, :rbs]
13
13
 
14
- # @return [Integer] The number of objects this generator has processed so
14
+ # @return [Integer] The number of objects this generator has processed so
15
15
  # far.
16
16
  def object_count
17
17
  @namespace_count + @method_count
18
18
  end
19
19
 
20
- # @return [Array<Array(String, YARD::CodeObjects::Base, Integer)>] The
20
+ # @return [Array<Array(String, YARD::CodeObjects::Base, Integer)>] The
21
21
  # errors encountered by by the generator. Each element is of the form
22
22
  # [message, item, line].
23
23
  attr_reader :warnings
@@ -28,6 +28,7 @@ module Sord
28
28
  # @option options [Integer] break_params
29
29
  # @option options [Boolean] replace_errors_with_untyped
30
30
  # @option options [Boolean] replace_unresolved_with_untyped
31
+ # @option options [Boolean] hide_private
31
32
  # @option options [Boolean] comments
32
33
  # @option options [Parlour::Generator] generator
33
34
  # @option options [Parlour::TypedObject] root
@@ -53,12 +54,28 @@ module Sord
53
54
  @replace_errors_with_untyped = options[:replace_errors_with_untyped]
54
55
  @replace_unresolved_with_untyped = options[:replace_unresolved_with_untyped]
55
56
  @keep_original_comments = options[:keep_original_comments]
57
+ @hide_private = options[:hide_private]
56
58
  @skip_constants = options[:skip_constants]
57
59
  @use_original_initialize_return = options[:use_original_initialize_return]
60
+ @exclude_untyped = options[:exclude_untyped]
61
+
62
+ @type_converter_config = TypeConverter::Configuration.new(
63
+ output_language: @mode,
64
+ replace_errors_with_untyped: @replace_errors_with_untyped,
65
+ replace_unresolved_with_untyped: @replace_unresolved_with_untyped,
66
+ )
58
67
 
59
68
  # Hook the logger so that messages are added as comments
60
- Logging.add_hook do |type, msg, item|
61
- @current_object.add_comment_to_next_child("sord #{type} - #{msg}")
69
+ Logging.add_hook do |type, msg, item, **opts|
70
+ # Hack: the "exclude untyped" log message needs to print somewhere, but
71
+ # if there's no future object for that comment to associate with, it'll
72
+ # never be printed!
73
+ # Instead, add an arbitrary containing the comment
74
+ if opts[:immediate]
75
+ @current_object.create_arbitrary(code: "# sord #{type} - #{msg}")
76
+ else
77
+ @current_object.add_comment_to_next_child("sord #{type} - #{msg}")
78
+ end
62
79
  end if options[:sord_comments]
63
80
 
64
81
  # Hook the logger so that warnings are collected
@@ -110,7 +127,8 @@ module Sord
110
127
  def add_constants(item)
111
128
  inserted_constant_names = Set.new
112
129
 
113
- item.constants(included: false).each do |constant|
130
+ item.constants(included: false).each do |constant|
131
+ next if @hide_private && constant.visibility == :private
114
132
  # Take a constant (like "A::B::CONSTANT"), split it on each '::', and
115
133
  # set the constant name to the last string in the array.
116
134
  constant_name = constant.to_s.split('::').last
@@ -119,7 +137,7 @@ module Sord
119
137
  next
120
138
  end
121
139
  inserted_constant_names << constant_name
122
-
140
+
123
141
  # Add the constant to the current object being generated.
124
142
  case @mode
125
143
  when :rbi
@@ -127,7 +145,18 @@ module Sord
127
145
  c.add_comments(constant.docstring.all.split("\n"))
128
146
  end
129
147
  when :rbs
130
- @current_object.create_constant(constant_name, type: Parlour::Types::Untyped.new) do |c|
148
+ return_tags = constant.tags('return')
149
+ returns = if return_tags.empty?
150
+ Logging.omit("no YARD return type given, using untyped", constant)
151
+ Parlour::Types::Untyped.new
152
+ else
153
+ TypeConverter.yard_to_parlour(
154
+ return_tags.map(&:types).flatten,
155
+ constant,
156
+ @type_converter_config,
157
+ )
158
+ end
159
+ @current_object.create_constant(constant_name, type: returns) do |c|
131
160
  c.add_comments(constant.docstring.all.split("\n"))
132
161
  end
133
162
  end
@@ -225,12 +254,33 @@ module Sord
225
254
  end
226
255
  end
227
256
 
257
+ # @param method [YARD::CodeObjects::MethodObject]
258
+ # @param tag_name [String]
259
+ # @return [Array<YARD::Tags::Tag>]
260
+ def method_tags(method, tag_name)
261
+ tags = method.tags(tag_name)
262
+ return tags if tags.any? || method.overridden_method.nil?
263
+
264
+ method.overridden_method.tags(tag_name)
265
+ end
266
+
267
+ # @param method [YARD::CodeObjects::MethodObject]
268
+ # @param tag_name [String]
269
+ # @return [YARD::Tags::Tag, nil]
270
+ def method_tag(method, tag_name)
271
+ tag = method.tag(tag_name)
272
+ return tag if tag || method.overridden_method.nil?
273
+
274
+ method.overridden_method.tag(tag_name)
275
+ end
276
+
228
277
  # Given a YARD NamespaceObject, add lines defining its methods and their
229
278
  # signatures to the current file.
230
279
  # @param [YARD::CodeObjects::NamespaceObject] item
231
280
  # @return [void]
232
281
  def add_methods(item)
233
282
  item.meths(inherited: false).each do |meth|
283
+ next if @hide_private && meth.visibility == :private
234
284
  count_method
235
285
 
236
286
  # If the method is an alias, skip it so we don't define it as a
@@ -243,37 +293,44 @@ module Sord
243
293
  if meth.is_attribute?
244
294
  next
245
295
  end
246
-
296
+
247
297
  # Sort parameters
248
298
  meth.parameters.reverse.sort! { |pair1, pair2| sort_params(pair1, pair2) }
249
- # This is better than iterating over YARD's "@param" tags directly
299
+
300
+ # This is better than iterating over YARD's "@param" tags directly
250
301
  # because it includes parameters without documentation
251
302
  # (The gsubs allow for better splat-argument compatibility)
252
303
  parameter_names_and_defaults_to_tags = meth.parameters.map do |name, default|
253
- [[name, default], meth.tags('param')
304
+ [[name, fix_default_if_unary_minus(default)], method_tags(meth, 'param')
254
305
  .find { |p| p.name&.gsub('*', '')&.gsub(':', '') == name.gsub('*', '').gsub(':', '') }]
255
306
  end.to_h
256
307
 
308
+ # Add block param if there is no named param but YARD tags are present
309
+ if !parameter_names_and_defaults_to_tags.any? { |((name, _), _)| name.start_with? '&' } \
310
+ && (method_tags(meth, 'yieldparam').any? || method_tag(meth, 'yieldreturn'))
311
+ parameter_names_and_defaults_to_tags[['&blk']] = nil
312
+ end
313
+
257
314
  parameter_types = parameter_names_and_defaults_to_tags.map do |name_and_default, tag|
258
315
  name = name_and_default.first
259
316
 
260
317
  if tag
261
- TypeConverter.yard_to_parlour(tag.types, meth, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
318
+ TypeConverter.yard_to_parlour(tag.types, meth, @type_converter_config)
262
319
  elsif name.start_with? '&'
263
320
  # Find yieldparams and yieldreturn
264
- yieldparams = meth.tags('yieldparam')
265
- yieldreturn = meth.tag('yieldreturn')&.types
321
+ yieldparams = method_tags(meth, 'yieldparam')
322
+ yieldreturn = method_tag(meth, 'yieldreturn')&.types
266
323
  yieldreturn = nil if yieldreturn&.length == 1 &&
267
324
  yieldreturn&.first&.downcase == 'void'
268
325
 
269
326
  # Create strings
270
- params = yieldparams.map do |param|
327
+ params = yieldparams.map.with_index do |param, i|
271
328
  Parlour::Types::Proc::Parameter.new(
272
- param.name.gsub('*', ''),
273
- TypeConverter.yard_to_parlour(param.types, meth, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
329
+ param.name&.gsub('*', '') || "arg#{i}",
330
+ TypeConverter.yard_to_parlour(param.types, meth, @type_converter_config)
274
331
  )
275
332
  end
276
- returns = TypeConverter.yard_to_parlour(yieldreturn, meth, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
333
+ returns = TypeConverter.yard_to_parlour(yieldreturn, meth, @type_converter_config)
277
334
 
278
335
  # Create proc types, if possible
279
336
  if yieldparams.empty? && yieldreturn.nil?
@@ -288,36 +345,36 @@ module Sord
288
345
 
289
346
  unless getter
290
347
  if parameter_names_and_defaults_to_tags.length == 1 \
291
- && meth.tags('param').length == 1 \
292
- && meth.tag('param').types
293
-
348
+ && method_tags(meth, 'param').length == 1 \
349
+ && method_tag(meth, 'param').types
350
+
294
351
  Logging.infer("argument name in single @param inferred as #{parameter_names_and_defaults_to_tags.first.first.first.inspect}", meth)
295
- next TypeConverter.yard_to_parlour(meth.tag('param').types, meth, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
296
- else
352
+ next TypeConverter.yard_to_parlour(method_tag(meth, 'param').types, meth, @type_converter_config)
353
+ else
297
354
  Logging.omit("no YARD type given for #{name.inspect}, using untyped", meth)
298
355
  next Parlour::Types::Untyped.new
299
356
  end
300
357
  end
301
358
 
302
- return_types = getter.tags('return').flat_map(&:types)
359
+ return_types = method_tags(getter, 'return').flat_map(&:types)
303
360
  unless return_types.any?
304
361
  Logging.omit("no YARD type given for #{name.inspect}, using untyped", meth)
305
362
  next Parlour::Types::Untyped.new
306
363
  end
307
364
  inferred_type = TypeConverter.yard_to_parlour(
308
- return_types, meth, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
309
-
365
+ return_types, meth, @type_converter_config)
366
+
310
367
  Logging.infer("inferred type of parameter #{name.inspect} as #{inferred_type.describe} using getter's return type", meth)
311
368
  inferred_type
312
369
  else
313
370
  # Is this the only argument, and was a @param specified without an
314
371
  # argument name? If so, infer it
315
372
  if parameter_names_and_defaults_to_tags.length == 1 \
316
- && meth.tags('param').length == 1 \
317
- && meth.tag('param').types
373
+ && method_tags(meth, 'param').length == 1 \
374
+ && method_tag(meth, 'param').types
318
375
 
319
376
  Logging.infer("argument name in single @param inferred as #{parameter_names_and_defaults_to_tags.first.first.first.inspect}", meth)
320
- TypeConverter.yard_to_parlour(meth.tag('param').types, meth, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
377
+ TypeConverter.yard_to_parlour(method_tag(meth, 'param').types, meth, @type_converter_config)
321
378
  else
322
379
  Logging.omit("no YARD type given for #{name.inspect}, using untyped", meth)
323
380
  Parlour::Types::Untyped.new
@@ -325,7 +382,7 @@ module Sord
325
382
  end
326
383
  end
327
384
 
328
- return_tags = meth.tags('return')
385
+ return_tags = method_tags(meth, 'return')
329
386
  returns = if meth.name == :initialize && !@use_original_initialize_return
330
387
  nil
331
388
  elsif return_tags.length == 0
@@ -334,14 +391,14 @@ module Sord
334
391
  elsif return_tags.length == 1 && %w{void nil}.include?(return_tags&.first&.types&.first&.downcase)
335
392
  nil
336
393
  else
337
- TypeConverter.yard_to_parlour(meth.tag('return').types, meth, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
394
+ TypeConverter.yard_to_parlour(method_tag(meth, 'return').types, meth, @type_converter_config)
338
395
  end
339
396
 
340
397
  rbs_block = nil
341
398
  parlour_params = parameter_names_and_defaults_to_tags
342
399
  .zip(parameter_types)
343
400
  .map do |((name, default), _), type|
344
- # If the default is "nil" but the type is not nilable, then it
401
+ # If the default is "nil" but the type is not nilable, then it
345
402
  # should become nilable
346
403
  # (T.untyped can include nil, so don't alter that)
347
404
  type = Parlour::Types::Nilable.new(type) \
@@ -369,10 +426,15 @@ module Sord
369
426
  end
370
427
  .compact
371
428
 
429
+ if @exclude_untyped && parlour_params.all? { |p| p.type.is_a?(Parlour::Types::Untyped) } && returns.is_a?(Parlour::Types::Untyped)
430
+ Logging.omit("excluding untyped", meth, immediate: true)
431
+ next
432
+ end
433
+
372
434
  case @mode
373
435
  when :rbi
374
436
  @current_object.create_method(
375
- meth.name.to_s,
437
+ meth.name.to_s,
376
438
  parameters: parlour_params,
377
439
  returns: returns,
378
440
  class_method: meth.scope == :class
@@ -391,7 +453,7 @@ module Sord
391
453
  ) do |m|
392
454
  add_comments(meth, m)
393
455
  end
394
- end
456
+ end
395
457
  end
396
458
  end
397
459
 
@@ -415,10 +477,12 @@ module Sord
415
477
  # Get all given types
416
478
  yard_types = []
417
479
  if reader
480
+ next if @hide_private && reader.visibility == :private
418
481
  yard_types += reader.tags('return').flat_map(&:types).compact.reject { |x| x.downcase == 'void' } +
419
482
  reader.tags('param').flat_map(&:types)
420
483
  end
421
484
  if writer
485
+ next if @hide_private && writer.visibility == :private
422
486
  yard_types += writer.tags('return').flat_map(&:types).compact.reject { |x| x.downcase == 'void' } +
423
487
  writer.tags('param').flat_map(&:types)
424
488
  end
@@ -433,7 +497,7 @@ module Sord
433
497
  parlour_type = Parlour::Types::Untyped.new
434
498
  else
435
499
  parlour_type = TypeConverter.yard_to_parlour(
436
- yard_types, reader || writer, @replace_errors_with_untyped, @replace_unresolved_with_untyped)
500
+ yard_types, reader || writer, @type_converter_config)
437
501
  end
438
502
 
439
503
  # Generate attribute
@@ -445,6 +509,11 @@ module Sord
445
509
  kind = :writer
446
510
  end
447
511
 
512
+ if @exclude_untyped && parlour_type.is_a?(Parlour::Types::Untyped)
513
+ Logging.omit("excluding untyped attribute", reader || writer, immediate: true)
514
+ next
515
+ end
516
+
448
517
  case @mode
449
518
  when :rbi
450
519
  @current_object.create_attribute(
@@ -457,7 +526,31 @@ module Sord
457
526
  end
458
527
  when :rbs
459
528
  if attr_loc == :class
460
- Logging.warn("RBS doesn't support class attributes, dropping", reader || writer)
529
+ # RBS doesn't support class attr_accessors so create individual methods
530
+
531
+ if reader
532
+ @current_object.create_method(
533
+ name.to_s,
534
+ [Parlour::RbsGenerator::MethodSignature.new([], parlour_type)],
535
+ class_method: true
536
+ ) do |m|
537
+ add_comments(reader, m)
538
+ end
539
+ end
540
+
541
+ if writer
542
+ @current_object.create_method(
543
+ "#{name}=",
544
+ [Parlour::RbsGenerator::MethodSignature.new([Parlour::RbsGenerator::Parameter.new(
545
+ "value",
546
+ type: parlour_type,
547
+ required: true
548
+ )], parlour_type)],
549
+ class_method: true
550
+ ) do |m|
551
+ add_comments(writer, m)
552
+ end
553
+ end
461
554
  else
462
555
  @current_object.create_attribute(
463
556
  name.to_s,
@@ -477,6 +570,7 @@ module Sord
477
570
  # @param [YARD::CodeObjects::NamespaceObject] item
478
571
  # @return [void]
479
572
  def add_namespace(item)
573
+ return if @hide_private && item.visibility == :private
480
574
  count_namespace
481
575
 
482
576
  superclass = nil
@@ -499,7 +593,7 @@ module Sord
499
593
  @current_object = parent
500
594
  end
501
595
 
502
- # Populates the generator with the contents of the YARD registry. You
596
+ # Populates the generator with the contents of the YARD registry. You
503
597
  # must load the YARD registry first!
504
598
  # @return [void]
505
599
  def populate
@@ -597,5 +691,20 @@ module Sord
597
691
 
598
692
  return pair_type_order[pair1_type] <=> pair_type_order[pair2_type]
599
693
  end
694
+
695
+ # Removes the last character of a default parameter value if it begins with
696
+ # '-', working around a bug in YARD. (See lsegal/yard #894)
697
+ #
698
+ # @param [String] default
699
+ # @return [String, nil]
700
+ def fix_default_if_unary_minus(default)
701
+ if default.nil?
702
+ nil
703
+ elsif default[0] == '-' && !default.start_with?('->')
704
+ default[0..-2]
705
+ else
706
+ default
707
+ end
708
+ end
600
709
  end
601
710
  end
data/lib/sord/logging.rb CHANGED
@@ -70,16 +70,17 @@ module Sord
70
70
  # is associated with, if any. This is shown before the log message if it is
71
71
  # specified.
72
72
  # @return [void]
73
- def self.generic(kind, header, msg, item)
73
+ def self.generic(kind, header, msg, item, **opts)
74
74
  return unless enabled_types.include?(kind)
75
75
 
76
- if item
77
- puts "#{header} (#{Rainbow(item.path).bold}) #{msg}" unless silent?
76
+ message = if item
77
+ "#{header} (#{Rainbow(item.path).bold}) #{msg}"
78
78
  else
79
- puts "#{header} #{msg}" unless silent?
79
+ "#{header} #{msg}"
80
80
  end
81
+ puts message unless silent?
81
82
 
82
- invoke_hooks(kind, msg, item)
83
+ invoke_hooks(kind, msg, item, **opts)
83
84
  end
84
85
 
85
86
  # Print a warning message. This should be used for things which require the
@@ -89,8 +90,8 @@ module Sord
89
90
  # is associated with, if any. This is shown before the log message if it is
90
91
  # specified.
91
92
  # @return [void]
92
- def self.warn(msg, item = nil)
93
- generic(:warn, Rainbow('[WARN ]').yellow, msg, item)
93
+ def self.warn(msg, item = nil, **opts)
94
+ generic(:warn, Rainbow('[WARN ]').yellow, msg, item, **opts)
94
95
  end
95
96
 
96
97
  # Print an info message. This should be used for generic informational
@@ -100,8 +101,8 @@ module Sord
100
101
  # is associated with, if any. This is shown before the log message if it is
101
102
  # specified.
102
103
  # @return [void]
103
- def self.info(msg, item = nil)
104
- generic(:info, '[INFO ]', msg, item)
104
+ def self.info(msg, item = nil, **opts)
105
+ generic(:info, '[INFO ]', msg, item, **opts)
105
106
  end
106
107
 
107
108
  # Print a duck-typing message. This should be used when the YARD
@@ -112,8 +113,8 @@ module Sord
112
113
  # is associated with, if any. This is shown before the log message if it is
113
114
  # specified.
114
115
  # @return [void]
115
- def self.duck(msg, item = nil)
116
- generic(:duck, Rainbow('[DUCK ]').cyan, msg, item)
116
+ def self.duck(msg, item = nil, **opts)
117
+ generic(:duck, Rainbow('[DUCK ]').cyan, msg, item, **opts)
117
118
  end
118
119
 
119
120
  # Print an error message. This should be used for things which require the
@@ -123,8 +124,8 @@ module Sord
123
124
  # is associated with, if any. This is shown before the log message if it is
124
125
  # specified.
125
126
  # @return [void]
126
- def self.error(msg, item = nil)
127
- generic(:error, Rainbow('[ERROR]').red, msg, item)
127
+ def self.error(msg, item = nil, **opts)
128
+ generic(:error, Rainbow('[ERROR]').red, msg, item, **opts)
128
129
  end
129
130
 
130
131
  # Print an infer message. This should be used when the user should be told
@@ -135,8 +136,8 @@ module Sord
135
136
  # is associated with, if any. This is shown before the log message if it is
136
137
  # specified.
137
138
  # @return [void]
138
- def self.infer(msg, item = nil)
139
- generic(:infer, Rainbow('[INFER]').blue, msg, item)
139
+ def self.infer(msg, item = nil, **opts)
140
+ generic(:infer, Rainbow('[INFER]').blue, msg, item, **opts)
140
141
  end
141
142
 
142
143
  # Print an omit message. This should be used as a special type of warning
@@ -147,8 +148,8 @@ module Sord
147
148
  # is associated with, if any. This is shown before the log message if it is
148
149
  # specified.
149
150
  # @return [void]
150
- def self.omit(msg, item = nil)
151
- generic(:omit, Rainbow('[OMIT ]').magenta, msg, item)
151
+ def self.omit(msg, item = nil, **opts)
152
+ generic(:omit, Rainbow('[OMIT ]').magenta, msg, item, **opts)
152
153
  end
153
154
 
154
155
  # Print a done message. This should be used when a process completes
@@ -158,8 +159,8 @@ module Sord
158
159
  # is associated with, if any. This is shown before the log message if it is
159
160
  # specified.
160
161
  # @return [void]
161
- def self.done(msg, item = nil)
162
- generic(:done, Rainbow('[DONE ]').green, msg, item)
162
+ def self.done(msg, item = nil, **opts)
163
+ generic(:done, Rainbow('[DONE ]').green, msg, item, **opts)
163
164
  end
164
165
 
165
166
  # Invokes all registered hooks on the logger.
@@ -169,9 +170,9 @@ module Sord
169
170
  # is associated with, if any. This is shown before the log message if it is
170
171
  # specified.
171
172
  # @return [void]
172
- def self.invoke_hooks(kind, msg, item)
173
+ def self.invoke_hooks(kind, msg, item, **opts)
173
174
  @@hooks.each do |hook|
174
- hook.(kind, msg, item) rescue nil
175
+ hook.(kind, msg, item, **opts)
175
176
  end
176
177
  end
177
178