Created
September 16, 2020 13:01
-
-
Save denisoster/60f6027c6e8d3176f322c07d240324d8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Memoizable | |
# Allows to define memoized methods with ease. | |
# Usage: | |
# | |
# class SomeService | |
# include Memoizable | |
# | |
# def initialize(customer_id) | |
# @customer_id = customer_id | |
# end | |
# | |
# define_memoizable :customer do | |
# customer.find(customer_id: @customer_id) if @customer_id | |
# end | |
# end | |
# | |
# s = SomeService.new(5) # no sql query | |
# s.customer # one sql query | |
# s.customer # no sql query - memoized value returned | |
# s = SomeService.new(nil) # no sql query | |
# s.customer # no sql query but value is memoized | |
# s.customer # no sql query - memoized value returned | |
# | |
extend ActiveSupport::Concern | |
class_methods do | |
# Creates memoized method which only executes once and return cached value after that. | |
# @param name [Symbol, String] - name of method | |
# @param variable [Symbol, String] - name of instance variable (default `__memoized_#{name}`) | |
# @param apply [Proc] - provide lambda instead of block here if needed | |
# @yield once per instance | |
# @yieldreturn value that will be memoized and returned on next accesses to this method | |
def define_memoizable(name, variable: nil, apply: nil, &block) | |
variable_name = :"@#{variable || "__memoized_#{name.to_s.gsub(/[!?]+/, '__')}"}" | |
apply = block if block_given? | |
raise ArgumentError, 'provide :apply callable object or block' if apply.nil? | |
define_method(name) do | |
return instance_variable_get(variable_name) if instance_variable_defined?(variable_name) | |
instance_variable_set variable_name, instance_exec(&apply) | |
end | |
name.to_sym | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment