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
@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 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
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
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
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
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
@see Mapper::API
@private
# File lib/remap/base.rb, line 283 def self.validate? config_options.validation end
Public Instance Methods
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
@return [Contract]
# File lib/remap/base.rb, line 319 def validation Contract.call(attributes: attributes, contract: contract, options: options, rules: rules) end