Skip to content

Commit

Permalink
Add :condition option for .memoize method (#7)
Browse files Browse the repository at this point in the history
Now you can specify a block for instance execute
whether to use memoization or not:

```ruby
def file_mtime
  File.mtime asset_file
end

memoize :file_mtime, condition: -> { environment == 'production' }
```
  • Loading branch information
AlexWayfer authored and tycooon committed Aug 31, 2018
1 parent b9df2f0 commit c64db6c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
10 changes: 6 additions & 4 deletions lib/memery.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ def self.method_visibility(klass, method_name)
end

module ClassMethods
def memoize(method_name)
def memoize(method_name, condition: nil)
prepend_memery_module!
define_memoized_method!(method_name)
define_memoized_method!(method_name, condition: condition)
end

private
Expand All @@ -33,14 +33,16 @@ def prepend_memery_module!
prepend @_memery_module
end

def define_memoized_method!(method_name)
def define_memoized_method!(method_name, condition: nil)
mod_id = @_memery_module.object_id
visibility = Memery.method_visibility(self, method_name)
raise ArgumentError, "Method #{method_name} is not defined on #{self}" unless visibility

@_memery_module.module_eval do
define_method(method_name) do |*args, &block|
return super(*args, &block) if block
if block || (condition && !instance_exec(&condition))
return super(*args, &block)
end

@_memery_memoized_values ||= {}

Expand Down
35 changes: 35 additions & 0 deletions spec/memery_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
class A
include Memery

attr_accessor :environment

memoize def m
m_private
end
Expand All @@ -21,6 +23,13 @@ class A
[x, y]
end

def m_condition
CALLS << __method__
__method__
end

memoize :m_condition, condition: -> { environment == "production" }

protected

memoize def m_protected
Expand Down Expand Up @@ -166,4 +175,30 @@ class << self
expect { klass }.to raise_error(ArgumentError, /Method foo is not defined/)
end
end

describe ":condition option" do
before do
a.environment = environment
end

context "returns true" do
let(:environment) { "production" }

specify do
values = [ a.m_condition, a.m_nil, a.m_condition, a.m_nil ]
expect(values).to eq([:m_condition, nil, :m_condition, nil])
expect(CALLS).to eq([:m_condition, nil])
end
end

context "returns false" do
let(:environment) { "development" }

specify do
values = [ a.m_condition, a.m_nil, a.m_condition, a.m_nil ]
expect(values).to eq([:m_condition, nil, :m_condition, nil])
expect(CALLS).to eq([:m_condition, nil, :m_condition])
end
end
end
end

0 comments on commit c64db6c

Please sign in to comment.