class ReeMapper::Mapper
def self.build(strategies, type = nil)
def self.build(strategies, type = nil) if type strategies.each do |strategy| method = strategy.method next if type.respond_to?(method) raise ReeMapper::UnsupportedTypeError, "type #{type.name} should implement method `#{method}`" end end klass = Class.new(self) klass.instance_eval do strategies.each do |strategy| method = strategy.method if type class_eval(<<~RUBY, __FILE__, __LINE__ + 1) def #{method}(obj, name: nil, role: nil) @type.#{method}(obj, name: name, role: role) end RUBY else class_eval(<<~RUBY, __FILE__, __LINE__ + 1) def #{method}(obj, name: nil, role: nil) @fields.each_with_object(@#{method}_strategy.build_object) do |(_, field), acc| next unless field.has_role?(role) nested_name = name ? "\#{name}[\#{field.name_as_str}]" : field.name_as_str if @#{method}_strategy.has_value?(obj, field) value = @#{method}_strategy.get_value(obj, field) unless value.nil? && field.null value = field.type.#{method}(value, name: nested_name, role: role) end @#{method}_strategy.assign_value(acc, field, value) elsif field.optional || @#{method}_strategy.always_optional if field.has_default? value = field.default unless value.nil? && field.null value = field.type.#{method}(value, name: nested_name, role: role) end @#{method}_strategy.assign_value(acc, field, value) end else raise ReeMapper::TypeError, "Missing required field `\#{field.from_as_str}` for `\#{name || 'root'}`" end end end RUBY end end end klass.new(strategies, type) end
def add_field(type, name, **opts)
def add_field(type, name, **opts) @fields[name] = ReeMapper::Field.new(type, name, **opts) nil end
def initialize(strategies, type)
def initialize(strategies, type) @fields = {} @type = type @strategies = strategies @strategy_methods = strategies.map(&:method) strategies.each do |strategy| method = strategy.method instance_variable_set(:"@#{method}_strategy", strategy) end end
def name
def name @name end
def name=(name)
def name=(name) @name = name end