Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/initializers/0_as_concern.rb22
-rw-r--r--lib/gitlab/patch/prependable.rb71
-rw-r--r--spec/lib/gitlab/patch/prependable_spec.rb121
-rw-r--r--spec/support/helpers/stub_configuration.rb3
4 files changed, 197 insertions, 20 deletions
diff --git a/config/initializers/0_as_concern.rb b/config/initializers/0_as_concern.rb
index 40232bd6252..ff132547225 100644
--- a/config/initializers/0_as_concern.rb
+++ b/config/initializers/0_as_concern.rb
@@ -1,25 +1,7 @@
-# This module is based on: https://gist.github.com/bcardarella/5735987
-
-module Prependable
- def prepend_features(base)
- if base.instance_variable_defined?(:@_dependencies)
- base.instance_variable_get(:@_dependencies) << self
- false
- else
- return false if base < self
-
- super
- base.singleton_class.send(:prepend, const_get('ClassMethods')) if const_defined?(:ClassMethods)
- @_dependencies.each { |dep| base.send(:prepend, dep) } # rubocop:disable Gitlab/ModuleWithInstanceVariables
- base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block) # rubocop:disable Gitlab/ModuleWithInstanceVariables
- end
- end
-end
+# frozen_string_literal: true
module ActiveSupport
module Concern
- prepend Prependable
-
- alias_method :prepended, :included
+ prepend Gitlab::Patch::Prependable
end
end
diff --git a/lib/gitlab/patch/prependable.rb b/lib/gitlab/patch/prependable.rb
new file mode 100644
index 00000000000..45fac0ed4a7
--- /dev/null
+++ b/lib/gitlab/patch/prependable.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+# rubocop:disable Gitlab/ModuleWithInstanceVariables
+module Gitlab
+ module Patch
+ module Prependable
+ class MultiplePrependedBlocks < StandardError
+ def initialize
+ super "Cannot define multiple 'prepended' blocks for a Concern"
+ end
+ end
+
+ module MetaConcern
+ def extended(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
+
+ prepend_features(base)
+ end
+
+ def prepend_features(base)
+ if base.instance_variable_defined?(:@_prepend_dependencies)
+ base.instance_variable_get(:@_prepend_dependencies) << self
+ false
+ else
+ return false if prepended?(base)
+
+ @_prepend_dependencies.each { |dep| base.prepend(dep) }
+
+ super
+
+ if const_defined?(:ClassMethods)
+ base.singleton_class.prepend const_get(:ClassMethods)
+ end
+
+ if instance_variable_defined?(:@_prepended_block)
+ base.class_eval(&@_prepended_block)
+ end
+ end
+ end
+
+ def prepended(base = nil, &block)
+ if base.nil?
+ raise MultiplePrependedBlocks if
+ instance_variable_defined?(:@_prepended_block)
+
+ @_prepended_block = block
+ else
+ super
+ end
+ end
+
+ def prepended?(base)
+ index = base.ancestors.index(base)
+
+ @_prepend_dependencies.index(self) ||
+ base.ancestors[0...index].index(self)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/patch/prependable_spec.rb b/spec/lib/gitlab/patch/prependable_spec.rb
new file mode 100644
index 00000000000..1c90a24c0e8
--- /dev/null
+++ b/spec/lib/gitlab/patch/prependable_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+# Patching ActiveSupport::Concern
+require_relative '../../../../config/initializers/0_as_concern'
+
+describe Gitlab::Patch::Prependable do
+ let(:prepended_modules) { [] }
+
+ let(:ee) do
+ # So that block in Module.new could see them
+ prepended_modules_ = prepended_modules
+
+ Module.new do
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def class_name
+ super.tr('C', 'E')
+ end
+ end
+
+ this = self
+ prepended do
+ prepended_modules_ << this
+ end
+
+ def name
+ super.tr('c', 'e')
+ end
+ end
+ end
+
+ let(:ce) do
+ prepended_modules_ = prepended_modules
+ ee_ = ee
+
+ Module.new do
+ extend ActiveSupport::Concern
+ prepend ee_
+
+ class_methods do
+ def class_name
+ 'CE'
+ end
+ end
+
+ this = self
+ prepended do
+ prepended_modules_ << this
+ end
+
+ def name
+ 'ce'
+ end
+ end
+ end
+
+ describe 'a class including a concern prepending a concern' do
+ subject { Class.new.include(ce) }
+
+ it 'returns values from prepended module ee' do
+ expect(subject.new.name).to eq('ee')
+ expect(subject.class_name).to eq('EE')
+ end
+
+ it 'prepends only once' do
+ ce.prepend(ee)
+ ce.prepend(ee)
+
+ subject
+
+ expect(prepended_modules).to eq([ee, ce])
+ end
+ end
+
+ describe 'a class prepending a concern prepending a concern' do
+ subject { Class.new.prepend(ce) }
+
+ it 'returns values from prepended module ce' do
+ expect(subject.new.name).to eq('ce')
+ expect(subject.class_name).to eq('CE')
+ end
+
+ it 'prepends only once' do
+ subject.prepend(ce)
+
+ expect(prepended_modules).to eq([ee, ce])
+ end
+ end
+
+ describe 'a class prepending a concern' do
+ subject do
+ ee_ = ee
+
+ Class.new do
+ prepend ee_
+
+ def self.class_name
+ 'CE'
+ end
+
+ def name
+ 'ce'
+ end
+ end
+ end
+
+ it 'returns values from prepended module ee' do
+ expect(subject.new.name).to eq('ee')
+ expect(subject.class_name).to eq('EE')
+ end
+
+ it 'prepends only once' do
+ subject.prepend(ee)
+
+ expect(prepended_modules).to eq([ee])
+ end
+ end
+end
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index 8475f91799b..776119564ec 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -1,5 +1,8 @@
require 'active_support/core_ext/hash/transform_values'
require 'active_support/hash_with_indifferent_access'
+require 'active_support/dependencies'
+
+require_dependency 'gitlab'
module StubConfiguration
def stub_application_setting(messages)