Class: Petra::Proxies::AbstractProxy
- Inherits:
-
Object
- Object
- Petra::Proxies::AbstractProxy
- Defined in:
- lib/petra/proxies/abstract_proxy.rb
Direct Known Subclasses
Class Method Summary collapse
-
.available_class_proxies ⇒ Hash
Determines the available object proxy classes and the ruby classes they can be used for.
-
.available_module_proxies ⇒ Object
Returns only module proxies.
-
.for(object, inherited: false, **options) ⇒ Object
Builds an ObjectProxy for the given object.
-
.inherited_config_for(object, name, *args) ⇒ Object
Retrieves a configuration value with the given name respecting custom configurations made for its class (or class family).
Instance Method Summary collapse
-
#mixin_module_proxies! ⇒ Object
As it might happen that a custom proxy has to be defined for behaviour introduced to different classes as an included module (an example would be Enumerable), it has to be possible to define an equivalent to object proxies for them.
- #object_config(name, *args) ⇒ Object
-
#transaction ⇒ Petra::Components::Transaction
The currently active transaction.
Class Method Details
.available_class_proxies ⇒ Hash
Determines the available object proxy classes and the ruby classes they can be used for. All classes in the Petra::Proxies namespace are automatically recognized as long as they define a CLASS_NAMES constant.
If multiple proxies specify the same class name, the last one by sorting wins.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/petra/proxies/abstract_proxy.rb', line 48 def available_class_proxies @available_class_proxies ||= Petra::Proxies.constants.each_with_object({}) do |c, h| klass = Petra::Proxies.const_get(c) # Skip non-class constants (this includes modules) next unless klass.is_a?(Class) # Skip every class which is not an ObjectProxy. There shouldn't be any # in this namespace, but you never know... next unless klass <= Petra::Proxies::ObjectProxy # Skip proxy classes which do not specify which classes # they were built for next unless klass.const_defined?(:CLASS_NAMES) klass.const_get(:CLASS_NAMES).each { |n| h[n] = "Petra::Proxies::#{c}" } end end |
.available_module_proxies ⇒ Object
Returns only module proxies
69 70 71 72 73 74 75 76 77 78 |
# File 'lib/petra/proxies/abstract_proxy.rb', line 69 def available_module_proxies @available_module_proxies ||= Petra::Proxies.constants.each_with_object({}) do |c, h| klass = Petra::Proxies.const_get(c) next unless klass.is_a?(Module) next unless klass.included_modules.include?(Petra::Proxies::ModuleProxy) next unless klass.const_defined?(:MODULE_NAMES) klass.const_get(:MODULE_NAMES).each { |n| h[n] = "Petra::Proxies::#{c}" } end end |
.for(object, inherited: false, **options) ⇒ Object
Builds an ObjectProxy for the given object. If a more specific proxy class exists for the given object, it will be used instead of the generic Petra::Proxies::ObjectProxy.
If there is no proxy for the exact class of the given object
, its superclasses are automatically tested.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/petra/proxies/abstract_proxy.rb', line 16 def for(object, inherited: false, **) # If the given object is configured not to use a possibly existing # specialized proxy (e.g. the ActiveRecord::Base proxy), we simply # build a default ObjectProxy for it, but we'll still try to extend it using # available ModuleProxies default_proxy = ObjectProxy.new(object, inherited, **) default_proxy.send :mixin_module_proxies! return default_proxy unless inherited_config_for(object, :use_specialized_proxy) # Otherwise, we search for a specialized proxy for the object's class # and its superclasses until we either find one or reach the # default ObjectProxy klass = object.is_a?(Class) ? object : object.class klass = klass.superclass until available_class_proxies.key?(klass.to_s) proxy = available_class_proxies[klass.to_s].constantize.new(object, inherited, **) # If we reached Object, we might still find one or more ModuleProxy module we might # mix into the resulting ObjectProxy. Otherwise, the specialized proxy will most likely # have included the necessary ModuleProxies itself. proxy.send(:mixin_module_proxies!) if proxy.instance_of?(Petra::Proxies::ObjectProxy) proxy end |
.inherited_config_for(object, name, *args) ⇒ Object
Retrieves a configuration value with the given name respecting custom configurations made for its class (or class family)
84 85 86 87 88 89 90 |
# File 'lib/petra/proxies/abstract_proxy.rb', line 84 def inherited_config_for(object, name, *args) # If the proxied object already is a class, we don't use its class (Class) # as there is a high chance nobody will ever use this object proxy on # this level of meta programming klass = object.is_a?(Class) ? object : object.class Petra.configuration.class_configurator(klass).__inherited_value(name, *args) end |
Instance Method Details
#mixin_module_proxies! ⇒ Object
As it might happen that a custom proxy has to be defined for behaviour introduced to different classes as an included module (an example would be Enumerable), it has to be possible to define an equivalent to object proxies for them. This function inspects all modules which were previously included into the proxied object’s singleton class and automatically adds matching module proxies.
Please take a look at Petra::Proxies::EnumerableProxy for an example module proxy
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/petra/proxies/abstract_proxy.rb', line 102 def mixin_module_proxies! # Neither symbols nor fixnums may have singleton classes, see the corresponding Kernel method return if proxied_object.is_a?(Integer) || proxied_object.is_a?(Symbol) # Do not load ModuleProxies if the object's configuration denies it return unless object_config(:mixin_module_proxies) proxied_object.singleton_class.included_modules.each do |mod| proxy_module = Petra::Proxies::ObjectProxy.available_module_proxies[mod.to_s].try(:constantize) # Skip all included modules without ModuleProxies next unless proxy_module singleton_class.class_eval do # Extend the proxy with the module proxy's class methods extend proxy_module.const_get(:ClassMethods) if proxy_module.const_defined?(:ClassMethods) # Include the module proxy's instance methods include proxy_module.const_get(:InstanceMethods) if proxy_module.const_defined?(:InstanceMethods) proxy_module.const_get(:INCLUDES).each { |m| include m } if proxy_module.const_defined?(:INCLUDES) end end end |
#object_config(name, *args) ⇒ Object
137 138 139 |
# File 'lib/petra/proxies/abstract_proxy.rb', line 137 def object_config(name, *args) self.class.inherited_config_for(proxied_object, name, *args) end |
#transaction ⇒ Petra::Components::Transaction
Returns the currently active transaction.
129 130 131 |
# File 'lib/petra/proxies/abstract_proxy.rb', line 129 def transaction Petra.transaction_manager.current_transaction end |