diff --git a/lib/memoizable.rb b/lib/memoizable.rb index 6413b671..d7cb64f4 100644 --- a/lib/memoizable.rb +++ b/lib/memoizable.rb @@ -21,6 +21,7 @@ module Memoizable # # @api private def self.included(descendant) + super descendant.module_eval do extend ModuleMethods include InstanceMethods diff --git a/lib/memoizable/module_methods.rb b/lib/memoizable/module_methods.rb index 0ca2d2be..73decccd 100644 --- a/lib/memoizable/module_methods.rb +++ b/lib/memoizable/module_methods.rb @@ -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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7b13cc39..fc9de46c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,7 +12,7 @@ add_filter 'spec' add_filter 'vendor' - minimum_coverage 89.8 + minimum_coverage 90.29 end require 'memoizable' diff --git a/spec/unit/memoizable/module_methods/included_spec.rb b/spec/unit/memoizable/module_methods/included_spec.rb new file mode 100644 index 00000000..fbe36049 --- /dev/null +++ b/spec/unit/memoizable/module_methods/included_spec.rb @@ -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