sord 3.0.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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