readme_yard 0.2.0 → 0.4.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/.rubocop.yml +1 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +18 -1
- data/Gemfile +3 -0
- data/Gemfile.lock +67 -15
- data/README.md +165 -55
- data/README_YARD.md +109 -37
- data/bin/readme +2 -2
- data/lib/readme_yard/code_tag.rb +28 -0
- data/lib/readme_yard/comment_tag.rb +14 -5
- data/lib/readme_yard/error.rb +2 -0
- data/lib/readme_yard/example_tag.rb +21 -3
- data/lib/readme_yard/logger.rb +12 -1
- data/lib/readme_yard/readme_tag.rb +15 -11
- data/lib/readme_yard/source_tag.rb +16 -4
- data/lib/readme_yard/string_tag.rb +86 -0
- data/lib/readme_yard/tag_registry.rb +21 -0
- data/lib/readme_yard/value_tag.rb +31 -0
- data/lib/readme_yard/version.rb +1 -1
- data/lib/readme_yard/yard_opts_manager.rb +49 -0
- data/lib/readme_yard.rb +60 -95
- data/readme_yard.gemspec +8 -3
- metadata +53 -12
- data/lib/readme_yard/object_tag.rb +0 -21
data/README_YARD.md
CHANGED
@@ -1,18 +1,29 @@
|
|
1
1
|
# Readme Yard 🌿
|
2
2
|
[](https://badge.fury.io/rb/readme_yard)
|
3
|
-
|
3
|
+
|
4
|
+
**Code Version: {@string ReadmeYard::VERSION}**
|
4
5
|
|
5
6
|
{@readme ReadmeYard}
|
6
7
|
|
7
8
|
---
|
8
9
|
|
10
|
+
⚠️ **Generated file warning** – Edit README_YARD.md, not README.md. Changes to README.md will be lost when running `readme build`.
|
11
|
+
|
12
|
+
### Future Work
|
13
|
+
- Implement safeguards to prevent accidental edits to README.md
|
14
|
+
- Support bidirectional editing through git integration
|
15
|
+
|
16
|
+
[PRs are welcome](#contributing) for these improvements.
|
17
|
+
|
18
|
+
---
|
19
|
+
|
9
20
|
## Table of Contents
|
10
21
|
- [Installation](#installation)
|
11
22
|
- [Getting Started](#getting-started)
|
12
23
|
- [Command Line Usage](#command-line-usage)
|
13
24
|
- [Tag Usage](#tag-usage)
|
14
25
|
- [Readme Tag](#readme-tag)
|
15
|
-
- [
|
26
|
+
- [Standalone Tag Usage](#standalone-tag-usage)
|
16
27
|
- [Example Tag](#example-tag)
|
17
28
|
- [Contributing](#contributing)
|
18
29
|
|
@@ -20,13 +31,17 @@
|
|
20
31
|
|
21
32
|
## Installation
|
22
33
|
|
23
|
-
Add [gem "readme_yard"](https://rubygems.org/gems/readme_yard) to your
|
34
|
+
Add [gem "readme_yard"](https://rubygems.org/gems/readme_yard) to your Gemfile and run `bundle install` or install it yourself with: `gem install readme_yard`
|
35
|
+
|
36
|
+
**Note:** As of version 0.3.0, Readme Yard requires Ruby 3.0 or higher.
|
24
37
|
|
25
38
|
## Getting Started
|
26
39
|
|
27
|
-
Run `readme build` at the command line.
|
40
|
+
Run `readme build` at the command line. This creates a README_YARD.md file if there isn't one by copying your existing README.md file.
|
28
41
|
|
29
|
-
README_YARD.md is the template from which `readme build` generates the README.
|
42
|
+
README_YARD.md is the template from which `readme build` generates the README. Readme Yard adds the ability to embed and reference your source code in your README via README_YARD.md.
|
43
|
+
|
44
|
+
See [Tag Usage](#tag-usage).
|
30
45
|
|
31
46
|
---
|
32
47
|
|
@@ -36,80 +51,139 @@ README_YARD.md is the template from which `readme build` generates the README. I
|
|
36
51
|
|
37
52
|
## Tag Usage
|
38
53
|
|
39
|
-
Readme Yard uses
|
54
|
+
Readme Yard uses YARD tags and custom markdown tags. YARD tags live inside Ruby source code. The markdown tags live inside README_YARD.md.
|
40
55
|
|
41
|
-
|
56
|
+
When the Readme Yard build process encounters a tag in README_YARD.md, it searches the Ruby source code for its YARD tag counterpart, formats the output, and embeds it in the README file.
|
42
57
|
|
43
|
-
|
58
|
+
### Tag Reference Table
|
44
59
|
|
45
|
-
|
60
|
+
| Tag Type | YARD Syntax (in source code) | Markdown Syntax (in README_YARD.md) | Standalone Tag* | Purpose |
|
61
|
+
|----------|------------------------------|-------------------------------------|----------------|---------|
|
62
|
+
| Readme | `@readme` | `{@readme ObjectPath}` | N/A | General purpose tag to embed content from source code |
|
63
|
+
| Readme (comment) | `@readme comment` | `{@readme ObjectPath}` | `{@comment ObjectPath}` | Embeds only the comment from source code |
|
64
|
+
| Readme (code) | `@readme code` | `{@readme ObjectPath}` | `{@code ObjectPath}` | Embeds only code implementation |
|
65
|
+
| Readme (source) | `@readme source` | `{@readme ObjectPath}` | `{@source ObjectPath}` | Embeds both comments and code |
|
66
|
+
| Readme (value) | `@readme value` | `{@readme ObjectPath}` | `{@value ObjectPath}` | Embeds a Ruby value as a Ruby code block |
|
67
|
+
| Readme (string) | `@readme string` | `{@readme ObjectPath}` | `{@string ObjectPath}` | Embeds a Ruby string as normal text |
|
68
|
+
| Example | `@example` | `{@example ObjectPath}` | N/A | Embeds example code from YARD @example tags |
|
69
|
+
|
70
|
+
> *Standalone tags allow embedding content without requiring corresponding YARD tags in source code. See [Standalone Tag Usage](#standalone-tag-usage) for details.
|
46
71
|
|
47
72
|
### Examples
|
48
73
|
|
49
|
-
|
74
|
+
The next line is a code snippet if you're looking at the [README](https://github.com/mattruzicka/readme_yard/blob/main/README.md) and `{@readme ReadmeYard::ExampleTag.hello_world}` if you're looking at [README_YARD.md](https://github.com/mattruzicka/readme_yard/blob/main/README_YARD.md).
|
50
75
|
|
51
|
-
{@readme ReadmeYard.hello_world}
|
76
|
+
{@readme ReadmeYard::ExampleTag.hello_world}
|
52
77
|
|
53
|
-
The
|
78
|
+
The markdown tag tells Readme Yard to parse the `@readme` tag located above the `hello_world` class method located in [lib/readme_yard/example_tag.rb](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard/example_tag.rb).
|
54
79
|
|
55
80
|
To use another "meta" example, `{@readme ReadmeYard}` is used at the top of this project's README_YARD.md file to generate the first few sentences of this README. `ReadmeYard` references the class located in [lib/readme_yard.rb](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard.rb).
|
56
81
|
|
57
|
-
Last one, `{@readme ReadmeYard#command_line_usage}` is used to generate the "Command Line Usage" section above from the comments
|
82
|
+
Last one, `{@readme ReadmeYard#command_line_usage}` is used to generate the "Command Line Usage" section above from the comments of the `command_line_usage` instance method located in [lib/readme_yard.rb](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard.rb). This method is extra meta: it returns the result of formatting its own comments as markdown. In this way, the usage instructions in the comments, the README, and as printed at the command line will always be in sync.
|
58
83
|
|
59
84
|
---
|
60
85
|
|
61
86
|
## Readme Tag
|
62
87
|
|
63
|
-
**
|
88
|
+
**Markdown** syntax: `{@readme ObjectPath}`
|
64
89
|
|
65
|
-
**YARD
|
90
|
+
**YARD** syntax: `@example <name>`
|
66
91
|
|
67
92
|
{@readme ReadmeYard::ReadmeTag}
|
68
93
|
|
69
|
-
|
94
|
+
### {@readme ReadmeYard::CommentTag}
|
95
|
+
|
96
|
+
**Usage:**
|
97
|
+
|
98
|
+
{@example ReadmeYard::CommentTag}
|
99
|
+
|
100
|
+
This example [@readme comment](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard/comment_tag.rb) tag embeds the below code snippet via the `{@readme ReadmeYard::CommentTag.format_tag}` markdown tag.
|
101
|
+
|
102
|
+
{@readme ReadmeYard::CommentTag.format_tag}
|
103
|
+
|
104
|
+
### {@readme ReadmeYard::CodeTag}
|
105
|
+
|
106
|
+
**Usage:**
|
70
107
|
|
71
|
-
|
108
|
+
{@example ReadmeYard::CodeTag}
|
72
109
|
|
110
|
+
This example [@readme code](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard/code_tag.rb) tag embeds the below code snippet via the `{@readme ReadmeYard::CodeTag.format_tag}` markdown tag.
|
73
111
|
|
74
|
-
|
112
|
+
{@readme ReadmeYard::CodeTag.format_tag}
|
75
113
|
|
76
|
-
{@readme ReadmeYard::
|
114
|
+
### {@readme ReadmeYard::SourceTag}
|
77
115
|
|
78
|
-
|
116
|
+
**Usage:**
|
79
117
|
|
80
|
-
{@
|
118
|
+
{@example ReadmeYard::SourceTag}
|
81
119
|
|
82
|
-
|
120
|
+
This example [@readme source](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard/source_tag.rb) tag embeds the below code snippet via the `{@readme ReadmeYard::SourceTag.format_tag}` markdown tag.
|
83
121
|
|
84
|
-
{@readme ReadmeYard::SourceTag}
|
122
|
+
{@readme ReadmeYard::SourceTag.format_tag}
|
85
123
|
|
86
|
-
|
124
|
+
### {@readme ReadmeYard::ValueTag}
|
87
125
|
|
88
|
-
|
126
|
+
**Usage:**
|
89
127
|
|
128
|
+
{@example ReadmeYard::ValueTag}
|
90
129
|
|
91
|
-
|
130
|
+
This example [@readme value](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard/value_tag.rb) tag embeds the below code snippet via the `{@value ReadmeYard::ValueTag::EXAMPLE}` markdown tag.
|
92
131
|
|
93
|
-
{@
|
132
|
+
{@value ReadmeYard::ValueTag::EXAMPLE}
|
94
133
|
|
95
|
-
|
134
|
+
### {@readme ReadmeYard::StringTag}
|
96
135
|
|
97
|
-
|
136
|
+
**Usage:**
|
98
137
|
|
138
|
+
Because a [@readme string](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard/string_tag.rb) tag:
|
139
|
+
|
140
|
+
{@example ReadmeYard::StringTag::XZAMPLE}
|
141
|
+
|
142
|
+
Is located above this constant:
|
143
|
+
|
144
|
+
{@code ReadmeYard::StringTag::XZAMPLE}
|
145
|
+
|
146
|
+
We see can see its string value as simple text below:
|
147
|
+
|
148
|
+
{@string ReadmeYard::StringTag::XZAMPLE}
|
149
|
+
|
150
|
+
---
|
151
|
+
|
152
|
+
## Standalone Tag Usage
|
153
|
+
|
154
|
+
While using the `@readme` tag in your source code is recommended because it makes the README's dependency on source code explicit, sometimes it's useful to embed source code snippets directly without it. This is especially valuable when a source object can only contain one `@readme` tag, but you want to highlight multiple aspects of the object.
|
155
|
+
|
156
|
+
You can use any of these tags directly in README_YARD.md without requiring a corresponding `@readme` tag in the source code:
|
157
|
+
|
158
|
+
- `{@comment ObjectPath}` - Embeds comments only
|
159
|
+
- `{@code ObjectPath}` - Embeds code only
|
160
|
+
- `{@source ObjectPath}` - Embeds both comments and code
|
161
|
+
- `{@value ObjectPath}` - Embeds a Ruby value as a Ruby code block
|
162
|
+
- `{@string ObjectPath}` - Embeds a Ruby string as plain text
|
163
|
+
|
164
|
+
For example, in the StringTag section above, we used both:
|
165
|
+
- `{@code ReadmeYard::StringTag::XZAMPLE}` to show the constant definition
|
166
|
+
- `{@string ReadmeYard::StringTag::XZAMPLE}` to display the string value as text
|
167
|
+
|
168
|
+
The standalone tag usage provides more flexibility when documenting your code and doesn't require modifications to the source files.
|
99
169
|
|
100
170
|
---
|
101
171
|
|
102
172
|
## Example Tag
|
103
173
|
|
104
|
-
**
|
174
|
+
**Markdown** syntax: `{@example ObjectPath}`
|
175
|
+
|
176
|
+
**YARD** syntax: `@example`
|
105
177
|
|
106
|
-
|
178
|
+
{@readme ReadmeYard::ExampleTag}
|
107
179
|
|
108
|
-
|
180
|
+
**Usage:**
|
109
181
|
|
110
|
-
|
182
|
+
{@source ReadmeYard::ExampleTag.hello_world}
|
111
183
|
|
112
|
-
{@example ReadmeYard.hello_world}
|
184
|
+
The below example code is generated from `{@example ReadmeYard::ExampleTag.hello_world}` because, as you can see above, the "hello_world" class method has an `@example` tag.
|
185
|
+
|
186
|
+
{@example ReadmeYard::ExampleTag.hello_world}
|
113
187
|
|
114
188
|
---
|
115
189
|
|
@@ -117,6 +191,4 @@ Given that the above comment is for the `hello_world` class method, the below ex
|
|
117
191
|
|
118
192
|
Bug reports and pull requests are welcome on GitHub at https://github.com/mattruzicka/yard-readme.
|
119
193
|
|
120
|
-
Thanks for
|
121
|
-
|
122
|
-
🌿 🥏 🌱 ⚽
|
194
|
+
Thanks for reading me, the README that documents how to document the README with code that documents itself 🤯
|
data/bin/readme
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ReadmeYard
|
4
|
+
#
|
5
|
+
# @readme
|
6
|
+
# Embed Ruby code
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # @readme code
|
10
|
+
#
|
11
|
+
class CodeTag
|
12
|
+
class << self
|
13
|
+
#
|
14
|
+
# The code for this method is in the README because
|
15
|
+
# `@readme code` is below (in the source code).
|
16
|
+
#
|
17
|
+
# @readme code
|
18
|
+
#
|
19
|
+
def format_tag(yard_object, _tag)
|
20
|
+
ExampleTag.format_ruby(yard_object.source)
|
21
|
+
end
|
22
|
+
|
23
|
+
def format_yard_object(yard_object)
|
24
|
+
format_tag(yard_object, nil)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,21 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class ReadmeYard
|
2
4
|
#
|
3
5
|
# @readme
|
4
|
-
#
|
6
|
+
# Embed comments
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # @readme comment
|
5
10
|
#
|
6
11
|
class CommentTag
|
7
12
|
class << self
|
8
13
|
#
|
9
14
|
# This comment is in the README because `@readme comment`
|
10
|
-
# is below
|
15
|
+
# is below (in the source code).
|
11
16
|
#
|
12
17
|
# @readme comment
|
13
18
|
#
|
14
|
-
def
|
19
|
+
def format_tag(yard_object, _tag)
|
15
20
|
comment = format_docstring_as_comment(yard_object)
|
16
21
|
ExampleTag.format_ruby(comment)
|
17
22
|
end
|
18
23
|
|
24
|
+
def format_yard_object(yard_object)
|
25
|
+
format_tag(yard_object, nil)
|
26
|
+
end
|
27
|
+
|
19
28
|
#
|
20
29
|
# @see https://rubydoc.info/gems/yard/YARD%2FDocstring:to_raw
|
21
30
|
#
|
@@ -29,12 +38,12 @@ class ReadmeYard
|
|
29
38
|
comment << line
|
30
39
|
end
|
31
40
|
last_line = yard_object.docstring.all.lines.last
|
32
|
-
comment << "#" if last_line
|
41
|
+
comment << "#" if last_line&.match?(/\n$/)
|
33
42
|
comment
|
34
43
|
end
|
35
44
|
|
36
45
|
def named_readme_tag_regex
|
37
|
-
@named_readme_tag_regex ||= /(\n|^)@readme\s(#{
|
46
|
+
@named_readme_tag_regex ||= /(\n|^)@readme\s(#{ReadmeYard::TagRegistry.tag_names.join("|")})\n/
|
38
47
|
end
|
39
48
|
end
|
40
49
|
end
|
data/lib/readme_yard/error.rb
CHANGED
@@ -1,11 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class ReadmeYard
|
4
|
+
#
|
5
|
+
# @readme
|
6
|
+
# The Example Tag leverages YARD's standard `@example` tag syntax, allowing you to
|
7
|
+
# include example code in your README directly from source files. This saves time and
|
8
|
+
# ensures your README stays in sync with your YARD documentation
|
9
|
+
#
|
2
10
|
class ExampleTag
|
3
11
|
class << self
|
4
|
-
|
5
|
-
|
12
|
+
#
|
13
|
+
# @readme source
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# ReadmeYard::ExampleTag.hello_world #=> "Hello 🌎 🌍 🌏"
|
17
|
+
#
|
18
|
+
def hello_world
|
19
|
+
"Hello 🌎 🌍 🌏"
|
20
|
+
end
|
21
|
+
|
22
|
+
def format_tags(yard_object, yard_tags)
|
23
|
+
yard_tags.map { |tag| format_tag(yard_object, tag) }.join("\n")
|
6
24
|
end
|
7
25
|
|
8
|
-
def
|
26
|
+
def format_tag(yard_object, tag)
|
9
27
|
text = tag.text.empty? ? yard_object.source : tag.text
|
10
28
|
format_ruby(text)
|
11
29
|
end
|
data/lib/readme_yard/logger.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class ReadmeYard
|
2
4
|
class Logger
|
3
5
|
class << self
|
4
6
|
def warn(msg)
|
7
|
+
msg = "Warning: #{msg}"
|
8
|
+
puts_md(msg)
|
9
|
+
end
|
10
|
+
|
11
|
+
def puts_md(msg)
|
5
12
|
puts TTY::Markdown.parse(msg)
|
6
13
|
end
|
14
|
+
|
15
|
+
def puts_text(msg)
|
16
|
+
puts msg
|
17
|
+
end
|
7
18
|
end
|
8
19
|
end
|
9
|
-
end
|
20
|
+
end
|
@@ -1,19 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class ReadmeYard
|
2
4
|
#
|
3
5
|
# @readme
|
4
|
-
# By default, only the text nested under
|
5
|
-
# will be embedded in the final output.
|
6
|
-
#
|
7
|
-
# Different embed options are provided via the following
|
8
|
-
# name options: `comment`, `source`, and `object`.
|
6
|
+
# By default, only the text nested under a @readme tag
|
7
|
+
# will be embedded in the final output. The default
|
8
|
+
# embed behavior can be changed through the use of tag names.
|
9
9
|
#
|
10
10
|
# @see ReadmeYard::CommentTag
|
11
|
+
# @see ReadmeYard::CodeTag
|
11
12
|
# @see ReadmeYard::SourceTag
|
12
|
-
# @see ReadmeYard::
|
13
|
+
# @see ReadmeYard::ValueTag
|
14
|
+
# @see ReadmeYard::StringTag
|
13
15
|
#
|
14
16
|
class ReadmeTag
|
15
17
|
class << self
|
16
|
-
def
|
18
|
+
def format_tags(yard_object, yard_tags)
|
17
19
|
md = +""
|
18
20
|
yard_tags.each do |tag|
|
19
21
|
res = format_yard_tag(yard_object, tag)
|
@@ -22,7 +24,7 @@ class ReadmeYard
|
|
22
24
|
md
|
23
25
|
end
|
24
26
|
|
25
|
-
def
|
27
|
+
def format_tag(_yard_object, tag)
|
26
28
|
"#{tag.text}\n"
|
27
29
|
end
|
28
30
|
|
@@ -30,10 +32,12 @@ class ReadmeYard
|
|
30
32
|
|
31
33
|
def format_yard_tag(yard_object, tag)
|
32
34
|
if tag.name && !tag.name.empty?
|
33
|
-
tag_class =
|
34
|
-
tag_class&.
|
35
|
+
tag_class = TagRegistry.find_class(tag.name)
|
36
|
+
tag_class&.format_tag(yard_object, tag)
|
35
37
|
elsif tag.text && !tag.text.empty?
|
36
|
-
|
38
|
+
format_tag(yard_object, tag)
|
39
|
+
else
|
40
|
+
Logger.warn("Empty `@readme` tag found in `#{yard_object}`.")
|
37
41
|
end
|
38
42
|
end
|
39
43
|
end
|
@@ -1,17 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class ReadmeYard
|
2
4
|
#
|
3
5
|
# @readme
|
4
|
-
#
|
6
|
+
# Embed Ruby comments and code
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # @readme source
|
5
10
|
#
|
6
11
|
class SourceTag
|
7
12
|
class << self
|
8
13
|
#
|
9
|
-
# The
|
14
|
+
# The comment and code for ReadmeYard::SourceTag#format_tag
|
15
|
+
# is in the README because `@readme source` is below (in the source code).
|
10
16
|
#
|
11
17
|
# @readme source
|
12
18
|
#
|
13
|
-
def
|
14
|
-
|
19
|
+
def format_tag(yard_object, _tag)
|
20
|
+
text = CommentTag.format_docstring_as_comment(yard_object)
|
21
|
+
text << "\n#{yard_object.source}"
|
22
|
+
ExampleTag.format_ruby(text)
|
23
|
+
end
|
24
|
+
|
25
|
+
def format_yard_object(yard_object)
|
26
|
+
format_tag(yard_object, nil)
|
15
27
|
end
|
16
28
|
end
|
17
29
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ReadmeYard
|
4
|
+
#
|
5
|
+
# @readme
|
6
|
+
# Embed a Ruby string as normal text
|
7
|
+
#
|
8
|
+
class StringTag
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # @readme string
|
12
|
+
#
|
13
|
+
# @readme string
|
14
|
+
#
|
15
|
+
XZAMPLE = <<~STRING
|
16
|
+
I heard you like self-documenting Ruby, so I wrote
|
17
|
+
self-documenting Ruby for your self-documenting Ruby.
|
18
|
+
STRING
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def format_tag(yard_object, _tag)
|
22
|
+
if yard_object.respond_to?(:value)
|
23
|
+
normalize_yard_value(yard_object.value)
|
24
|
+
else
|
25
|
+
Logger.warn("Cannot parse `@readme string`: #{yard_object.class.name} lacks `value` method.")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def format_yard_object(yard_object)
|
30
|
+
format_tag(yard_object, nil)
|
31
|
+
end
|
32
|
+
|
33
|
+
def normalize_yard_value(string_value)
|
34
|
+
return "" if string_value.nil? || string_value.empty?
|
35
|
+
|
36
|
+
string_value = string_value.dup
|
37
|
+
|
38
|
+
# Handle heredoc format
|
39
|
+
return normalize_value_for_heredoc(string_value) if string_value.strip.start_with?("<<~")
|
40
|
+
|
41
|
+
# Handle regular string format
|
42
|
+
string_value.delete_prefix!('"')
|
43
|
+
string_value.delete_suffix!('"')
|
44
|
+
|
45
|
+
# Replace different line continuation patterns
|
46
|
+
# This handles patterns like: " \\\n" and \\\n"
|
47
|
+
string_value.gsub!(/" \\\n"/, "")
|
48
|
+
string_value.gsub!(/\\\n\s*"/, "")
|
49
|
+
string_value.gsub!(/"\\\n"/, "")
|
50
|
+
string_value.gsub!(/"\\\n/, "")
|
51
|
+
|
52
|
+
# Unescape common escape sequences
|
53
|
+
string_value.gsub!(/\\n/, "\n")
|
54
|
+
string_value.gsub!(/\\t/, "\t")
|
55
|
+
string_value.gsub!(/\\r/, "\r")
|
56
|
+
string_value.gsub!(/\\"/, '"')
|
57
|
+
string_value.gsub!(/\\'/, "'")
|
58
|
+
string_value.gsub!(/\\\\/, "\\")
|
59
|
+
string_value
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def normalize_value_for_heredoc(string_value)
|
65
|
+
# Extract the content between the heredoc delimiters
|
66
|
+
lines = string_value.lines
|
67
|
+
delimiter = lines.first.strip.gsub(/<<~/, "").strip
|
68
|
+
content_lines = []
|
69
|
+
|
70
|
+
in_content = false
|
71
|
+
lines.each do |line|
|
72
|
+
if in_content && line.strip == delimiter
|
73
|
+
break
|
74
|
+
elsif in_content
|
75
|
+
content_lines << line
|
76
|
+
elsif line.strip.start_with?("<<~")
|
77
|
+
in_content = true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return the joined content with proper indentation removed
|
82
|
+
content_lines.join.gsub(/^\s+/, "").strip
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ReadmeYard
|
4
|
+
class TagRegistry
|
5
|
+
TAGS = { "readme" => ReadmeTag,
|
6
|
+
"example" => ExampleTag,
|
7
|
+
"code" => CodeTag,
|
8
|
+
"source" => SourceTag,
|
9
|
+
"comment" => CommentTag,
|
10
|
+
"value" => ValueTag,
|
11
|
+
"string" => StringTag }.freeze
|
12
|
+
|
13
|
+
def self.find_class(tag_name)
|
14
|
+
TAGS[tag_name.downcase]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.tag_names
|
18
|
+
TAGS.keys
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ReadmeYard
|
4
|
+
#
|
5
|
+
# @readme
|
6
|
+
# Embed a Ruby value as a Ruby code block
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # @readme value
|
10
|
+
#
|
11
|
+
class ValueTag
|
12
|
+
#
|
13
|
+
# @readme value
|
14
|
+
#
|
15
|
+
EXAMPLE = { key: "value" }.freeze
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def format_tag(yard_object, _tag)
|
19
|
+
if yard_object.respond_to?(:value)
|
20
|
+
"```ruby\n#{yard_object.value}\n```"
|
21
|
+
else
|
22
|
+
Logger.warn("Cannot parse `@readme value`: #{yard_object.class.name} lacks `value` method.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def format_yard_object(yard_object)
|
27
|
+
format_tag(yard_object, nil)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/readme_yard/version.rb
CHANGED
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ReadmeYard
|
4
|
+
class YardOptsManager
|
5
|
+
class << self
|
6
|
+
YARDOPTS_FILE = ".yardopts"
|
7
|
+
|
8
|
+
def upsert_yardopts
|
9
|
+
File.exist?(YARDOPTS_FILE) ? update_yardopts_file : create_yardopts_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_yardopts_file
|
13
|
+
text = File.read(YARDOPTS_FILE)
|
14
|
+
text_addition = build_yardopts_text_addition(text)
|
15
|
+
File.open(YARDOPTS_FILE, "a") { |f| f.write(text_addition) } if text_addition
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_yardopts_text_addition(yardopts_text)
|
19
|
+
return if yardopts_text.match?(/\s*--plugin\s+readme\W/)
|
20
|
+
|
21
|
+
readme_plugin_opts = default_readme_plugin_opts(yardopts_text)
|
22
|
+
case yardopts_text
|
23
|
+
when /\s*--markup\s+markdown/, /\s*-m\s+markdown/
|
24
|
+
readme_plugin_opts
|
25
|
+
when /\s*--markup\s/, /\s*-m\s/
|
26
|
+
warn_about_supported_markdown
|
27
|
+
readme_plugin_opts
|
28
|
+
else
|
29
|
+
readme_plugin_opts << "--markup markdown\n"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def default_readme_plugin_opts(yardopts_text)
|
34
|
+
readme_opts = +""
|
35
|
+
readme_opts << "\n" unless yardopts_text.lines.last.include?("\n")
|
36
|
+
readme_opts << "--plugin readme\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_yardopts_file
|
40
|
+
File.write(YARDOPTS_FILE, "--plugin readme\n--markup markdown\n")
|
41
|
+
end
|
42
|
+
|
43
|
+
def warn_about_supported_markdown
|
44
|
+
Logger.warn "*Readme Yard* works best with markdown. " \
|
45
|
+
"Consider adding `--markup markdown` to your `.yardopts` file."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|