How to execute a method only once in Ruby? Are there static variables?

I wrote a script that contains several definitions of methods, classes, and some publicly available code. Some of these methods run some fairly time-consuming shell programs. However, these shell programs should only run the first time the method is called.

Now in C, I declare a static variable in each method to make sure that these programs run only once. How can I do this in Ruby?

+4
source share
6 answers

There is an idiom in ruby: x ||= y .

 def something @something ||= calculate_something end private def calculate_something # some long process end 

But there is a problem with this idiom if your "long-running utility" can return a false value (false or nil), since the ||= operator will still evaluate the right side. If you expect false values, use an additional variable similar to that proposed by DigitalRoss:

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

Do not try to save a line of code by setting the @something_calculated variable first and then running calculate_something. If the calculation function throws an exception, your function will always return zero and will never again call the calculation.

In general, Ruby uses instance variables. Please note, however, that they are visible in all methods of this object - they are not local to the method. If you need a variable shared by all instances, define a method in the class object and in each case call self.class.something

 class User def self.something @something ||= calculate_something end def self.calculate_something # .... end def something self.class.something end end 
+8
source

"Memory" may be good. When you memoize a method, it is called no more than once:

 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 # => 
+4
source
 def f system "echo hello" unless @justonce @justonce = true end 

And, hmm, if you want it to run a shell command when called before it fails, you can try:

 def fx @justonce = system x unless @justonce end 
+1
source
 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
source

Unlike other solutions in this thread, this solution does not require you to hold any state:

Get the method to delete after the call or overwrite it with an empty method:

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

OR

 def hello puts "hello" singleton_class.send(:undef_method, __method__) end 
+1
source

Shell commands are satisfied only once - this is a repeating pattern. One of the solutions I wrote makes a checksum on the input files on the command line and only executes it when the shell command has not been executed before. It also runs again when the input files change. Cm

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

Just use it by adding "once" to the shell command. For instance.

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

becomes

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

For PBS, add the -pbs switch.

0
source

All Articles