module BBLib module Serializer def self.included(base) base.extend ClassMethods end module ClassMethods def _serialize_fields @_serialize_fields ||= _ancestor_serialize_fields end def _ancestor_serialize_fields hash = {} ancestors.reverse.map do |ancestor| next unless ancestor.respond_to?(:_serialize_fields) && ancestor != self hash = hash.deep_merge(ancestor._serialize_fields) end hash end def _dont_serialize_fields @_dont_serialize_fields ||= _ancestor_dont_serialize_fields end def _ancestor_dont_serialize_fields ancestors.reverse.flat_map do |ancestor| next unless ancestor.respond_to?(:_dont_serialize_fields) && ancestor != self ancestor._dont_serialize_fields end.compact.uniq end def dont_serialize_method(method) _dont_serialize_fields.push(method) unless _dont_serialize_fields.include?(method) end def serialize_method(name, method = nil, **opts) return false if method == :serialize || name == :serialize && method.nil? _serialize_fields[name.to_sym] = { method: (method || name).to_sym }.merge(opts) end end def serialize(ignore_defaults = false) self.class._serialize_fields.map do |name, opts| next if self.class._dont_serialize_fields.include?(name) args = [opts[:method]] + (opts.include?(:args) ? [opts[:args]].flatten(1) : []) value = send(*args) next if value == self unless opts[:flat] if value.is_a?(Hash) value = value.map { |k, v| [k, v != self && v.respond_to?(:serialize) ? v.serialize(ignore_defaults) : v] }.to_h elsif value.is_a?(Array) value = value.map { |v| v != self && v.respond_to?(:serialize) ? v.serialize(ignore_defaults) : v } elsif value.respond_to?(:serialize) value = value.serialize(ignore_defaults) end end if !opts[:always] && (ignore_defaults && value == opts[:default] || opts.include?(:ignore) && value == opts[:ignore]) nil else [name, value] end end.compact.to_h end end end