Как правильно форматировать длинные составные, если в Coffeescript

Если бы у меня был сложный оператор if, который я не хотел переполнять просто для эстетических целей, каков был бы самый кошерный способ его разбить, поскольку coffeescript интерпретирует возвраты как тело оператора в этом случае?

if (foo is bar.data.stuff and foo isnt bar.data.otherstuff) or (not foo and not bar)
  awesome sauce
else lame sauce

Ответ 1

CoffeeScript не будет интерпретировать следующую строку как тело оператора, если строка заканчивается оператором, поэтому это нормально:

# OK!
if a and
not 
b
  c()

он компилируется в

if (a && !b) {
  c();
}

поэтому ваш if можно отформатировать как

# OK!
if (foo is 
bar.data.stuff and 
foo isnt bar.data.otherstuff) or 
(not foo and not bar)
  awesome sauce
else lame sauce

или любой другой схемы разрыва строки, если строки заканчиваются на and или or или is или == или not, или какой-либо такой оператор

Что касается отступов, вы можете отступать от непервых строк вашего if, пока тело еще больше отступов:

# OK!
if (foo is 
  bar.data.stuff and 
  foo isnt bar.data.otherstuff) or 
  (not foo and not bar)
    awesome sauce
else lame sauce

Что вы не можете сделать, так это:

# BAD
if (foo  #doesn't end on operator!
  is bar.data.stuff and 
  foo isnt bar.data.otherstuff) or 
  (not foo and not bar)
    awesome sauce
else lame sauce

Ответ 2

Это немного изменяет ваш код, но может быть полезным:

return lame sauce unless foo and bar
if foo is bar.data.stuff isnt bar.data.otherstuff
  awesome sauce
else
  lame sauce

Обратите внимание на цепочку is...isnt, которая является законной, так же как a < b < c является законным в CoffeeScript. Конечно, повторение lame sauce является неудачным, и вы можете не хотеть return сразу же. Другим подходом было бы использование soaks для записи

data = bar?.data
if foo and foo is data?.stuff isnt data?.otherstuff
  awesome sauce
else
  lame sauce

if foo and немного неэлегантен; вы можете отбросить его, если нет возможности, чтобы foo был undefined.

Ответ 3

Как и любой другой язык, не имея их в первую очередь. Дайте имена различным частям обрабатывать их отдельно. Либо объявляя предикаты, либо просто создавая пару логических варов.

bar.isBaz = -> @data.stuff != @data.otherstuff
bar.isAwsome = (foo) -> @isBaz() && @data.stuff == foo
if not bar? or bar.isAwesome foo
  awesome sauce
else lame sauce

Ответ 4

Побег над строкой выглядит наиболее читаемым для меня:

if (foo is bar.data.stuff and foo isnt bar.data.otherstuff) \
or (not foo and not bar)
  awesome sauce
else lame sauce

Ответ 5

Когда происходит много низкоуровневого шаблона, вы должны увеличить уровень абстрактного.

Лучшие решения:

  • использовать хорошие именованные переменные и функции

  • логические правила в операторах if/else

Один из логических правил:

(не A, а не B) == not (A или B)

Первый способ. Переменные:

isStuff              = foo is bar.data.stuff
isntOtherStuff       = foo isnt bar.data.otherstuff
isStuffNotOtherStuff = isStuff and isntOtherStuff
bothFalse            = not (foo or bar)
if isStuffNotOtherStuff or bothFalse
  awesome sauce
else lame sauce

Основным недостатком этого метода является его медленность. Мы получим лучшую производительность, если будем использовать функции операторов and и or и заменим переменные на функции:

  • C = A и B

Если A является ложным оператором and не вызывает

  • C = A или B

Если A является истинным оператором or не будет вызывать

Второй способ. Функции:

isStuff              = -> foo is bar.data.stuff
isntOtherStuff       = -> foo isnt bar.data.otherstuff
isStuffNotOtherStuff = -> do isStuff and do isntOtherStuff
bothFalse            = -> not (foo or bar)
if do isStuffNotOtherStuff or do bothFalse
  awesome sauce
else lame sauce