Skip to content

Instantly share code, notes, and snippets.

@mbj
Last active December 25, 2015 07:19

Revisions

  1. mbj revised this gist Oct 11, 2013. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions illustrative_ducktrap.rb
    Original file line number Diff line number Diff line change
    @@ -76,9 +76,9 @@ class Item

    evaluator = item.call(input)

    evaluator.success? # => true
    evaluator.class # => Item
    evaluator.output # => <Item @foo='a value for foo', @bar == 'a value for bar'
    evaluator.success? # => true
    evaluator.output.class # => Item
    evaluator.output # => <Item @foo='a value for foo', @bar == 'a value for bar'

    # Inversible properties:
    item.inverse.call(Item.new(:foo => 'foo', :bar => 'bar')) # => { 'complex_name' => 'foo', 'bar' => 'bar' }
  2. mbj created this gist Oct 11, 2013.
    450 changes: 450 additions & 0 deletions illustrative_ducktrap.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,450 @@
    require 'ducktrap'

    # Very simple ducktrap without any real world use
    #
    # Not transforming.
    #
    string = Ducktrap.build do
    primitive(String)
    end

    evaluator = string.call("")

    evaluator.success? # => true
    evaluator.output # => ""



    evaluator = string.call(:foo)

    evaluator.success? # => false
    evaluator.output # => Ducktrap::Evaluator::Invalid

    # A composed example
    #
    # Not transforming.
    #
    ducktrap = Ducktrap.build do
    primitive(Array)
    # stupid dsl node name, must be replaced
    map do
    # using another ducktrap node here
    #
    # Equivalent to:
    #
    # primitive(String)
    #
    add(string)
    end
    end

    ducktrap.call([]).success? # => true
    ducktrap.call([""]).success? # => true
    ducktrap.call(nil).success? # => false
    ducktrap.call([nil]).success? # => false

    # A transforming example

    # Some PORO to map to
    class Item
    include Anima.new(:foo, :bar)
    end # Item


    item = Ducktrap.build do
    primitive(Hash)
    # Suboptimal dsl I know.
    hash_transform do
    # fetch_key => dump_key will be tranform_key(origin => target, origin2 => target2) in future
    fetch_key('complex_name') do
    primitive(String)
    dump_key(:foo)
    end

    fetch_key('bar') do
    primitive(String)
    dump_key(:bar)
    end
    end
    anima_load(Item)
    end

    input = {
    'complex_name' => 'a value for foo',
    'bar' => 'a value for bar'
    }

    evaluator = item.call(input)

    evaluator.success? # => true
    evaluator.class # => Item
    evaluator.output # => <Item @foo='a value for foo', @bar == 'a value for bar'

    # Inversible properties:
    item.inverse.call(Item.new(:foo => 'foo', :bar => 'bar')) # => { 'complex_name' => 'foo', 'bar' => 'bar' }
    # Round trippable on node level
    item.inverse.inverse == item # => true
    # Round trippable semantics
    item.inverse.inverse.call(input) == item.call(input) # => true

    # A composed transforming example:

    class SomeOtherItem
    include Anima.new(:items, :title)
    end

    some_other_item = Ducktrap.build do
    primitive(Hash)
    hash_transform do
    fetch_key('items') do
    map do
    add(item)
    end
    dump_key(:item)
    end
    fetch_key('title') do
    primitive(String)
    dump_key(:title)
    end
    end
    end

    input = {
    'items' => [
    {
    'complex_name' => 'A complex name',
    'bar' => 'A value for bar'
    },
    {
    'complex_name' => 'Another complex name',
    'bar' => 'Another value for bar'
    }
    ],
    'title' => 'A title'
    }

    evaluator = some_other_item.call(input)

    evaluator.success? # => true
    evaluator.output # => <SomeOtherItem @items=[<Item @foo='A complex name'> ....] @title='A title'>

    # Error behavior
    input = {
    'items' => [
    nil, # Note incompatible input here
    {
    'complex_name' => 'A complex name',
    'bar' => 'A value for bar'
    },
    {
    'complex_name' => 'Another complex name',
    'bar' => 'Another value for bar'
    }
    ],
    'title' => 'A title'
    }

    evaluator = some_other_item.call(input)
    evaluator.success? # => false
    # Precise error location here:
    evaluator.output # => #<Ducktrap::Error context=#<Ducktrap::Node::Hash::Transform::Evaluator context=#<Ducktr...
    # And pretty dumpable/inspectable of course :D
    #
    # Yeah this is TOO verbose. But guys this is a 0.0.1 version and many times more than a:
    #
    # NoMethodError: undefined method `each' for nil:NilClass
    # With a stacktrace NOT showing input data ;)
    #
    evaluator.output.pretty_dump
    # prints:
    # Ducktrap::Error
    # input: {"items"=>[nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}], "title"=>"A title"}
    # context:
    # Ducktrap::Node::Hash::Transform::Evaluator
    # input: {"items"=>[nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}], "title"=>"A title"}
    # error:
    # Ducktrap::Error
    # input: {"items"=>[nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}], "title"=>"A title"}
    # context:
    # Ducktrap::Node::Key::Fetch::Evaluator
    # input: {"items"=>[nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}], "title"=>"A title"}
    # error:
    # Ducktrap::Error
    # input: {"items"=>[nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}], "title"=>"A title"}
    # context:
    # Ducktrap::Node::Block::Evaluator
    # input: [nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}]
    # error:
    # Ducktrap::Error
    # input: [nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}]
    # context:
    # Ducktrap::Node::Map::Evaluator
    # input: [nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}]
    # error:
    # Ducktrap::Error
    # input: [nil, {"complex_name"=>"A complex name", "bar"=>"A value for bar"}, {"complex_name"=>"Another complex name", "bar"=>"Another value for bar"}]
    # context:
    # Ducktrap::Node::Block::Evaluator
    # input: nil
    # error:
    # Ducktrap::Error
    # input: nil
    # context:
    # Ducktrap::Node::Block::Evaluator
    # input: nil
    # error:
    # Ducktrap::Error
    # input: nil
    # context:
    # Ducktrap::Evaluator::Invalid
    # input: nil
    # error:
    # Ducktrap::Error
    # input: nil
    # context:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # context:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # context:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # Ducktrap::Node::Hash::Transform
    # body:
    # Ducktrap::Node::Key::Fetch
    # key: "complex_name"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :foo
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Key::Fetch
    # key: "bar"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :bar
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Anima::Load
    # model: Item
    # context:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # Ducktrap::Node::Hash::Transform
    # body:
    # Ducktrap::Node::Key::Fetch
    # key: "complex_name"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :foo
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Key::Fetch
    # key: "bar"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :bar
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Anima::Load
    # model: Item
    # context:
    # Ducktrap::Node::Map
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # Ducktrap::Node::Hash::Transform
    # body:
    # Ducktrap::Node::Key::Fetch
    # key: "complex_name"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :foo
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Key::Fetch
    # key: "bar"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :bar
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Anima::Load
    # model: Item
    # context:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Map
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # Ducktrap::Node::Hash::Transform
    # body:
    # Ducktrap::Node::Key::Fetch
    # key: "complex_name"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :foo
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Key::Fetch
    # key: "bar"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :bar
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Anima::Load
    # model: Item
    # Ducktrap::Node::Key::Dump
    # key: :item
    # operand:
    # Ducktrap::Node::Noop
    # context:
    # Ducktrap::Node::Key::Fetch
    # key: "items"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Map
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # Ducktrap::Node::Hash::Transform
    # body:
    # Ducktrap::Node::Key::Fetch
    # key: "complex_name"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :foo
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Key::Fetch
    # key: "bar"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :bar
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Anima::Load
    # model: Item
    # Ducktrap::Node::Key::Dump
    # key: :item
    # operand:
    # Ducktrap::Node::Noop
    # context:
    # Ducktrap::Node::Hash::Transform
    # body:
    # Ducktrap::Node::Key::Fetch
    # key: "items"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Map
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: Hash
    # Ducktrap::Node::Hash::Transform
    # body:
    # Ducktrap::Node::Key::Fetch
    # key: "complex_name"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :foo
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Key::Fetch
    # key: "bar"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :bar
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Anima::Load
    # model: Item
    # Ducktrap::Node::Key::Dump
    # key: :item
    # operand:
    # Ducktrap::Node::Noop
    # Ducktrap::Node::Key::Fetch
    # key: "title"
    # operand:
    # Ducktrap::Node::Block
    # body:
    # Ducktrap::Node::Primitive
    # primitive: String
    # Ducktrap::Node::Key::Dump
    # key: :title
    # operand:
    # Ducktrap::Node::Noop