From 1bff320b95eeb5893141d653f00ae66a0ddcfb25 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Fri, 16 Feb 2018 11:29:54 +0100 Subject: [PATCH 1/3] Add InventoryObject interface automatically Add InventoryObject interface automatically, without need to specify it in :inventory_object_attributes --- .../manager_refresh/inventory_object.rb | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/app/models/manager_refresh/inventory_object.rb b/app/models/manager_refresh/inventory_object.rb index ae6bf9bf940..acc7d3273be 100644 --- a/app/models/manager_refresh/inventory_object.rb +++ b/app/models/manager_refresh/inventory_object.rb @@ -151,6 +151,48 @@ def self.add_attributes(inventory_object_attributes) private + def allowed_writers + return [] unless model_class + + # Get all writers of a model + @allowed_writers ||= (model_class.new.methods - Object.methods).grep(/^[\w]+?\=$/) + end + + def allowed_readers + return [] unless model_class + + # Get all readers inferred from writers of a model + @allowed_readers ||= allowed_writers.map { |x| x.to_s.delete("=").to_sym } + end + + def method_missing(method_name, *arguments, &block) + if allowed_writers.include?(method_name) + self.class.define_data_writer(method_name) + public_send(method_name, arguments[0]) + elsif allowed_readers.include?(method_name) + self.class.define_data_reader(method_name) + public_send(method_name) + else + super + end + end + + def respond_to_missing?(method_name, _include_private = false) + allowed_writers.include?(method_name) || allowed_readers.include?(method_name) || super + end + + def self.define_data_writer(data_key) + define_method(data_key) do |value| + public_send(:[]=, data_key.to_s.delete("=").to_sym, value) + end + end + + def self.define_data_reader(data_key) + define_method(data_key) do + public_send(:[], data_key) + end + end + def association?(inventory_collection_scope, key) # Is the key an association on inventory_collection_scope model class? !inventory_collection_scope.association_to_foreign_key_mapping[key].nil? From de032a3346c982700248dccc092169640a796850 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Mon, 26 Feb 2018 16:36:23 +0100 Subject: [PATCH 2/3] Add missing YARD docs for InventoryObject Add missing YARD docs for InventoryObject --- .../manager_refresh/inventory_object.rb | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/app/models/manager_refresh/inventory_object.rb b/app/models/manager_refresh/inventory_object.rb index acc7d3273be..97d962c29cb 100644 --- a/app/models/manager_refresh/inventory_object.rb +++ b/app/models/manager_refresh/inventory_object.rb @@ -6,6 +6,9 @@ class InventoryObject delegate :manager_ref, :base_class_name, :model_class, :to => :inventory_collection delegate :[], :[]=, :to => :data + # @param inventory_collection [ManagerRefresh::InventoryCollection] InventoryCollection object owning the + # InventoryObject + # @param data [Hash] Data of the InventoryObject object def initialize(inventory_collection, data) @inventory_collection = inventory_collection @data = data @@ -14,10 +17,12 @@ def initialize(inventory_collection, data) @reference = inventory_collection.build_reference(data) end + # @return [String] stringified reference def manager_uuid reference.stringified_reference end + # @return [Hash] serialized InventoryObject into Lazy format def to_raw_lazy_relation { :type => "ManagerRefresh::InventoryObjectLazy", @@ -26,10 +31,16 @@ def to_raw_lazy_relation } end + # @return [ManagerRefresh::InventoryObject] returns self def load self end + # Transforms InventoryObject object data into hash format with keys that are column names and resolves correct + # values of the foreign keys (even the polymorphic ones) + # + # @param inventory_collection_scope [ManagerRefresh::InventoryCollection] parent InventoryCollection object + # @return [Hash] Data in DB format def attributes(inventory_collection_scope = nil) # We should explicitly pass a scope, since the inventory_object can be mapped to more InventoryCollections with # different blacklist and whitelist. The generic code always passes a scope. @@ -78,6 +89,12 @@ def attributes(inventory_collection_scope = nil) attributes_for_saving end + # Transforms InventoryObject object data into hash format with keys that are column names and resolves correct + # values of the foreign keys (even the polymorphic ones) + # + # @param inventory_collection_scope [ManagerRefresh::InventoryCollection] parent InventoryCollection object + # @param all_attribute_keys [Array] Attribute keys we will modify based on object's data + # @return [Hash] Data in DB format def attributes_with_keys(inventory_collection_scope = nil, all_attribute_keys = []) # We should explicitly pass a scope, since the inventory_object can be mapped to more InventoryCollections with # different blacklist and whitelist. The generic code always passes a scope. @@ -120,23 +137,33 @@ def attributes_with_keys(inventory_collection_scope = nil, all_attribute_keys = attributes_for_saving end + # Given hash of attributes, we assign them to InventoryObject object using its public writers + # + # @param attributes [Hash] attributes we want to assign + # @return [ManagerRefresh::InventoryObject] self def assign_attributes(attributes) attributes.each { |k, v| public_send("#{k}=", v) } self end + # @return [String] stringified UUID def to_s manager_uuid end + # @return [String] string format for nice logging def inspect "InventoryObject:('#{manager_uuid}', #{inventory_collection})" end + # @return [TrueClass] InventoryObject object is always a dependency def dependency? true end + # Adds setters and getters based on :inventory_object_attributes kwarg passed into InventoryCollection + # + # @param inventory_object_attributes [Array] def self.add_attributes(inventory_object_attributes) inventory_object_attributes.each do |attr| define_method("#{attr}=") do |value| @@ -151,18 +178,20 @@ def self.add_attributes(inventory_object_attributes) private + # @return [Set] all model's writer names def allowed_writers return [] unless model_class # Get all writers of a model - @allowed_writers ||= (model_class.new.methods - Object.methods).grep(/^[\w]+?\=$/) + @allowed_writers ||= (model_class.new.methods - Object.methods).grep(/^[\w]+?\=$/).to_set end + # @return [Set] all model's reader names def allowed_readers return [] unless model_class # Get all readers inferred from writers of a model - @allowed_readers ||= allowed_writers.map { |x| x.to_s.delete("=").to_sym } + @allowed_readers ||= allowed_writers.map { |x| x.to_s.delete("=").to_sym }.to_set end def method_missing(method_name, *arguments, &block) @@ -193,11 +222,22 @@ def self.define_data_reader(data_key) end end + # Return true passed key representing a getter is an association + # + # @param inventory_collection_scope [ManagerRefresh::InventoryCollection] + # @param key [Symbol] key representing getter + # @return [Boolean] true if the passed key points to association def association?(inventory_collection_scope, key) # Is the key an association on inventory_collection_scope model class? !inventory_collection_scope.association_to_foreign_key_mapping[key].nil? end + # Return true if the attribute is allowed to be saved into the DB + # + # @param inventory_collection_scope [ManagerRefresh::InventoryCollection] InventoryCollection object owning the + # attribute + # @param key [Symbol] attribute name + # @return true if the attribute is allowed to be saved into the DB def allowed?(inventory_collection_scope, key) foreign_to_association = inventory_collection_scope.foreign_key_to_association_mapping[key] || inventory_collection_scope.foreign_type_to_association_mapping[key] @@ -213,6 +253,10 @@ def allowed?(inventory_collection_scope, key) true end + # Return true if the object is loadable, which we determine by a list of loadable classes. + # + # @param value [Object] object we test + # @return true if the object is loadable def loadable?(value) value.kind_of?(::ManagerRefresh::InventoryObjectLazy) || value.kind_of?(::ManagerRefresh::InventoryObject) || value.kind_of?(::ManagerRefresh::ApplicationRecordReference) From 68d996c662bc187e745489b5f0d8f98752cc9db4 Mon Sep 17 00:00:00 2001 From: Adam Grare Date: Wed, 18 Apr 2018 14:52:37 +0200 Subject: [PATCH 3/3] Fix private class methods --- app/models/manager_refresh/inventory_object.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/manager_refresh/inventory_object.rb b/app/models/manager_refresh/inventory_object.rb index 97d962c29cb..6d6797ff6fb 100644 --- a/app/models/manager_refresh/inventory_object.rb +++ b/app/models/manager_refresh/inventory_object.rb @@ -215,12 +215,14 @@ def self.define_data_writer(data_key) public_send(:[]=, data_key.to_s.delete("=").to_sym, value) end end + private_class_method :define_data_writer def self.define_data_reader(data_key) define_method(data_key) do public_send(:[], data_key) end end + private_class_method :define_data_reader # Return true passed key representing a getter is an association #