*args w Ruby 1.9

Czy ktoś ma pomysł, jak w Ruby 1.9 zachować semantykę wywołania *args z Ruby 1.8?

Przykład

class A def test=(a, *b) puts a.inspect puts b.inspect end def test1=(a,*b) self.test = a, *b end end
Ruby 1.8

a = A.new a.test1 {"a" => "b"} {"a" => "b"} []
Ruby 1.9

a = A.new a.test1 {"a" => "b"} [{"a" => "b"}] []

Coś jest nie tak z tymi przykładami - wywołujesz test1 jak zwykłą metodę, podczas gdy ma ona w definicji znak “=”.

Po kilku próbach widzę, że różnica tkwi w poniższym zapisie:

print "#{RUBY_VERSION}: " a = 1, *[] puts a.inspect
Wyniki:

1.8.7: 1 1.9.1: [1]
(edit) Idąc o krok dalej:

print "#{RUBY_VERSION}: " a = *[] puts a.inspect
Wyniki:

1.8.7: nil 1.9.1: []
(edit2) Prawdopodobnie jest to związane z tym: http://ruby.about.com/od/newinruby191/qt/MultipleSplats.htm

W skrócie: w Ruby 1.8 można użyć w wyrażeniu jednego operatora “splat”, tj. kod a = *[], *[] nie wykona się na 1.8 (błąd składni), a w 1.9 jest jak najbardziej prawidłowy.

(edit3) Dość ciekawe, bo różnice są widoczne głównie w przypisaniu. Przy wywoływaniu funkcji wygląda, że działa tak samo (przy czym tak jak poprzednio, w 1.8 można użyć gwiazdki tylko raz):

[code=ruby]def f(a)
puts “#{RUBY_VERSION}: #{a.inspect}”
end

f(*[1])[/code]
Wyniki:

1.8.7: 1 1.9.1: 1

Fakt miało być oczywiście:

a.test1 = {"a" => "b"}

Oczywiście wyniki takie, jak pokazana powyżej.

1.9 potyka sie przy splacie jednoelementowych tablic: http://redmine.ruby-lang.org/issues/show/2422

Dokładnie. Wygląda mi to na “bug” w składni Rubiego 1.9. Jak robimy przypisanie

a = b,c

to niejawnie b,c są zamieniane na tablicę. No i ze względu na multiple-splats nie ma możliwości wymuszenia, aby pierwszy argument (przed przecinkiem) był przekazywany jako argument, a nie “zwijany” do tablicy. Dodatkowo w Ruby 1.9 nie mogę zrobić self.test1=(a,*b), bo wywala mi błąd składni (w Ruby 1.8 mogłem).

To jest problem wzięty z Redmine, gdzie jest alias_method_chain dla attributes= Obszedłem to aliasując attributes_wthout…= na attributes_without…, ale jest to brzydki hak.
Widać pomysł z opcjonalnymi argumentami wewnątrz wymaganych jest najgorszym jaki został zaproponowany i wprowadzony do Rubiego 1.9.

Widać Redmine Rubiego nie stoi na Rubim 1.9, bo szybciej by to zauważyli :stuck_out_tongue:

Widać Redmine Rubiego nie stoi na Rubim 1.9, bo szybciej by to zauważyli :P[/quote]
Redmine korzysta z jakichś archaicznych Railsów, które wymuszają użycie archaicznego Rubiego ;-).