morph 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +46 -39
  2. data/lib/morph.rb +27 -8
  3. data/morph.gemspec +3 -3
  4. data/spec/morph_spec.rb +75 -0
  5. metadata +2 -2
data/README CHANGED
@@ -2,7 +2,7 @@ Morph allows you to emerge class definitions via calling assignment methods; mix
2
2
 
3
3
 
4
4
 
5
- == Morph example with Hpricot
5
+ == Morph playing with +Hpricot+
6
6
 
7
7
  Here's example code showing Morph playing with Hpricot:
8
8
 
@@ -36,16 +36,18 @@ What new methods do we have?
36
36
 
37
37
  Ah-ha, so we have a name attribute now:
38
38
 
39
- why.name #=> "why the lucky stiff"
39
+ why.name # => "why the lucky stiff"
40
40
 
41
41
 
42
42
  Let's add some of why's projects:
43
43
 
44
- why.projects = %w[shoes hacketyhack camping hoodwinkd hpricot markaby mousehole parkplace poignant sandbox]
44
+ why.projects = %w[shoes hacketyhack camping hoodwinkd hpricot
45
+ markaby mousehole parkplace poignant sandbox]
45
46
 
46
47
  That why's a productive fellow! Note new accessor methods have been added:
47
48
 
48
- Hubbit.morph_methods # => ["email", "email=", "name", "name=", "projects", "projects="]
49
+ Hubbit.morph_methods
50
+ # => ["email", "email=", "name", "name=", "projects", "projects="]
49
51
 
50
52
 
51
53
  Let's do some more morphing:
@@ -54,66 +56,71 @@ Let's do some more morphing:
54
56
 
55
57
  Do we have more methods now?
56
58
 
57
- Hubbit.morph_methods # => ["blog", "blog=", "company", "company=", "email", "email=", "location", "location=" "name", "name=", "projects", "projects="]
59
+ Hubbit.morph_methods
60
+ # => ["blog", "blog=", "company", "company=", "email", "email=",
61
+ # "location", "location=" "name", "name=", "projects", "projects="]
58
62
 
59
63
  So, a new company method has appeared:
60
64
 
61
65
  dhh.company #=> "37signals"
62
66
 
63
67
 
68
+ == Morph making sample Active Record line via +script_generate+
64
69
 
65
- == Morph example from Hash
70
+ Time to generate an Active Record model? Get a sample script line like this:
66
71
 
67
- How about adding a hash of attribute values?
72
+ Hubbit.script_generate
73
+ # => "ruby script/destroy rspec_model Hubbit;
74
+ # ruby script/generate rspec_model Hubbit blog:string company:string
75
+ # email:string location:string name:string projects:string"
76
+
77
+ or specify the generator:
78
+
79
+ Hubbit.script_generate :generator => 'model'
80
+ # => "ruby script/destroy model Hubbit;
81
+ # ruby script/generate model Hubbit blog:string company:string
82
+ # email:string location:string name:string projects:string"
83
+
84
+ You'll have to edit this as it currently sets all data types to be string, and
85
+ doesn't understand associations.
86
+
87
+
88
+ == Morph setting hash of attributes via +morph+
68
89
 
69
90
  class Order; include Morph; end
70
91
  order = Order.new
92
+
93
+ How about adding a hash of attribute values?
94
+
71
95
  order.morph :drink => 'tea', :spoons_of_sugar => 2, :milk => 'prefer soya thanks'
72
96
 
97
+ Looks like we got 'em:
98
+
73
99
  order.drink # => "tea"
74
100
  order.spoons_of_sugar # => 2
75
101
  order.milk # => "prefer soya thanks"
76
102
 
77
103
 
104
+ == Morph obtaining hash of attributes via +morph_attributes+
78
105
 
79
- == Morph example hijacking method creation
80
-
81
- class VegieFoxes
82
- include Morph
106
+ Create an item:
83
107
 
84
- def method_missing symbol, *args
85
- if (is_writer = symbol.to_s =~ /=$/)
86
- morph_method_missing(symbol, *args) do |base, attribute|
87
- create_accessors base, attribute
88
- end
89
- send(symbol, *args)
90
- else
91
- super
92
- end
93
- end
108
+ class Item; include Morph; end
109
+ item = Item.new
110
+ item.morph :name => 'spinach', :cost => 0.50
94
111
 
95
- private
96
- def create_accessors base, attribute
97
- base.class_eval "attr_reader :#{attribute}"
112
+ Now an order:
98
113
 
