Class: LedgerSync::Domains::Serializer::Struct

Inherits:
Object
  • Object
show all
Defined in:
lib/ledger_sync/domains/serializer/struct.rb

Class Method Summary collapse

Class Method Details

.build(hash, serializer_name, resource:, references:) ⇒ Object

This is the most ruby hackery I ever did Defining Record class that inherits from SimpleDelegator is not enough. Adding methods through define_method was adding these methods to all objects created through this main class. Specifically address record has an attribute called address, which returned serialized address. This is a same approach, but with dynamic class definition to avoid defining methods in unrelated classes. We are using SimpleDelegator to delegate these methods into OpenStruct passed in. Pure hackery.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ledger_sync/domains/serializer/struct.rb', line 18

def self.build(hash, serializer_name, resource:, references:) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
  klass = Class.new(SimpleDelegator) do
    def self.with_lazy_references(hash, struct_class:, resource:, references:) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
      define_method('valid?') { resource.valid? }
      define_method('errors') { resource.errors }
      define_method('to_hash') { hash }
      define_method('class_name') { resource.class.name }
      define_method('model_name') { resource.model_name }
      define_method('to_key') { resource.to_key }
      references.each do |args|
        if args.type.instance_of?(LedgerSync::Serialization::Type::SerializerReferencesOneType) # rubocop:disable Layout/LineLength
          define_method("#{args.hash_attribute}_id") do
            resource.send("#{args.hash_attribute}_id")
          end
        end
        define_method(args.hash_attribute) do
          Query.const_get(
            args.type.class.to_s.split('::').last
          ).new.proxy(
            serializer: args.type.serializer.new,
            resource: resource,
            attribute: args.resource_attribute
          )
        end
      end

      new(struct_class.new(hash))
    end

    def to_param
      id.to_s
    end

    def persisted?
      id.present?
    end

    def to_model
      self
    end

    def to_json(*args)
      JSON.generate(to_hash, *args)
    end
  end

  name = serializer_name.split('::')
  class_name = name.pop.gsub(/[^0-9a-z ]/i, '').gsub(/.*\KSerializer/, '')
  struct_name = "#{class_name}Struct"
  module_name = name.empty? ? Object : Object.const_get(name.join('::'))
  begin
    v, $VERBOSE = $VERBOSE, v
    # module_name.remove_const(struct_name) if module_name.const_defined?(struct_name)
    module_name.const_set(struct_name, Class.new(OpenStruct))
  ensure
    $VERBOSE = v
  end
  klass.with_lazy_references(
    hash,
    struct_class: module_name.const_get(struct_name),
    resource: resource, references: references
  )
end