2013-07-02 17 views
6

Biorąc pod uwagę niektóre local variables, jaki byłby najprostszy sposób, aby je compact w Ruby?Co to jest odpowiednik języka PHP w języku Ruby?

def foo 
    name = 'David' 
    age = 25 
    role = :director 
    ... 
    # How would you build this: 
    # { :name => 'David', :age => 25, :role => :director } 
    # or 
    # { 'name' => 'David', 'age' => 25, 'role' => :director } 
end 

W PHP, I może po prostu to zrobić:

$foo = compact('name', 'age', 'role'); 
+2

http://stackoverflow.com/questions/6589894/access-local-variables- from-a-different-inding-in-ruby –

+3

Jestem szczerze zaskoczony, że PHP pozwala na takie aberry ..., mmm, nieortodoksyjny kod . Czy 'compact' rzeczywiście pobiera zmienne lokalne według nazw i uzyskuje dostęp do nich z poziomu innej funkcji? – tokland

Odpowiedz

9

wymyśliłem znaczącej poprawy na moim oryginalnym odpowiedź. Jest czystszy, jeśli dziedziczysz sam od Binding. The to_sym jest tam, ponieważ starsze wersje ruby ​​mają local_variables jako łańcuchy.

metoda instancji

class Binding 
    def compact(*args) 
    compacted = {} 
    locals = eval("local_variables").map(&:to_sym) 
    args.each do |arg| 
     if locals.include? arg.to_sym 
     compacted[arg.to_sym] = eval(arg.to_s) 
     end 
    end 
    return compacted 
    end 
end 

Wykorzystanie

foo = "bar" 
bar = "foo" 
binding.compact("foo") # => {:foo=>"bar"} 
binding.compact(:bar) # => {:bar=>"foo"} 

Original odpowiedź

To nea Reszta mogłem dostać się do metody, która zachowuje się jak compact PHP -

metody

def compact(*args, &prok) 
    compacted = {} 
    args.each do |arg| 
    if prok.binding.send(:eval, "local_variables").include? arg 
     compacted[arg.to_sym] = prok.binding.send(:eval, arg) 
    end 
    end 
    return compacted 
end 

Przykład użycia

foo = "bar" 
compact("foo"){} 
# or 
compact("foo", &proc{}) 

Nie jest doskonały, choć, bo trzeba przejść proc w. Jestem otwarty na sugestie, jak to poprawić.

+1

Wygląda na to, że możesz umieścić 'eval' poza pętlą, nie? –

+0

@SergioTulentsev dzięki za to. – Bungus

1

Jest to wariant odpowiedzi Bungus', ale tu jest jeden-liner, że jest zdecydowanie brzydsze, ale nie obejmuje oprawy lub cokolwiek:

foo = :bar 
baz = :bin 
hash = [:foo, :baz].inject({}) {|h, v| h[v] = eval(v.to_s); h } 
# hash => {:baz=>:bin, :foo=>:bar} 

Można również sprawić wrażenie kinda-coś w stylu wywołanie metody nadużywając blok wiążący - kolejny wariant na pierwotną odpowiedź Bungus': (. ja po prostu mówię sobie, że {[..]} jest symbolem Zgniatarka śmieci)

module Kernel 
    def compact(&block) 
    args = block.call.map &:to_sym 
    lvars = block.binding.send(:eval, "local_variables").map &:to_sym 
    (args & lvars).inject({}) do |h, v| 
     h[v] = block.binding.send(:eval, v.to_s); h 
    end 
    end 
end 

foo = :bar 
baz = :bin 
compact {[ :foo, :bar, :baz ]} 
# {:foo=>:bar, :baz=>:bin} 

Jeśli używasz binding_of_caller gem, można zrezygnować z proc i wyraźne wiązanie wszystko razem:

require 'binding_of_caller' 
module Kernel 
    def compact(*args) 
    lvars = binding.of_caller(1).send(:eval, "local_variables").map &:to_sym 
    (args.map(&:to_sym) & lvars).inject({}) do |h, v| 
     h[v] = binding.of_caller(2).send(:eval, v.to_s); h 
    end 
    end 
end 

foo = :bar 
baz = :bin 
compact :foo, :bar, :baz 
# {:foo=>:bar, :baz=>:bin} 

Uważajcie, to powoli. W kodzie produkcyjnym prawdopodobnie nigdy nie powinieneś próbować tego robić, a zamiast tego po prostu zachować wartość hash, więc programista, który musi to utrzymywać, nie będzie cię ścigał i zabije cię we śnie.

Powiązane problemy