readme_yard 0.1.2 → 0.3.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.
data/README_YARD.md CHANGED
@@ -1,89 +1,196 @@
1
1
  # Readme Yard 🌿
2
2
  [![Gem Version](https://badge.fury.io/rb/readme_yard.svg)](https://badge.fury.io/rb/readme_yard)
3
- [![Maintainability](https://api.codeclimate.com/v1/badges/9fe0012930c3886dbe00/maintainability)](https://codeclimate.com/github/mattruzicka/readme_yard/maintainability)
4
3
 
5
4
  {@readme ReadmeYard}
6
5
 
7
6
  ---
8
7
 
9
- {@readme ReadmeYard#command_line_usage}
8
+ ⚠️ **Generated file warning** – Edit README_YARD.md, not README.md. Changes to README.md will be lost when running `readme build`.
9
+
10
+ ### Future Work
11
+ - Implement safeguards to prevent accidental edits to README.md
12
+ - Support bidirectional editing through git integration
13
+
14
+ [PRs are welcome](#contributing) for these improvements.
15
+
16
+ ---
17
+
18
+ ## Table of Contents
19
+ - [Installation](#installation)
20
+ - [Getting Started](#getting-started)
21
+ - [Command Line Usage](#command-line-usage)
22
+ - [Tag Usage](#tag-usage)
23
+ - [Readme Tag](#readme-tag)
24
+ - [Standalone Tag Usage](#standalone-tag-usage)
25
+ - [Example Tag](#example-tag)
26
+ - [Contributing](#contributing)
10
27
 
11
28
  ---
12
29
 
30
+ ## Installation
31
+
32
+ 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`
33
+
34
+ **Note:** As of version 0.3.0, Readme Yard requires Ruby 3.0 or higher.
35
+
13
36
  ## Getting Started
14
37
 
15
- Add [gem "readme_yard"](https://rubygems.org/gems/readme_yard) to your application's Gemfile and run `bundle install` or install it yourself with `gem install readme_yard`.
38
+ 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.
16
39
 
17
- Next run `readme build` at the command line. This creates a README_YARD.md file if there isn’t one by copying the README file if it exists. It then parses README_YARD.md and writes the result to README.md.
40
+ 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.
41
+
42
+ See [Tag Usage](#tag-usage).
43
+
44
+ ---
18
45
 
19
- In addition to being able to use tags as documented in the next section, you can edit the README_YARD file just as you would edit any README. Then to see changes made to README_YARD reflected in the README, run `readme build`.
46
+ {@readme ReadmeYard#command_line_usage}
20
47
 
21
48
  ---
22
49
 
23
- ## Usage
50
+ ## Tag Usage
51
+
52
+ Readme Yard uses YARD tags and custom markdown tags. YARD tags live inside Ruby source code. The markdown tags live inside README_YARD.md.
24
53
 
25
- The following tags can be used in README_YARD.md to generate YARD documentation inside your README.
54
+ 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.
26
55
 
27
- ### @readme
56
+ ### Tag Reference Table
28
57
 
29
- Usage: `{@readme ObjectPath}`
58
+ | Tag Type | YARD Syntax (in source code) | Markdown Syntax (in README_YARD.md) | Standalone Tag* | Purpose |
59
+ |----------|------------------------------|-------------------------------------|----------------|---------|
60
+ | Readme | `@readme` | `{@readme ObjectPath}` | N/A | General purpose tag to embed content from source code |
61
+ | Readme (comment) | `@readme comment` | `{@readme ObjectPath}` | `{@comment ObjectPath}` | Embeds only the comment from source code |
62
+ | Readme (code) | `@readme code` | `{@readme ObjectPath}` | `{@code ObjectPath}` | Embeds only code implementation |
63
+ | Readme (source) | `@readme source` | `{@readme ObjectPath}` | `{@source ObjectPath}` | Embeds both comments and code |
64
+ | Readme (value) | `@readme value` | `{@readme ObjectPath}` | `{@value ObjectPath}` | Embeds a Ruby value as a Ruby code block |
65
+ | Readme (string) | `@readme string` | `{@readme ObjectPath}` | `{@string ObjectPath}` | Embeds a Ruby string as normal text |
66
+ | Example | `@example` | `{@example ObjectPath}` | N/A | Embeds example code from YARD @example tags |
30
67
 
31
- `{@readme ReadmeYard}` is used at the top of this project's README_YARD.md file to generate this README's title and description. `ReadmeYard` references the class located in [lib/readme_yard.rb](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard.rb).
68
+ > *Standalone tags allow embedding content without requiring corresponding YARD tags in source code. See [Standalone Tag Usage](#standalone-tag-usage) for details.
32
69
 
33
- `{@readme ReadmeYard#command_line_usage}` is used to generate the "Command Line Usage" section above from the comments located above. `ReadmeYard#command_line_usage` references the instance method `command_line_usage` located in [lib/readme_yard.rb](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard.rb).
70
+ ### Examples
34
71
 
35
- `{@readme ReadmeYard.hello_world}` - {@readme ReadmeYard.hello_world}
72
+ The next line is a code snippet if you're looking at [README.md](https://github.com/mattruzicka/README/blob/main/README_YARD.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).
36
73
 
37
- ### @example
74
+ {@readme ReadmeYard::ExampleTag.hello_world}
38
75
 
39
- Usage: `{@example ObjectPath}`
76
+ 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).
40
77
 
41
- The below example code is generated from placing `{@example ReadmeYard.hello_world}` in README_YARD.md.
78
+ 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).
42
79
 
43
- {@example ReadmeYard.hello_world}
80
+ 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.
44
81
 
45
82
  ---
46
83
 
47
- ## Inspiration
84
+ ## Readme Tag
85
+
86
+ **Markdown** syntax: `{@readme ObjectPath}`
87
+
88
+ **YARD** syntax: `@example <name>`
89
+
90
+ {@readme ReadmeYard::ReadmeTag}
91
+
92
+ ### {@readme ReadmeYard::CommentTag}
93
+
94
+ **Usage:**
95
+
96
+ {@example ReadmeYard::CommentTag}
97
+
98
+ 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.
99
+
100
+ {@readme ReadmeYard::CommentTag.format_tag}
101
+
102
+ ### {@readme ReadmeYard::CodeTag}
103
+
104
+ **Usage:**
48
105
 
49
- The desire to have the code, README, and documentation for [Evolvable](https://github.com/mattruzicka/evolvable) be useful, synced, and correct as I work on documenting the [1.1.0 Release](https://github.com/mattruzicka/evolvable/pull/8).
106
+ {@example ReadmeYard::CodeTag}
50
107
 
51
- I want a README that summarizes and contextualizes the code and documentation, without duplicating them, so as to make keeping it up-to-date easier. Laziness!
108
+ 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.
109
+
110
+ {@readme ReadmeYard::CodeTag.format_tag}
111
+
112
+ ### {@readme ReadmeYard::SourceTag}
113
+
114
+ **Usage:**
115
+
116
+ {@example ReadmeYard::SourceTag}
117
+
118
+ 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.
119
+
120
+ {@readme ReadmeYard::SourceTag.format_tag}
121
+
122
+ ### {@readme ReadmeYard::ValueTag}
123
+
124
+ **Usage:**
125
+
126
+ {@example ReadmeYard::ValueTag}
127
+
128
+ 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.
129
+
130
+ {@value ReadmeYard::ValueTag::EXAMPLE}
131
+
132
+ ### {@readme ReadmeYard::StringTag}
133
+
134
+ **Usage:**
135
+
136
+ Because a [@readme string](https://github.com/mattruzicka/readme_yard/blob/main/lib/readme_yard/string_tag.rb) tag:
137
+
138
+ {@example ReadmeYard::StringTag::XZAMPLE}
139
+
140
+ Is located above this constant:
141
+
142
+ {@code ReadmeYard::StringTag::XZAMPLE}
143
+
144
+ We see can see its string value as simple text below:
145
+
146
+ {@string ReadmeYard::StringTag::XZAMPLE}
52
147
 
53
148
  ---
54
149
 
55
- ## Ideas
150
+ ## Standalone Tag Usage
56
151
 
57
- - Embed whole doc string if @readme tag is found, but there’s no text.
152
+ 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.
58
153
 
59
- - Embed whole method if @example tag is found, but no text.
154
+ You can use any of these tags directly in README_YARD.md without requiring a corresponding `@readme` tag in the source code:
60
155
 
61
- - `readme tags` - Prints usage and a list of all tags
156
+ - `{@comment ObjectPath}` - Embeds comments only
157
+ - `{@code ObjectPath}` - Embeds code only
158
+ - `{@source ObjectPath}` - Embeds both comments and code
159
+ - `{@value ObjectPath}` - Embeds a Ruby value as a Ruby code block
160
+ - `{@string ObjectPath}` - Embeds a Ruby string as plain text
62
161
 
63
- - `readme tags -v` - Prints docstrings of all tags
162
+ For example, in the StringTag section above, we used both:
163
+ - `{@code ReadmeYard::StringTag::XZAMPLE}` to show the constant definition
164
+ - `{@string ReadmeYard::StringTag::XZAMPLE}` to display the string value as text
64
165
 
65
- - `readme tags <tag>` - Prints list of matching tags
166
+ The standalone tag usage provides more flexibility when documenting your code and doesn't require modifications to the source files.
66
167
 
67
- - `readme tags <tag>` - Prints list of matching tag docstrings
168
+ ---
68
169
 
69
- - Improve linking. At the moment, there's lots of room for error when adding links in the YARD documentation.
170
+ ## Example Tag
70
171
 
71
- - Support @todo tags or any other native YARD tags that might be useful.
172
+ **Markdown** syntax: `{@example ObjectPath}`
72
173
 
73
- - Add ability to target a particular tag in a doc string from README_YARD.md. Maybe via a tag directive?
174
+ **YARD** syntax: `@example`
74
175
 
75
- - Follow @see links to find tags
176
+ {@readme ReadmeYard::ExampleTag}
76
177
 
77
- - Integrate something like https://github.com/lsegal/yard-examples/blob/master/doctest/doctest.rb to add red/green test status to code example. Maybe via some sort of tag directive?
178
+ **Usage:**
78
179
 
79
- - Be able to customize the name of the source and target files.
180
+ {@source ReadmeYard::ExampleTag.hello_world}
80
181
 
81
- - Integrate with the YARD server so that changes to documentation or README_YARD.md automatically regenerate the README
182
+ 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.
82
183
 
83
- - Be able to register regexes for matching tags and running given blocks. Use to create functionality for tagging GitHub source.
184
+ {@example ReadmeYard::ExampleTag.hello_world}
84
185
 
85
186
  ---
86
187
 
87
188
  ## Contributing
88
189
 
89
190
  Bug reports and pull requests are welcome on GitHub at https://github.com/mattruzicka/yard-readme.
191
+
192
+ If you're interested in contributing, but don't know where to get started, feel free to message me on twitter at [@mattruzicka](https://twitter.com/mattruzicka). I have a lot of ideas!
193
+
194
+ Thanks for taking the time to think about me, the README.
195
+
196
+ 🌿 🥏 🌱 ⚽
data/bin/readme CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  require "bundler/setup"
5
5
  require "readme_yard"
6
- require "tty-markdown"
7
6
 
8
- arg, options = ARGV
7
+ arg, *arg_options = ARGV.dup
8
+ options = arg_options.join(" ") unless arg_options.empty?
9
9
  ReadmeYard.call(arg, options)
@@ -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
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReadmeYard
4
+ #
5
+ # @readme
6
+ # Embed comments
7
+ #
8
+ # @example
9
+ # # @readme comment
10
+ #
11
+ class CommentTag
12
+ class << self
13
+ #
14
+ # This comment is in the README because `@readme comment`
15
+ # is below (in the source code).
16
+ #
17
+ # @readme comment
18
+ #
19
+ def format_tag(yard_object, _tag)
20
+ comment = format_docstring_as_comment(yard_object)
21
+ ExampleTag.format_ruby(comment)
22
+ end
23
+
24
+ def format_yard_object(yard_object)
25
+ format_tag(yard_object, nil)
26
+ end
27
+
28
+ #
29
+ # @see https://rubydoc.info/gems/yard/YARD%2FDocstring:to_raw
30
+ #
31
+ def format_docstring_as_comment(yard_object)
32
+ comment = +""
33
+ docstring = yard_object.docstring.all
34
+ docstring.gsub!(named_readme_tag_regex, "")
35
+ docstring.lines.each do |line|
36
+ comment << "#"
37
+ comment << " " unless line[0] == "\n"
38
+ comment << line
39
+ end
40
+ last_line = yard_object.docstring.all.lines.last
41
+ comment << "#" if last_line&.match?(/\n$/)
42
+ comment
43
+ end
44
+
45
+ def named_readme_tag_regex
46
+ @named_readme_tag_regex ||= /(\n|^)@readme\s(#{ReadmeYard::TagRegistry.tag_names.join("|")})\n/
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReadmeYard
4
+ class Error < StandardError
5
+ class << self
6
+ #
7
+ # @todo
8
+ # Look for instance method with same name if
9
+ # class method and vise versa to give a more helpful error.
10
+ # Look for the object path in other scopes.
11
+ #
12
+ def object_not_found(object_path, tag_name)
13
+ new("*Readme Yard* could not find `#{object_path}`. Perhaps" \
14
+ " the `@#{tag_name}` tag was moved, mispelled," \
15
+ " or the `.yardopts` YARD file is missing the file path.")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
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
+ #
10
+ class ExampleTag
11
+ class << self
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")
24
+ end
25
+
26
+ def format_tag(yard_object, tag)
27
+ text = tag.text.empty? ? yard_object.source : tag.text
28
+ format_ruby(text)
29
+ end
30
+
31
+ def format_ruby(text)
32
+ "```ruby\n#{text}\n```\n"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReadmeYard
4
+ class Logger
5
+ class << self
6
+ def warn(msg)
7
+ msg = "Warning: #{msg}"
8
+ puts_md(msg)
9
+ end
10
+
11
+ def puts_md(msg)
12
+ puts TTY::Markdown.parse(msg)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReadmeYard
4
+ #
5
+ # @readme
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
+ #
10
+ # @see ReadmeYard::CommentTag
11
+ # @see ReadmeYard::CodeTag
12
+ # @see ReadmeYard::SourceTag
13
+ # @see ReadmeYard::ValueTag
14
+ # @see ReadmeYard::StringTag
15
+ #
16
+ class ReadmeTag
17
+ class << self
18
+ def format_tags(yard_object, yard_tags)
19
+ md = +""
20
+ yard_tags.each do |tag|
21
+ res = format_yard_tag(yard_object, tag)
22
+ md << res if res
23
+ end
24
+ md
25
+ end
26
+
27
+ def format_tag(_yard_object, tag)
28
+ "#{tag.text}\n"
29
+ end
30
+
31
+ private
32
+
33
+ def format_yard_tag(yard_object, tag)
34
+ if tag.name && !tag.name.empty?
35
+ tag_class = TagRegistry.find_class(tag.name)
36
+ tag_class&.format_tag(yard_object, tag)
37
+ elsif tag.text && !tag.text.empty?
38
+ format_tag(yard_object, tag)
39
+ else
40
+ Logger.warn("Empty `@readme` tag found in `#{yard_object}`.")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ReadmeYard
4
+ #
5
+ # @readme
6
+ # Embed Ruby comments and code
7
+ #
8
+ # @example
9
+ # # @readme source
10
+ #
11
+ class SourceTag
12
+ class << self
13
+ #
14
+ # The comment and code for ReadmeYard::SourceTag#format_tag
15
+ # is in the README because `@readme source` is below (in the source code).
16
+ #
17
+ # @readme source
18
+ #
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)
27
+ end
28
+ end
29
+ end
30
+ 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ReadmeYard
4
- VERSION = "0.1.2"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -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