Noosfero/noosfero

View on GitHub
plugins/orders/lib/serialized_synced_data.rb

Summary

Maintainability
A
0 mins
Test Coverage
module SerializedSyncedData

  def self.prepare_data _hash
    return {} unless _hash
    hash = {}; _hash.each do |key, value|
      next if value.blank?
      hash[key.to_sym] = value
    end
    hash
  end

  module ClassMethods

    def sync_serialized_field field, &block
      class_attribute :serialized_synced_fields unless self.respond_to? :serialized_synced_fields
      self.serialized_synced_fields ||= []
      self.serialized_synced_fields << field

      field_data = "#{field}_data".to_sym
      field_data_without_sync = "#{field_data}_without_sync".to_sym

      serialize field_data
      before_save "fill_#{field_data}"

      # Rails doesn't define getters/setter for attributes
      if not self.method_defined? field_data and field_data.to_s.in? self.column_names
        define_method field_data do
          self[field_data] || {}
        end
      else
        define_method "#{field_data}_with_sync_default" do
          self.send("#{field_data}_without_sync_default") || {}
        end
        alias_method :field_data_without_sync, :field_data
        alias_method :field_data, :field_data_with_sync
      end
      if not self.method_defined? "#{field_data}=" and field_data.to_s.in? self.column_names
        define_method "#{field_data}=" do |value|
          self[field_data] = SerializedSyncedData.prepare_data value
        end
      else
        define_method "#{field_data}_with_prepare=" do |value|
          self.send "#{field_data}_without_prepare=", SerializedSyncedData.prepare_data(value)
        end
        alias_method ("#{field_data}="_without_prepare).to_sym, :("#{field_data}=").to_sym
        alias_method :("#{field_data}=").to_sym, ("#{field_data}="_with_prepare).to_sym
      end

      # return data from foreign registry if any data was synced yet
      define_method "#{field_data}_with_sync" do
        current_data = self.send field_data_without_sync
        if current_data.present? then current_data else self.send "#{field}_synced_data" end
      end
      alias_method :field_data_without_sync, :field_data
      alias_method :field_data, :field_data_with_sync

      # get the data to sync as defined
      define_method "#{field}_synced_data" do
        source = self.send field
        if block_given?
          data = SerializedSyncedData.prepare_data instance_exec(source, &block)
        elsif source.is_a? ApplicationRecord
          data = SerializedSyncedData.prepare_data source.attributes
        elsif source.is_a? Array
          data = source.map{ |source| SerializedSyncedData.prepare_data source.attributes }
        end || {}
      end

      define_method "sync_#{field_data}" do
        value = self.send "#{field}_synced_data"
        current = self.send field_data
        value = current.deep_merge! value
        self.send "#{field_data}=", value
      end

      define_method "fill_#{field_data}" do
        return if self.send(field_data_without_sync).present?
        self.send "sync_#{field_data}"
      end

      include InstanceMethods
    end

  end

  module InstanceMethods

    def sync_serialized_data
      self.class.serialized_synced_fields.each do |field|
        self.send "sync_#{field}_data"
      end
    end

  end

end