99
- base.class_def("#{attribute}=") do |value|
100
- is_meat = %w[bacon ham].include? value
101
- value = is_meat ? 'spinach' : value
102
- instance_variable_set "@#{attribute}".to_sym, value
103
- end
104
- end
105
- end
106
-
107
- foxes = VegieFoxes.new
114
+ class Order; include Morph; end
115
+ order = Order.new
116
+ order.no = 123
117
+ order.items = [item]
108
118
 
109
- foxes.chunky = 'bacon'
110
- foxes.inspect # => #<VegieFoxes @chunky="spinach">
119
+ Want to retrieve all that as a nested hash of values? No problem:
111
120
 
112
- foxes.chunky = 'cheese'
113
- puts foxes.inspect # => #<VegieFoxes @chunky="cheese">
121
+ order.morph_attributes
122
+ # => {:items=>[{:name=>"spinach", :cost=>0.5}], :no=>123}
114
123
 
115
- foxes.pet = 'ham'
116
- foxes.inspect # => #<VegieFoxes @pet="spinach", @chunky="cheese">
117
124
 
118
125
  == Last bits
119
126
 
data/lib/morph.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Morph
2
- VERSION = "0.1.5"
2
+ VERSION = "0.2.0"
3
3
 
4
4
  def self.included(base)
5
5
  base.extend ClassMethods
@@ -9,15 +9,15 @@ module Morph
9
9
 
10
10
  module ClassMethods
11
11
 
12
- @@adding_morph_method = false
13
- @@morph_methods = {}
12
+ @@adding_morph_method = Hash.new {|hash,klass| hash[klass] = false }
13
+ @@morph_methods = Hash.new {|hash,klass| hash[klass] = {} }
14
14
 
15
15
  def morph_methods
16
- @@morph_methods.keys.sort
16
+ @@morph_methods[self].keys.sort
17
17
  end
18
18
 
19
19
  def adding_morph_method= true_or_false
20
- @@adding_morph_method = true_or_false
20
+ @@adding_morph_method[self] = true_or_false
21
21
  end
22
22
 
23
23
  def class_def name, &block
@@ -33,14 +33,23 @@ module Morph
33
33
  end
34
34
  end
35
35
 
36
+ def script_generate options={}
37
+ name = self.name.to_s.split('::').last
38
+ name = yield name if block_given?
39
+ generator = options[:generator] || 'rspec_model'
40
+ line = ["ruby script/destroy #{generator} #{name}; ruby script/generate #{generator} #{name}"]
41
+ morph_methods.select{|m| not(m =~ /=$/) }.each {|attribute| line << " #{attribute}:string"}
42
+ line.join('')
43
+ end
44
+
36
45
  protected
37
46
 
38
47
  def method_added symbol
39
- @@morph_methods[symbol.to_s] = true if @@adding_morph_method
48
+ @@morph_methods[self][symbol.to_s] = true if @@adding_morph_method[self]
40
49
  end
41
50
 
42
51
  def method_removed symbol
43
- @@morph_methods.delete symbol.to_s if @@morph_methods.has_key? symbol.to_s
52
+ @@morph_methods[self].delete symbol.to_s if @@morph_methods[self].has_key? symbol.to_s
44
53
  end
45
54
 
46
55
  end
@@ -86,7 +95,17 @@ module Morph
86
95
  attributes = self.class.morph_methods.inject({}) do |hash, attribute|
87
96
  unless attribute =~ /=\Z/
88
97
  symbol = attribute.to_sym
89
- hash[symbol] = send(symbol)
98
+ value = send(symbol)
99
+
100
+ value.each do |key, v|
101
+ value[key] = v.morph_attributes if v.respond_to?(:morph_attributes)
102
+ end if value.is_a? Hash
103
+
104
+ value = value.collect {|v| v.respond_to?(:morph_attributes) ? v.morph_attributes : v } if value.is_a? Array
105
+ value = value.morph_attributes if value.respond_to? :morph_attributes
106
+
107
+
108
+ hash[symbol] = value
90
109
  end
91
110
  hash
92
111
  end
data/morph.gemspec CHANGED
@@ -1,16 +1,16 @@
1
1
 
2
- # Gem::Specification for Morph-0.1.5
2
+ # Gem::Specification for Morph-0.2.0
3
3
  # Originally generated by Echoe
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = %q{morph}
7
- s.version = "0.1.5"
7
+ s.version = "0.2.0"
8
8
 
9
9
  s.specification_version = 2 if s.respond_to? :specification_version=
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.authors = ["Rob McKinnon"]
13
- s.date = %q{2008-04-14}
13
+ s.date = %q{2008-05-01}
14
14
  s.description = %q{Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.}
15
15
  s.email = ["rob ~@nospam@~ rubyforge.org"]
