[ruby-on-rails] 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


답변

다음과 같은 상수를 정의 할 수 있습니다.

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

그리고 다음과 같이 코드에서 사용하십시오.

args = eval(ARGS_TO_HASH)
another_method_that_takes_the_same_arguments(**args)


답변

더 나아 가기 전에 foo에 너무 많은 인수를 전달하고 있습니다. 모든 인수가 모델의 속성 인 것 같습니다. 맞습니까? 정말 객체 자체를 전달해야합니다. 연설의 끝.

“splat”인수를 사용할 수 있습니다. 그것은 모든 것을 배열로 밀어 넣습니다. 다음과 같이 표시됩니다.

def foo(*bar)
  ...
  log.error "Error with arguments #{bar.joins(', ')}"
end