shioyama/mobility

View on GitHub
lib/mobility/plugins/cache.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module Mobility
  module Plugins
=begin

Caches values fetched from the backend so subsequent fetches can be performed
more quickly. The cache stores cached values in a simple hash, which is not
optimal for some storage strategies, so some backends (KeyValue, Table) use a
custom module by defining a method, +include_cache+, on the backend class.

The cache is reset when one of a set of events happens (saving, reloading,
etc.). See {BackendResetter} for details.

Values are added to the cache in two ways:

1. first read from backend
2. any write to backend

=end
    module Cache
      extend Plugin

      default true
      requires :backend, include: :before

      # Applies cache plugin to attributes.
      included_hook do |_, backend_class|
        if options[:cache]
          if backend_class.respond_to?(:include_cache)
            backend_class.include_cache
          else
            include_cache(backend_class)
          end
        end
      end

      private

      def include_cache(backend_class)
        backend_class.include BackendMethods
      end

      # Used in ORM cache plugins
      def define_cache_hooks(klass, *reset_methods)
        mod = self
        private_methods = reset_methods & klass.private_instance_methods
        reset_methods.each do |method_name|
          define_method method_name do |*args|
            super(*args).tap do
              mod.names.each { |name| mobility_backends[name].clear_cache }
            end
          end
        end
        klass.class_eval { private(*private_methods) }
      end

      module BackendMethods
        # @group Backend Accessors
        #
        # @!macro backend_reader
        # @!method read(locale, value, options = {})
        #   @option options [Boolean] cache *false* to disable cache.
        def read(locale, **options)
          return super(locale, **options) if options.delete(:cache) == false
          if cache.has_key?(locale)
            cache[locale]
          else
            cache[locale] = super(locale, **options)
          end
        end

        # @!macro backend_writer
        # @option options [Boolean] cache
        #   *false* to disable cache.
        def write(locale, value, **options)
          return super if options.delete(:cache) == false
          cache[locale] = super
        end
        # @!endgroup

        def clear_cache
          @cache = {}
        end

        private

        def cache
          @cache ||= {}
        end
      end
    end

    register_plugin(:cache, Cache)
  end
end