2016-01-12 10 views
9
クラスを考えると

ルビの方法でオプションのパラメータのデフォルト値は何ですか?

class MyClass 
    def index(arg1, arg2="hello") 
    end 
end 

それはClass#instance_method、または何かのようないくつかの方法を介して、arg2のデフォルト値を取得することは可能ですか?

+1

なぜ好きではないのですか? – jeffdill2

+1

この質問の会話には、次のようないくつかのオプションがあります。http://stackoverflow.com/questions/622324/getting-argument-names-in-ruby-reflection –

+0

もう1つです:http://stackoverflow.com/questions/2452077 /ルーのメソッド名パラメータ名へ戻る –

答えて

4

私はそのようなユーティリティが利用できない理由は、デフォルト引数の値が割り当てられなければならないときに評価されるということだと思います。したがって、それらを評価しようとすると副次的な影響が生じる可能性があります。


私はあなたにロシア政府の核計画について話教えてみましょう:いくつかの時間前

を、彼らはエラー防止およびメガの両方であるAA解決策を考え出すために超ハードコア、ロシアのハッカーを雇っ利用可能なすべての核を発射するか、単にシミュレーションを実行することができます。彼らはlaunch_all_nukesという1つのメソッドを作成することにしました。これはオプションでキーワード引数simulation_number:を受け入れます。彼らは実装をREPLにロードし、コードを削除して敵のスパイが実際にどのように動作するかを決して知ることができないようにしました。過去数年のための


毎日、信頼できる専門家イワンは、彼が定期的IRBになりそうだ何の前に座っているとロシアの可能性を評価ギガ秘密の場所に移動します連邦は、相互に保証された破壊を生き延びた。

$: launch_all_nukes simulation_number: 1 

...
ちょうど別の正規の日。

$: launch_all_nukes simulation_number: 2 

...

$: launch_all_nukes simulation_number: 3 

...
これらは平均で25分かかるにもかかわらず、それは時々時間のように感じています。画面を見つめ

$: launch_all_nukes simulation_number: 4 
...
。ちょうど別の通常の日。もう...定期的な...日...

$: launch_all_nukes simulation_number: 5 

...
ティック-TOK、TIK-TOK、TIK-TOK ...昼食のためにそこにあるかもしれないか疑問に思いますか?最後に

$: launch_all_nukes simulation_number: 6 

...
! 7は常に最も興味深いものです。唯一消滅しない可能性があるのは、0.03%〜0.08%の確率であることが時々分かります。アイバンは7号の背後に何があるのか​​全く分かりません。他のシミュレーションもそうです。彼はちょうどコマンドを実行し、待っている。しかし、確かに、数字7は、そうでなければ鈍い課題で喜びと興奮の小さな梁をもたらすものです。 Aaaaaaand、go!

$: launch_all_nukes simulation_number: 7 

...
0%。他のすべてのものとして。どのように定期的に。

$: launch_all_nukes simulation_number: 8 

...
は実際に、それを重要ですか?なぜ、ある国が他の国より優れているのだろうか?人生はそれだけで価値がありますか?地球は本質的に貴重なものですか?無限の宇宙に浮かぶ岩のほんの光景...

$: launch_all_nukes simulation_number: 9 

...
何が起こったのか?イワンはかつて偉大な開発者だった。そして今、彼は時々、繰り返しコマンドを実行し、コンソールを凝視...進歩のような感じ何本です...

$: launch_all_nukes simulation_number: 10 

...
は何ですか...ちょっと待ってデフォルト値はsimulation_number:?それは何ですか?確かに実装には__actually_launch_nukes__ if simulation_number.nil?のようなチェックがあります。しかし、それは本当にnilですか?それとも別のことですか? ...

$: launch_all_nukes simulation_number: 11 

...
繰り返しイヤーワームと同様に 、この小さな問題は、それが何であるか... を彼の心を残したことはありませんか? ...引数がないlaunch_all_nukesを実行すると3つの異なるアクセスキーが要求され、そのうちのどれも知っていないことがわかったので、彼は誤って世界を危険にさらすことを恐れなかった。

