Project

ducktrap

0.0
Repository is archived
No commit activity in last 3 years
No release in over 3 years
Invertible data filter/mutator on data structures
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

~> 0.1.0
~> 2.3.5
~> 0.1.1
~> 0.1.4
~> 0.0.7
 Project Readme

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:

  • Domain to JSON and vice versa, for building rest style APIS
  • Domain to document db and vice versa, for buidling mappers
  • Form processing
  • ...

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

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with Rakefile or version (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

License

See LICENSE file.