Как выполнить метод только один раз в Ruby? Есть ли статические переменные? - PullRequest
5 голосов
/ 04 ноября 2010

Я написал скрипт, который содержит несколько определений методов, никаких классов и некоторый открытый код. Некоторые из этих методов выполняют некоторые довольно трудоемкие программы оболочки. Однако эти программы оболочки необходимо выполнять только при первом вызове метода.

Теперь в C я бы объявил статическую переменную в каждом методе, чтобы убедиться, что эти программы выполняются только один раз. Как я мог сделать это в Ruby?

Ответы [ 6 ]

10 голосов
/ 04 ноября 2010

В рубине есть идиома: x ||= y.

def something
  @something ||= calculate_something
end

private

def calculate_something
  # some long process
end

Но есть проблема с этой идиомой, если ваша «долго работающая утилита» может возвращать ложное значение (false или nil), так как оператор ||= все равно вызовет оценку правой стороны. Если вы ожидаете ложные значения, тогда используйте дополнительную переменную, способом, аналогичным предложенному DigitalRoss:

def something
  return @something if @something_calculated
  @something = calculate_something
  @something_calculated = true
  return @something
end

Не пытайтесь сохранить строку кода, сначала установив переменную @something_calculated, а затем запустив Calculate_something. Если ваша функция вычисления вызывает исключение, ваша функция всегда будет возвращать ноль и никогда больше не будет вызывать функцию вычисления.

В более общем смысле в Ruby вы используете переменные экземпляра. Обратите внимание, что они видны во всех методах данного объекта - они не являются локальными для метода. Если вам нужна переменная, совместно используемая всеми экземплярами, определите метод в объекте класса, и в каждом экземпляре вызовите self.class.something

class User
  def self.something
    @something ||= calculate_something
  end

  def self.calculate_something
    # ....
  end

  def something
    self.class.something
  end
end
4 голосов
/ 04 ноября 2010

Драгоценный камень "memoize" может быть хорош здесь.Когда вы запоминаете метод, он вызывается не более одного раза:

require 'memoize'

include Memoize

def thing_that_should_happen_once
  puts "foo"
end
memoize :thing_that_should_happen_once

thing_that_should_happen_once    # => foo
thing_that_should_happen_once    # =>
1 голос
/ 06 ноября 2010

В отличие от других решений в этой теме, это решение не требует, чтобы вы удерживали какое-либо состояние:

Получите метод, чтобы удалить себя после вызова или перезаписать себя пустым методом:

def hello
  puts "hello"
  define_singleton_method(:hello) {}
end

ИЛИ:

def hello
  puts "hello"
  singleton_class.send(:undef_method, __method__)
end
1 голос
/ 04 ноября 2010
def my_time_consuming_method
  @result ||= begin
    sleep 5
    true
  end
end

my_time_consuming_method # true after 5 secs
my_time_consuming_method # true directly
1 голос
/ 04 ноября 2010
def f
  system "echo hello" unless @justonce
  @justonce = true
end

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

def f x
  @justonce = system x unless @justonce
end
0 голосов
/ 27 августа 2013

Регулярное выполнение команд оболочки только один раз.Одно решение, которое я написал, создает контрольную сумму для входных файлов в командной строке и выполняет ее только тогда, когда команда оболочки ранее не выполнялась.Он также выполняется снова, когда входные файлы изменились.См.

https://github.com/pjotrp/once-only

Просто используйте его, добавляя «один раз» к команде оболочки.Например,

bowtie -t e_coli reads/e_coli_1000.fq e_coli.map

становится

once-only bowtie -t e_coli reads/e_coli_1000.fq e_coli.map

Для PBS добавьте параметр --pbs.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...