require 'spec_helper' describe SuperModule do ['V1', 'V2', 'V2Alt' ].each do |version| Object.send(:remove_const, :SupportVersion) rescue nil SupportVersion = Support.const_get(version) Object.send(:remove_const, :FakeActiveRecord) rescue nil class FakeActiveRecord include SupportVersion::FakeActiveModel end Object.send(:remove_const, :FooActiveRecord) rescue nil class FooActiveRecord < FakeActiveRecord include SupportVersion::Foo end Object.send(:remove_const, :BarActiveRecord) rescue nil class BarActiveRecord < FakeActiveRecord include SupportVersion::Bar end Object.send(:remove_const, :BazActiveRecord) rescue nil class BazActiveRecord < FakeActiveRecord include SupportVersion::Baz end context version do context "included by a module (Foo) that is included by a class (FooActiveRecord)" do subject { FooActiveRecord } it 'allows invoking class methods' do expect(subject.validations).to include(['foo', {:presence => true}]) end it 'includes class method declared via "self.method_name"' do expect(subject.foo).to eq('self.foo') end it 'includes class method declared via "self.method_name" taking a single parameter' do expect(subject.foo_single_param('param1_value')).to eq('self.foo(param1_value)') end it 'includes class method declared via "self.method_name" taking multiple parameters' do expect(subject.foo_multi_params('param1_value', 'param2_value', 'param3_value')).to eq('self.foo(param1_value,param2_value,param3_value)') end it 'includes class method declared via "self.method_name" taking a block' do formatter = Proc.new {|value| "Block formatted #{value}"} expect(subject.foo_block(&formatter)).to eq('Block formatted self.foo') end it 'includes class method declared via "self.method_name" taking a single paramter and a block' do formatter = Proc.new {|value, param1| "Block formatted #{value} with #{param1}"} expect(subject.foo_single_param_block('param1_value', &formatter)).to eq('Block formatted self.foo with param1_value') end it 'includes class method declared via "self.method_name" taking multiple paramters and a block' do formatter = Proc.new {|value, param1, param2, param3| "Block formatted #{value} with #{param1},#{param2},#{param3}"} expect(subject.foo_multi_params_block('param1_value', 'param2_value', 'param3_value', &formatter)).to eq('Block formatted self.foo with param1_value,param2_value,param3_value') end it 'includes class method declared via "self.method_name" on one line' do expect(subject.foo_one_line).to eq('self.foo_one_line') end it 'includes class method declared via "class < self"' do expect(subject.foo_class_self).to eq('self.foo_class_self') end it 'includes class method declared via "class < self" using define_method' do expect(subject.foo_class_self_define_method).to eq('self.foo_class_self_define_method') end it 'includes private class method' do expect{subject.foo_private}.to raise_error expect(subject.private_methods.map(&:to_s)).to include('foo_private') expect(subject.send(:foo_private)).to eq('self.foo_private') end it 'includes protected class method (declared using protected :method_name)' do expect{subject.foo_protected}.to raise_error expect(subject.protected_methods.map(&:to_s)).to include('foo_protected') expect(subject.send(:foo_protected)).to eq('self.foo_protected') end it 'includes empty class method' do expect(subject.empty).to eq(nil) end it 'includes empty class method with one empty line' do expect(subject.empty_one_empty_line).to eq(nil) end it 'includes empty class method with comment' do expect(subject.empty_with_comment).to eq(nil) end it 'includes empty class method one line definition' do expect(subject.empty_one_line_definition).to eq(nil) end it 'includes empty class method one line definition with spaces' do expect(subject.empty_one_line_definition_with_spaces).to eq(nil) end it 'includes instance methods' do instance = subject.new expect(instance.foo).to eq('foo') end it 'provides class method self as the including base class as in the class method (meh)' do expect(subject.meh).to eq(subject) end end context "included by a module (Foo) that is included by a second module (Bar) that is included by a class (BarActiveRecord)" do subject { BarActiveRecord } it 'allows invoking class methods' do expect(subject.validations).to include(['foo', {:presence => true}]) expect(subject.validations).to include(['bar', {:presence => true}]) end it 'includes class methods declared via "class << self"' do expect(subject.foo).to eq('self.foo') expect(subject.bar).to eq('self.bar') end it 'includes instance methods' do instance = subject.new expect(instance.foo).to eq('foo') expect(instance.bar).to eq('bar') end it 'can include a basic module (Forwardable) into singleton class by placing in class << self' do instance = subject.new expect(instance.length).to eq(3) end it 'applies super module (Bar) class method invocation (make_barrable) on including class (BarActiveRecord), whereby the method that is defined in the same super module that declares it (Bar)' do expect(subject.barrable).to eq(true) end it 'can include a basic module (Comparable)' do now = Time.now allow(Time).to receive(:now).and_return(now) instance = subject.new allow(Time).to receive(:now).and_return(now + 100) instance2 = subject.new expect(instance2 > instance).to eq(true) end it 'provides class method self as the including base class as in the class method (meh)' do expect(subject.meh).to eq(subject) end end context "(with SuperModule.define alternate syntax in Baz) included by a module (Foo), included by another module (Bar), included by a third module (Baz) that is included by a class (BazActiveRecord)" do subject { BazActiveRecord } it 'allows invoking class methods' do expect(subject.validations).to include(['foo', {:presence => true}]) expect(subject.validations).to include(['bar', {:presence => true}]) expect(subject.validations).to include(['baz', {:presence => true}]) end it 'includes class methods declared via "class << self"' do expect(subject.foo).to eq('self.foo') expect(subject.bar).to eq('self.bar') expect(subject.baz).to eq('self.baz') end it 'includes instance methods' do instance = BazActiveRecord.new(100) expect(instance.foo).to eq('foo') expect(instance.bar).to eq('bar') expect(instance.baz).to eq('baz') end it 'invokes singleton method (make_barrable) from super module' do expect(subject.barrable).to eq(true) end it 'can override super module behavior (<=>)' do instance = subject.new(50) instance2 = subject.new(7) expect(instance2 > instance).to eq(false) end it 'provides class method self as the including base class as in the class method (meh)' do expect(subject.meh).to eq(subject) end end end end end