Module: MarkdownRubyDocumentation::TemplateParser::CommentMacros

Includes:
Parsing
Included in:
MarkdownRubyDocumentation::TemplateParser
Defined in:
lib/markdown_ruby_documentation/template_parser.rb

Defined Under Namespace

Classes: MethodLink

Constant Summary collapse

RUBY_TO_MARKDOWN_PROCESSORS =
[
  :readable_ruby_numbers,
  :pretty_early_return,
  :convert_early_return_to_if_else,
  :ternary_to_if_else,
  :ruby_if_statement_to_md,
  :ruby_case_statement_to_md,
  :ruby_operators_to_english,
  :nil_check_readable,
  :question_mark_method_format,
  :symbol_to_proc,
  :methods_as_local_links,
  :remove_end_keyword,
  :constants_with_name_and_value,
  :remove_memoized_vars,
  :comment_format,
  :rescue_format
]
UnimplementedMethod =
Class.new(StandardError)
IGNORE_METHOD_OWNERS =
[
  Object
]

Constants included from Parsing

Parsing::CLASS_MACROS

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Parsing

#extract_dsl_comment, #extract_dsl_comment_from_method, #get_line_number, #insert_method_name, #look_for_class_macro_comment, #parse_erb, #ruby_class_meth_comment, #ruby_class_meth_source_location, #source_location, #strip_comment_hash, #when_only_start, #when_start_and_end

Instance Attribute Details

#output_objectObject

Returns the value of attribute output_object.



66
67
68
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 66

def output_object
  @output_object
end

Instance Method Details

#array_to_markdown_table(array, key_name:) ⇒ Object



454
455
456
457
458
459
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 454

def array_to_markdown_table(array, key_name:)
  key_max_length = [array.group_by(&:size).max.first, key_name.size + 1].max
  header         = markdown_table_header([[key_name, key_max_length+3]])
  rows           = array.map { |key| "| #{key.to_s.ljust(key_max_length)} |" }.join("\n")
  [header, rows].join("\n")
end

#comment_format(source_code = print_method_source, proc: false) ⇒ Object



169
170
171
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 169

