zrób..end vs curly szelki dla bloków w Ruby

Mam współpracownika, który aktywnie próbuje mnie przekonać, że nie powinienem używać do..koniec i zamiast tego użyj nawiasów klamrowych do definiowania bloków wielowierszowych w Ruby.

Jestem mocno w obozie tylko za pomocą kręconych szelek dla krótkich jednolinijek i zrobić..koniec na wszystko inne. Ale pomyślałem, że skontaktuję się z większą społecznością, aby uzyskać jakieś rozwiązanie. Więc co to jest i dlaczego? (Przykład jakiegoś kodu)
context do
  setup { do_some_setup() }
  should "do somthing" do
    # some more code...
  end
end

Lub

context {
  setup { do_some_setup() }
  should("do somthing") {
    # some more code...
  }
}
[[2]} osobiście, po prostu patrząc na powyższe odpowiada na pytanie dla mnie, ale chciałem otworzyć to na większą społeczność.
Author: chollida, 2011-04-08

13 answers

Ogólna Konwencja ma używać do..end for multi-line blocks and curly braces for single line blocks, but there is also a difference between the two that can be illustrated with this example:

puts [1,2,3].map{ |k| k+1 }
2
3
4
=> nil
puts [1,2,3].map do |k| k+1; end
#<Enumerator:0x0000010a06d140>
=> nil

Oznacza to, że {} ma wyższy priorytet niż do..koniec, więc miej to na uwadze przy podejmowaniu decyzji, czego chcesz użyć.

P. S: jeszcze jeden przykład, o którym należy pamiętać podczas rozwijania swoich preferencji.

Następujący kod:

task :rake => pre_rake_task do
  something
end

Naprawdę oznacza:

task(:rake => pre_rake_task){ something }

I ten kod:

task :rake => pre_rake_task {
  something
}

Naprawdę oznacza:

task :rake => (pre_rake_task { something })

Więc aby uzyskać rzeczywistą definicję, którą chcesz, z klamrami kręconymi, musisz zrobić: {]}

task(:rake => pre_rake_task) {
  something
}

Może używanie szelek do parametrów jest czymś, co i tak chcesz zrobić, ale jeśli tego nie robisz, prawdopodobnie najlepiej jest użyć do..Zakończ w tych przypadkach, aby uniknąć tego zamieszania.

 218
Author: Pan Thomakos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 20:57:46

From Programowanie Ruby :

Szelki mają wysoki priorytet; do ma niski priorytet. Jeśli wywołanie metody ma parametry, które nie są zamknięte w nawiasach, nawiasowa forma bloku będzie wiązać się z ostatnim parametrem, a nie z ogólnym wywołaniem. Formularz do wiąże się z wywołaniem.

Więc kod

f param {do_something()}

Wiąże blok ze zmienną param podczas gdy kod

f param do do_something() end

Wiąże blok z funkcją f.

Jednak nie jest to problemem, jeśli w nawiasie umieścisz argumenty funkcji.

 46
Author: David Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 20:43:24

Jest kilka punktów widzenia na ten temat, to naprawdę kwestia osobistych preferencji. Wielu rubyistów przyjmuje takie podejście jak ty. Jednak dwa inne style, które są wspólne, to zawsze używać jednego lub drugiego, lub używać {[0] } dla bloków, które zwracają wartości, i do ... end dla bloków, które są wykonywane dla efektów ubocznych.

 14
Author: GSto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 20:38:51

Jest jedna zasadnicza zaleta nawiasów klamrowych-wiele edytorów ma znacznie łatwiejszy czas dopasowania, co znacznie ułatwia niektóre rodzaje debugowania. Tymczasem słowo kluczowe " do...koniec "jest nieco trudniejszy do dopasowania, zwłaszcza, że "koniec" jest również dopasowany "Jeśli".

 8
Author: GlyphGryph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-09 20:41:17

Głosuję na do / end


Konwencja jest do .. end dla wielowierszowych i { ... } dla jednowierszowych.

Ale ja wolę do .. end, więc jak mam jedną linijkę, to i tak używam do .. end, ale formatuję ją jak zwykle Dla do / end w trzech linijkach. To sprawia, że wszyscy są szczęśliwi.

  10.times do 
    puts ...
  end

Jeden problem z { } polega na tym, że jest to poezja-mode-wrogie (ponieważ wiążą się ściśle z ostatnim parametrem, a nie całym wywołaniem metody, więc musisz dołączyć parens metody) i po prostu, moim zdaniem, nie wyglądaj tak ładnie. Nie są to grupy twierdzeń i zderzają się ze stałymi hash dla czytelności.

