markdown_ruby_documentation 0.2.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 98da1a6202c25d0e20c630339f0ec5c9c6bb1898
4
- data.tar.gz: 6af3bf690dd9f17d014ea6c5cc28eca39e975172
3
+ metadata.gz: 0195aa8a642b4e01747ef74e449c4a0e0195fcc5
4
+ data.tar.gz: c752bf835f1c6fbf3bbf5ed968cc35a3810bb930
5
5
  SHA512:
6
- metadata.gz: 333233006d8b7304ed481d52b0b5d38b2b7605d644fae481d584be890ac59af4f9b3c43faaa8c29cc2f1e6dc3fa954fcb18d7481060640e86be4abb014188eb0
7
- data.tar.gz: a06f239ab1f24aabf81c63e0adf2f34f35d01a4df7558d2a5f1eed1119d5393991c64a83ea6b721e4097be79846ada30dc425e349a49b514a641650e204858e1
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
- output_proc: html_generator
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
- *example ruby_to_markdown readable_ruby_numbers: false*
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
@@ -1,9 +1,5 @@
1
1
  module MarkdownRubyDocumentation
2
2
  module DefaultErbMethods
3
- def link_to_markdown(klass, title:)
4
- "[#{title}](#{klass})"
5
- end
6
-
7
3
  def self.erb_methods_module
8
4
  self
9
5
  end
@@ -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] output_proc given name: and text: for use in saving the the files.
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:, erb_methods: DefaultErbMethods, output_proc: -> (name:, text:) { { name => text } }
8
+ subjects:,
9
+ erb_methods: DefaultErbMethods,
10
+ output_object:,
11
+ load_path:
8
12
  )
9
- erb_methods_class = Class.new
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 = ProgressBar.create(title: "Compiling Markdown".ljust(left_padding), total: subjects.count+ 1)
15
- pages = subjects.map do |subject|
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
- output_proc: output_proc,
19
- erb_methods_class: erb_methods_class).call.tap { progressbar.increment }
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 = pages.each_with_object({}) do |page, hash|
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, :output_proc, :erb_methods_class
47
+ attr_reader :subject, :output_object, :erb_methods_class, :load_path
37
48
 
38
49
  def initialize(subject:,
39
50
  methods: [],
40
- output_proc:,
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
- @output_proc = output_proc
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
- output_proc.call(name: subject.name,
54
- text: text)
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 = items
8
- @summary = summary
9
- @title_key = title_key
10
- @skip_blanks = 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
- <<-MD
16
- # #{summary.title}
17
- #{summary.summary}
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 present_items
26
- items.map do |name, hash|
27
- begin
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, *, &block)
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
- value = eval(match)
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
- def link_to_markdown(klass, title:)
239
- return super if defined? super
240
- raise "Client needs to define MarkdownRubyDocumentation::TemplateParser::CommentMacros#link_to_markdown"
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
- proc: -> (match, anchor) { "[#{match}](#{anchor})" })
246
- ruby_source.gsub(/(\b(?<!['"])[a-z_][a-z_0-9?!]*(?!['"]))/) do |match|
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
- title = if call_on_title
250
- call_on_title = [*call_on_title].compact
251
- match.public_send(call_on_title.first, *call_on_title[1..-1])
252
- else
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(.*)/ => "* __ElseIf__\\1\n__Then__",
282
- /elsif(.*)/ => "* __ElseIf__\\1\n__Then__",
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,3 +1,3 @@
1
1
  module MarkdownRubyDocumentation
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -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.2.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-28 00:00:00.000000000 Z
11
+ date: 2016-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: method_source