module Topoisomerase
Module for parsing and creating stubs for dynamic methods
Constants
- VERSION
@return [String] Version of the gem
Attributes
@todo Use custom object for this @return [Hash] Comments
added to stubs generated grouped by inheriting class and then by
message, matcher patterns
@return [String] Folder where stubs are stored
Public Class Methods
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 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 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
@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
@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
@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
@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