Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.
Here’s example code showing Morph playing with Hpricot:
require 'hpricot'; require 'open-uri'; require 'morph' class Hubbit include Morph # allows class to morph def initialize name doc = Hpricot open("http://github.com/#{name}") (doc/'label').collect do |node| label = node.inner_text value = node.next_sibling.inner_text.strip morph(label, value) # morph magic happening here! end 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 # => ["email", "email=", "name", "name="]
Ah-ha, so we have a name attribute now:
why.name # => "why the lucky stiff"
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 # => ["email", "email=", "name", "name=", "projects", "projects="]
Let’s do some more morphing:
dhh = Hubbit 'dhh'
Do we have more methods now?
Hubbit.morph_methods # => ["blog", "blog=", "company", "company=", "email", "email=", # "location", "location=" "name", "name=", "projects", "projects="]
So, a new company method has appeared:
dhh.company #=> "37signals"
Time to generate an Active Record model? Get a sample script line like this:
Hubbit.script_generate # => "ruby script/destroy rspec_model Hubbit; # ruby script/generate rspec_model Hubbit blog:string company:string # email:string location:string name:string projects:string"
or specify the generator:
Hubbit.script_generate :generator => 'model' # => "ruby script/destroy model Hubbit; # ruby script/generate model Hubbit blog:string company:string # email:string location:string name:string projects:string"
You’ll have to edit this as it currently sets all data types to be string, and doesn’t understand associations.
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"
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}
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 .