lib/raap/symbolic_caller.rb in raap-0.3.0 vs lib/raap/symbolic_caller.rb in raap-0.4.0

- old
+ new

@@ -16,10 +16,11 @@ # c = C.new(a: a, b: b) # c.run() { } class SymbolicCaller class Var attr_reader :name + def initialize(name) @name = name end def +(other) @@ -44,54 +45,70 @@ eval_one(symbolic_call) end end def call_str - symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, b] + symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, block] receiver = try_eval(receiver) args, kwargs, block = try_eval([args, kwargs, block]) a = [] - a << args.map(&:inspect).join(', ') if !args.empty? - a << kwargs.map { |k ,v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty? + a << args.map(&BindCall.method(:inspect)).join(', ') if !args.empty? + a << kwargs.map { |k, v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty? argument_str = a.join(', ') block_str = block ? "{ }" : nil "#{BindCall.inspect(receiver)}.#{method_name}(#{argument_str})#{block_str}" end def to_lines [].tap do |lines| - walk do |symbolic_call| + walk do |symbolic_call, is_last| symbolic_call => [:call, receiver_value, method_name, args, kwargs, block] is_mod = receiver_value.is_a?(Module) case when receiver_value == Kernel var = Var.new(method_name.to_s.downcase) var_eq = "#{var} = " receiver = '' when BindCall.instance_of?(receiver_value, Var) - var_eq = "" + var_eq = "#{receiver_value} = " var = Var.new(receiver_value.name) receiver = var + '.' when is_mod var = Var.new(var_name(receiver_value)) var_eq = "#{var} = " receiver = receiver_value.name + '.' else - var_eq = "" + var_eq = '' receiver = Var.new(printable(receiver_value)) + '.' end + var_eq = '' if is_last + arguments = [] - arguments << args.map { |a| printable(a) } if !args.empty? - arguments << kwargs.map{|k,v| "#{k}: #{printable(v)}" }.join(', ') if !kwargs.empty? + if !args.empty? + # The reproduction code is kept short and executable. + if [Value::Interface, Value::Intersection].include?(receiver_value) + if args.all? { |a| a.respond_to?(:free_variables) } && !args.all? { |a| a.free_variables.empty? } + # FIXME: Type arguments are not yet supported. + args.each do |a| + lines << "# Free variables: #{a.free_variables.to_a.join(', ')}" + end + end + arguments << args.map { |a| printable(a.to_s) } + else + arguments << args.map { |a| printable(a) } + end + end + arguments << kwargs.map { |k, v| "#{k}: #{printable(v)}" }.join(', ') if !kwargs.empty? block_str = block ? " { }" : "" - lines << "#{var_eq}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}" + line = "#{var_eq}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}" + lines << line var end end end @@ -103,29 +120,28 @@ rescue RuntimeError, NotImplementedError symbolic_call end def walk(&) - _walk(@symbolic_call, &) + _walk(@symbolic_call, true, &) end - def _walk(symbolic_call, &block) + def _walk(symbolic_call, is_last, &block) return symbolic_call if BindCall::instance_of?(symbolic_call, BasicObject) return symbolic_call if !BindCall.respond_to?(symbolic_call, :deconstruct) && !BindCall.respond_to?(symbolic_call, :deconstruct_keys) case symbolic_call in [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, b] - receiver = _walk(receiver, &block) - args = _walk(args, &block) if !args.empty? - kwargs = _walk(kwargs, &block) if !kwargs.empty? - block.call [:call, receiver, method_name, args, kwargs, b] - in Var - symbolic_call.name + receiver = _walk(receiver, false, &block) + args = _walk(args, false, &block) if !args.empty? + kwargs = _walk(kwargs, false, &block) if !kwargs.empty? + block.call [:call, receiver, method_name, args, kwargs, b], is_last in Array - symbolic_call.map { |sc| _walk(sc, &block) } + symbolic_call.map { |sc| _walk(sc, false, &block) } in Hash - symbolic_call.transform_values { |sc| _walk(sc, &block) } + symbolic_call.transform_keys { |k| _walk(k, false, &block) } + .transform_values! { |v| _walk(v, false, &block) } else symbolic_call end end @@ -141,19 +157,15 @@ def var_name(mod) printable(mod).gsub('::', '_').downcase end def printable(obj) - if obj in [:call, _, Symbol, Array, Hash, _] - return _walk(obj) - end - case obj when Var obj.name # Object from which it can get strings that can be eval with `#inspect` - when Symbol, Integer, Float, Regexp, nil, true, false + when Symbol, Integer, Float, Regexp, Range, nil, true, false obj.inspect when String obj.inspect.gsub('"', "'") or raise when Hash hash_body = obj.map do |k, v| @@ -163,12 +175,12 @@ end "{#{hash_body.join(', ')}}" when Array "[#{obj.map { |o| printable(o) }.join(', ')}]" when Module - BindCall.name(obj) or raise + BindCall.name(obj) or raise "`#class` method returns nil" else - var_name(obj.class) + var_name(BindCall.class(obj)) end end end end