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 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