module Fasterer class MethodCall attr_reader :element attr_reader :receiver attr_reader :method_name attr_reader :arguments attr_reader :block_body attr_reader :block_argument_names alias_method :name, :method_name def initialize(element) @element = element set_call_element set_receiver set_method_name set_arguments set_block_presence set_block_body set_block_argument_names end def has_block? @block_present || false end def receiver_element call_element[1] end def arguments_element call_element[3..-1] || [] end private attr_reader :call_element # TODO: explanation def set_call_element @call_element = case element.sexp_type when :call @element when :iter @element[1] end end def set_receiver @receiver = ReceiverFactory.new(receiver_element) end def set_method_name @method_name = call_element[2] end def set_arguments @arguments = arguments_element.map { |argument| Argument.new(argument) } end def set_block_presence if element.sexp_type == :iter || (arguments.last && arguments.last.type == :block_pass) @block_present = true end end def set_block_body @block_body = element[3] if has_block? end # TODO: write specs for lambdas and procs def set_block_argument_names @block_argument_names = if has_block? && element[2].is_a?(Sexp) # HACK: for lambdas element[2].drop(1).map { |argument| argument } end || [] end end # For now, used for determening if the # receiver is a reference or a method call. class ReceiverFactory def self.new(receiver_info) return unless receiver_info.is_a?(Sexp) case receiver_info.sexp_type when :lvar return VariableReference.new(receiver_info) when :call, :iter return MethodCall.new(receiver_info) when :array, :dot2, :dot3, :lit return Primitive.new(receiver_info) end end end class VariableReference attr_reader :name def initialize(reference_info) @reference_info = reference_info @name = reference_info[1] end end class Argument attr_reader :element def initialize(element) @element = element end def type @type ||= @element[0] end def value @value ||= @element[1] end end class Primitive attr_reader :element def initialize(element) @element = element end def type @type ||= @element[0] end def range? [:dot2, :dot3, :lit].include?(type) end def array? type == :array end end end