DEV Community

@kon_yu
@kon_yu

Posted on

How to realize caching in Ruby classes

First things first

Let's say you're developing a web app in Rails and you have a method that reads data in a file and returns the necessary values.
If you are called many times, it is expensive to read the data of the file each time, so you want to save it in memory.
There are various methods to write a program in such a case, but I studied a simple way to reuse the value stored in the variable.

I'll try to write code that examines class methods, instance methods, and methods that use class variables and instance variables.

To conclude, when you access through Rails from a browser, it is appropriate to use a class variable and call it with an instance method.

What to do with the sample code

  • Prepare a hash for the variable.
  • method as a key value and the
  • Returns a value if the hash has a value, and
  • If not, use the string "val" as the key of the input value and store it in the hash.
  • In the case of the instance method and the class method, we are trying

Sample code using class variables

class Aaa
  @@hash = {}

  def instance_method(key)
    if @@hash[key]
      P. "Cache was used, sir."
      @@hash[key]
    else
      p "I've stored it."
      @@hash[key] = "val"
    end
  end

  def self.class_method(key)
    if @@hash[key]
      P. "Cache was used, sir."
      @@hash[key]
    else
      @@hash[key] = "val"
      "I have it in place."
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Example of executing an instance method

You can use the cache by instantiating the class

aaa = Aaa.new
=> #<Aaa:0x007ff5e06edba0>
> aaa.instance_method(:bar)
"I have it in place."
=> "val"
> aaa.instance_method(:bar)
"I used the cache, sir."
=> "val"
Enter fullscreen mode Exit fullscreen mode

Example of class method execution

Class methods can also use the cache

> Aaa.class_method(:foo)
=> "I've stored it"
> Aaa.class_method(:foo)
"I used the cache, sir."
=> "val"
Enter fullscreen mode Exit fullscreen mode

Sample code using instance variables

class Bbb
  def initialize
    @hash = {}
  end

  def instance_method(key)
    if @hash[key]
      P. "Cache was used, sir."
      @hash[key]
    else
      p "I've stored it."
      @hash[key] = "val"
    end
  end

  def self.class_method(key)
    if @hash[key]
      P. "Cache was used, sir."
      @hash[key]
    else
      @hash[key] = "val"
      "I have it in place."
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Example of executing an instance method

You can use the cache by instantiating the class

bbb = Bbb.new
=> #<Bbb:0x007ff5e54c6a70 @hash={}>
> bbb.instance_method(:foo)
"I have it in place."
=> "val"
> bbb.instance_method(:foo)
"I used the cache, sir."
=> "val"
Enter fullscreen mode Exit fullscreen mode

Example of class method execution

@hash is not visible because the class method is out of scope. As a matter of fact, it doesn't exist, so it's treated as a nil.

Bbb.class_method(:foo)
NoMethodError: undefined method `[]' for nil:NilClass
Enter fullscreen mode Exit fullscreen mode

It is possible to invoke the cache many times if it is instantiated from the verification results.
However, if it is called from a Rails controller, it must be newly instantiated each time and cannot be cached.
So, if you want to create a cache function with this scheme, you should use classes that use class variables to create a cache function.

Writing sample code with class variables in a more Ruby-like way

Make class_method2 a little more like Ruby
||๏ผ nil guard in

This caching method is used by many gems.
The code I saw the other day was also used in the gem that returns this holiday (https://github.com/holiday-jp/holiday_jp-ruby/blob/master/lib/holiday_jp.rb#L14)

class Ccc
  @@hash = {}
  def self.class_method(key)
    if @@hash[key]
      P. "Cache was used, sir."
      @@hash[key]
    else
      @@hash[key] = "val"
      "I have it in place."
    end
  end

  def self.class_method2(key)
    p @@hash[key] ? "Cache used." : "Stored."
    @@hash[key] ||= "val"
  end
end
Enter fullscreen mode Exit fullscreen mode
Ccc.class_method2(:foo)
"I have it in place."
=> "val"
> Ccc.class_method2(:foo)
"I used the cache, sir."
=> "val"
Enter fullscreen mode Exit fullscreen mode

Class instance variables are not targeted this time because they are complicated.
class variables and class instance variables

Translated with www.DeepL.com/Translator (free version)

Top comments (0)