module MethodIntrospection::CodeHelpers

Public Instance Methods

comment_describing(file, line_number) click to toggle source
#

comment_describing

This method will retrieve the comment describing the expression on the given line of the given file.

This is useful to get the module or method documentation, in String format.

@param [Array<String>, File, String] file The file to parse, either as a File or as

a String or an Array of lines.

@param [Fixnum] line_number The line number at which to look.

NOTE: The first line in a file is line 1!

@return [String] The comment

#
# File lib/method_introspection/code_helpers.rb, line 52
def comment_describing(file, line_number)
  if file.is_a? Array
    lines = file
  else
    lines = file.each_line.to_a
  end
  # ======================================================================= #
  # At this point, lines is now an Array. We extract the proper lines
  # by making use of the line number.
  # ======================================================================= #
  extract_last_comment(lines[0..(line_number - 2)])
end
complete_expression?(i) click to toggle source
#

complete_expression?

Determine if a string of code is a complete Ruby expression.

@param [String] code The code to validate. @return [Boolean] Whether or not the code is a complete Ruby expression. @raise [SyntaxError] Any SyntaxError that does not represent incompleteness.

@Usage examples

complete_expression?("class Hello")      # => false
complete_expression?("class Hello; end") # => true
complete_expression?("class 123")        # => SyntaxError: unexpected tINTEGER
#
# File lib/method_introspection/code_helpers.rb, line 134
def complete_expression?(i)
  old_verbose = $VERBOSE
  $VERBOSE = nil
  catch(:valid) {
    eval("BEGIN{throw :valid}\n#{i}")
  }
  # Assert that a line which ends with a , or \ is incomplete.
  i !~ /[,\\]\s*\z/
rescue IncompleteExpression
  false
ensure
  $VERBOSE = old_verbose # Reinstate the old verbosity level here.
end
expression_at( file, line_number, options = {} ) click to toggle source
#

expression_at

Retrieve the first expression starting on the given line of the given file.

This is useful to get module or method source code.

@param [Array<String>, File, String] file The file to parse, either as a File or as

@param [Fixnum] line_number The line number at which to look.

  NOTE: The first line in a file is
line 1!

@param [Hash] options The optional configuration parameters.

@option options [Boolean] :strict If set to true, then only completely

valid expressions are returned. Otherwise heuristics are used to extract
expressions that may have been valid inside an eval.

@option options [Fixnum] :consume A number of lines to automatically

consume (add to the expression buffer) without checking for validity.

@return [String] The first complete expression

@raise [SyntaxError] If the first complete expression can't be identified

#
# File lib/method_introspection/code_helpers.rb, line 91
def expression_at(
    file,
    line_number,
    options = {}
  )
  options = {
    :strict  => false,
    :consume => 0
  }.merge!(options)

  if file.is_a? Array
    lines = file
  else
    lines = file.each_line.to_a
  end
  relevant_lines = lines[(line_number - 1)..-1] || []
  extract_first_expression(relevant_lines, options[:consume])
rescue SyntaxError => e
  raise if options[:strict]
  begin
    extract_first_expression(relevant_lines) { |code|
      code.gsub(/\#\{.*?\}/, "temp")
    }
  rescue SyntaxError
    raise e
  end
end

Private Instance Methods

extract_first_expression(lines, consume = 0, &block) click to toggle source
#

extract_first_expression

Get the first expression from the input.

@param [Array<String>] lines @param [Fixnum] consume A number of lines to automatically

consume (add to the expression buffer) without checking for validity.

@yield a clean-up function to run before checking for complete_expression @return [String] a valid ruby expression @raise [SyntaxError]

#
# File lib/method_introspection/code_helpers.rb, line 160
def extract_first_expression(lines, consume = 0, &block)
  code = consume.zero? ? '' : lines.slice!(0..(consume - 1)).join
  lines.each { |entry|
    code << entry
    return code if complete_expression?(block ? block.call(code) : code)
  }
  raise SyntaxError, "unexpected $end"
end
extract_last_comment(lines) click to toggle source
#

extract_last_comment

Get the last comment from the input. We will build up the result.

@param [Array<String>] lines @return [String]

#
# File lib/method_introspection/code_helpers.rb, line 17
def extract_last_comment(lines)
  result = ''
  lines.each { |line|
    # ===================================================================== #
    # Add any line that is a valid ruby comment but stop the moment
    # we hit a non-comment line.
    # ===================================================================== #
    if (line =~ /^\s*#/) || (line =~ /^\s*$/)
      # =================================================================== #
      # Append onto result next. In the past we called .lstrip() here but
      # this is no longer legal as we modify the original comment.
      # =================================================================== #
      result << line
    else
      result.replace("")
    end
  }
  return result
end