def comment_format(source_code=print_method_source, proc: false)
  gsub_replacement(source_code, { /^#(.*)/ => "</br>*(\\1)*</br>" }, proc: proc)
end

#constants_with_name_and_value(ruby_source, proc: false) ⇒ Object



392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 392

def constants_with_name_and_value(ruby_source, proc: false)
  ruby_source.gsub(/([A-Z]+[A-Z_0-9]+)/) do |match|
    begin
      value           = ruby_class.const_get(match)
      link            = "##{match.dasherize.downcase}"
      formatted_value = ConstantsPresenter.format(value)
      replacement     = format_link(formatted_value, link)
      proc ? proc.call(replacement, match, { value: value, link: link, formatted_value: formatted_value }) : replacement
    rescue NameError
      match
    end
  end
end

#convert_early_return_to_if_else(source_code = print_method_source, proc: false) ⇒ Object



221
222
223
224
225
226
227
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 221

def convert_early_return_to_if_else(source_code=print_method_source, proc: false)
  conversions = {
    /(.+) if (.+)/   => "if \\2\n\\1\nend",
    /(.+) unless (.+)/ => "unless \\2\n\\1\nend"
  }
  gsub_replacement(source_code, conversions, proc: proc)
end

#default_title(klass_or_path, _ruby_class) ⇒ Object



280
281
282
283
284
285
286
287
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 280

def default_title(klass_or_path, _ruby_class)
  method = MarkdownRubyDocumentation::Method.create(klass_or_path, null_method: true, context: _ruby_class)
  if method.name
    method.name
  else
    method.context_name.to_s.demodulize
  end.to_s.titleize
end

#elsif_to_else_if(source_code = print_method_source, proc: false) ⇒ Object



187
188
189
190
191
192
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 187

def elsif_to_else_if(source_code=print_method_source, proc: false)
  conversions = {
    "elsif" => "else if"
  }
  gsub_replacement(source_code, conversions, proc: proc)
end

#eval_method(str = current_method) ⇒ Object

Returns anything that the evaluated method would return.

Parameters:

  • str (String) (defaults to: current_method)

Returns:

  • (Object)

    anything that the evaluated method would return.



85
86
87
88
89
90
91
92
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 85

def eval_method(str=current_method)
  case (method = Method.create(str, context: ruby_class))
  when ClassMethod
    method.context.public_send(method.name)
  when InstanceMethod
    InstanceToClassMethods.new(method: method).eval_instance_method
  end
end

Examples:

format_link(“MyLink”, “path/to/it#method_name?”)

#=> "[MyLink](#path/to/it#method-name)"

Parameters:

  • title (String)

    the name of the link

  • link_ref (String)

    the url with method anchor



247
248
249
250
251
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 247

def format_link(title, link_ref)
  path, anchor   = *link_ref.to_s.split("#")
  formatted_path = [path, anchor.try!(:dasherize).try!(:delete, "?").try(:delete, "!")].compact.join("#")
  "[#{title}](#{formatted_path})"
end

#git_hub_file_url(file_path_or_const) ⇒ Object



108
109
110
111
112
113
114
115
116
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 108

def git_hub_file_url(file_path_or_const)
  if file_path_or_const.include?("/")
    GitHubLink::FileUrl.new(file_path: file_path_or_const)
  else
    const    = Object.const_get(file_path_or_const)
    a_method = const.public_instance_methods.first
    git_hub_method_url("#{file_path_or_const}##{a_method}")
  end
end

#git_hub_method_url(method_reference = current_method) ⇒ Object

Parameters:

  • method_reference (String) (defaults to: current_method)


103
104
105
106
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 103

def git_hub_method_url(method_reference=current_method)
  method = Method.create(method_reference.dup, context: ruby_class)
  GitHubLink::MethodUrl.new(subject: method.context, method_object: method)
end

#hash_to_markdown_table(hash, key_name:, value_name:) ⇒ Object



446
447
448
449
450
451
452
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 446

def hash_to_markdown_table(hash, key_name:, value_name:)
  key_max_length   = [hash.keys.group_by(&:size).max.first, key_name.size + 1].max
  value_max_length = [hash.values.group_by { |v| v.try!(:size) || 1 }.max.first, value_name.size + 1].max
  header           = markdown_table_header([[key_name, key_max_length+2], [value_name, value_max_length+2]])
  rows             = hash.map { |key, value| "| #{key.to_s.ljust(key_max_length)} | #{value.to_s.ljust(value_max_length)}|" }.join("\n")
  [header, rows].join("\n")
end

Returns Creates link to a given generated markdown file or returns :non_project_location message.

  1. “[title](path/to/markdown/file.md#method-name)”

  2. :non_project_location.

Parameters:

  • klass_or_path (Class, String, Pathname)
    1. String or Class representing a method reference

    2. Pathname representing the full path of the file location a method is defined

  • title (String) (defaults to: default_title(klass_or_path, _ruby_class))

    is the link display value

Returns:

  • (String, Symbol)

    Creates link to a given generated markdown file or returns :non_project_location message.

    1. “[title](path/to/markdown/file.md#method-name)”

    2. :non_project_location



268
269
270
271
272
273
274
275
276
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 268

def link_to_markdown(klass_or_path, _ruby_class: ruby_class, title: default_title(klass_or_path, _ruby_class))
  if klass_or_path.is_a?(String) || klass_or_path.is_a?(Class) || klass_or_path.is_a?(Module)
    link_to_markdown_method_reference(method_reference: klass_or_path, title: title, ruby_class: _ruby_class)
  elsif klass_or_path.is_a?(Pathname)
    link_to_markdown_full_path(path: klass_or_path, title: title, ruby_class: _ruby_class)
  else
    raise ArgumentError, "invalid first arg given: #{klass_or_path} for #{__method__}"
  end
end


302
303
304
305
306
307
308
309
310
311
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 302

def link_to_markdown_full_path(path:, title:, ruby_class:)
  if path.to_s.include?(MarkdownRubyDocumentation::Generate.load_path)
    relative_path    = path.to_s.gsub(MarkdownRubyDocumentation::Generate.load_path, "")
    const_nest, meth = relative_path.split("#")
    const            = const_nest.split("/").map(&:camelize).join("::")
    link_to_markdown_method_reference(method_reference: "#{const.gsub(".rb", "")}##{meth}", title: title, ruby_class: ruby_class)
  else
    :non_project_location
  end
end


293
294
295
296
297
298
299
300
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 293

def link_to_markdown_method_reference(method_reference:, title:, ruby_class:)
  return title if IGNORE_METHOD_OWNERS.include?(ruby_class)
  method = MarkdownRubyDocumentation::Method.create(method_reference, null_method: true, context: ruby_class)
  parts  = method.context_name.to_s.split("::").reject(&:blank?)
  path   = parts.map { |p| p.underscore }.join("/")
  path   = "#{path}.md#{method.type_symbol}#{method.name}"
  format_link title, MarkdownRubyDocumentation::GitHubLink::FileUrl.new(file_path: File.join(MarkdownRubyDocumentation::Generate.output_object.relative_dir, path)).to_s
end

#markdown_table_header(array_headers) ⇒ Object



461
462
463
464
465
466
467
468
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 461

def markdown_table_header(array_headers)
  parts      = array_headers.map { |header, pad_length=0| " #{header.ljust(pad_length-1)}" }
  bar        = parts.map(&:length).map { |length| ("-" * (length)) }.join("|")
  bar[-1]    = "|"
  header     = parts.join("|")
  header[-1] = "|"
  [("|" + header), ("|" + bar)].join("\n")
end


374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 374

def methods_as_local_links(ruby_source,
                           call_on_title: :titleize,
                           method_to_class: {},
                           proc: false)
  ruby_source.gsub(MethodLink::RUBY_METHOD_REGEX) do |match|
    if is_a_method_on_ruby_class?(match)
      replacement = MethodLink.new(match:            match,
                                   ruby_class:       ruby_class,
                                   call_on_title:    call_on_title,
                                   method_to_class:  method_to_class,
                                   link_to_markdown: method(:link_to_markdown)).link
      proc ? proc.call(replacement, match) : replacement
    else
      match
    end
  end
end

#nil_check_readable(source_code = print_method_source, proc: false) ⇒ Object



180
181
182
183
184
185
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 180

def nil_check_readable(source_code=print_method_source, proc: false)
  conversions = {
    ".nil?" => " is missing?"
  }
  gsub_replacement(source_code, conversions, proc: proc)
end

#pretty_early_return(source_code = print_method_source, proc: false) ⇒ Object



229
230
231
232
233
234
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 229

def pretty_early_return(source_code=print_method_source, proc: false)
  conversions = {
    /return (unless|if)/   => 'return nothing \1'
  }
  gsub_replacement(source_code, conversions, proc: proc)
end

Parameters:

  • str (String)

Returns:

  • (String)


77
78
79
80
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 77

def print_mark_doc_from(str)
  method = Method.create(str, context: ruby_class)
  parse_erb(insert_method_name(extract_dsl_comment(print_raw_comment(str)), method), method)
end

Returns the source of a method block is returned as text.

Parameters:

  • method_reference (String) (defaults to: current_method)

Returns:

  • (String)

    the source of a method block is returned as text.



96
97
98
99
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 96

def print_method_source(method_reference=current_method)
  method = Method.create(method_reference.dup, context: ruby_class)
  PrintMethodSource.new(method: method).print
end

Returns of any comments proceeding a method def.

Parameters:

  • str (String)

Returns:

  • (String)

    of any comments proceeding a method def



70
71
72
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 70

def print_raw_comment(str)
  strip_comment_hash(ruby_class_meth_comment(Method.create(str, context: ruby_class)))
end

#question_mark_method_format(ruby_source) ⇒ Object



406
407
408
409
410
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 406

def question_mark_method_format(ruby_source, *)
  ruby_source.gsub(/(\b(?<!['"])\.[a-z_][a-z_0-9]+\?(?!['"]))/) do |match|
    " is #{match}".sub(".", "")
  end
end

#readable_ruby_numbers(source_code = print_method_source, proc: -> (replacement, _) { ActiveSupport::NumberHelper.number_to_delimited(replacement) }) ⇒ Object



215
216
217
218
219
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 215

def readable_ruby_numbers(source_code=print_method_source, proc: -> (replacement, _) { ActiveSupport::NumberHelper.number_to_delimited(replacement) })
  source_code.gsub(/([0-9][0-9_]+[0-9]+)/) do |match|
    proc.call(eval(match), match)
  end
end

#remove_colons(source_code = print_method_source, proc: false) ⇒ Object



194
195
196
197
198
199
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 194

def remove_colons(source_code=print_method_source, proc: false)
  conversions = {
    ":" => ''
  }
  gsub_replacement(source_code, conversions, proc: proc)
end

#remove_end_keyword(ruby_source, proc: false) ⇒ Object



419
420
421
422
423
424
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 419

def remove_end_keyword(ruby_source, proc: false)
  conversions = {
    /^[\s]*end\n?/ => ""
  }
  gsub_replacement(ruby_source, conversions, proc: proc)
end

#remove_memoized_vars(source_code = print_method_source, proc: false) ⇒ Object



173
174
175
176
177
178
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 173

def remove_memoized_vars(source_code=print_method_source, proc: false)
  conversions = {
    /@[a-z][a-z0-9_]+ \|\|=?\s/ => "" # @memoized_vars ||=
  }
  gsub_replacement(source_code, conversions, proc: proc)
end

#rescue_format(source_code = print_method_source, proc: false) ⇒ Object



162
163
164
165
166
167
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 162

def rescue_format(source_code=print_method_source, proc: false)
  gsub_replacement(source_code, {
    /=>\s.*/                     => "",
    /rescue ([a-zA-Z0-9::]*)./ => "Given a failure of \\1 __Then__\n",
  }, proc: proc)
end

#ruby_case_statement_to_md(ruby_source, proc: false) ⇒ Object



437
438
439
440
441
442
443
444
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 437

def ruby_case_statement_to_md(ruby_source, proc: false)
  conversions = {
    /case(.*)/ => "* __Given__\\1",
    /when(.*)/ => "* __When__\\1\n__Then__",
    "else"     => "* __Else__"
  }
  gsub_replacement(ruby_source, conversions, proc: proc)
end

#ruby_if_statement_to_md(ruby_source, proc: false) ⇒ Object



426
427
428
429
430
431
432
433
434
435
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 426

def ruby_if_statement_to_md(ruby_source, proc: false)
  conversions = {
    /elsif(.*)/                    => "* __Else If__\\1\n__Then__",
    /^\s?if(.*)\s([|&]{0,2})\n(.*)/ => "* __If__\\1 \\2 \\3\n__Then__",
    /^\s?if(.*)/                   => "* __If__\\1\n__Then__",
    /unless(.*)/                   => "* __Unless__\\1\n__Then__",
    "else"                         => "* __Else__"
  }
  gsub_replacement(ruby_source, conversions, proc: proc)
end

#ruby_operators_to_english(source_code = print_method_source, proc: false) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 201

def ruby_operators_to_english(source_code=print_method_source, proc: false)
  conversions = {
    "&&"   => "and",
    ">="   => "is greater than or equal to",
    "<="   => "is less than or equal to",
    " < "  => " is less than ",
    " > "  => " is greater than ",
    " == " => " Equal to ",
    "||"   => "or"
  }

  gsub_replacement(source_code, conversions, proc: proc)
end

#ruby_to_markdown(*args) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 137

def ruby_to_markdown(*args)
  any_args           = AnyArgs.new(args:                args,
                                   print_method_source: method(:print_method_source),
                                   caller:              caller,
                                   for_method:          __method__,
                                   method_creator:      method(:create_method_with_ruby_class))
  disable_processors = any_args.disable_processors
  ruby_source        = any_args.source_code

  RUBY_TO_MARKDOWN_PROCESSORS.each do |processor|
    options     = disable_processors.fetch(processor, :enabled)
    ruby_source = case options
                  when :enabled
                    send(processor, ruby_source)
                  when Hash
                    send(processor, ruby_source, options)
                  when Proc
                    send(processor, ruby_source, proc: options)
                  else
                    ruby_source
                  end
  end
  ruby_source
end

#symbol_to_proc(ruby_source, proc: false) ⇒ Object



412
413
414
415
416
417
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 412

def symbol_to_proc(ruby_source, proc: false)
  conversions = {
    /\(&:([a-z_?!]*)\)/ => " \\1"
  }
  gsub_replacement(ruby_source, conversions, proc: proc)
end

#ternary_to_if_else(source_code = print_method_source, proc: false) ⇒ Object



236
237
238
239
240
241
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 236

def ternary_to_if_else(source_code=print_method_source, proc: false)
  conversions = {
    /(.*) \? (.*) \: (.*)/   =>  "if \\1\n\\2\nelse\n\\3\nend"
  }
  gsub_replacement(source_code, conversions, proc: proc)
end

Examples:

title_from_link“path/to/it#method_name?”)

#=> "[Method Name](#path/to/it#method-name)"

Parameters:

  • link_ref (String)

    the url with method anchor



256
257
258
# File 'lib/markdown_ruby_documentation/template_parser.rb', line 256

def title_from_link(link_ref)
  [link_ref.split("/").last.split("#").last.to_s.humanize, link_ref]
end