Module: Minitwin::Serialization
- Included in:
- Minitwin
- Defined in:
- lib/minitwin/serialization.rb
Overview
Serialization to Hash/JSON and ActiveModel validation aggregation. Converts nested twins recursively and preserves array items (dropping only nil). When ActiveModel validations are available, nested errors are surfaced on the parent using dot/bracket notation.
Constant Summary collapse
- ALIASES_VAR =
Cache constant references for JIT optimization
Minitwin::DYNAMIC_ALIASES_VAR
- NESTED_PREFIX =
Minitwin::NESTED_READER_PREFIX
Instance Method Summary collapse
-
#attributes ⇒ Object
: () -> Hash[Symbol, untyped].
-
#inspect ⇒ Object
: () -> String.
-
#pretty_print(pretty_printer) ⇒ Object
Internal helper for PrettyPrint.
-
#to_hash(render_nil: false) ⇒ Object
(also: #to_h)
: (render_nil: bool) -> Hash[Symbol, untyped].
-
#to_json ⇒ Object
: (**untyped) -> String.
-
#valid? ⇒ Boolean
: () -> bool.
Instance Method Details
#attributes ⇒ Object
: () -> Hash[Symbol, untyped]
58 59 60 61 62 63 64 |
# File 'lib/minitwin/serialization.rb', line 58 def attributes # Use setter-based attribute names and read via `send` to allow # accessing protected original readers when aliases (`as:`) are used. attribute_methods.each_with_object({}) do |m, h| h[m] = send(m) if respond_to?(m, true) end end |
#inspect ⇒ Object
: () -> String
102 103 104 105 |
# File 'lib/minitwin/serialization.rb', line 102 def inspect attrs = to_hash.map { |k, v| "#{k}: #{v.inspect}" }.join(", ") "#<#{self.class.name} #{attrs}>" end |
#pretty_print(pretty_printer) ⇒ Object
Internal helper for PrettyPrint. Do not call this on your own. : (PP) -> void
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/minitwin/serialization.rb', line 109 def pretty_print(pretty_printer) pretty_printer.object_group(self) do pretty_printer.breakable pretty_printer.seplist( ordered_attributes_for_pp, -> { pretty_printer.text(",") pretty_printer.breakable } ) do |(name, value)| pretty_printer.group do pretty_printer.text name.to_s pretty_printer.text ": " pretty_printer.pp value end end end end |
#to_hash(render_nil: false) ⇒ Object Also known as: to_h
: (render_nil: bool) -> Hash[Symbol, untyped]
15 16 17 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 |
# File 'lib/minitwin/serialization.rb', line 15 def to_hash(render_nil: false) hash = Minitwin.hash_klass.new methods_to_serialize = self.class.send(:serializable_getters) methods_to_serialize.each do |method| value = send(method) next if value.nil? && !render_nil hash[method] = transform_value_for_serialization(value) end # Include dynamic alias keys (defined per instance via `as: -> { ... }`). if instance_variable_defined?(ALIASES_VAR) aliases = instance_variable_get(ALIASES_VAR) if aliases && !aliases.empty? aliases.each do |target_method, alias_method| # Skip nested proxy aliases at the top level; nested groups # serialize under their container key only. next if target_method.is_a?(Symbol) && target_method.to_s.start_with?(NESTED_PREFIX) # Read the value from the original target method to avoid issues if # the alias method is overridden. Apply the same transformation rules # as above for nested twins and arrays. value = send(target_method) next if value.nil? && !render_nil hash[alias_method] = transform_value_for_serialization(value) end end end hash end |
#to_json ⇒ Object
: (**untyped) -> String
53 54 55 |
# File 'lib/minitwin/serialization.rb', line 53 def to_json(**) to_hash(**).to_json end |
#valid? ⇒ Boolean
: () -> bool
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/minitwin/serialization.rb', line 67 def valid? # If ActiveModel validations are available and included, run them and # aggregate nested errors. Otherwise, consider the twin valid. if defined?(ActiveModel::Validations) && self.class.ancestors.include?(ActiveModel::Validations) super self.class.block_properties.each do |property| child = send(property) next unless child.respond_to?(:valid?) child.valid? child.errors.each do |attribute| errors.add("#{property}.#{attribute.attribute}", attribute.) end end self.class.collection_properties.each do |property| send(property).each_with_index do |value, index| next unless value.respond_to?(:valid?) value.valid? value.errors.each do |attribute| errors.add("#{property}[#{index}].#{attribute.attribute}", attribute.) end end end errors.empty? else # When ActiveModel is not available, consider the twin valid by default. true end end |