Plus, widziałem dość { } w programach C. Sposób Ruby, jak zwykle, jest lepszy. Istnieje dokładnie jeden typ if bloku i nigdy nie musisz wracać i konwertować instrukcji do instrukcji złożonej.

 7
Author: DigitalRoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 23:08:34

Najczęściej spotykaną zasadą jaką widziałem (ostatnio w elokwentny Ruby ) jest:

  • jeśli jest to blok wielowierszowy, użyj do / end
  • jeśli jest to pojedynczy blok liniowy, użyj {}
 6
Author: Peter Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 20:42:31

Kilka wpływowych rubyistów sugeruje, aby używać szelek, gdy używasz zwracanej wartości, i robić / kończyć, gdy tego nie robisz.

Http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace (on archive.org)

Http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc (on archive.org)

Wydaje się to dobrą praktyką w ogóle.

Zmodyfikowałbym nieco tę zasadę, aby powiedzieć, że należy unikać używania do / end na pojedynczej linii, ponieważ jest trudniej czytać.

Musisz być bardziej ostrożny używając szelek, ponieważ będzie to wiązać się z ostatnim param metody zamiast całego wywołania metody. Wystarczy dodać nawiasy, aby tego uniknąć.

 5
Author: Kelvin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-27 21:00:01

Sprowadza się do osobistych uprzedzeń, wolę nawiasy klamrowe niż blok do / end, ponieważ jest bardziej zrozumiały dla większej liczby programistów, ponieważ większość języków tła używa ich w konwencji do / end. Biorąc to pod uwagę, prawdziwym kluczem jest dojść do Porozumienia w Twoim sklepie, jeśli do / end jest używany przez programistów 6/10, niż wszyscy powinni ich używać, jeśli 6/10 używa kręconych szelek, a następnie trzymać się tego paradygmatu.

Its all about making a pattern so that the team as a whole can szybciej identyfikuj struktury kodu.

 1
Author: Jake Kalstad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 20:37:58

Istnieje subtelna różnica między nimi, ale {} wiąże się mocniej niż do/end.

 1
Author: Shankar Raju,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-07 20:38:51

W rzeczywistości jest to osobiste preferencje, ale powiedziawszy to, przez ostatnie 3 lata moich doświadczeń z ruby nauczyłem się, że ruby ma swój styl.

Jednym z przykładów może być , jeśli korzystasz z tła Javy, dla metody boolean możesz użyć

def isExpired
  #some code
end 

Zwróć uwagę na przypadek wielbłąda i najczęściej przedrostek "is", aby zidentyfikować go jako metodę logiczną.

Ale w świecie ruby, ta sama metoda byłaby

def expired?
  #code
end
Więc osobiście uważam, że lepiej wybrać 'ruby way' (Ale wiem, że potrzeba trochę czasu, aby zrozumieć (Zajęło mi to około 1 roku: D)).

W końcu wybrałbym

do 
  #code
end

Bloki.

 1
Author: sameera207,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-10 22:46:47

Umieściłem inną odpowiedź, chociaż duża różnica była już wskazana (prcedence/binding), a to może powodować trudne do znalezienia problemy (blaszany człowiek i inni na to wskazywali). Myślę, że mój przykład pokazuje problem z nie tak zwykłym fragmentem kodu, nawet doświadczeni programiści nie czytają jak sunday times: {]}

module I18n
    extend Module.new {
        old_translate=I18n.method(:translate)
        define_method(:translate) do |*args|
            InplaceTrans.translate(old_translate, *args)
        end
        alias :t :translate
    }
end

module InplaceTrans
    extend Module.new {
        def translate(old_translate, *args)
            Translator.new.translate(old_translate, *args)
        end
    }
end

Potem zrobiłem trochę kodu upiększającego ...

#this code is wrong!
#just made it 'better looking'
module I18n
    extend Module.new do
        old_translate=I18n.method(:translate)
        define_method(:translate) do |*args|
            InplaceTrans.translate(old_translate, *args)
        end
        alias :t :translate
    end
end

Jeśli zmienisz {} tutaj na do/end otrzymasz błąd, ta metoda translate robi nie istnieje ...

Dlaczego tak się dzieje, wskazuje się tutaj więcej niż jeden-pierwszeństwo. Ale gdzie tu umieścić aparat ortodontyczny? @ blaszany: ja zawsze używam aparatów ortodontycznych, tak jak ty, ale tutaj ... nadzorowane)

Więc każda odpowiedź jak

