class Remap::Base

@example Select all elements

class Mapper < Remap::Base
  define do
    map [all, :name]
  end
end

Mapper.call([{ name: "John" }, { name: "Jane" }]) # => ["John", "Jane"]

@example Given an option

class Mapper < Remap::Base
  option :name

  define do
    set [:person, :name], to: option(:name)
  end
end

Mapper.call({}, name: "John") # => { person: { name: "John" } }

@example Given a value

class Mapper < Remap::Base
  define do
    set [:api_key], to: value("ABC-123")
  end
end

Mapper.call({}) # => { api_key: "ABC-123" }

@example Maps [“A”, “B”, “C”] to [“A”, “C”]

class IfNotMapper < Remap::Base
  define do
    each do
      map?.if_not do |value|
        value.include?("B")
      end
    end
  end
end

IfNotMapper.call(["A", "B", "C"]) # => ["A", "C"]

@example Maps [“A”, “B”, “C”] to [“B”]

class IfMapper < Remap::Base
  define do
    each do
      map?.if do |value|
        value.include?("B")
      end
    end
  end
end

IfMapper.call(["A", "B", "C"]) # => ["B"]

@example Maps { a: { b: “A” } } to “A”

class EnumMapper < Remap::Base
  define do
    map(:a, :b).enum do
      value "A", "B"
    end
  end
end

EnumMapper.call({ a: { b: "A" } }) # => "A"
EnumMapper.call({ a: { b: "B" } }) # => "B"

@example Map { people: [{ name: “John” }] } to { names: [“John”] }

class PeopleMapper < Remap::Base
  define do
    map :people, to: :names do
      each do
        map :name
      end
    end
  end
end

PeopleMapper.call({ people: [{ name: "John" }] }) # => { names: ["John"] }

@example Map “Hello” to “Hello!”

class HelloMapper < Remap::Base
  define do
    map.adjust do |value|
      "#{value}!"
    end
  end
end

HelloMapper.call("Hello") # => "Hello!"

@example Select the second element from an array

class Mapper < Remap::Base
  define do
    map [at(1)]
  end
end

Mapper.call([1, 2, 3]) # => 2

Public Class Methods

call!(state, &error) click to toggle source

@param state [State]

@yield [Failure]

when a non-critical error occurs

@yieldreturn T

@return [State, T]

when request is a success

@raise [Remap::Error]

when a fatal error occurs

@private

# File lib/remap/base.rb, line 264
def self.call!(state, &error)
  new(state.options).call(state, &error)
end
configuration(&block) click to toggle source

Configuration options for the mapper

@yield [Config] @yieldreturn [void]

@return [void]

# File lib/remap/base.rb, line 274
def self.configuration(&block)
  config = Config.new
  block[config]
  self.config_options = config
end
contract(&context) click to toggle source

Defines a schema for the mapper If the schema fail, the mapper will fail

@example Guard against missing values

class MapperWithAge < Remap::Base
  contract do
    required(:age).filled(:integer)
  end

  define do
    map :age, to: [:person, :age]
  end
end

MapperWithAge.call({age: 50}) # => { person: { age: 50 } }
MapperWithAge.call({age: '10'}) do |failure|
  # ...
end

@see dry-rb.org/gems/dry-schema/1.5/

@return [void]

# File lib/remap/base.rb, line 148
def self.contract(&context)
  self.contract = Dry::Schema.define(&context)
end
define(target = Nothing, method: :new, strategy: :argument, backtrace: caller, &context) click to toggle source

Defines a mapper rules and possible constructor

@param target (Nothing) [#call]

@option method (:new) [Symbol] @option strategy (:argument) [:argument, :keywords, :none]

@example A mapper, which maps a value at [:a] to [:b]

class Mapper < Remap::Base
  define do
    map :a, to: :b
  end
end

Mapper.call({a: 1}) # => { b: 1 }

@example A mapper with an output constructor

class Person < Dry::Struct
  attribute :first_name, Dry::Types['strict.string']
end

class Mapper < Remap::Base
  define(Person) do
    map :name, to: :first_name
  end
end

Mapper.call({name: "John"}).first_name # => "John"

@return [void] rubocop:disable Layout/LineLength

# File lib/remap/base.rb, line 242
def self.define(target = Nothing, method: :new, strategy: :argument, backtrace: caller, &context)
  unless context
    raise ArgumentError, "#{self}.define requires a block"
  end

  self.constructor = Constructor.call(method: method, strategy: strategy, target: target)
  self.context = Compiler.call(backtrace: backtrace, &context)
end
option(field, type: Types::Any) click to toggle source

Defines a required option for the mapper

@example A mapper that takes an argument name

class MapperWithOption < Remap::Base
  option :name

  define do
    set :name, to: option(:name)
  end
end

MapperWithOption.call({}, name: "John") # => { name: "John" }

@param field [Symbol] @option type (Types::Any) [#call]

@return [void]

# File lib/remap/base.rb, line 201
def self.option(field, type: Types::Any)
  attribute(field, type)

  unless (key = schema.keys.find { _1.name == field })
    raise ArgumentError, "[BUG] Could not locate [#{field}] in [#{self}]"
  end

  self.options = options + [-> * { option(field, type: key) }]
end
rule(...) click to toggle source

Defines a rule for the mapper If the rule fail, the mapper will fail

@example Guard against values

class MapperWithRule < Remap::Base
  contract do
    required(:age)
  end

  rule(:age) do
    unless value >= 18
      key.failure("must be at least 18 years old")
    end
  end

  define do
    map :age, to: [:person, :age]
  end
end

MapperWithRule.call({age: 50}) # => { person: { age: 50 } }
MapperWithRule.call({age: 10}) do |failure|
  # ...
end

@see dry-rb.org/gems/dry-validation/1.6/rules/

@return [void]

# File lib/remap/base.rb, line 180
def self.rule(...)
  self.rules = rules + [-> { rule(...) }]
end
validate?() click to toggle source

@see Mapper::API

@private

# File lib/remap/base.rb, line 283
def self.validate?
  config_options.validation
end

Public Instance Methods

call(state, &error) click to toggle source

Mappers state according to the mapper rules

@param state [State]

@yield [Failure] if mapper fails

@return [State]

@private

# File lib/remap/base.rb, line 296
def call(state, &error)
  state._ do |reason|
    raise ArgumentError, "Invalid state due to #{reason.formatted}"
  end

  state.tap do |input|
    validation.call(input, state.options).tap do |result|
      unless result.success?
        return error[state.failure(result.errors.to_h)]
      end
    end
  end

  s1 = catch_ignored(state) do |s0|
    return context.call(s0).then(&constructor).remove_id
  end

  error[s1.failure]
end

Private Instance Methods

validation() click to toggle source

@return [Contract]

# File lib/remap/base.rb, line 319
def validation
  Contract.call(attributes: attributes, contract: contract, options: options, rules: rules)
end