Podczas OP już zaakceptowane odpowiedź korzystając instance_eval(string)
, Gorąco zachęcam OP aby uniknąć formy ciągów o eval
chyba że jest to absolutnie konieczne. Eval wywołuje kompilator ruby - jest on drogi w obliczeniach i niebezpieczny w użyciu, ponieważ otwiera wektor do ataków z użyciem kodu.
Jak stwierdził że nie ma potrzeby wysyłania w ogóle:
obj.foo.bar
Jeśli rzeczywiście nazwy foo i bar pochodzą z jakiegoś non-obliczeniach statycznych, a następnie
obj.send(foo_method).send(bar_method)
jest proste i wszystko trzeba na to.
Jeżeli metody idą w postaci przerywanej ciąg, można użyć rozłamu i wstrzyknąć do łańcucha metody:
'foo.bar'.split('.').inject(obj, :send)
wyjaśnieniu w odpowiedzi na komentarze: eval ciąg jest jednym z najbardziej ryzykownych jednej rzeczy może zrobić z perspektywy bezpieczeństwa. Jeśli istnieje jakikolwiek sposób, w jaki łańcuch jest zbudowany z danych wprowadzonych przez użytkownika bez niewiarygodnie dokładnej kontroli i sprawdzania poprawności tego wejścia, powinieneś po prostu wziąć pod uwagę swój system.
send (metoda), w której metoda jest uzyskiwana z danych wprowadzanych przez użytkownika, również jest zagrożona, ale istnieje bardziej ograniczony wektor ataku. Wprowadzane przez użytkownika dane mogą spowodować wykonanie dowolnej metody 0-arghument, którą można wysłać za pośrednictwem odbiornika. Dobra praktyka tutaj byłoby zawsze białej listy metod przed wysłaniem:
VALID_USER_METHODS = %w{foo bar baz}
def safe_send(method)
raise ArgumentError, "#{method} not allowed" unless VALID_USER_METHODS.include?(method.to_s)
send(method)
end
'obj.send ('foo'). Send ('bar')' –
@SergioTulentsev - Przepraszam, powinienem był wyjaśnić - czy istnieje sposób zrób to w jednym kroku. To, co opisujesz, wymagałoby przeanalizowania napisu "foo.bar", aby zdać sobie sprawę, że musisz wywoływać rekurencyjnie send(). Właśnie zastanawiałem się, czy istnieje jakiś mechanizm, który robi to automatycznie lub bardziej czysto. – Lynn
@Lynn: Nie jestem świadomy takiego wbudowanego mechanizmu. –