Skip to content

Commit

Permalink
Add ModuleMethods#included to allow module methods to be memoized
Browse files Browse the repository at this point in the history
  • Loading branch information
dkubb committed Dec 1, 2013
1 parent 4f5d7a5 commit dcca137
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/memoizable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module Memoizable
#
# @api private
def self.included(descendant)
super
descendant.module_eval do
extend ModuleMethods
include InstanceMethods
Expand Down
13 changes: 13 additions & 0 deletions lib/memoizable/module_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ def unmemoized_instance_method(name)

private

# Hook called when module is included
#
# @param [Module] descendant
# the module including ModuleMethods
#
# @return [self]
#
# @api private
def included(descendant)
super
descendant.module_eval { include Memoizable }
end

# Memoize the named method
#
# @param [Symbol] method_name
Expand Down
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
add_filter 'spec'
add_filter 'vendor'

minimum_coverage 89.8
minimum_coverage 90.29
end

require 'memoizable'
Expand Down
40 changes: 40 additions & 0 deletions spec/unit/memoizable/module_methods/included_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# encoding: utf-8

require 'spec_helper'

describe Memoizable::ModuleMethods, '#included' do
subject { descendant.instance_exec(object) { |mod| include mod } }

let(:object) { Module.new.extend(described_class) }
let(:descendant) { Class.new }
let(:superclass) { Module }

before do
# Prevent Module.included from being called through inheritance
Memoizable.stub(:included)
end

around do |example|
# Restore included method after each example
superclass.class_eval do
alias_method :original_included, :included
example.call
undef_method :included
alias_method :included, :original_included
end
end

it 'delegates to the superclass #included method' do
# This is the most succinct approach I could think of to test whether the
# superclass#included method is called. All of the built-in rspec helpers
# did not seem to work for this.
included = false
superclass.class_eval { define_method(:included) { |_| included = true } }
expect { subject }.to change { included }.from(false).to(true)
end

it 'includes Memoizable into the descendant' do
subject
expect(descendant.included_modules).to include(Memoizable)
end
end

0 comments on commit dcca137

Please sign in to comment.