1313# To make a feature conditionally supported, pass a block to the +supports+ method.
1414# The block is evaluated in the context of the instance.
1515# If a feature is not supported, return a string for the reason. A nil means it is supported
16- # Alternatively, calling the private method +unsupported_reason_add+ with the feature
17- # and a reason, marks the feature as unsupported, and the reason will be
18- # accessible through
16+ # The reason will be accessible through
1917#
2018# instance.unsupported_reason(:feature)
2119#
@@ -50,9 +48,7 @@ module SupportsFeatureMixin
5048 # Whenever this mixin is included we define all features as unsupported by default.
5149 # This way we can query for every feature
5250 included do
53- private_class_method :unsupported
54- private_class_method :unsupported_reason_add
55- class_attribute :supports_features , :instance_writer => false , :default => { }
51+ class_attribute :supports_features , :instance_writer => false , :instance_reader => false , :default => { }
5652 end
5753
5854 def self . default_supports_reason
@@ -61,29 +57,16 @@ def self.default_supports_reason
6157
6258 # query instance for the reason why the feature is unsupported
6359 def unsupported_reason ( feature )
64- feature = feature . to_sym
65- supports? ( feature ) unless unsupported . key? ( feature )
66- unsupported [ feature ]
60+ self . class . unsupported_reason ( feature , :instance => self )
6761 end
6862
6963 # query the instance if the feature is supported or not
7064 def supports? ( feature )
71- self . class . check_supports ( feature . to_sym , :instance => self )
65+ ! unsupported_reason ( feature )
7266 end
7367
7468 private
7569
76- # used inside a +supports+ block to add a reason why the feature is not supported
77- # just adding a reason will make the feature unsupported
78- def unsupported_reason_add ( feature , reason )
79- feature = feature . to_sym
80- unsupported [ feature ] = reason
81- end
82-
83- def unsupported
84- @unsupported ||= { }
85- end
86-
8770 class_methods do
8871 # This is the DSL used a class level to define what is supported
8972 def supports ( feature , &block )
@@ -96,34 +79,26 @@ def supports_not(feature, reason: nil)
9679 self . supports_features = supports_features . merge ( feature . to_sym => reason . presence || false )
9780 end
9881
99- # query the class if the feature is supported or not
10082 def supports? ( feature )
101- check_supports ( feature . to_sym , :instance => self )
83+ ! unsupported_reason ( feature )
10284 end
10385
104- def check_supports ( feature , instance :)
105- instance . send ( :unsupported ) . delete ( feature )
106-
86+ # query the class if the feature is supported or not
87+ def unsupported_reason ( feature , instance : self )
10788 # undeclared features are not supported
10889 value = supports_features [ feature . to_sym ]
109-
11090 if value . respond_to? ( :call )
11191 begin
11292 # for class level supports, blocks are not evaluated and assumed to be true
11393 result = instance . instance_eval ( &value ) unless instance . kind_of? ( Class )
114- # if no errors yet but result was an error message
115- # then add the error
116- if !instance . send ( :unsupported ) . key? ( feature ) && result . kind_of? ( String )
117- instance . send ( :unsupported_reason_add , feature , result )
118- end
94+ result if result . kind_of? ( String )
11995 rescue => e
12096 _log . log_backtrace ( e )
121- instance . send ( :unsupported_reason_add , feature , "Internal Error: #{ e . message } " )
97+ "Internal Error: #{ e . message } "
12298 end
12399 elsif value != true
124- instance . send ( :unsupported_reason_add , feature , value || SupportsFeatureMixin . default_supports_reason )
100+ value || SupportsFeatureMixin . default_supports_reason
125101 end
126- !instance . send ( :unsupported ) . key? ( feature )
127102 end
128103
129104 # all subclasses that are considered for supporting features
@@ -158,23 +133,5 @@ def supporting(feature)
158133 def providers_supporting ( feature )
159134 ExtManagementSystem . where ( :type => provider_classes_supporting ( feature ) . map ( &:name ) )
160135 end
161-
162- # query the class for the reason why something is unsupported
163- def unsupported_reason ( feature )
164- feature = feature . to_sym
165- supports? ( feature ) unless unsupported . key? ( feature )
166- unsupported [ feature ]
167- end
168-
169- def unsupported
170- # This is a class variable and it might be modified during runtime
171- # because we do not eager load all classes at boot time, so it needs to be thread safe
172- @unsupported ||= Concurrent ::Hash . new
173- end
174-
175- # use this for making a class not support a feature
176- def unsupported_reason_add ( feature , reason )
177- unsupported [ feature . to_sym ] = reason
178- end
179136 end
180137end
0 commit comments