Дополнительные параметры 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 (за исключением прототипального наследования).