Skip to content

Commit 35b7423

Browse files
authored
[1.2.0] Add @!attribute docs for Struct.new declarations (#14)
1 parent 606c82f commit 35b7423

File tree

18 files changed

+524
-60
lines changed

18 files changed

+524
-60
lines changed

.rubocop_todo.yml

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2026-03-23 22:08:56 UTC using RuboCop version 1.84.0.
3+
# on 2026-03-27 06:40:04 UTC using RuboCop version 1.84.0.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
@@ -32,24 +32,24 @@ Metrics/BlockNesting:
3232
# Offense count: 4
3333
# Configuration parameters: CountComments, CountAsOne.
3434
Metrics/ClassLength:
35-
Max: 413
35+
Max: 393
3636

3737
# Offense count: 30
3838
# Configuration parameters: AllowedMethods, AllowedPatterns.
3939
Metrics/CyclomaticComplexity:
4040
Max: 41
4141

42-
# Offense count: 63
42+
# Offense count: 65
4343
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
4444
Metrics/MethodLength:
4545
Max: 105
4646

4747
# Offense count: 6
4848
# Configuration parameters: CountComments, CountAsOne.
4949
Metrics/ModuleLength:
50-
Max: 393
50+
Max: 396
5151

52-
# Offense count: 8
52+
# Offense count: 9
5353
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
5454
Metrics/ParameterLists:
5555
Max: 8
@@ -69,32 +69,47 @@ Naming/MethodParameterName:
6969
- 'lib/docscribe/infer/returns.rb'
7070
- 'lib/docscribe/inline_rewriter/doc_builder.rb'
7171

72-
# Offense count: 4
72+
# Offense count: 5
7373
# Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
7474
# AllowedMethods: call
7575
# WaywardPredicates: nonzero?
7676
Naming/PredicateMethod:
7777
Exclude:
7878
- 'lib/docscribe/inline_rewriter/collector.rb'
7979

80-
# Offense count: 58
80+
# Offense count: 60
8181
# Configuration parameters: IgnoredMetadata.
8282
RSpec/DescribeClass:
8383
Enabled: false
8484

85-
# Offense count: 128
85+
# Offense count: 135
8686
# Configuration parameters: CountAsOne.
8787
RSpec/ExampleLength:
8888
Max: 34
8989

90-
# Offense count: 114
90+
# Offense count: 121
9191
RSpec/MultipleExpectations:
9292
Max: 7
9393

94-
# Offense count: 20
94+
# Offense count: 13
9595
# Configuration parameters: AllowedConstants.
9696
Style/Documentation:
97-
Enabled: false
97+
Exclude:
98+
- 'spec/**/*'
99+
- 'test/**/*'
100+
- 'lib/docscribe/cli.rb'
101+
- 'lib/docscribe/cli/config_builder.rb'
102+
- 'lib/docscribe/cli/init.rb'
103+
- 'lib/docscribe/cli/options.rb'
104+
- 'lib/docscribe/config.rb'
105+
- 'lib/docscribe/config/emit.rb'
106+
- 'lib/docscribe/config/filtering.rb'
107+
- 'lib/docscribe/config/loader.rb'
108+
- 'lib/docscribe/config/rbs.rb'
109+
- 'lib/docscribe/config/sorbet.rb'
110+
- 'lib/docscribe/config/sorting.rb'
111+
- 'lib/docscribe/config/template.rb'
112+
- 'lib/docscribe/config/utils.rb'
98113

99114
# Offense count: 3
100115
# This cop supports safe autocorrection (--autocorrect).

README.md

Lines changed: 115 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ returns), and respects Ruby visibility semantics — without using YARD to parse
1717
Sorbet `sig`, new docs are inserted above the first `sig`.
1818
- Heuristic type inference for params and return values, including conditional returns in rescue branches.
1919
- Safe and aggressive update modes:
20-
- safe mode inserts missing docs, merges existing doc-like blocks, and normalizes sortable tags
21-
- aggressive mode rebuilds existing doc blocks
20+
- safe mode inserts missing docs, merges existing doc-like blocks, and normalizes sortable tags;
21+
- aggressive mode rebuilds existing doc blocks.
2222
- Ruby 3.4+ syntax supported using Prism translation (see "Parser backend" below).
2323
- Optional external type integrations:
24-
- RBS via `--rbs` / `--sig-dir`
25-
- Sorbet via inline `sig` declarations and RBI files with `--sorbet` / `--rbi-dir`
26-
- Optional `attr_reader`/`attr_writer`/`attr_accessor` documentation via YARD `@!attribute` (see Configuration).
24+
- RBS via `--rbs` / `--sig-dir`;
25+
- Sorbet via inline `sig` declarations and RBI files with `--sorbet` / `--rbi-dir`.
26+
- Optional `@!attribute` generation for:
27+
- `attr_reader` / `attr_writer` / `attr_accessor`;
28+
- `Struct.new` declarations in both constant-assigned and class-based styles.
2729

2830
Common workflows:
2931

