module Topoisomerase

Module for parsing and creating stubs for dynamic methods

Constants

VERSION

@return [String] Version of the gem

Attributes

comments_added[RW]

@todo Use custom object for this @return [Hash] Comments added to stubs generated grouped by inheriting class and then by

message, matcher patterns
stub_folder[RW]

@return [String] Folder where stubs are stored

Public Class Methods

comment_for(stub_method, method_data) click to toggle source

Reads from 'comments_added' variable if no comment added above dynamic method @return [String] Comment defined by 'comments_added'

# File lib/topoisomerase.rb, line 71
def comment_for(stub_method, method_data)
  return extracted_comment(method_data) unless comments_added[@inheriting_class]

  stub_method = stub_method.to_s
  comments_added[@inheriting_class].each do |comment_matcher|
    matchers = comment_matcher[:matchers]
    return ERB.new(comment_matcher[:message]).result(binding) if matchers.all? do |matcher_type, matcher_value|
      extracted_match = case matcher_type
                        when :method_name then match?(stub_method, matcher_value)
                        when :source then match? method_data[:source], matcher_value
                        else
                          raise Topoisomerase::Error, "Undefined matcher #{matcher_type}"
                        end
      extracted_match
    end
  end
  ''
end
create_stubs_based_on(inheriting_class) { |class_name| ... } click to toggle source

Create stub files for each class that inherits from passed in class @param [Object] inheriting_class Object to check for inheriting classes for

# File lib/topoisomerase.rb, line 110
def create_stubs_based_on(inheriting_class)
  @inheriting_class = inheriting_class
  classes = ObjectSpace.each_object(Class).select { |class_name| class_name < inheriting_class }.reject do |class_name|
    class_name.to_s.split(':')[0] == inheriting_class.to_s
  end
  classes.each do |class_name|
    @class_instance = block_given? ? yield(class_name) : class_name.new
    create_stubs_for(class_name, inheriting_class.to_s.snakecase) { @class_instance }
  end
end
create_stubs_for(class_name, inner_folder = nil) { |class_name| ... } click to toggle source

Create stub file for passed in class @param [Object] class_name Object to create stub file for

# File lib/topoisomerase.rb, line 92
def create_stubs_for(class_name, inner_folder = nil)
  template = File.join(File.dirname(__FILE__), 'topoisomerase', 'stub_template.rb.erb')
  @class_name = class_name
  @class_instance = block_given? ? yield(class_name) : class_name.new
  @dynamic_methods = dynamic_instance_methods(class_name) do
    @class_instance
  end
  class_folder = inner_folder ? File.join(stub_folder, inner_folder) : stub_folder
  filename = File.join(class_folder, "#{class_name.to_s.snakecase}.rb")
  puts "Creating stubs for #{class_name} at #{filename}"
  FileUtils.mkdir_p File.dirname(filename)
  IO.write filename, ERB.new(File.read(template)).result(binding)
  RuboCop::CLI.new.run(['-a', filename, '-o', 'stub_log'])
  FileUtils.rm 'stub_log' # TODO: Should be a way of not producing this in first place
end
dynamic_instance_methods(class_name) { |class_name| ... } click to toggle source

@param [Object] class_name Class to retrieve dynamic methods for @return [Hash] Hash with dynamic methods as keys and values being the source, comment

and location
# File lib/topoisomerase.rb, line 35
def dynamic_instance_methods(class_name)
  class_instance = block_given? ? yield(class_name) : class_name.new
  methods_hash = {}
  (class_instance.public_methods - Object.public_methods).each do |method|
    method_obj = class_instance.method(method)
    next unless dynamic_method? class_instance.method(method)

    methods_hash.merge!(method => { source: method_obj.source, comment: method_obj.comment,
                                    location: method_obj.source_location,
                                    parameters: method_obj.parameters.collect { |p| p.last.to_s } })
    # TODO: May be worth checking required parameters and documenting non-required differently
    # receiver - Shows object that will call method
    # owner - shows class from which method belongs to
    # parameters - Array with params and :req
  end
  methods_hash
end
dynamic_method?(method) click to toggle source

@todo This is only covering 'define_method'. More methods will be added later @return [Boolean] Whether method is defined dynamically

# File lib/topoisomerase.rb, line 27
def dynamic_method?(method)
  source_code = method.source
  source_code.strip.start_with? 'define_method'
end
extracted_comment(method_data) click to toggle source

@return [String] Comment extracted from dynamic element

# File lib/topoisomerase.rb, line 54
def extracted_comment(method_data)
  method_data[:comment].strip.empty? ? '' : "Extracted comment #{method_data[:comment].strip}"
end
match?(value_to_test, matcher_value) click to toggle source

@return [Boolean] Whether there is a match based on value and matcher

# File lib/topoisomerase.rb, line 59
def match?(value_to_test, matcher_value)
  value_to_test = value_to_test.to_s
  case matcher_value
  when Regexp then !value_to_test[matcher_value].nil?
  when String then value_to_test == matcher_value
  else
    raise "Unknown matcher type for #{value_to_test}, value of #{matcher_value}"
  end
end