Programing

Ruby에서 메서드 인수에 액세스하는 방법이 있습니까?

lottogame 2020. 8. 31. 08:17
반응형

Ruby에서 메서드 인수에 액세스하는 방법이 있습니까?


Ruby와 ROR을 처음 접하고 매일 그것을 좋아하므로 Google을 어떻게하는지 몰랐기 때문에 여기에 내 질문이 있습니다 (그리고 시도했습니다 :))

우리는 방법이 있습니다

def foo(first_name, last_name, age, sex, is_plumber)
    # some code
    # error happens here
    logger.error "Method has failed, here are all method arguments #{SOMETHING}"    
end

그래서 내가 찾고있는 방법은 각각을 나열하지 않고 모든 인수를 메서드에 전달하는 방법입니다. 이것이 Ruby이기 때문에 나는 방법이 있다고 가정합니다 :) 그것이 자바라면 나는 그들을 나열 할 것입니다 :)

출력은 다음과 같습니다.

Method has failed, here are all method arguments {"Mario", "Super", 40, true, true}

Ruby 1.9.2 이상에서는 parameters메서드에 대한 메서드를 사용하여 해당 메서드에 대한 매개 변수 목록을 가져올 수 있습니다. 그러면 매개 변수 이름과 필수 여부를 나타내는 쌍 목록이 반환됩니다.

예 :

만약 당신이

def foo(x, y)
end

그때

method(:foo).parameters # => [[:req, :x], [:req, :y]]

특수 변수 __method__사용 하여 현재 메서드의 이름을 가져올 수 있습니다 . 따라서 메소드 내에서 매개 변수의 이름은 다음을 통해 얻을 수 있습니다.

args = method(__method__).parameters.map { |arg| arg[1].to_s }

그런 다음 다음을 사용하여 각 매개 변수의 이름과 값을 표시 할 수 있습니다.

logger.error "Method failed with " + args.map { |arg| "#{arg} = #{eval arg}" }.join(', ')

참고 : 이 답변은 원래 작성되었으므로 현재 버전의 Ruby eval에서는 더 이상 기호로 호출 할 수 없습니다. 이 문제를 해결하기 위해 to_s매개 변수 이름 목록을 작성할 때 명시 적 ( 예 :parameters.map { |arg| arg[1].to_s }


Ruby 2.1부터 binding.local_variable_get사용 하여 메서드 매개 변수 (인수)를 포함한 모든 지역 변수의 값을 읽을 수 있습니다 . 덕분에 허용되는 답변개선하여 eval.

def foo(x, y)
  method(__method__).parameters.map do |_, name|
    binding.local_variable_get(name)
  end
end

foo(1, 2)  # => 1, 2

이를 처리하는 한 가지 방법은 다음과 같습니다.

def foo(*args)
    first_name, last_name, age, sex, is_plumber = *args
    # some code
    # error happens here
    logger.error "Method has failed, here are all method arguments #{args.inspect}"    
end

이것은 흥미로운 질문입니다. 어쩌면 local_variables를 사용 하고 있습니까? 그러나 eval을 사용하는 것 외에 다른 방법이 있어야합니다. 커널 문서 에서 찾고 있습니다.

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

도움이 될 수 있습니다 ...

  def foo(x, y)
    args(binding)
  end

  def args(callers_binding)
    callers_name = caller[0][/`.*'/][1..-2]
    parameters = method(callers_name).parameters
    parameters.map { |_, arg_name|
      callers_binding.local_variable_get(arg_name)
    }    
  end

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

If you would change the method signature, you can do something like this:

def foo(*args)
  # some code
  # error happens here
  logger.error "Method has failed, here are all method arguments #{args}"    
end

Or:

def foo(opts={})
  # some code
  # error happens here
  logger.error "Method has failed, here are all method arguments #{opts.values}"    
end

In this case, interpolated args or opts.values will be an array, but you can join if on comma. Cheers


It seems like what this question is trying to accomplish could be done with a gem I just released, https://github.com/ericbeland/exception_details. It will list local variables and vlaues (and instance variables) from rescued exceptions. Might be worth a look...


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)

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

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]] 

참고URL : https://stackoverflow.com/questions/9211813/is-there-a-way-to-access-method-arguments-in-ruby

반응형