Morph allows you to emerge Ruby class definitions from data or by calling assignment methods.
Installing Morph
gem install morph
To use Morph:
require 'morph'
Tested to work with Ruby 2.2 - 2.6.
Morph creating classes from_json
Here's an example showing Morph creating classes and objects from JSON:
json = '{
"id": "3599110793",
"type": "PushEvent",
"actor": {
"id": 3447,
"login": "robmckinnon",
"url": "https://api.github.com/users/robmckinnon"
},
"repo": {
"id": 5092,
"name": "robmckinnon/morph",
"url": "https://api.github.com/repos/robmckinnon/morph"
}
}'
module Github; end
type = :push_event
namespace = Github
event = Morph.from_json json, type, namespace
# => <Github::PushEvent @id="3599110793", @type="PushEvent",
# @actor=#<Github::Actor:0x007faa0c86b790 @id=3447, @login="robmckinnon",
# @url="https://api.github.com/users/robmckinnon">,
# @repo=#<Github::Repo:0x007faa0c869198 @id=5092, @name="robmckinnon/morph",
# @url="https://api.github.com/repos/robmckinnon/morph">
# >
event.class # => Github::PushEvent
event.class.morph_attributes # => [:id, :type, :actor, :repo]
event.actor.class # => Github::Actor
event.repo.class # => Github::Repo
If namespace module not provided, new classes are created in Morph module.
event = Morph.from_json json, type, namespace
event.class # => Morph::PushEvent
Morph creating classes from_csv
Here's an example showing Morph playing with CSV (comma-separated values):
csv = %Q[name,party\nTed Roe,red\nAli Davidson,blue\nSue Smith,green]
people = Morph.from_csv(csv, 'person')
# => [#<Morph::Person @name="Ted Roe", @party="red">,
#<Morph::Person @name="Ali Davidson", @party="blue">,
#<Morph::Person @name="Sue Smith", @party="green">]
people.last.party # => "green"
Morph creating classes from_tsv
Here's example code showing Morph playing with TSV (tab-separated values):
tsv = %Q[name\tparty\nTed Roe\tred\nAli Davidson\tblue\nSue Smith\tgreen]
people = Morph.from_tsv(tsv, 'person')
# => [#<Morph::Person @name="Ted Roe", @party="red">,
#<Morph::Person @name="Ali Davidson", @party="blue">,
#<Morph::Person @name="Sue Smith", @party="green">]
people.last.party # => "green"
Morph creating classes from_xml
Here's example code showing Morph playing with XML:
xml = %Q[<?xml version="1.0" encoding="UTF-8"?>
<councils type="array">
<council code='1'>
<name>Aberdeen City Council</name>
</council>
<council code='2'>
<name>Allerdale Borough Council</name>
</council>
</councils>]
councils = Morph.from_xml(xml)
# => [#<Morph::Council @code="1", @name="Aberdeen City Council">,
#<Morph::Council @code="2", @name="Allerdale Borough Council">]
councils.first.name # => "Aberdeen City Council"
Registering a listener to new class / methods via register_listener
You can use register_listener
to get callbacks when new methods on a class are
created.
For example given Morph used as a mixin:
class Project
include Morph
end
project = Project.new
Register listener:
listener = -> (klass, method) do
puts "class: #{klass.to_s} --- method: #{method}"
end
Morph.register_listener listener
Callback prints string as new methods are created via assignment calls:
project.deadline = "11 11 2075"
# class: Project --- method: deadline
project.completed = true
# class: Project --- method: completed
To unregister a listener use unregister_listener
:
Morph.unregister_listener listener
For an example of Morph's register_listener
being used to
create a Github API
see the Hubbit module.
Morph making sample Active Record line via script_generate
Time to generate an Active Record model? Get a sample script line like this:
Morph.script_generate(Project)
#=> "rails destroy model Project;
# rails generate model Project completed:string deadline:string
or specify the generator:
Morph.script_generate(Project, :generator => 'rspec_model')
#=> "rails destroy rspec_model Project;
# rails generate rspec_model Project completed:string deadline:string
You'll have to edit this as it currently sets all data types to be string, and doesn't understand associations.
Morph setting hash of attributes via morph
class Order
include Morph
end
order = Order.new
How about adding a hash of attribute values?
order.morph :drink => 'tea', :spoons_of_sugar => 2, :milk => 'prefer soya thanks'
Looks like we got 'em:
order.drink # => "tea"
order.spoons_of_sugar # => 2
order.milk # => "prefer soya thanks"
Morph obtaining hash of attributes via morph_attributes
Create an item:
class Item
include Morph
end
item = Item.new
item.morph :name => 'spinach', :cost => 0.50
Now an order:
class Order
include Morph
end
order = Order.new
order.no = 123
order.items = [item]
Want to retrieve all that as a nested hash of values? No problem:
order.morph_attributes # => {:items=>[{:name=>"spinach", :cost=>0.5}], :no=>123}
Last bits
See LICENSE for the terms of this software.
. ,
. ?7+~::+II~
. ?7: ,:+7
. 777IIII777? 7: :?7
. =I= I: 7? ,+7
. I? ,, 77 7: :I
. = ?7777 77 7 7 7+, :7
. 7 777777 ~77+=77 I+ I? ,7
. :7 77 ~77 I I7 7 ?: ?
. I 77 7, 7 7 :I I ?
. 7 ?77=7~ 77777 7 ~+ ,+
. 7~ 7 :I7?~ 7
. =? 7 ?I ~I77= I=
. 7 ? :, 7 I7777, 7 7
. ? 777?~~7777+ 7 7~ 7
. ?7 ,777777=, ,7 7 ,7
. 7= , =7 7: 7
. +7 :7 7 ,I
. :7 ?~ 7? 7
. 7 7 ~II7~, 7
. 7 7 , =7777777?+,,, I=
. :7, ~==, 7
. II~,, 77~
. ,I? +777
. 7+, ~7777:
. == :77
. :7: ,7I
. 7I 7
. I ,7, 7
. =7 77=7 7
. ,7 7I 7 7
. I, I7 7 7
. ?, ,7 7, 7
. 7 7~ 7, 7
. 7 ,7I 7 7
. =+ =7 7 ~=
. =7 7, 7 7
. ,7, ~7IIII7+, 7
. +: II I
. ?7 I? +~
. II, +I 7
. ~7 ,I 7
. 7= ~7 7
. ?7, ~7+ ?~
. ~7777I= ,7
. 7: 7
. I 7
. I ,:77I 7
. I :7 I
. I =~
. 7 , ,7
. +, 7 : ,7
. + 7 + 7
. + 7 + ,7
. 7 I ? ,7
. 7 +: 7 ,7
. 7 =+ 7 ,7
. 7 :I I ,7
. 7 :I 7 7
. 7 :I I 7
. I, ,7 I: 7
. =+ ,7 ? 7
. :?, ,7 7, 7
. I: ,7 7, ?
. :7 ,7 7, ,
. +I, : ? ,=
. += ~ =~ 7
. :II,, = I ?
. =I= ? 7, :7
. II~ I 7, ,II
. 7~ ~7 7 ,=7
. = =7 I, ::
. 77II?==?II777777777777777 7~ 7
. 77+,, 7:
. 777777+:,~777
.