Class: Remap::Base

Inherits:
Mapper show all
Extended by:
Mapper::API
Includes:
ActiveSupport::Configurable, Dry::Core::Constants, Dry::Core::Memoizable, Catchable
Defined in:
lib/remap/base.rb

Overview

Examples:

Select all elements

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

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

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" } }

Given a value

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

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

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"]

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"]

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"

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"] }

Map “Hello” to “Hello!”

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

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

Select the second element from an array

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

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

Direct Known Subclasses

State::Dummy

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mapper::API

validate?

Methods included from Catchable

#catch_fatal, #catch_ignored

Methods included from Mapper::Operations

#&, #^, #|

Class Method Details

.call!(state) {|Failure| ... } ⇒ State, T

Returns when request is a success.

Parameters:

Yields:

  • (Failure)

    when a non-critical error occurs

Yield Returns:

  • T

Returns:

  • (State, T)

    when request is a success

Raises:



264
265
266
# File 'lib/remap/base.rb', line 264

def self.call!(state, &error)
  new(state.options).call(state, &error)
end

.configuration {|Config| ... } ⇒ void

This method returns an undefined value.

Configuration options for the mapper

Yields:

Yield Returns:

  • (void)


274
275
276
277
278
# File 'lib/remap/base.rb', line 274

def self.configuration(&block)
  config = Config.new
  block[config]
  self.config_options = config
end

.contract(&context) ⇒ void

This method returns an undefined value.

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

Examples:

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 Also:



148
149
150
# 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) ⇒ void

This method returns an undefined value.

Defines a mapper rules and possible constructor

rubocop:disable Layout/LineLength

Examples:

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 }

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"

Parameters:

  • target (Nothing) (defaults to: Nothing)
    #call
  • method (Hash) (defaults to: :new)

    a customizable set of options

  • strategy (Hash) (defaults to: :argument)

    a customizable set of options

Options Hash (method:):

  • (:new) (Symbol)

Options Hash (strategy:):

  • (:argument) (:argument, :keywords, :none)


242
243
244
245
246
247
248
249
# 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) ⇒ void

This method returns an undefined value.

Defines a required option for the mapper

Examples:

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" }

Parameters:

  • field (Symbol)
  • type (Hash) (defaults to: Types::Any)

    a customizable set of options

Options Hash (type:):

  • (Types::Any) (#call)


201
202
203
204
205
206
207
208
209
# 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

.rulevoid

This method returns an undefined value.

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

Examples:

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 Also:



180
181
182
# File 'lib/remap/base.rb', line 180

def self.rule(...)
  self.rules = rules + [-> { rule(...) }]
end

.validate?Boolean

Returns:

  • (Boolean)

See Also:



283
284
285
# File 'lib/remap/base.rb', line 283

def self.validate?
  config_options.validation
end

Instance Method Details

#call(state) {|Failure| ... } ⇒ State

Mappers state according to the mapper rules

Parameters:

Yields:

Returns:



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# 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