Commit 07da8f91 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Preserve prepend semantics for Ruby

However we still want to make ClassMethods work!

And we'll need to fix codes using the wrong include/prepend
along the way. There were a lot of misuses.
parent d7f87a2b
...@@ -10,42 +10,29 @@ module Gitlab ...@@ -10,42 +10,29 @@ module Gitlab
end end
end end
module MetaConcern def prepend_features(base)
def extended(base) return false if prepended?(base)
super
base.instance_variable_set(:@_prepend_dependencies, [])
end
end
def self.prepended(base)
super
base.singleton_class.prepend MetaConcern
end
def append_features(base)
super super
prepend_features(base) if const_defined?(:ClassMethods)
end klass_methods = const_get(:ClassMethods)
base.singleton_class.prepend klass_methods
def prepend_features(base) base.instance_variable_set(:@_prepended_class_methods, klass_methods)
if base.instance_variable_defined?(:@_prepend_dependencies) end
base.instance_variable_get(:@_prepend_dependencies) << self
false
else
return false if prepended?(base)
@_prepend_dependencies.each { |dep| base.prepend(dep) } if instance_variable_defined?(:@_prepended_block)
base.class_eval(&@_prepended_block)
end
super true
end
if const_defined?(:ClassMethods) def class_methods
base.singleton_class.prepend const_get(:ClassMethods) super
end
if instance_variable_defined?(:@_prepended_block) if instance_variable_defined?(:@_prepended_class_methods)
base.class_eval(&@_prepended_block) const_get(:ClassMethods).prepend @_prepended_class_methods
end
end end
end end
...@@ -63,8 +50,7 @@ module Gitlab ...@@ -63,8 +50,7 @@ module Gitlab
def prepended?(base) def prepended?(base)
index = base.ancestors.index(base) index = base.ancestors.index(base)
@_prepend_dependencies.index(self) || base.ancestors[0...index].index(self)
base.ancestors[0...index].index(self)
end end
end end
end end
......
...@@ -71,22 +71,41 @@ describe Gitlab::Patch::Prependable do ...@@ -71,22 +71,41 @@ describe Gitlab::Patch::Prependable do
subject subject
expect(prepended_modules).to eq([[subject, ee], [subject, ce]]) expect(prepended_modules).to eq([[ce, ee]])
end
context 'overriding a method' do
before do
subject.module_eval do
def self.class_name
'Custom'
end
def name
'custom'
end
end
end
it 'returns values from the class' do
expect(subject.new.name).to eq('custom')
expect(subject.class_name).to eq('Custom')
end
end end
end end
describe 'a class prepending a concern prepending a concern' do describe 'a class prepending a concern prepending a concern' do
subject { Class.new.prepend(ce) } subject { Class.new.prepend(ce) }
it 'returns values from prepended module ce' do it 'returns values from prepended module ee' do
expect(subject.new.name).to eq('ce') expect(subject.new.name).to eq('ee')
expect(subject.class_name).to eq('CE') expect(subject.class_name).to eq('EE')
end end
it 'prepends only once' do it 'prepends only once' do
subject.prepend(ce) subject.prepend(ce)
expect(prepended_modules).to eq([[subject, ee], [subject, ce]]) expect(prepended_modules).to eq([[ce, ee], [subject, ce]])
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment