Skip to content

Commit

Permalink
Merge pull request #22898 from kbrock/supports_unsupports
Browse files Browse the repository at this point in the history
Drop Supports' unsupports variable
  • Loading branch information
Fryguy authored Aug 22, 2024
2 parents a04c02d + ce9c449 commit 3f7c1b7
Showing 1 changed file with 10 additions and 53 deletions.
63 changes: 10 additions & 53 deletions app/models/mixins/supports_feature_mixin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
# To make a feature conditionally supported, pass a block to the +supports+ method.
# The block is evaluated in the context of the instance.
# If a feature is not supported, return a string for the reason. A nil means it is supported
# Alternatively, calling the private method +unsupported_reason_add+ with the feature
# and a reason, marks the feature as unsupported, and the reason will be
# accessible through
# The reason will be accessible through
#
# instance.unsupported_reason(:feature)
#
Expand Down Expand Up @@ -50,9 +48,7 @@ module SupportsFeatureMixin
# Whenever this mixin is included we define all features as unsupported by default.
# This way we can query for every feature
included do
private_class_method :unsupported
private_class_method :unsupported_reason_add
class_attribute :supports_features, :instance_writer => false, :default => {}
class_attribute :supports_features, :instance_writer => false, :instance_reader => false, :default => {}
end

def self.default_supports_reason
Expand All @@ -61,29 +57,16 @@ def self.default_supports_reason

# query instance for the reason why the feature is unsupported
def unsupported_reason(feature)
feature = feature.to_sym
supports?(feature) unless unsupported.key?(feature)
unsupported[feature]
self.class.unsupported_reason(feature, :instance => self)
end

# query the instance if the feature is supported or not
def supports?(feature)
self.class.check_supports(feature.to_sym, :instance => self)
!unsupported_reason(feature)
end

private

# used inside a +supports+ block to add a reason why the feature is not supported
# just adding a reason will make the feature unsupported
def unsupported_reason_add(feature, reason)
feature = feature.to_sym
unsupported[feature] = reason
end

def unsupported
@unsupported ||= {}
end

class_methods do
# This is the DSL used a class level to define what is supported
def supports(feature, &block)
Expand All @@ -96,34 +79,26 @@ def supports_not(feature, reason: nil)
self.supports_features = supports_features.merge(feature.to_sym => reason.presence || false)
end

# query the class if the feature is supported or not
def supports?(feature)
check_supports(feature.to_sym, :instance => self)
!unsupported_reason(feature)
end

def check_supports(feature, instance:)
instance.send(:unsupported).delete(feature)

# query the class if the feature is supported or not
def unsupported_reason(feature, instance: self)
# undeclared features are not supported
value = supports_features[feature.to_sym]

if value.respond_to?(:call)
begin
# for class level supports, blocks are not evaluated and assumed to be true
result = instance.instance_eval(&value) unless instance.kind_of?(Class)
# if no errors yet but result was an error message
# then add the error
if !instance.send(:unsupported).key?(feature) && result.kind_of?(String)
instance.send(:unsupported_reason_add, feature, result)
end
result if result.kind_of?(String)
rescue => e
_log.log_backtrace(e)
instance.send(:unsupported_reason_add, feature, "Internal Error: #{e.message}")
"Internal Error: #{e.message}"
end
elsif value != true
instance.send(:unsupported_reason_add, feature, value || SupportsFeatureMixin.default_supports_reason)
value || SupportsFeatureMixin.default_supports_reason
end
!instance.send(:unsupported).key?(feature)
end

# all subclasses that are considered for supporting features
Expand Down Expand Up @@ -158,23 +133,5 @@ def supporting(feature)
def providers_supporting(feature)
ExtManagementSystem.where(:type => provider_classes_supporting(feature).map(&:name))
end

# query the class for the reason why something is unsupported
def unsupported_reason(feature)
feature = feature.to_sym
supports?(feature) unless unsupported.key?(feature)
unsupported[feature]
end

def unsupported
# This is a class variable and it might be modified during runtime
# because we do not eager load all classes at boot time, so it needs to be thread safe
@unsupported ||= Concurrent::Hash.new
end

# use this for making a class not support a feature
def unsupported_reason_add(feature, reason)
unsupported[feature.to_sym] = reason
end
end
end

0 comments on commit 3f7c1b7

Please sign in to comment.