Is there a way to access method arguments in Ruby?

后端 未结 11 1073
没有蜡笔的小新
没有蜡笔的小新 2020-11-29 17:00

New to Ruby and ROR and loving it each day, so here is my question since I have not idea how to google it (and I have tried :) )

we have method

def f         


        
相关标签:
11条回答
  • 2020-11-29 17:33

    If you need arguments as a Hash, and you don't want to pollute method's body with tricky extraction of parameters, use this:

    def mymethod(firstarg, kw_arg1:, kw_arg2: :default)
      args = MethodArguments.(binding) # All arguments are in `args` hash now
      ...
    end
    

    Just add this class to your project:

    class MethodArguments
      def self.call(ext_binding)
        raise ArgumentError, "Binding expected, #{ext_binding.class.name} given" unless ext_binding.is_a?(Binding)
        method_name = ext_binding.eval("__method__")
        ext_binding.receiver.method(method_name).parameters.map do |_, name|
          [name, ext_binding.local_variable_get(name)]
        end.to_h
      end
    end
    
    0 讨论(0)
  • 2020-11-29 17:43

    This is an interesting question. Maybe using local_variables? But there must be a way other than using eval. I'm looking in Kernel doc

    class Test
      def method(first, last)
        local_variables.each do |var|
          puts eval var.to_s
        end
      end
    end
    
    Test.new().method("aaa", 1) # outputs "aaa", 1
    
    0 讨论(0)
  • 2020-11-29 17:43

    Before I go further, you're passing too many arguments into foo. It looks like all of those arguments are attributes on a Model, correct? You should really be passing the object itself. End of speech.

    You could use a "splat" argument. It shoves everything into an array. It would look like:

    def foo(*bar)
      ...
      log.error "Error with arguments #{bar.joins(', ')}"
    end
    
    0 讨论(0)
  • 2020-11-29 17:44

    If the function is inside some class then you can do something like this:

    class Car
      def drive(speed)
      end
    end
    
    car = Car.new
    method = car.method(:drive)
    
    p method.parameters #=> [[:req, :speed]] 
    
    0 讨论(0)
  • 2020-11-29 17:49

    Since Ruby 2.1 you can use binding.local_variable_get to read value of any local variable, including method parameters (arguments). Thanks to that you can improve the accepted answer to avoid evil eval.

    def foo(x, y)
      method(__method__).parameters.map do |_, name|
        binding.local_variable_get(name)
      end
    end
    
    foo(1, 2)  # => 1, 2
    
    0 讨论(0)
  • 2020-11-29 17:49

    You can define a constant such as:

    ARGS_TO_HASH = "method(__method__).parameters.map { |arg| arg[1].to_s }.map { |arg| { arg.to_sym => eval(arg) } }.reduce Hash.new, :merge"
    

    And use it in your code like:

    args = eval(ARGS_TO_HASH)
    another_method_that_takes_the_same_arguments(**args)
    
    0 讨论(0)
提交回复
热议问题