Дополнительные параметры Ruby

Если я определяю Ruby-функции следующим образом:

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

Как я могу его назвать, поставляя только первые 2 и последние аргументы? Почему не что-то вроде

ldap_get( base_dn, filter, , X)

возможно или если это возможно, как это можно сделать?

Ответ 1

В рубине это невозможно. Вы не можете передавать "пустые" атрибуты методам. Самое близкое, что вы можете получить, это передать nil:

ldap_get(base_dn, filter, nil, X)

Однако это приведет к тому, что область будет равна нулю, а не LDAP:: LDAP_SCOPE_SUBTREE.

Что вы можете сделать, это установить значение по умолчанию в вашем методе:

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

Теперь, если вы вызываете метод, как указано выше, поведение будет таким, как вы ожидаете.

Ответ 2

Вы почти всегда лучше используете хэш параметров.

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

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

Ответ 3

Время перешло, и с версии 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"

Ответ 4

Это невозможно сделать так, как вы определили ldap_get. Однако, если вы определяете ldap_get следующим образом:

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

Теперь вы можете:

ldap_get( base_dn, filter, X )

Но теперь у вас есть проблема, что вы не можете вызвать ее с помощью первых двух аргументов и последнего arg (та же проблема, что и раньше, но теперь последний аргумент отличается).

Обоснование для этого просто: для каждого аргумента в Ruby не требуется значение по умолчанию, поэтому вы не можете называть его так, как вы указали. В вашем случае, например, первые два аргумента не имеют значений по умолчанию.

Ответ 5

1) Вы не можете перегрузить метод (Почему не перегружает метод поддержки ruby?), так почему бы вообще не написать новый метод?

2) Я решил аналогичную проблему, используя оператор splat * для массива с нулевой или большей длиной. Затем, если я хочу передать параметр (ы), я могу, он интерпретируется как массив, но если я хочу вызвать метод без какого-либо параметра, мне не нужно ничего пропускать. См. Страницы языка программирования Ruby 186/187

Ответ 6

Это возможно:) Просто измените определение

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

to

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]

Даунсайд - это... непонятное решение, действительно уродливое. Это значит, что можно опустить аргумент в середине вызова функции в ruby:)

Еще одна вещь, которую вам нужно сделать, - переписать значение по умолчанию для области видимости.

Ответ 7

Недавно я нашел способ обойти это. Я хотел создать метод в классе массива с необязательным параметром, чтобы сохранить или отбросить элементы в массиве.

То, как я имитировал это, это передать массив в качестве параметра, а затем проверить, было ли значение в этом индексе нулевым или нет.

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 what the optional 1 is for)

вывод: ["1", "2", "a", "b", "c"]

Хорошо, круто, как работает. Теперь давайте проверим и посмотрим, что произойдет, если мы не передадим третий параметр (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"]

Как вы можете видеть, третья опция в массиве была удалена, тем самым инициировав другой раздел в методе и удалив все значения ASCII, которые не находятся в нашем диапазоне (32-126)

В качестве альтернативы мы могли бы указать значение в качестве параметра 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

Ответ 8

Вы можете сделать это с помощью частичного приложения, хотя использование названных переменных определенно приводит к более читаемому коду. Джон Ресиг написал статью в блоге в 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 (за исключением прототипального наследования).