Skip to content

Instantly share code, notes, and snippets.

@mbj
Last active December 25, 2015 07:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mbj/6938357 to your computer and use it in GitHub Desktop.
Save mbj/6938357 to your computer and use it in GitHub Desktop.
Illustrative ducktrap example:
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.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' }
# 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment