Rubyオプションパラメータ


121

このようなRuby関数を定義すると:

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

最初の2つと最後の引数のみを指定して呼び出すにはどうすればよいですか?なぜそんなものではないのですか

ldap_get( base_dn, filter, , X)

可能ですか、それが可能であれば、どのように行うことができますか?

回答:


131

これはルビーでは現在不可能です。「空」の属性をメソッドに渡すことはできません。あなたが得ることができる最も近いものはnilを渡すことです:

ldap_get(base_dn, filter, nil, X)

ただし、これによりスコープがnilに設定され、LDAP :: LDAP_SCOPE_SUBTREEではありません。

あなたができることはあなたのメソッド内でデフォルト値を設定することです:

def ldap_get(base_dn, filter, scope = nil, attrs = nil)
  scope ||= LDAP::LDAP_SCOPE_SUBTREE
  ... do something ...
end

上記のようにメソッドを呼び出すと、期待どおりの動作になります。


21
このメソッドには少し落とし穴があります。たとえば、scopetrue のデフォルト値を作成しようとしていて、を渡したfalse場合、機能しscope ||= trueません。と同じように評価されnil、次のように設定されますtrue
Joshua Pinter

4
この回答から3年後のルビーの現在のバージョンでそれは可能ですか?
dalloliogm

1
@JoshPinter、いい説明。基本的に|| =はa = bでもcでもありませんxyz||=true。それがnilなら、それは常に本当だと言っています。それが本当なら、それは本当です。
デイモンAw

7
誰もが悪いと言っscope ||= trueているので、これを行うためのより良い方法がであると誰も言っていないことに驚いていscope = LDAP::LDAP_SCOPE_SUBTREE if scope.nil?ます。もちろん、それnilは無効な値であると想定しています。
Erik Sandberg、2013年

1
この古いバージョンへの更新:アンダースコア表記を使用する方法もあります。残念ながら、これはパラメータをに設定するのと同じ効果がありますnil。いくつかは表記を好むことがあります。ldap_get(base_dn, filter, _, X)(注:私は知りません(まだ)これはRubyで導入された際に興味深い。SOスレッドを)。
エリックプラトン2014年

137

ほとんどの場合、オプションハッシュを使用する方がベターです。

def ldap_get(base_dn, filter, options = {})
  options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE
  ...
end

ldap_get(base_dn, filter, :attrs => X)

23
一般的な戦略は、渡されたものは何でもデフォルトのオプションのハッシュとマージを持つことです:options = default_options.merge(options)
ネイサンロング

7
オプションはメソッドが期待するものやデフォルト値が何であるかを教えてくれないので、これはお勧めしません
Bron Davies

53

時間は進んでおり、バージョン2以降、Rubyは名前付きパラメーターをサポートしています。

def ldap_get ( base_dn, filter, scope: "some_scope", attrs: nil )
  p attrs
end

ldap_get("first_arg", "second_arg", attrs: "attr1, attr2") # => "attr1, attr2"

1
二重スプラットを使用して、追加の未定義のキーワード引数を収集することもできます。これはこの問題に関連しています:stackoverflow.com/a/35259850/160363
Henry Tseng

3

定義した方法で行うことはできませんldap_get。ただし、次のように定義した場合ldap_get

def ldap_get ( base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE )

今することができます:

ldap_get( base_dn, filter, X )

しかし、今、最初の2つの引数と最後の引数を使用してそれを呼び出すことができないという問題があります(以前と同じ問題ですが、最後の引数が異なります)。

この理由は単純です。Rubyのすべての引数にデフォルト値を設定する必要はないため、指定した方法で呼び出すことはできません。たとえば、最初の2つの引数にデフォルト値がない場合などです。


1

1)メソッドをオーバーロードすることはできません(Rubyがメソッドのオーバーロードをサポートしないのはなぜですか?)それで、新しいメソッドを完全に記述しないのはなぜですか?

2)長さが0以上の配列に対して、splat演算子*を使用して同様の問題を解決しました。次に、できる限りパラメーターを渡したい場合は、配列として解釈されますが、パラメーターなしでメソッドを呼び出したい場合は、何も渡す必要はありません。Rubyプログラミング言語のページ186/187を参照してください


