Home

Awesome

WARNING

This repository/lib is unlikely to receive any issues / bugfixes. The ducktrap idea had grown into morpher.

With the first release of morpher, ducktrap will be unmaintained.

ducktrap

Build Status Dependency Status Code Climate

Ducktrap is a spike for a data transformation algebra. The main idea is to define the transformations with composable blocks that allow to generate an inverse transformation.

It can be used at various places:

Installation

There is no gem release.

Examples

For slightly more details, have a look at this gist for now.

A simple real world scenario would probably look something like this:

require 'anima'
require 'ducktrap'

class Address
  include Anima.new(:id, :city, :zip)

  TRAP = Ducktrap.build do
    primitive(Hash)
    hash_transform do
      fetch_key(:id) do
        primitive(Integer)
        dump_key(:id)
      end

      fetch_key(:city) do
        primitive(String)
        dump_key(:city)
      end

      fetch_key(:zip) do
        primitive(Integer)
        dump_key(:zip)
      end
    end
    anima_load(Address)
  end
end

class Task
  include Anima.new(:id, :name)

  TRAP = Ducktrap.build do
    primitive(Hash)
    hash_transform do
      fetch_key(:id) do
        primitive(Integer)
        dump_key(:id)
      end

      fetch_key(:name) do
        primitive(String)
        dump_key(:name)
      end
    end
    anima_load(Task)
  end
end

class Person
  include Anima.new(:id, :name, :address, :tasks)

  TRAP = Ducktrap.build do
    primitive(Hash)
    hash_transform do
      fetch_key(:id) do
        primitive(Integer)
        dump_key(:id)
      end

      fetch_key(:name) do
        primitive(String)
        dump_key(:name)
      end

      fetch_key(:address) do
        add(Address::TRAP)
        dump_key(:address)
      end

      fetch_key(:tasks) do
        map { add(Task::TRAP) }
        dump_key(:tasks)
      end
    end
    anima_load(Person)
  end
end

t_hash = {id: 1, name: 'DOIT'}
a_hash = {id: 1, city: 'Linz', zip: 4040}
p_hash = {id: 1, name: 'John', address: a_hash, tasks: [t_hash]}

result = Person::TRAP.call(p_hash)

if result.success?
  person = result.output
  puts person.inspect
  # => #<Person id=1 name="John" address=#<Address id=1 city="Linz" zip=4040> tasks=[#<Task id=1 name="DOIT">]>

  result = Person::TRAP.inverse.call(person)
  if result.success?
    p_hash = result.output
    puts p_hash.inspect
    # => {:id=>1, :name=>"John", :address=>{:id=>1, :city=>"Linz", :zip=>4040}, :tasks=>[{:id=>1, :name=>"DOIT"}]}
  else
    puts result.pretty_dump
  end
else
  puts result.pretty_dump
end

Credits

Contributing

License

See LICENSE file.