public
Description: Morph makes it easy to emerge Ruby class definitions at runtime. Mix with Hpricot for screen scrapping fun.
Homepage: http://github.com/robmckinnon/morph
Clone URL: git://github.com/robmckinnon/morph.git
robmckinnon (author)
Mon Apr 13 05:56:37 -0700 2009
commit  4fab1d298c45d84fcacc51be368ab12fbda82ac1
tree    d14fa098023ad210712617d82e885acc5cc68754
parent  8840159bc0e273cee215f916b7e2e558134e7455
morph / README
100644 206 lines (150 sloc) 7.664 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.
 
 
 
== Morph playing with +Hpricot+
 
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"
 
 
== Morph making sample Active Record line via +script_generate+
 
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.
 
 
== 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
 .