markdown_ruby_documentation 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -4
- data/lib/markdown_ruby_documentation/default_erb_methods.rb +0 -4
- data/lib/markdown_ruby_documentation/generate.rb +26 -13
- data/lib/markdown_ruby_documentation/markdown_presenter.rb +42 -16
- data/lib/markdown_ruby_documentation/summary.rb +2 -2
- data/lib/markdown_ruby_documentation/template_parser.rb +105 -34
- data/lib/markdown_ruby_documentation/template_parser/parsing.rb +8 -0
- data/lib/markdown_ruby_documentation/version.rb +1 -1
- data/lib/markdown_ruby_documentation/write_markdown_to_disk.rb +3 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0195aa8a642b4e01747ef74e449c4a0e0195fcc5
|
4
|
+
data.tar.gz: c752bf835f1c6fbf3bbf5ed968cc35a3810bb930
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a736068cff89585b1efa8dbce9dc0854effea63f90a38819dbe75c406594240824162f0e297c6095054e65824caeae4abf47f19d76fecafc7b445caa9566ca92
|
7
|
+
data.tar.gz: c2ce815983eb44535d554e0599a61588a9f1d7adff1892ad52330f3256fb6eb7a28575af2a198aa625de755f34e3483df4f920dc1aa1ad4e6f32c81673d2dd5b
|
data/README.md
CHANGED
@@ -40,7 +40,7 @@ html_generator = MarkdownRubyDocumentation::HtmlGenerator.new(
|
|
40
40
|
|
41
41
|
MarkdownRubyDocumentation::Generate.run(
|
42
42
|
subjects: [RubyClassToBeInspected],
|
43
|
-
|
43
|
+
output_object: html_generator
|
44
44
|
).call
|
45
45
|
```
|
46
46
|
|
@@ -94,7 +94,8 @@ Converts case statements and if statements to bulleted markdown
|
|
94
94
|
*example ruby_to_markdown "def method_name\n'hello'\nend", readable_ruby_numbers: false**
|
95
95
|
**option 2 - Assumes methods source of current method**
|
96
96
|
* param [Hash] disable_processors (optional) See processors list.
|
97
|
-
|
97
|
+
`example ruby_to_markdown(readable_ruby_numbers: false)`
|
98
|
+
`example ruby_to_markdown(ruby_operators_to_english: { proc: ->(replacement, match) { "do some alteration" }})`
|
98
99
|
|
99
100
|
**processors**
|
100
101
|
* readable_ruby_numbers
|
@@ -103,8 +104,9 @@ Converts case statements and if statements to bulleted markdown
|
|
103
104
|
* ternary_to_if_else
|
104
105
|
* ruby_if_statement_to_md
|
105
106
|
* ruby_case_statement_to_md
|
106
|
-
* ruby_operators_to_english
|
107
|
-
* methods_as_local_links
|
107
|
+
* ruby_operators_to_english, options: proc(replacement, match)
|
108
|
+
* methods_as_local_links, options: method_to_class: { method_name => OwningConstant }
|
109
|
+
* question_mark_method_format
|
108
110
|
* remove_end_keyword
|
109
111
|
* constants_with_name_and_value
|
110
112
|
* remove_memoized_vars
|
@@ -2,24 +2,31 @@ module MarkdownRubyDocumentation
|
|
2
2
|
class Generate
|
3
3
|
# @param [Class] subjects ruby classes to generate documentation from.
|
4
4
|
# @param [Module] erb_methods must contain #link_to_markdown and contain any additional methods for comment ERB
|
5
|
-
# @param [Proc]
|
5
|
+
# @param [Proc] output_object given name: and text: for use in saving the the files.
|
6
|
+
# @param [String] load_path
|
6
7
|
def self.run(
|
7
|
-
subjects:,
|
8
|
+
subjects:,
|
9
|
+
erb_methods: DefaultErbMethods,
|
10
|
+
output_object:,
|
11
|
+
load_path:
|
8
12
|
)
|
9
|
-
|
13
|
+
self.output_object = output_object
|
14
|
+
self.load_path = load_path
|
15
|
+
erb_methods_class = Class.new
|
10
16
|
erb_methods_class.extend TemplateParser::CommentMacros
|
11
17
|
erb_methods_class.extend erb_methods
|
12
18
|
TemplateParser::CommentMacros.include erb_methods
|
13
19
|
left_padding = subjects.map(&:name).group_by(&:size).max.first
|
14
|
-
progressbar
|
15
|
-
pages
|
20
|
+
progressbar = ProgressBar.create(title: "Compiling Markdown".ljust(left_padding), total: subjects.count+ 1)
|
21
|
+
pages = subjects.map do |subject|
|
16
22
|
progressbar.title = subject.name.ljust(left_padding)
|
17
23
|
Page.new(subject: subject,
|
18
|
-
|
19
|
-
erb_methods_class: erb_methods_class
|
24
|
+
output_object: output_object,
|
25
|
+
erb_methods_class: erb_methods_class,
|
26
|
+
load_path: load_path).call.tap { progressbar.increment }
|
20
27
|
end
|
21
28
|
|
22
|
-
return_value
|
29
|
+
return_value = pages.each_with_object({}) do |page, hash|
|
23
30
|
name_parts = page.subject.name.split("::")
|
24
31
|
name = name_parts.pop
|
25
32
|
namespace = name_parts.join("::")
|
@@ -32,26 +39,32 @@ module MarkdownRubyDocumentation
|
|
32
39
|
return_value
|
33
40
|
end
|
34
41
|
|
42
|
+
class << self
|
43
|
+
attr_accessor :load_path, :output_object
|
44
|
+
end
|
45
|
+
|
35
46
|
class Page
|
36
|
-
attr_reader :subject, :
|
47
|
+
attr_reader :subject, :output_object, :erb_methods_class, :load_path
|
37
48
|
|
38
49
|
def initialize(subject:,
|
39
50
|
methods: [],
|
40
|
-
|
51
|
+
load_path:,
|
52
|
+
output_object:,
|
41
53
|
erb_methods_class:)
|
42
54
|
initialize_methods(methods, subject)
|
43
55
|
@erb_methods_class = erb_methods_class
|
44
56
|
@subject = subject
|
45
57
|
methods = methods
|
46
58
|
@methods = methods
|
47
|
-
@
|
59
|
+
@load_path = load_path
|
60
|
+
@output_object = output_object
|
48
61
|
end
|
49
62
|
|
50
63
|
def call
|
51
64
|
methods_pipes = run_pipeline(methods_pipeline)
|
52
65
|
text = run_pipeline(string_pipeline, methods_pipes)
|
53
|
-
|
54
|
-
|
66
|
+
output_object.call(name: subject.name,
|
67
|
+
text: text)
|
55
68
|
self
|
56
69
|
end
|
57
70
|
|
@@ -4,33 +4,59 @@ module MarkdownRubyDocumentation
|
|
4
4
|
attr_reader :items, :title_key, :summary
|
5
5
|
|
6
6
|
def initialize(items: nil, summary:, title_key:, skip_blanks: true)
|
7
|
-
@items
|
8
|
-
@summary
|
9
|
-
@title_key
|
10
|
-
@skip_blanks
|
7
|
+
@items = items
|
8
|
+
@summary = summary
|
9
|
+
@title_key = title_key
|
10
|
+
@skip_blanks = skip_blanks
|
11
|
+
@present_items = []
|
11
12
|
end
|
12
13
|
|
13
14
|
def call(items=nil)
|
14
15
|
@items ||= items
|
15
|
-
|
16
|
-
# #{summary.title}
|
17
|
-
|
18
|
-
|
19
|
-
#{present_items}
|
20
|
-
MD
|
16
|
+
return "" if nothing_to_display?
|
17
|
+
md = ["# #{summary.title}", "#{summary.summary}\n".gsub(/\n\n\n/, "\n\n"), instances_methods, class_methods, "#{null_methods}\n".gsub(/\n\n\n/, "\n\n")].join("\n").gsub(/[\n]+\Z/, "\n\n")
|
18
|
+
other_types!
|
19
|
+
md
|
21
20
|
end
|
22
21
|
|
23
22
|
private
|
24
23
|
|
25
|
-
def
|
26
|
-
items.
|
27
|
-
|
24
|
+
def item_types
|
25
|
+
@item_types ||= items.group_by { |_, hash| hash[:method_object].class.name }
|
26
|
+
end
|
27
|
+
|
28
|
+
def instances_methods
|
29
|
+
@instance_methods ||= item_types.delete("MarkdownRubyDocumentation::InstanceMethod") || {}
|
30
|
+
@instance_methods.map do |name, hash|
|
31
|
+
%[## #{name.to_s.titleize}\n#{hash[:text]}] unless hash[:text].blank?
|
32
|
+
end.join("\n\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
def class_methods
|
36
|
+
@class_methods ||= item_types.delete("MarkdownRubyDocumentation::ClassMethod") || {}
|
37
|
+
@class_methods.map do |name, hash|
|
28
38
|
%[## #{name.to_s.titleize}\n#{hash[:text]}] unless hash[:text].blank?
|
29
|
-
rescue =>e
|
30
|
-
puts e
|
31
|
-
end
|
32
39
|
end.join("\n\n")
|
33
40
|
end
|
34
41
|
|
42
|
+
def null_methods
|
43
|
+
@null_methods ||= item_types.delete("MarkdownRubyDocumentation::NullMethod") || {}
|
44
|
+
md = @null_methods.map do |name, hash|
|
45
|
+
%[### #{name.to_s.titleize}\n#{hash[:text]}] unless hash[:text].blank?
|
46
|
+
end.join("\n\n")
|
47
|
+
if md.blank?
|
48
|
+
""
|
49
|
+
else
|
50
|
+
"## Reference Values\n" << md
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def other_types!
|
55
|
+
raise "Unhandled methods types: #{item_types}" unless item_types.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
def nothing_to_display?
|
59
|
+
[instances_methods, class_methods, null_methods].all?(&:empty?)
|
60
|
+
end
|
35
61
|
end
|
36
62
|
end
|
@@ -9,12 +9,12 @@ class Summary
|
|
9
9
|
def title
|
10
10
|
ancestors = subject.ancestors.select do |klass|
|
11
11
|
klass.is_a?(Class) && ![BasicObject, Object, subject].include?(klass)
|
12
|
-
end
|
12
|
+
end.sort_by { |klass| klass.name }
|
13
13
|
[format_class(subject), *ancestors.map { |a| create_link(a) }].join(" < ")
|
14
14
|
end
|
15
15
|
|
16
16
|
def summary
|
17
|
-
descendants = ObjectSpace.each_object(Class).select { |klass| klass < subject && !klass.name.include?("InstanceToClassMethods") }
|
17
|
+
descendants = ObjectSpace.each_object(Class).select { |klass| klass < subject && !klass.name.include?("InstanceToClassMethods") }.sort_by { |klass| klass.name }
|
18
18
|
|
19
19
|
descendants_links = descendants.map { |d| create_link(d) }.join(", ")
|
20
20
|
"Descendants: #{descendants_links}" if descendants.count >= 1
|
@@ -44,7 +44,7 @@ module MarkdownRubyDocumentation
|
|
44
44
|
using
|
45
45
|
)
|
46
46
|
|
47
|
-
attr_reader :ruby_class, :methods, :erb_methods_class, :current_method
|
47
|
+
attr_reader :ruby_class, :methods, :erb_methods_class, :current_method, :output_object, :load_path
|
48
48
|
|
49
49
|
def parser
|
50
50
|
@parser ||= methods.each_with_object({}) do |method, hash|
|
@@ -64,7 +64,7 @@ module MarkdownRubyDocumentation
|
|
64
64
|
|
65
65
|
module CommentMacros
|
66
66
|
include Parsing
|
67
|
-
|
67
|
+
attr_accessor :output_object
|
68
68
|
# @param [String] str
|
69
69
|
# @example
|
70
70
|
# @return [String] of any comments proceeding a method def
|
@@ -184,27 +184,12 @@ module MarkdownRubyDocumentation
|
|
184
184
|
gsub_replacement(source_code, conversions, proc: proc)
|
185
185
|
end
|
186
186
|
|
187
|
-
def readable_ruby_numbers(source_code,
|
187
|
+
def readable_ruby_numbers(source_code, proc: -> (value) { ActiveSupport::NumberHelper.number_to_delimited(value) })
|
188
188
|
source_code.gsub(/([0-9][0-9_]+[0-9]+)/) do |match|
|
189
|
-
|
190
|
-
if block_given?
|
191
|
-
block.call(value)
|
192
|
-
else
|
193
|
-
ActiveSupport::NumberHelper.number_to_delimited(value)
|
194
|
-
end
|
189
|
+
proc.call(eval(match))
|
195
190
|
end
|
196
191
|
end
|
197
192
|
|
198
|
-
def include_code(include, text, &do_action)
|
199
|
-
if include.nil? || (include.present? && include.include?(remove_quotes(text)))
|
200
|
-
do_action.call(text)
|
201
|
-
else
|
202
|
-
text
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
private :include_code
|
207
|
-
|
208
193
|
def convert_early_return_to_if_else(source_code, *)
|
209
194
|
source_code = source_code.gsub(/(.+) if (.+)/, "if \\2\n\\1\nend")
|
210
195
|
source_code.gsub(/(.+) unless (.+)/, "unless \\2\n\\1\nend")
|
@@ -235,24 +220,110 @@ module MarkdownRubyDocumentation
|
|
235
220
|
[link_ref.split("/").last.split("#").last.to_s.humanize, link_ref]
|
236
221
|
end
|
237
222
|
|
238
|
-
|
239
|
-
|
240
|
-
|
223
|
+
UnimplementedMethod = Class.new(StandardError)
|
224
|
+
# @param [Class, String, Pathname] klass_or_path
|
225
|
+
# 1. String or Class representing a method reference
|
226
|
+
# 2. Pathname representing the full path of the file location a method is defined
|
227
|
+
# @param [String] title is the link display value
|
228
|
+
# @return [String, Symbol] Creates link to a given generated markdown file or returns :non_project_location message.
|
229
|
+
# 1. "[title](path/to/markdown/file.md#method-name)"
|
230
|
+
# 2. :non_project_location
|
231
|
+
def link_to_markdown(klass_or_path, title:, _ruby_class: ruby_class)
|
232
|
+
if klass_or_path.is_a?(String) || klass_or_path.is_a?(Class) || klass_or_path.is_a?(Module)
|
233
|
+
link_to_markdown_method_reference(method_reference: klass_or_path, title: title, ruby_class: _ruby_class)
|
234
|
+
elsif klass_or_path.is_a?(Pathname)
|
235
|
+
link_to_markdown_full_path(path: klass_or_path, title: title, ruby_class: _ruby_class)
|
236
|
+
else
|
237
|
+
raise ArgumentError, "invalid first arg given: #{klass_or_path} for #{__method__}"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def link_to_markdown_method_reference(method_reference:, title:, ruby_class:)
|
242
|
+
method = MarkdownRubyDocumentation::Method.create(method_reference, null_method: true, context: ruby_class)
|
243
|
+
parts = method.context_name.to_s.split("::").reject(&:blank?)
|
244
|
+
path = parts.map { |p| p.underscore }.join("/")
|
245
|
+
path = "#{path}.md#{method.type_symbol}#{method.name}"
|
246
|
+
format_link title, MarkdownRubyDocumentation::GitHubLink::FileUrl.new(file_path: File.join(MarkdownRubyDocumentation::Generate.output_object.relative_dir, path)).to_s
|
247
|
+
end
|
248
|
+
|
249
|
+
def link_to_markdown_full_path(path:, title:, ruby_class:)
|
250
|
+
if path.to_s.include?(MarkdownRubyDocumentation::Generate.load_path)
|
251
|
+
relative_path = path.to_s.gsub(MarkdownRubyDocumentation::Generate.load_path, "")
|
252
|
+
const_nest, meth = relative_path.split("#")
|
253
|
+
const = const_nest.split("/").map(&:camelize).join("::")
|
254
|
+
link_to_markdown_method_reference(method_reference: "#{const.gsub(".rb", "")}##{meth}", title: title, ruby_class: ruby_class)
|
255
|
+
else
|
256
|
+
:non_project_location
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
class MethodLink
|
261
|
+
RUBY_METHOD_REGEX = /(\b(?<!['"])[a-z_][a-z_0-9?!]*(?!['"]))/.freeze
|
262
|
+
|
263
|
+
def initialize(match:,
|
264
|
+
call_on_title: :titleize,
|
265
|
+
method_to_class: {},
|
266
|
+
link_to_markdown:,
|
267
|
+
ruby_class:)
|
268
|
+
@match = match
|
269
|
+
@ruby_class = ruby_class
|
270
|
+
@call_on_title = call_on_title
|
271
|
+
@method_to_class = method_to_class
|
272
|
+
@link_to_markdown = link_to_markdown
|
273
|
+
end
|
274
|
+
|
275
|
+
def link
|
276
|
+
if constant_override
|
277
|
+
constant_override_method_path
|
278
|
+
else
|
279
|
+
link = link_to_markdown.call(method_path, title: title)
|
280
|
+
if link == :non_project_location
|
281
|
+
match
|
282
|
+
else
|
283
|
+
link
|
284
|
+
end
|
285
|
+
end
|
286
|
+
rescue UnimplementedMethod => e
|
287
|
+
"[#{title}](##{match.downcase.dasherize.delete(" ").delete('?')})"
|
288
|
+
end
|
289
|
+
|
290
|
+
private
|
291
|
+
|
292
|
+
attr_reader :match, :ruby_class, :call_on_title, :method_to_class, :link_to_markdown
|
293
|
+
|
294
|
+
def title
|
295
|
+
@title ||= if call_on_title
|
296
|
+
@call_on_title = [*call_on_title].compact
|
297
|
+
match.public_send(call_on_title.first, *call_on_title[1..-1])
|
298
|
+
else
|
299
|
+
match
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def constant_override
|
304
|
+
@constant_override ||= method_to_class[match.to_sym]
|
305
|
+
end
|
306
|
+
|
307
|
+
def method_path
|
308
|
+
Pathname(Method.create("##{match}", context: ruby_class).to_proc.source_location.first+"##{match}")
|
309
|
+
end
|
310
|
+
|
311
|
+
def constant_override_method_path
|
312
|
+
method_object = Method.create("##{match}", context: constant_override)
|
313
|
+
link_to_markdown.call("#{method_object.context.name}##{method_object.name}", title: title)
|
314
|
+
end
|
241
315
|
end
|
242
316
|
|
243
317
|
def methods_as_local_links(ruby_source,
|
244
318
|
call_on_title: :titleize,
|
245
|
-
|
246
|
-
ruby_source.gsub(
|
319
|
+
method_to_class: {})
|
320
|
+
ruby_source.gsub(MethodLink::RUBY_METHOD_REGEX) do |match|
|
247
321
|
if is_a_method_on_ruby_class?(match)
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
match
|
254
|
-
end
|
255
|
-
proc.call(title, "##{match.downcase.dasherize.delete(" ").delete('?')}")
|
322
|
+
MethodLink.new(match: match,
|
323
|
+
ruby_class: ruby_class,
|
324
|
+
call_on_title: call_on_title,
|
325
|
+
method_to_class: method_to_class,
|
326
|
+
link_to_markdown: method(:link_to_markdown)).link
|
256
327
|
else
|
257
328
|
match
|
258
329
|
end
|
@@ -278,8 +349,8 @@ module MarkdownRubyDocumentation
|
|
278
349
|
|
279
350
|
def ruby_if_statement_to_md(ruby_source, proc: false)
|
280
351
|
conversions = {
|
281
|
-
/else if(.*)/ => "*
|
282
|
-
/elsif(.*)/ => "*
|
352
|
+
/else if(.*)/ => "* __Else If__\\1\n__Then__",
|
353
|
+
/elsif(.*)/ => "* __Else If__\\1\n__Then__",
|
283
354
|
/if(.*)/ => "* __If__\\1\n__Then__",
|
284
355
|
/unless(.*)/ => "* __Unless__\\1\n__Then__",
|
285
356
|
"else" => "* __Else__"
|
@@ -13,6 +13,14 @@ module MarkdownRubyDocumentation
|
|
13
13
|
method
|
14
14
|
end
|
15
15
|
|
16
|
+
ruby_class.send(:define_singleton_method, :output_object) do
|
17
|
+
output_object
|
18
|
+
end
|
19
|
+
|
20
|
+
ruby_class.send(:define_singleton_method, :load_path) do
|
21
|
+
load_path
|
22
|
+
end
|
23
|
+
|
16
24
|
ruby_class.extend(CommentMacros)
|
17
25
|
|
18
26
|
erb = ERB.new(str, nil, "-")
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module MarkdownRubyDocumentation
|
2
2
|
class WriteMarkdownToDisk
|
3
3
|
|
4
|
-
attr_reader :dir, :skip_if_blank
|
4
|
+
attr_reader :dir, :skip_if_blank, :relative_dir
|
5
5
|
|
6
|
-
def initialize(dir:, skip_if_blank: false)
|
6
|
+
def initialize(dir:, skip_if_blank: false, relative_dir:)
|
7
7
|
@dir = dir
|
8
8
|
@skip_if_blank = skip_if_blank
|
9
|
+
@relative_dir = relative_dir
|
9
10
|
end
|
10
11
|
|
11
12
|
def call(name:, text:)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: markdown_ruby_documentation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dustin Zeisler
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: method_source
|