2009-05-01 25 views
115

Gdybym zdefiniować funkcje Ruby tak:Ruby opcjonalne parametry

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

Jak mogę nazwać dostarczanie tylko pierwsza i ostatnia 2 args? Dlaczego nie jest możliwe, lub jeśli jest to możliwe, jak można to zrobić?

Odpowiedz

122

Nie jest to obecnie możliwe w przypadku ruby. Nie można przekazać "pustych" atrybutów metodom. Najbliżej można dostać się do przejść nil:

ldap_get(base_dn, filter, nil, X) 

to jednak będzie ustawić zakres do zera, a nie LDAP :: LDAP_SCOPE_SUBTREE.

Co można zrobić, to ustawić wartość domyślną w swoim sposobem:

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

Teraz, jeśli wywołać metodę jak powyżej, zachowanie będzie, jak można się spodziewać.

+21

Nieco się z tym sposobem: np. Jeśli próbujesz ustawić wartość domyślną dla 'scope' true i przekazujesz wartość' false', 'scope || = true' nie będzie działać. To ocenia to samo co 'nil' i ustawi go na' true' –

+4

czy jest to możliwe z aktualną wersją ruby, 3 lata po tej odpowiedzi? – dalloliogm

+1

@JoshPinter, ładne wyjaśnienie. Zasadniczo || = nie jest a = b lub c, wzdrygnąłem się widząc 'xyz || = true'. Mówi się, że jeśli jest zero, zawsze jest prawdą. Jeśli to prawda, to prawda. –

3

Nie można tego zrobić tak, jak zdefiniowałeś ldap_get. Jeśli jednak określić ldap_get takiego:

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

Teraz możesz:

ldap_get(base_dn, filter, X) 

Ale teraz masz problem, że nie można połączyć go z pierwszymi dwoma argumentami i ostatniej arg (the ten sam problem co poprzednio, ale teraz ostatni argument jest inny).

Uzasadnienie jest proste: każdy argument w Ruby nie musi mieć wartości domyślnej, więc nie można go nazwać tak, jak to określiłeś. W twoim przypadku na przykład pierwsze dwa argumenty nie mają wartości domyślnych.

134

Niemal zawsze lepiej jest używać skrótu z opcjami.

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

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

Wspólną strategią jest posiadanie domyślnego skrótu opcji i scalanie wszystkiego, co zostało przekazane: 'options = default_options.merge (options)' –

+4

Odradzam to, ponieważ opcje nie informują o tym, czego oczekuje metoda lub jakie wartości domyślne są –

0

Jest możliwe :) Wystarczy zmienić definicję

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

do

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

zakresie będą teraz w tablicy na pierwszym miejscu. Kiedy podać 3 argumenty, następnie trzeba będzie przypisany base_dn, filtr i attrs i param_array będzie [] Po 4 i więcej argumentów wtedy param_array być [argument1, or_more, and_more]

Minusem jest to, że ... jest niejasnym rozwiązaniem, naprawdę brzydkim. To jest odpowiedź, że możliwe jest anulowanie argumentu w trakcie wywoływania funkcji w rubinie :)

Inną rzeczą, którą musisz zrobić, jest przepisanie domyślnej wartości zakresu.

+3

To rozwiązanie jest całkowicie błędne. Jest to błąd składniowy, aby użyć domyślnego parametru wartości ('attrs = nil') po splat (' * param_array'). –

+3

-1: Erik jest poprawny. Powoduje błąd składni w irb 2.0.0p247. Zgodnie z _ Ruby Programming Language_, w Ruby 1.8 parametr splat musi być ostatni, z wyjątkiem parametru '& ', ale w Rubim 1.9 może być również podany" zwykły parametr ". W żadnym przypadku nie było parametru o domyślnej wartości prawnej po parametrze z ikoną. – andyg0808

+0

Język programowania Ruby strona 186/187 ikona jest w porządku do użycia z metodami. Musi to być ostatni parametr w metodzie, chyba że & jest używany. – rupweb

0

Niedawno znalazłem sposób obejścia tego. Chciałem stworzyć metodę w klasie tablicy z opcjonalnym parametrem, aby zachować lub odrzucić elementy w tablicy.

Sposób, w jaki to symulowałem polegał na przekazaniu tablicy jako parametru, a następnie sprawdzeniu, czy wartość tego indeksu była zerowa, czy nie.

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 

Próbując naszą metodę klasy z różnymi parametrami:

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) 

wyjściowa: ["1", "2", "a", "b", "c"]

Ok, fajnie, że działa zgodnie z planem. Teraz sprawdźmy, co się stanie, jeśli nie przejdziemy do trzeciej opcji parametru (1) w tablicy.

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) 

wyjściowa: ["a", "b", "c"]

Jak widać, trzecia opcja w tablicy zostały usunięte, inicjując inną sekcję w metodzie i wyprowadzenie wszystkich wartości ASCII, które nie są w naszym zasięgu (32 -126)

Alternatywnie, moglibyśmy wystawić wartość jako zero w parametrach. Które wyglądają podobnie do poniższego bloku kodu:

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

1) Nie można przeciążać metody (Why doesn't ruby support method overloading?), więc dlaczego nie napisać nową metodę całkowicie?

2) Rozwiązałem podobny problem używając operatora splat * dla tablicy o zerowej lub większej długości. Następnie, jeśli chcę przekazać parametr (y), mogę to zinterpretować jako tablicę, ale jeśli chcę wywołać metodę bez żadnego parametru, to nie muszę niczego przekazywać. Zobacz Ruby Programming Language stron 186/187

44

czas przeniósł się i od wersji 2 Ruby obsługuje nazwane parametry:

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" 
+0

Możesz również użyć podwójnej splat do zebrania dodatkowych niezdefiniowanych argumentów słów kluczowych. Jest to związane z tym problemem: http://stackoverflow.com/a/35259850/160363 –

0

można zrobić to z częściowym zastosowaniu, chociaż za pomocą nazwanych zmiennych zdecydowanie prowadzi do bardziej czytelny kod. John Resig napisał blogu w 2008 roku o tym, jak to zrobić w 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); 
    }; 
}; 

Prawdopodobnie byłoby możliwe, aby zastosować tę samą zasadę w Ruby (z wyjątkiem prototypal dziedziczenia).

Powiązane problemy