0

最近、これを回避する方法を見つけました。配列内の要素を保持または破棄するために、オプションのパラメーターを使用して配列クラスにメソッドを作成したかったのです。

これをシミュレートする方法は、パラメーターとして配列を渡し、そのインデックスの値がnilかどうかをチェックすることでした。

class Array
  def ascii_to_text(params)
    param_len = params.length
    if param_len > 3 or param_len < 2 then raise "Invalid number of arguments #{param_len} for 2 || 3." end
    bottom  = params[0]
    top     = params[1]
    keep    = params[2]
    if keep.nil? == false
      if keep == 1
        self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
      else
        raise "Invalid option #{keep} at argument position 3 in #{p params}, must be 1 or nil"
      end
    else
      self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
    end
  end
end

さまざまなパラメーターを使用してクラスメソッドを試してみます。

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126, 1]) # Convert all ASCII values of 32-126 to their chr value otherwise keep it the same (That's what the optional 1 is for)

出力: ["1", "2", "a", "b", "c"]

かしこまりました。計画どおりに機能します。次に、配列の3番目のパラメーターオプション(1)を渡さない場合に何が起こるかを確認してみましょう。

array = [1, 2, 97, 98, 99]
p array.ascii_to_text([32, 126]) # Convert all ASCII values of 32-126 to their chr value else remove it (1 isn't a parameter option)

出力: ["a", "b", "c"]

ご覧のとおり、配列の3番目のオプションが削除されているため、メソッドの別のセクションが開始され、範囲(32〜126)にないすべてのASCII値が削除されます。

あるいは、パラメーターで値をnilとして発行することもできます。次のコードブロックのようになります。

def ascii_to_text(top, bottom, keep = nil)
  if keep.nil?
    self.map{|x| if x >= bottom and x <= top then x = x.chr end}.compact
  else
    self.map{|x| if x >= bottom and x <= top then x = x.chr else x = x.to_s end}
end

-1

可能です:)定義を変更するだけです

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil )

def ldap_get ( base_dn, filter, *param_array, attrs=nil )
scope = param_array.first || LDAP::LDAP_SCOPE_SUBTREE

スコープは最初は配列になりました。3つの引数を指定すると、base_dn、filter、attrsが割り当てられ、param_arrayは[]になります。4つ以上の引数を指定すると、param_arrayは[argument1、or_more、and_more]になります

欠点は...それは不明確な解決策であり、本当に醜いです。これは、ルビの関数呼び出しの途中で引数を省略できることを示しています:)

あなたがしなければならないもう一つは、スコープのデフォルト値を書き換えることです。


4
この解決策は完全に間違っています。attrs=nilスプラット(*param_array)の後にデフォルト値パラメーター()を使用するのは構文エラーです。
Erik Sandberg

3
-1:エリックは正しいです。irb 2.0.0p247で構文エラーが発生します。Rubyプログラミング言語によれば、Ruby 1.8ではsplatパラメータはを除いて最後でなければなりませんでした&parameterが、Ruby 1.9では「通常のパラメータ」が後に続く可能性があります。どちらの場合も、スプラットのあるパラメータの後に、デフォルトが有効なパラメータはありませんでした。
andyg0808 2013

Rubyプログラミング言語ページ186/187スプラットはメソッドで使用するのに適しています。&が使用されない限り、メソッドの最後のパラメーターでなければなりません。
rupweb

AndyGは正しいです。順序は次のようにする必要があります:def ldap_get(base_dn、filter、attrs = nil、* param_array)
rupweb

-1

名前付き変数を使用すると、コードが読みやすくなりますが、部分的なアプリケーションでこれを行うことができます。John Resigが2008年にJavaScriptでそれを行う方法についてブログ記事を書いた:http : //ejohn.org/blog/partial-functions-in-javascript/

Function.prototype.partial = function(){
  var fn = this, args = Array.prototype.slice.call(arguments);
  return function(){
    var arg = 0;
    for ( var i = 0; i < args.length && arg < arguments.length; i++ )
      if ( args[i] === undefined )
        args[i] = arguments[arg++];
    return fn.apply(this, args);
  };
};

Rubyで同じ原則を適用することはおそらく可能です(プロトタイプの継承を除く)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.