If it's a multi-line block, use do/end
If it's a single line block, use {}

Is just wrong if used without the " BUT Keep an eye on braces / precedence!"

Jeszcze raz:

extend Module.new {} evolves to extend(Module.new {})

I

extend Module.new do/end evolves to extend(Module.new) do/end

(co wynik extend robi z blokiem ...)

Więc jeśli chcesz użyć do / end use this:

#this code is ok!
#just made it 'better looking'?
module I18n
    extend(Module.new do 
        old_translate=I18n.method(:translate)
        define_method(:translate) do |*args|
            InplaceTrans.translate(old_translate, *args)
        end
        alias :t :translate
    end)
end
 1
Author: halfbit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-11 10:40:29

Moim osobistym stylem jest podkreślanie czytelności nad sztywnymi zasadami {...} vs do...end Wybór, gdy taki wybór jest możliwy. Moja idea czytelności jest następująca:

[ 1, 2, 3 ].map { |e| e + 1 }      # preferred
[ 1, 2, 3 ].map do |e| e + 1 end   # acceptable

[ 1, 2, 3 ].each_with_object [] do |e, o| o << e + 1 end # preferred, reads like a sentence
[ 1, 2, 3 ].each_with_object( [] ) { |e, o| o << e + 1 } # parens make it less readable

Foo = Module.new do     # preferred for a multiline block, other things being equal
  include Comparable
end

Foo = Module.new {      # less preferred
  include Comparable
}

Foo = Module.new { include Comparable }      # preferred for a oneliner
Foo = module.new do include Comparable end   # imo less readable for a oneliner

[ [ 1 ], [ 1, 2 ] ].map { |e| e.map do |e| e + 1 end }  # slightly better
[ [ 1 ], [ 1, 2 ] ].map { |e| e.map { |e| e + 1 } }     # slightly worse

W bardziej złożonej składni, takiej jak Wielowierszowe zagnieżdżone bloki, staram się przeplatać {...} i do...end ograniczniki dla większości naturalnych wyników, np.

Foo = Module.new { 
  if true then
    Bar = Module.new {                          # I intersperse {} and keyword delimiters
      def quux
        "quux".tap do |string|                  # I choose not to intersperse here, because
          puts "(#{string.size} characters)"    # for multiline tap, do ... end in this
        end                                     # case still loks more readable to me.
      end
    }
  end
}

Chociaż brak sztywnych reguł może spowodować, że różne opcje dla różnych programistów będą sprytnie różne, uważam, że każdy przypadek optymalizacja pod kątem czytelności, choć subiektywna, to zysk netto nad przestrzeganiem sztywnych zasad.

 1
Author: Boris Stitnicky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-03 14:25:47

Jest trzecia opcja: napisz preprocesor, aby wywnioskować "koniec" na własnej linii, z wcięcia. Głęboko myślący, którzy wolą zwięzły kod, mają rację.

Jeszcze lepiej, hack ruby więc jest to flaga.

Oczywiście najprostszym rozwiązaniem" pick your fights " jest przyjęcie konwencji stylu, zgodnie z którą Sekwencja końców pojawia się w tej samej linii i nauczenie kolorowania składni, aby je wyciszyć. Dla ułatwienia edycji, można użyć skryptów edytora, aby rozwinąć/zwinąć te sekwencje.

20% do 25% moich wierszy kodu ruby kończy się na ich własnej linii, wszystkie trywialnie wywnioskowane przez moje konwencje wcięć. Ruby jest językiem podobnym do Lispu, który osiągnął największy sukces. Kiedy ludzie kwestionują to, pytając, gdzie są wszystkie upiorne nawiasy, pokazuję im funkcję ruby kończącą się na siedmiu liniach zbędnego "końca".

Przez lata robiłem kod używając preprocesora Lispu, aby wywnioskować większość nawiasów: Pasek ' / ' otworzył grupę, która autoklazła się na końcu linia, A znak dolara " $ " służył jako pusty element zastępczy, w którym w przeciwnym razie nie byłoby symboli pomagających wnioskować o grupach. To oczywiście terytorium wojny religijnej. Lisp / scheme bez nawiasów jest najbardziej poetycki ze wszystkich języków. Jednak łatwiej jest po prostu wyciszyć nawiasy za pomocą kolorowania składni.

Nadal koduję z preprocesorem dla Haskell, aby dodać heredocs i domyślnie wszystkie linie spłukiwania jako komentarze, wszystko wcięte jako kod. Nie lubię komentarzy, bez względu na język.

 -1
Author: Syzygies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-29 22:06:08