$: launch_all_nukes simulation_number: 12 


...
イワンは、通常のRubyは前にコンソールでコマンドを実行しています。是非とも、それは単なる普通のイブです...単純なイントロスペクションメソッドを1つ実行しています...彼はそれができないことを知っています...しかし誰も知りませんよね?誰でもこのプログラムは、とにかくどのように動作するか...ああ...

$: launch_all_nukes simulation_number: 13 

...
13と14は最悪です!知りません13時間は通常1時間半かかります。 14はさらに長い。やっぱり、イワンは、少なくとも数分は彼の心を握るためにちょっとした情報を欲しがっています。

$: method(:launch_all_nukes).default_value_for(:simulation_number) 

...
突然の実現が彼を襲ったとして恥ずかしい、イワンは動か凍結しました。彼は今、デフォルト値が何であるか知っています。しかし、それは遅すぎる...ここで


貧乏人の試みです:

argument_name = 'arg2' 

origin_file, definition_line = MyClass.instance_method(:index).source_location 
method_signature = IO.readlines(origin_file)[definition_line.pred] 
eval(method_signature.match(/#{argument_name}\s*[=:]\s*\K[^\s),]*/)[0]) # => "hello" 

明らかに非常にエラーが発生しやすい:

  • は、ネイティブメソッド
  • では動作しません方法では動作しませんREPLsで定義されています
  • 読み取り権限が必要ですes
  • 正規表現では、より複雑なデフォルト値(空白を含む、)または,など)は処理されませんが、これを改善できます。

誰かが純粋に内省的解決策を付属している場合、それで行きます。

4

メソッドの引数の値を検査できるのは、メソッドのbindingにアクセスすることだけです。 Tracepointクラスを使用すると、このようなバインディングオブジェクトを取得し、すべてのoptionalパラメータの値を検査できます。

デフォルトのパラメータにデフォルト値が割り当てられるように、必要なパラメータだけを指定してメソッドを呼び出す必要があります。

これは私の試みです。インスタンスメソッドとクラスメソッドの両方で動作します。インスタンスメソッドを呼び出すには、クラスをインスタンス化する必要があります。コンストラクタにパラメータが必要な場合は、オブジェクトを作成するのが難しくなります。この問題を回避するために、このコードでは、指定されたクラスのサブクラスを動的に作成し、それに対して引数なしのコンストラクタを定義しています。

class MyClass 

    # one arg constructor to make life complex 
    def initialize param 
    end 

    def index(arg1, arg2="hello", arg3 = 1, arg4 = {a:1}, arg5 = [1,2,3]) 
    raise "Hi" # for testing purpose 
    end 

    def self.hi(arg6, arg7="default param") 
    end 
end 

def opt_values(clazz, meth) 
    captured_binding = nil 

    TracePoint.new(:call) do |tp| 
     captured_binding = tp.binding 
    end.enable { 
     # Dummy sub-class so that we can create instances with no-arg constructor 
     obj = Class.new(clazz) do 
      def initialize 
      end 
     end.new 

     # Check if it's a class method 
     meth_obj = clazz.method(meth) rescue nil 

     # If not, may be an instance method. 
     meth_obj = obj.method(meth) rescue nil if not meth_obj 

     if meth_obj 
      params = meth_obj.parameters 
      optional_params = params.collect {|i| i.last if i.first == :opt}.compact 
      dummy_required_params = [""] * (params.size - optional_params.size) 

      # Invoke the method, and handle any errors raise    
      meth_obj.call *dummy_required_params rescue nil 

      # Create a hash for storing optional argument name and its default value 
      optional_params.each_with_object({}) do |i, hash| 
       hash[i] = captured_binding.local_variable_get(i) 
      end 
     end 
    } 
end 

p opt_values MyClass, :index 
#=> {:arg2=>"hello", :arg3=>1, :arg4=>{:a=>1}, :arg5=>[1, 2, 3]} 
p opt_values MyClass, :hi 
#=> {:arg7=>"default param"} 
関連する問題