morph 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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