16
16
  s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README"]
data/spec/morph_spec.rb CHANGED
@@ -19,6 +19,18 @@ describe Morph, "when writer method that didn't exist before is called with non-
19
19
  it 'should return hash of attributes when morph_attributes called' do
20
20
  @morph.morph_attributes.should == {@attribute.to_sym => @quack}
21
21
  end
22
+
23
+ it 'should generate rails model generator script line, with given model name' do
24
+ @morphed_class.script_generate {|model_name| 'SomethingDifferent'}.should == "ruby script/destroy rspec_model SomethingDifferent; ruby script/generate rspec_model SomethingDifferent noise:string"
25
+ end
26
+
27
+ it 'should generate rails model generator script line' do
28
+ @morphed_class.script_generate.should == "ruby script/destroy rspec_model ExampleMorph; ruby script/generate rspec_model ExampleMorph noise:string"
29
+ end
30
+
31
+ it 'should generate rails model generator script line' do
32
+ @morphed_class.script_generate(:generator=>'model').should == "ruby script/destroy model ExampleMorph; ruby script/generate model ExampleMorph noise:string"
33
+ end
22
34
  end
23
35
 
24
36
  describe Morph, "when writer method that didn't exist before is called with nil value" do
@@ -31,6 +43,61 @@ describe Morph, "when writer method that didn't exist before is called with nil
31
43
  it_should_behave_like "class without generated accessor methods added"
32
44
  end
33
45
 
46
+ describe Morph, "when different writer method called on two different morph classes" do
47
+ include MorphSpecHelperMethods
48
+
49
+ before :each do
50
+ initialize_morph
51
+ initialize_another_morph
52
+ end
53
+
54
+ it 'should have morph_method return appropriate methods for each class' do
55
+ @morph.every = 'where'
56
+ @another_morph.no = 'where'
57
+
58
+ @morphed_class.morph_methods.size.should == 2
59
+ @another_morphed_class.morph_methods.size.should == 2
60
+
61
+ @morphed_class.morph_methods.should == ['every','every=']
62
+ @another_morphed_class.morph_methods.should == ['no','no=']
63
+ end
64
+
65
+ it 'should call morph_attributes on both objects, when one object has a reference to another' do
66
+ @morph.every = 'which'
67
+ @another_morph.way = 'but'
68
+ @morph.loose = @another_morph
69
+
70
+ attributes = @morph.morph_attributes
71
+ attributes[:every].should == 'which'
72
+ attributes[:loose].should == {:way => 'but'}
73
+ end
74
+
75
+ it 'should call morph_attributes on both objects, when one object has a reference to array of others' do
76
+ @morph.every = 'which'
77
+ @another_morph.way = 'but'
78
+ @morph.loose = [@another_morph]
79
+
80
+ attributes = @morph.morph_attributes
81
+ attributes[:every].should == 'which'
82
+ attributes[:loose].should == [{:way => 'but'}]
83
+ end
84
+
85
+ it 'should call morph_attributes on both objects, when one object has a reference to hash of others' do
86
+ @morph.every = 'which'
87
+ @another_morph.way = 'but'
88
+ @morph.loose = { :honky_tonk => @another_morph}
89
+
90
+ attributes = @morph.morph_attributes
91
+ attributes[:every].should == 'which'
92
+ attributes[:loose].should == { :honky_tonk => {:way => 'but'} }
93
+ end
94
+
95
+ after :each do
96
+ remove_morph_methods
97
+ remove_another_morph_methods
98
+ end
99
+ end
100
+
34
101
  describe Morph, "when class definition contains methods and morph is included" do
35
102
  include MorphSpecHelperMethods
36
103
 
@@ -87,6 +154,14 @@ describe Morph, 'when morph method used to set an attribute value hash' do
87
154
  @morph.sugars.should == 2
88
155
  @morph.milk.should == 'yes please'
89
156
  end
157
+
158
+ it 'should generate rails model generator script line' do
159
+ @morphed_class.script_generate.should == "ruby script/destroy rspec_model ExampleMorph; ruby script/generate rspec_model ExampleMorph drink:string milk:string sugars:string"
160
+ end
161
+
162
+ it 'should generate rails model generator script line' do
163
+ @morphed_class.script_generate(:generator=>'model').should == "ruby script/destroy model ExampleMorph; ruby script/generate model ExampleMorph drink:string milk:string sugars:string"
164
+ end
90
165
  end
91
166
 
92
167
  describe Morph, "when morph method used to set unicode attribute name with a value" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob McKinnon
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-14 00:00:00 +01:00
12
+ date: 2008-05-01 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15