Converting one ruby object into another with some rules.
Add this line to your application's Gemfile:
gem 'yaoc'
And then execute:
$ bundle
Or install it yourself as:
$ gem install yaoc
You say transform an object of class A into an object of class B:
mapper =Yaoc::ObjectMapper.new(B, A) # yes, first what you want, then where to get it
Then you define some rules how it should be done:
mapper.add_mapping do
fetcher :public_send
strategy :to_hash_mapping # default or :to_array_mapping
rule to: :role, from: :r_role
rule to: :firstname,
from: :fullname,
converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :firstname, source.fullname.split().first) },
reverse_converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :fullname, "#{source.firstname} #{source.lastname}") }
rule to: :lastname,
from: :fullname,
converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :lastname, source.fullname.split().last ) },
reverse_converter: ->(source, result){ result }
rule to: :id
end
After this you can transform an object of class A into an object of class B:
mapper.load(A.new)
Or reverse:
mapper.dump(B.new)
Depending on strategy
or reverse_strategy
the input object is first
transformed into a Hash or Array and after this passed to the class constructor.
You can also pass an existing object to load and dump:
b = B.new
mapper.load(A.new, b)
a = A.new
mapper.dump(B.new, a)
In this case setters with matching name to the hash key are invoked with the hash value as value.
require 'yaoc'
include Yaoc::Helper
User = StructHE(:id, :firstname, :lastname, :role)
OldUser = StructHE(:id, :fullname, :r_role)
mapper = Yaoc::ObjectMapper.new(User, OldUser).tap do |mapper|
mapper.add_mapping do
fetcher :public_send
rule to: :role, from: :r_role
rule to: :firstname,
from: :fullname,
converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :firstname, source.fullname.split().first) },
reverse_converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :fullname, "#{source.firstname} #{source.lastname}") }
rule to: :lastname,
from: :fullname,
converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :lastname, source.fullname.split().last ) },
reverse_converter: ->(source, result){ result }
rule to: :id
end
end
old_user = OldUser.new({id: 1, fullname: "myfirst mysecond", r_role: "admin" })
new_user = mapper.load(old_user)
puts old_user
puts new_user
new_user.firstname = "no"
new_user.lastname = "name"
puts mapper.dump(new_user)
#<struct OldUser id=1, fullname="myfirst mysecond", r_role="admin">
#<struct User id=1, firstname="myfirst", lastname="mysecond", role="admin">
#<struct OldUser id=1, fullname="no name", r_role="admin">
require 'yaoc'
include Yaoc::Helper
OldUser2 = Struct.new(:id, :fullname, :r_role)
User2 = Struct.new(:id, :firstname, :lastname, :role)
reverse_source = ->(attrs){
OldUser2.new.tap do |old_user|
attrs.each_pair do |key, value|
old_user.public_send "#{key}=", value
end
end
}
source = ->(attrs){
User2.new.tap do |old_user|
attrs.each_pair do |key, value|
old_user.public_send "#{key}=", value
end
end
}
mapper = Yaoc::ObjectMapper.new(source, reverse_source).tap do |mapper|
mapper.add_mapping do
fetcher :public_send
rule to: :role, from: :r_role
rule to: :firstname,
from: :fullname,
converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :firstname, source.fullname.split().first ) },
reverse_converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :fullname, "#{source.firstname} #{source.lastname}") }
rule to: :lastname,
from: :fullname,
converter: ->(source, result){ Yaoc::TransformationCommand.fill_result_with_value(result, :lastname, source.fullname.split().last) },
reverse_converter: ->(source, result){ result }
rule to: :id
end
end
old_user2 = OldUser2.new(1, "myfirst mysecond", "admin" )
new_user2 = mapper.load(old_user2)
puts old_user2
puts new_user2
new_user2.firstname = "no"
new_user2.lastname = "name"
puts mapper.dump(new_user2)
#<struct OldUser2 id=1, fullname="myfirst mysecond", r_role="admin">
#<struct User2 id=1, firstname="myfirst", lastname="mysecond", role="admin">
#<struct OldUser2 id=1, fullname="no name", r_role="admin">
require 'yaoc'
include Yaoc::Helper
puts "\n" * 5
OldUser3 = Struct.new(:id, :fullname, :r_role)
User3 = Struct.new(:id, :firstname, :lastname, :role)
# alternative to proc for converter
converter = Yaoc::TransformationCommand.create(to: 1,
from: :fullname,
deferred: false,
fetcher_proc: ->(source, fetcher, from){source.fullname.split().first} )
reverse_converter = Yaoc::TransformationCommand.create(to: 1,
from: :first_and_lastname,
deferred: false,
fetcher_proc: ->(source, fetcher, from){ "#{source.firstname} #{source.lastname}"} )
mapper = Yaoc::ObjectMapper.new(User3, OldUser3).tap do |mapper|
mapper.add_mapping do
fetcher :public_send
strategy :to_array_mapping
reverse_strategy :to_array_mapping
rule to: 0, from: :id,
reverse_to: 0, reverse_from: :id
rule to: 1,
from: :fullname,
converter: converter,
reverse_converter: reverse_converter
rule to: 2,
from: :fullname,
converter: ->(source, result){ result[2] = source.fullname.split().last },
reverse_converter: ->(source, result){ result }
rule to: 3, from: :r_role,
reverse_to: 2, reverse_from: :role
end
end
old_user3 = OldUser3.new(1, "myfirst mysecond", "admin" )
new_user3 = mapper.load(old_user3)
puts old_user3
puts new_user3
new_user3.firstname = "no"
new_user3.lastname = "name"
puts mapper.dump(new_user3)
#<struct OldUser3 id=1, fullname="myfirst mysecond", r_role="admin">
#<struct User3 id=1, firstname="myfirst", lastname="mysecond", role="admin">
#<struct OldUser3 id=1, fullname="no name", r_role="admin">
require 'yaoc'
include Yaoc::Helper
puts "\n" * 5
User4 = StructHE(:id, :firstname, :lastname, :roles)
OldUser4 = StructHE(:o_id, :o_firstname, :o_lastname, :o_roles)
Role = StructHE(:id, :name)
OldRole = StructHE(:o_id, :o_name)
Yaoc::ObjectMapper.new(Role, OldRole).tap do |mapper|
mapper.add_mapping do
register_as :role_mapper
fetcher :public_send
rule to: :id, from: :o_id
rule to: :name, from: :o_name
end
end
user_mapper = Yaoc::ObjectMapper.new(User4, OldUser4).tap do |mapper|
mapper.add_mapping do
fetcher :public_send
rule to: [:id, :firstname, :lastname],
from: [:o_id, :o_firstname, :o_lastname]
rule to: :roles,
from: :o_roles,
object_converter: :role_mapper,
is_collection: true
end
end
old_user4 = OldUser4.new(o_id: 1,
o_firstname: "firstname",
o_lastname:"lastname",
o_roles: [OldRole.new(o_id: 1, o_name: "admin"), OldRole.new(o_id: 2, o_name: "guest")] )
new_user4 = user_mapper.load(old_user4)
puts old_user4
puts new_user4
puts user_mapper.dump(new_user4)
#<struct OldUser4 o_id=1, o_firstname="firstname", o_lastname="lastname",
# o_roles=[#<struct OldRole o_id=1, o_name="admin">, #<struct OldRole o_id=2, o_name="guest">]>
#<struct User4 id=1, firstname="firstname", lastname="lastname",
# roles=[#<struct Role id=1, name="admin">, #<struct Role id=2, name="guest">]>
#<struct OldUser4 o_id=1, o_firstname="firstname", o_lastname="lastname",
# o_roles=[#<struct OldRole o_id=1, o_name="admin">, #<struct OldRole o_id=2, o_name="guest">]>
require 'yaoc'
include Yaoc::Helper
puts "\n" * 5
OldUser5 = StructHE(:id, :name)
RoleThing = StructHE(:id, :role)
User5 = StructHE(:id, :name, :role)
user_mapper = Yaoc::ObjectMapper.new(User5, OldUser5).tap do |mapper|
mapper.add_mapping do
fetcher :public_send
rule to: [:id, :name]
end
end
role_mapper = Yaoc::ObjectMapper.new(User5, RoleThing).tap do |mapper|
mapper.add_mapping do
fetcher :public_send
rule to: [:role]
end
end
old_role = RoleThing.new(id: 1, role: "my_role")
old_user5 = OldUser5.new(id: 1, name: "my fullname")
new_user5 = user_mapper.load(old_user5)
role_mapper.load(old_role, new_user5)
# OR
#
# mapper_chain = Yaoc::ManyToOneMapperChain.new(user_mapper, role_mapper)
# new_user5 = mapper_chain.load_all([old_user5, old_role])
puts old_user5
puts old_role
puts new_user5
#<struct OldUser5 id=1, name="my fullname">
#<struct RoleThing id=1, role="my_role">
#<struct User5 id=1, name="my fullname", role="my_role">
require 'yaoc'
include Yaoc::Helper
puts "\n" * 5
OldUser6 = StructHE(:id) do
def names=(new_names)
@names = new_names
end
def names
puts 'some expensive operation in progress ...'
sleep 10
@names
end
end
User6 = StructHE(:id, :names)
user_mapper = Yaoc::ObjectMapper.new(User6, OldUser6).tap do |mapper|
mapper.add_mapping do
fetcher :public_send
rule to: [:id, :names],
lazy_loading: [false, true]
end
end
old_user6 = OldUser6.new(id: 'my_id_1', names: ['one', 'two', 'three', 'four'])
new_user6 = user_mapper.load(old_user6)
puts new_user6.id.inspect
puts new_user6.names.inspect
puts new_user6
puts "\n" * 5
# "my_id_1"
# some expensive operation in progress ...
# ["one", "two", "three", "four"]
#<struct User6 id="my_id_1", names=["one", "two", "three", "four"]>
- Fork it ( http://github.com/slowjack2k/yaoc/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request