@@ -69,7 +71,12 @@ Common workflows:
6971
* [API (library) usage](#api-library-usage)
7072
* [Configuration](#configuration)
7173
* [Filtering](#filtering)
72-
* [Attribute macros (`attr_*`)](#attribute-macros-attr_)
74+
* [`attr_*` example](#attr_-example)
75+
* [`Struct.new` examples](#structnew-examples)
76+
* [Constant-assigned struct](#constant-assigned-struct)
77+
* [Class-based struct](#class-based-struct)
78+
* [Merge behavior](#merge-behavior)
79+
* [Param tag style](#param-tag-style)
7380
* [Create a starter config](#create-a-starter-config)
7481
* [CI integration](#ci-integration)
7582
* [Comparison to YARD's parser](#comparison-to-yards-parser)
@@ -470,7 +477,6 @@ sorbet:
470477
### Inline Sorbet example
471478
472479
```ruby
473-
474480
class Demo
475481
extend T::Sig
476482

@@ -484,7 +490,6 @@ end
484490
Docscribe will use the Sorbet signature instead of the inferred body type:
485491

486492
```ruby
487-
488493
class Demo
489494
extend T::Sig
490495

@@ -749,51 +754,129 @@ docscribe --exclude-file '/^spec\//' lib
749754
> `/regex/` passed to `--include`/`--exclude` is treated as a **method-id** pattern. Use `--include-file` /
750755
`--exclude-file` for file regex filters.
751756

752-
### Attribute macros (`attr_*`)
753-
754-
Docscribe can generate YARD `@!attribute` directives above `attr_reader`, `attr_writer`, and `attr_accessor`.
755-
756-
Enable it:
757+
Enable attribute-style documentation generation with:
757758

758759
```yaml
759760
emit:
760761
attributes: true
761762
```
762763

763-
Example:
764+
When enabled, Docscribe can generate YARD `@!attribute` docs for:
764765

765-
```ruby
766-
class User
767-
attr_reader :name
766+
- `attr_reader`
767+
- `attr_writer`
768+
- `attr_accessor`
769+
- `Struct.new` declarations
768770

769-
private
771+
### `attr_*` example
770772

771-
attr_accessor :token
773+
> [!NOTE]
774+
> - Attribute docs are inserted above the `attr_*` call, not above generated methods (since they don’t exist as `def`
775+
nodes).
776+
> - If RBS is enabled, Docscribe will try to use the RBS return type of the reader method as the attribute type.
777+
778+
```ruby
779+
class User
780+
attr_accessor :name
772781
end
773782
```
774783

775-
Becomes:
784+
Generated docs:
776785

777786
```ruby
778787
class User
779-
# @!attribute [r] name
788+
# @!attribute [rw] name
780789
# @return [Object]
781-
attr_reader :name
790+
# @param [Object] value
791+
attr_accessor :name
792+
end
793+
```
782794

783-
private
795+
### `Struct.new` examples
784796

785-
# @!attribute [rw] token
786-
# @private
787-
# @return [Object]
788-
# @param value [Object]
789-
attr_accessor :token
797+
Docscribe supports both common `Struct.new` declaration styles.
798+
799+
#### Constant-assigned struct
800+
801+
```ruby
802+
User = Struct.new(:name, :email, keyword_init: true)
803+
```
804+
805+
Generated docs:
806+
807+
```ruby
808+
# @!attribute [rw] name
809+
# @return [Object]
810+
# @param [Object] value
811+
#
812+
# @!attribute [rw] email
813+
# @return [Object]
814+
# @param [Object] value
815+
User = Struct.new(:name, :email, keyword_init: true)
816+
```
817+
818+
#### Class-based struct
819+
820+
```ruby
821+
class User < Struct.new(:name, :email, keyword_init: true)
790822
end
791823
```
792824

793-
> [!NOTE]
794-
> - Attribute docs are inserted above the `attr_*` call, not above generated methods (since they don’t exist as `def`
795-
nodes).
796-
> - If RBS is enabled, Docscribe will try to use the RBS return type of the reader method as the attribute type.
825+
Generated docs:
826+
827+
```ruby
828+
# @!attribute [rw] name
829+
# @return [Object]
830+
# @param [Object] value
831+
#
832+
# @!attribute [rw] email
833+
# @return [Object]
834+
# @param [Object] value
835+
class User < Struct.new(:name, :email, keyword_init: true)
836+
end
837+
```
838+
839+
Docscribe preserves the original declaration style and does not rewrite one form into the other.
840+
841+
### Merge behavior
842+
843+
Struct member docs use the same attribute documentation pipeline as `attr_*` macros, which means they participate in the
844+
normal safe/aggressive rewrite flow.
845+
846+
In safe mode, Docscribe can:
847+
848+
- insert full `@!attribute` docs when no doc-like block exists
849+
- append missing struct member docs into an existing doc-like block
850+
851+
### Param tag style
852+
853+
Generated writer-style attribute docs respect `doc.param_tag_style`.
854+
855+
For example, with:
856+
857+
```yaml
858+
doc:
859+
param_tag_style: "type_name"
860+
```
861+
862+
writer params are emitted as:
863+
864+
```ruby
865+
# @param [Object] value
866+
```
867+
868+
With:
869+
870+
```yaml
871+
doc:
872+
param_tag_style: "name_first"
873+
```
874+
875+
they are emitted as:
876+
877+
```ruby
878+
# @param value [Object]
879+
```
797880

798881
### Create a starter config
799882

lib/docscribe/config.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ module Docscribe
88
class Config
99
# Raw config hash after deep-merging user config with defaults.
1010
#
11-
# @return [Hash]
12-
#
1311
# @!attribute [r] raw
14-
# @return [Object]
12+
# @return [Hash]
1513
attr_reader :raw
1614

1715
# Create a configuration object from a raw config hash.

lib/docscribe/config/emit.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def treat_options_keyword_as_hash?
109109
#
110110
# Supported values:
111111
# - `"type_name"` => `@param [String] name`
112-
# - `"name_first"` => `@param name [String]`
112+
# - `"name_type"` => `@param name [String]`
113113
#
114114
# @return [String]
115115
def param_tag_style

lib/docscribe/config/template.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def self.default_yaml
5959
6060
# Style for generated @param tags:
6161
# - type_name => @param [Type] name
62-
# - name_first => @param name [Type]
62+
# - name_type => @param name [Type]
6363
param_tag_style: "type_name"
6464
6565
# Sort generated / merged tags in safe mode when possible.

0 commit comments

Comments
 (0)