Лучшая идиома Ruby для логики, подобной этой - PullRequest
1 голос
/ 13 февраля 2011

Я выделил две функции здесь. Js_funct - это общий стиль js, а test_funct - моя попытка что-то вроде Ruby-ize

Какие-нибудь лучшие / альтернативные / более чистые / рубиновые способы справиться с этим?

@flipped_on = true

# assume my_funct is expensive
def my_funct
  'success'
end

def test_funct
  res = my_funct if @flipped_on
  res.length if res
end

def js_funct
  if @flipped_on
    res = my_funct
    if res
      return res.length
    end
  end
  return nil
end

p test_funct
p js_funct

РЕДАКТИРОВАТЬ:

Думаю, я мог бы ответить на свой вопрос здесь. Требуется много размышлений, чтобы интерпретировать это.

def test_funct
  res = my_funct and res.length if @flipped_on
end

Ответы [ 3 ]

2 голосов
/ 13 февраля 2011

Вот общая идиома Ruby для однократного выполнения дорогостоящих вычислений и кэширования результата:

def expensive_function
  @expensive_function ||= compute_expensive_function
end

Это приводит к тому, что compute_exорого_function вызывается только один раз, независимо от того, сколько раз вызывается дорогая_функция.1005 * Предостережение: поскольку этот метод основан на коротком замыкании или операторе, он не будет работать правильно для функций, которые возвращают истину / ложь (или истину / ложь).Для этого есть камень обещаний :

def initialize
  @expensive_function = promise {compute_expensive_function}
end

def do_something
  ...
  puts @expensive_function
  ...
end

Камень обещаний более универсален, чем представлен здесь.Кроме того, он поставляется с функцией future, которая кэширует результат как promise, но также выполняет вычисления в отдельном потоке, так что вы можете получить преимущество над дорогой функцией:

def initialize
  @expensive_function = future {compute_expensive_function}
end

def do_something
  ...
  puts @expensive_function
  ...
end
0 голосов
/ 13 февраля 2011

Я не совсем уверен, что должен делать js_funct. res в нем совершенно бесполезно:

def js_funct
  if @flipped_on
    res = my_funct
    if res
      return res.length
    end
  end
  return nil
end

Вы можете просто сказать my_funct.length и получить длину того, что возвращает функция my_funct.

Но, похоже, вас смущает следующее: в Ruby функции (мы называем их методами, поскольку они всегда принадлежат объекту) не являются объектами первого класса. Поэтому вы не можете сказать res = my_funct, надеясь, что вы назначите функцию переменной, как в JavaScript. В Ruby эта строка сначала выполнит метод my_funct и поместит результат в переменную с именем res.

Если вы хотите проверить, определен ли метод, вы можете, например, использовать метод Object#respond_to?.

Если вы хотите обернуть ваш метод в объект для его передачи, вы должны использовать метод Object#method. Но в Ruby более распространено передавать блоки (замыкания), чем целые методы . Вы на самом деле делаете это каждый раз, когда используете map, each или другие распространенные методы Ruby.

Если вы хотите увидеть, как конкретная задача кодируется в Ruby, вы должны сказать, что это за задача. Ваш пример этого не говорит.

0 голосов
/ 13 февраля 2011

Я должен сказать, что ваша версия достаточно чистая и читаемая, за исключением того, что вы можете удалить последнюю строку return nil , поскольку по умолчанию функция ruby ​​возвращает nil, если не указано.

Или вы могли бы также написать одну строку для этого:

def test_funct
  @flipped_on && (res = my_funct) && res.length || nil
end

Если возвращение false не является проблемой, ||nil часть также может быть удалена.

Редактировать: ваша собственная версия лучше: ->

...