Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Morph mixin allows you to emerge Ruby class definitions from data via calling assignment methods.

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 autotest
Octocat-spinner-32 examples
Octocat-spinner-32 lib
Octocat-spinner-32 spec
Octocat-spinner-32 .gitignore
Octocat-spinner-32 .rspec
Octocat-spinner-32 .travis.yml
Octocat-spinner-32 CHANGELOG
Octocat-spinner-32 Gemfile
Octocat-spinner-32 Guardfile
Octocat-spinner-32 LICENSE
Octocat-spinner-32 Manifest
Octocat-spinner-32 README
Octocat-spinner-32 README.rdoc
Octocat-spinner-32 Rakefile
Octocat-spinner-32 init.rb
README.rdoc

Morph mixin allows you to emerge Ruby class definitions from data via calling assignment methods.

Travis CI
build status

Installing Morph

gem install morph

To use Morph:

require 'morph'

Morph creating classes from_csv

Here's example code 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"

Morph playing with Nokogiri

Here's example code showing Morph playing with Nokogiri in Ruby 1.9.2:

require 'morph'; require 'nokogiri'; require 'open-uri'

class Hubbit
  include Morph  # allows class to morph

  def initialize name
    doc = Nokogiri::HTML open("https://github.com/#{name}")

    profile_fields = doc.search('.vcard dt')

    profile_fields.each do |node|
      label = node.inner_text
      value = node.next_element.inner_text.strip

      morph(label, value)  # morph magic adds accessor methods!
    end
  end

  def member_since_date
    Date.parse member_since
  end
end

def Hubbit name; Hubbit.new name; end

The model emerges from the data. Let's start by looking up 'why':

why = Hubbit 'why'

What new methods do we have?

Hubbit.morph_methods.map {|m| m.to_s}

#=> ["location", "location=", "member_since", "member_since=", "name", "name="]

Ah-ha, so we have a name attribute now:

why.name # => "Squatting until _why gets home."

We wrote a member_since_date method in our class, let's call that now:

why.member_since_date # => Wed, 19 Aug 2009

Let's add some of why's projects:

why.projects = %w[shoes hacketyhack camping hoodwinkd hpricot
                 markaby mousehole parkplace poignant sandbox]

That why's a productive fellow! Note new accessor methods have been added:

Hubbit.morph_methods.map {|m| m.to_s}

#=> ["location", "location=", "member_since", "member_since=", "name", "name=",
#    "projects", "projects="]

Let's do some more morphing:

dhh = Hubbit 'dhh'

Do we have more methods now?

Hubbit.morph_methods.map {|m| m.to_s}

#=> ["company", "company=", "email", "email=", "location", "location=",
#    "member_since", "member_since=", "name", "name=", "projects", "projects=",
#    "website_blog", "website_blog="]

So, a new company method has appeared:

dhh.company #=> "37signals"

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(Hubbit)

#=> "rails destroy model Hubbit;
#    rails generate model Hubbit company:string email:string location:string
#          member_since:string name:string projects:string website_blog:string"

or specify the generator:

Morph.script_generate(Hubbit, :generator => 'rspec_model')

#=> "rails destroy rspec_model Hubbit;
#    rails generate rspec_model Hubbit company:string email:string
#          location:string member_since:string name:string projects:string
#          website_blog: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 examples/ directory for some example code. 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
.
Something went wrong with that request. Please try again.