morph 0.3.4 → 0.3.5

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ v0.3.5. retain morph_methods when inheriting class and parent both include Morph
2
+
1
3
  v0.3.4. return instance morph_attributes ordered by original addition of attribute
2
4
 
3
5
  v0.3.3. removed show_ruby() method; updated script_generate() to utilise new rails commands
data/Manifest CHANGED
@@ -1,10 +1,5 @@
1
1
  CHANGELOG
2
- examples/forger.rb
3
- examples/hubbit.rb
4
2
  lib/morph.rb
5
3
  LICENSE
6
4
  README
7
- spec/lib/morph_spec.rb
8
- spec/morph_spec_helper.rb
9
- spec/spec_helper.rb
10
5
  Manifest
data/README CHANGED
@@ -1,44 +1,50 @@
1
- Morph mixin allows you to emerge class definitions via calling assignment methods; mix with Nokogiri for screen scraping fun.
1
+ Morph mixin allows you to emerge Ruby class definitions from data via calling assignment methods.
2
2
 
3
3
 
4
+ == Installing Morph
5
+
6
+ gem install morph
7
+
8
+ To use Morph:
9
+
10
+ require 'morph'
11
+
4
12
  == Morph creating classes +from_csv+
5
13
 
6
14
  Here's example code showing Morph playing with CSV (comma-separated values):
7
15
 
8
- require 'rubygems'; require 'morph'
9
-
10
16
  csv = %Q[name,party\nTed Roe,red\nAli Davidson,blue\nSue Smith,green]
11
17
 
12
18
  people = Morph.from_csv(csv, 'person')
19
+
13
20
  # => [#<Morph::Person @name="Ted Roe", @party="red">,
14
21
  #<Morph::Person @name="Ali Davidson", @party="blue">,
15
22
  #<Morph::Person @name="Sue Smith", @party="green">]
16
23
 
17
24
  people.last.party
25
+
18
26
  # => "green"
19
27
 
20
28
  == Morph creating classes +from_tsv+
21
29
 
22
30
  Here's example code showing Morph playing with TSV (tab-separated values):
23
31
 
24
- require 'rubygems'; require 'morph'
25
-
26
32
  tsv = %Q[name\tparty\nTed Roe\tred\nAli Davidson\tblue\nSue Smith\tgreen]
27
33
 
28
34
  people = Morph.from_tsv(tsv, 'person')
35
+
29
36
  # => [#<Morph::Person @name="Ted Roe", @party="red">,
30
37
  #<Morph::Person @name="Ali Davidson", @party="blue">,
31
38
  #<Morph::Person @name="Sue Smith", @party="green">]
32
39
 
33
40
  people.last.party
41
+
34
42
  # => "green"
35
43
 
36
44
  == Morph creating classes +from_xml+
37
45
 
38
46
  Here's example code showing Morph playing with XML:
39
47
 
40
- require 'rubygems'; require 'morph'
41
-
42
48
  xml = %Q[<?xml version="1.0" encoding="UTF-8"?>
43
49
  <councils type="array">
44
50
  <council code='1'>
@@ -50,18 +56,20 @@ Here's example code showing Morph playing with XML:
50
56
  </councils>]
51
57
 
52
58
  councils = Morph.from_xml(xml)
59
+
53
60
  # => [#<Morph::Council @code="1", @name="Aberdeen City Council">,
54
61
  #<Morph::Council @code="2", @name="Allerdale Borough Council">]
55
62
 
56
63
  councils.first.name
64
+
57
65
  # => "Aberdeen City Council"
58
66
 
59
67
  == Morph playing with +Nokogiri+
60
68
 
61
69
  Here's example code showing Morph playing with Nokogiri in Ruby 1.9.2:
62
70
 
63
- require 'rubygems'; require 'nokogiri'; require 'open-uri'
64
- require 'morph'
71
+ require 'morph'; require 'nokogiri'; require 'open-uri'
72
+
65
73
 
66
74
  class Hubbit
67
75
  include Morph # allows class to morph
@@ -93,6 +101,7 @@ The model emerges from the data. Let's start by looking up 'why':
93
101
  What new methods do we have?
94
102
 
95
103
  Hubbit.morph_methods.map {|m| m.to_s}
104
+
96
105
  #=> ["location", "location=", "member_since", "member_since=", "name", "name="]
97
106
 
98
107
  Ah-ha, so we have a name attribute now:
@@ -112,6 +121,7 @@ Let's add some of why's projects:
112
121
  That why's a productive fellow! Note new accessor methods have been added:
113
122
 
114
123
  Hubbit.morph_methods.map {|m| m.to_s}
124
+
115
125
  #=> ["location", "location=", "member_since", "member_since=", "name", "name=",
116
126
  # "projects", "projects="]
117
127
 
@@ -123,6 +133,7 @@ Let's do some more morphing:
123
133
  Do we have more methods now?
124
134
 
125
135
  Hubbit.morph_methods.map {|m| m.to_s}
136
+
126
137
  #=> ["company", "company=", "email", "email=", "location", "location=",
127
138
  # "member_since", "member_since=", "name", "name=", "projects", "projects=",
128
139
  # "website_blog", "website_blog="]
@@ -137,6 +148,7 @@ So, a new company method has appeared:
137
148
  Time to generate an Active Record model? Get a sample script line like this:
138
149
 
139
150
  Hubbit.script_generate
151
+
140
152
  #=> "rails destroy model Hubbit;
141
153
  # rails generate model Hubbit company:string email:string location:string
142
154
  # member_since:string name:string projects:string website_blog:string"
@@ -144,6 +156,7 @@ Time to generate an Active Record model? Get a sample script line like this:
144
156
  or specify the generator:
145
157
 
146
158
  Hubbit.script_generate :generator => 'rspec_model'
159
+
147
160
  #=> "rails destroy rspec_model Hubbit;
148
161
  # rails generate rspec_model Hubbit company:string email:string
149
162
  # location:string member_since:string name:string projects:string
@@ -187,6 +200,7 @@ Now an order:
187
200
  Want to retrieve all that as a nested hash of values? No problem:
188
201
 
189
202
  order.morph_attributes
203
+
190
204
  # => {:items=>[{:name=>"spinach", :cost=>0.5}], :no=>123}
191
205
 
192
206
 
data/lib/morph.rb CHANGED
@@ -18,7 +18,7 @@ rescue Exception => e
18
18
  end
19
19
 
20
20
  module Morph
21
- VERSION = "0.3.4" unless defined? Morph::VERSION
21
+ VERSION = "0.3.5" unless defined? Morph::VERSION
22
22
 
23
23
  class << self
24
24
  def generate_migrations object, options={}
@@ -183,20 +183,29 @@ module Morph
183
183
 
184
184
  module ClassMethods
185
185
 
186
- @@adding_morph_method = Hash.new {|hash,klass| hash[klass] = false }
187
- @@morph_methods = Hash.new {|hash,klass| hash[klass] = {} }
188
- @@morph_attributes = Hash.new {|hash,klass| hash[klass] = [] }
186
+ @@adding_morph_method = Hash.new {|hash,klass| hash[klass] = false } unless defined?(@@adding_morph_method)
187
+ @@morph_methods = Hash.new {|hash,klass| hash[klass] = {} } unless defined?(@@morph_methods)
188
+ @@morph_attributes = Hash.new {|hash,klass| hash[klass] = [] } unless defined?(@@morph_attributes)
189
189
 
190
190
  def morph_attributes
191
- @@morph_attributes[self] + []
191
+ if superclass.respond_to?(:morph_attributes)
192
+ @@morph_attributes[self] + superclass.morph_attributes
193
+ else
194
+ @@morph_attributes[self] + []
195
+ end
192
196
  end
193
197
 
194
198
  def morph_methods
195
- if RUBY_VERSION >= "1.9"
199
+ methods = if RUBY_VERSION >= "1.9"
196
200
  @@morph_methods[self].keys.sort.map(&:to_sym)
197
201
  else
198
202
  @@morph_methods[self].keys.sort
199
203
  end
204
+
205
+ if superclass.respond_to?(:morph_attributes)
206
+ methods += superclass.morph_methods
207
+ end
208
+ methods
200
209
  end
201
210
 
202
211
  def adding_morph_method= true_or_false
data/morph.gemspec CHANGED
@@ -2,21 +2,21 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "morph"
5
- s.version = "0.3.4"
5
+ s.version = "0.3.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Rob McKinnon"]
9
- s.date = "2012-06-15"
10
- s.description = "Morph mixin allows you to emerge class definitions via calling assignment methods; mix with Nokogiri for screen scraping fun.\n"
9
+ s.date = "2012-08-31"
10
+ s.description = "Morph mixin allows you to emerge Ruby class definitions from data via calling assignment methods.\n"
11
11
  s.email = ["rob ~@nospam@~ rubyforge.org"]
12
12
  s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README"]
13
- s.files = ["CHANGELOG", "examples/forger.rb", "examples/hubbit.rb", "lib/morph.rb", "LICENSE", "README", "spec/lib/morph_spec.rb", "spec/morph_spec_helper.rb", "spec/spec_helper.rb", "Manifest", "morph.gemspec", "Rakefile"]
13
+ s.files = ["CHANGELOG", "lib/morph.rb", "LICENSE", "README", "Manifest", "morph.gemspec", "Rakefile"]
14
14
  s.homepage = "https://github.com/robmckinnon/morph"
15
15
  s.post_install_message = "Read usage examples at: https://github.com/robmckinnon/morph#readme"
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Morph", "--main", "README", "--inline-source"]
17
17
  s.require_paths = ["lib"]
18
18
  s.rubyforge_project = "morph"
19
- s.rubygems_version = "1.8.18"
19
+ s.rubygems_version = "1.8.24"
20
20
  s.summary = "Morph mixin allows you to emerge class definitions via calling assignment methods."
21
21
 
22
22
  if s.respond_to? :specification_version then
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.3.4
4
+ version: 0.3.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-15 00:00:00.000000000 Z
12
+ date: 2012-08-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -59,8 +59,8 @@ dependencies:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
- description: ! 'Morph mixin allows you to emerge class definitions via calling assignment
63
- methods; mix with Nokogiri for screen scraping fun.
62
+ description: ! 'Morph mixin allows you to emerge Ruby class definitions from data
63
+ via calling assignment methods.
64
64
 
65
65
  '
66
66
  email:
@@ -73,14 +73,9 @@ extra_rdoc_files:
73
73
  - README
74
74
  files:
75
75
  - CHANGELOG
76
- - examples/forger.rb
77
- - examples/hubbit.rb
78
76
  - lib/morph.rb
79
77
  - LICENSE
80
78
  - README
81
- - spec/lib/morph_spec.rb
82
- - spec/morph_spec_helper.rb
83
- - spec/spec_helper.rb
84
79
  - Manifest
85
80
  - morph.gemspec
86
81
  - Rakefile
@@ -111,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
106
  version: '1.2'
112
107
  requirements: []
113
108
  rubyforge_project: morph
114
- rubygems_version: 1.8.18
109
+ rubygems_version: 1.8.24
115
110
  signing_key:
116
111
  specification_version: 3
117
112
  summary: Morph mixin allows you to emerge class definitions via calling assignment
data/examples/forger.rb DELETED
@@ -1,31 +0,0 @@
1
- require 'rubygems'; require 'hpricot'; require 'open-uri'; require 'morph'
2
-
3
- # An example of Morph playing with Hpricot
4
- class Forger
5
-
6
- include Morph
7
-
8
- def initialize name
9
- begin
10
- doc = Hpricot open("http://rubyforge.org/users/#{name}")
11
-
12
- table = doc.at('td[text() = "Personal Information"]').parent.parent
13
- values = table/'tr/td/strong'
14
-
15
- values.collect do |node|
16
- value = node.inner_text.strip
17
- label = node.at('../../td[1]').inner_text
18
- morph(label, value)
19
- end
20
- rescue
21
- raise "Couldn't find forger with name: #{name}"
22
- end
23
- end
24
- end
25
-
26
- def Forger name
27
- Forger.new name
28
- end
29
-
30
- #> why = Forger 'why'
31
-
data/examples/hubbit.rb DELETED
@@ -1,32 +0,0 @@
1
- require 'morph'
2
-
3
- require 'rubygems'; require 'nokogiri'; require 'open-uri'
4
-
5
- # An example of Morph playing with Nokogiri
6
- class Hubbit
7
- include Morph # allows class to morph
8
-
9
- def initialize name
10
- doc = Nokogiri::HTML open("https://github.com/#{name}")
11
-
12
- profile_fields = doc.search('.vcard dt')
13
-
14
- profile_fields.each do |node|
15
- label = node.inner_text
16
- value = node.next_element.inner_text.strip
17
-
18
- morph(label, value) # morph magic adds accessor methods!
19
- end
20
- end
21
-
22
- def member_since_date
23
- Date.parse member_since
24
- end
25
- end
26
-
27
- def Hubbit name
28
- Hubbit.new name
29
- end
30
-
31
- # why = Hubbit 'why'
32
- # dhh = Hubbit 'dhh'
@@ -1,642 +0,0 @@
1
- # encoding: utf-8
2
- require File.dirname(__FILE__) + '/../morph_spec_helper'
3
-
4
- describe Morph do
5
- include MorphSpecHelperMethods
6
-
7
- describe "when writer method that didn't exist before is called with non-nil value" do
8
- before :all do initialize_morph; end
9
- after :all do remove_morph_methods; end
10
-
11
- before :each do
12
- remove_morph_methods
13
- @quack = 'quack'
14
- @morph.noise= @quack
15
- @attribute = 'noise'
16
- @expected_morph_methods_count = 2
17
- end
18
-
19
- it_should_behave_like "class with generated accessor methods added"
20
-
21
- it 'should return assigned value when reader method called' do
22
- @morph.noise.should == @quack
23
- end
24
-
25
- it 'should return hash of attributes when morph_attributes called' do
26
- @morph.morph_attributes.should == {@attribute.to_sym => @quack}
27
- end
28
-
29
- it 'should generate rails model generator script line, with given model name' do
30
- @morphed_class.script_generate {|model_name| 'SomethingDifferent'}.should == "rails destroy model SomethingDifferent; rails generate model SomethingDifferent noise:string"
31
- end
32
-
33
- it 'should generate rails model generator script line' do
34
- @morphed_class.script_generate.should == "rails destroy model ExampleMorph; rails generate model ExampleMorph noise:string"
35
- end
36
-
37
- it 'should generate rails model generator script line' do
38
- @morphed_class.script_generate(:generator=>'model').should == "rails destroy model ExampleMorph; rails generate model ExampleMorph noise:string"
39
- end
40
- end
41
-
42
- describe "when writer method that didn't exist before is called with nil value" do
43
- before :each do
44
- remove_morph_methods
45
- @morph.noise= nil
46
- @attribute = 'noise'
47
- end
48
-
49
- it_should_behave_like "class without generated accessor methods added"
50
- end
51
-
52
- describe "when different writer method called on two different morph classes" do
53
- include MorphSpecHelperMethods
54
-
55
- before :each do
56
- initialize_morph
57
- initialize_another_morph
58
- end
59
-
60
- it 'should have morph_method return appropriate methods for each class' do
61
- @morph.every = 'where'
62
- @another_morph.no = 'where'
63
-
64
- @morphed_class.morph_methods.size.should == 2
65
- @another_morphed_class.morph_methods.size.should == 2
66
-
67
- if RUBY_VERSION >= "1.9"
68
- @morphed_class.morph_methods.should == [:every,:every=]
69
- @another_morphed_class.morph_methods.should == [:no,:no=]
70
- else
71
- @morphed_class.morph_methods.should == ['every','every=']
72
- @another_morphed_class.morph_methods.should == ['no','no=']
73
- end
74
- end
75
-
76
- it 'should call morph_attributes on both objects, when one object has a reference to another' do
77
- @morph.every = 'which'
78
- @another_morph.way = 'but'
79
- @morph.loose = @another_morph
80
-
81
- attributes = @morph.morph_attributes
82
- attributes[:every].should == 'which'
83
- attributes[:loose].should == {:way => 'but'}
84
- end
85
-
86
- it 'should call morph_attributes on both objects, when one object has a reference to array of others' do
87
- @morph.every = 'which'
88
- @another_morph.way = 'but'
89
- @morph.loose = [@another_morph]
90
-
91
- attributes = @morph.morph_attributes
92
- attributes[:every].should == 'which'
93
- attributes[:loose].should == [{:way => 'but'}]
94
- end
95
-
96
- it 'should call morph_attributes on both objects, when one object has a reference to hash of others' do
97
- @morph.every = 'which'
98
- @another_morph.way = 'but'
99
- @morph.loose = { :honky_tonk => @another_morph}
100
-
101
- attributes = @morph.morph_attributes
102
- attributes[:every].should == 'which'
103
- attributes[:loose].should == { :honky_tonk => {:way => 'but'} }
104
- attributes.delete(:every)
105
- attributes = @morph.morph_attributes
106
- attributes[:every].should == 'which'
107
-
108
- attributes = @morph.class.morph_attributes
109
- attributes.should == [:every, :loose]
110
- attributes.delete(:every)
111
- attributes = @morph.class.morph_attributes
112
- attributes.should == [:every, :loose]
113
- end
114
-
115
- after :each do
116
- remove_morph_methods
117
- remove_another_morph_methods
118
- end
119
- end
120
-
121
- describe "when class definition contains methods and morph is included" do
122
- include MorphSpecHelperMethods
123
-
124
- after :all do
125
- remove_morph_methods
126
- @morphed_class.class_eval "remove_method :happy" if @morphed_class
127
- end
128
-
129
- it 'should not return methods defined in class in morph_methods list' do
130
- initialize_morph "class ExampleMorph\n include Morph\n def happy\n 'happy, joy, joy'\n end\n end"
131
- morph_methods.should be_empty
132
- end
133
- end
134
-
135
- describe "when writer method that didn't exist before is called with blank space attribute value" do
136
- before :each do
137
- remove_morph_methods
138
- @morph.noise= ' '
139
- @attribute = 'noise'
140
- end
141
-
142
- it_should_behave_like "class without generated accessor methods added"
143
- end
144
-
145
- describe 'when morph method used to set attribute value' do
146
- before :all do initialize_morph; end
147
- after :all do remove_morph_methods; end
148
-
149
- before :each do
150
- remove_morph_methods
151
- @value = '20 Mar 2008'
152
- @morph.morph('Reading', @value)
153
- @attribute = 'reading'
154
- @expected_morph_methods_count = 2
155
- end
156
-
157
- it_should_behave_like "class with generated accessor methods added"
158
-
159
- it 'should return assigned value when reader method called' do
160
- @morph.reading.should == @value
161
- end
162
- end
163
-
164
- describe 'when morph method used to set an attribute value hash' do
165
- before :all do initialize_morph; end
166
- after :all do remove_morph_methods; end
167
-
168
- before :each do
169
- remove_morph_methods
170
- @attributes = [:drink,:sugars,:milk]
171
- @morph.morph :drink => 'tea', :sugars => 2, :milk => 'yes please'
172
- @expected_morph_methods_count = 6
173
- end
174
-
175
- it_should_behave_like "class with generated accessor methods added"
176
-
177
- it 'should return assigned value when reader method called' do
178
- @morph.drink.should == 'tea'
179
- @morph.sugars.should == 2
180
- @morph.milk.should == 'yes please'
181
- end
182
-
183
- it 'should generate rails model generator script line' do
184
- @morphed_class.script_generate.should == "rails destroy model ExampleMorph; rails generate model ExampleMorph drink:string milk:string sugars:string"
185
- end
186
-
187
- it 'should generate rails model generator script line' do
188
- @morphed_class.script_generate(:generator=>'model').should == "rails destroy model ExampleMorph; rails generate model ExampleMorph drink:string milk:string sugars:string"
189
- end
190
- end
191
-
192
- =begin
193
- describe "when morph method used to set unicode attribute name with a value" do
194
- before :all do initialize_morph; end
195
- after :all do remove_morph_methods; end
196
-
197
- before :each do
198
- $KCODE = "u" unless RUBY_VERSION >= "1.9"
199
- remove_morph_methods
200
- @age = 19
201
- @attribute = "年龄"
202
- @morph.morph(@attribute, @age)
203
- @expected_morph_methods_count = 2
204
- end
205
-
206
- after :all do
207
- $KCODE = "NONE" unless RUBY_VERSION >= "1.9"
208
- end
209
-
210
- it_should_behave_like "class with generated accessor methods added"
211
-
212
- it 'should return assigned value when reader method called' do
213
- @morph.send(@attribute.to_sym) == @age
214
- end
215
- end
216
- describe "when morph method used to set japanese and latin unicode attribute name with a value" do
217
- before :all do initialize_morph; end
218
- after :all do remove_morph_methods; end
219
-
220
- before :each do
221
- $KCODE = "u" unless RUBY_VERSION >= "1.9"
222
- remove_morph_methods
223
- @age = 19
224
- @attribute = "ページビュー_graph"
225
- @morph.morph(@attribute, @age)
226
- @expected_morph_methods_count = 2
227
- end
228
-
229
- after :all do
230
- $KCODE = "NONE" unless RUBY_VERSION >= "1.9"
231
- end
232
-
233
- it_should_behave_like "class with generated accessor methods added"
234
-
235
- it 'should return assigned value when reader method called' do
236
- @morph.send(@attribute.to_sym) == @age
237
- end
238
- end
239
- =end
240
- describe 'when morph method used to set blank space attribute value' do
241
- before :each do
242
- remove_morph_methods
243
- @morph.morph('Pizza', ' ')
244
- @attribute = 'pizza'
245
- end
246
-
247
- it_should_behave_like "class without generated accessor methods added"
248
- end
249
-
250
- describe 'when morph method used to set nil attribute value' do
251
- before :each do
252
- remove_morph_methods
253
- @morph.morph('Pizza', nil)
254
- @attribute = 'pizza'
255
- end
256
-
257
- it_should_behave_like "class without generated accessor methods added"
258
- end
259
-
260
-
261
- describe "when reader method that didn't exist before is called" do
262
-
263
- include MorphSpecHelperMethods
264
-
265
- it 'should raise NoMethodError' do
266
- initialize_morph
267
- lambda { @morph.noise }.should raise_error(/undefined method `noise'/)
268
- end
269
- end
270
-
271
- describe "when reader method called that didn't exist before is a class method" do
272
-
273
- include MorphSpecHelperMethods
274
-
275
- it 'should raise NoMethodError' do
276
- initialize_morph
277
- lambda { @morph.name }.should raise_error(/undefined method `name'/)
278
- end
279
- end
280
-
281
- describe "when writer method called matches a class reader method" do
282
-
283
- before :all do initialize_morph; end
284
- after :all do remove_morph_methods; end
285
-
286
- before :each do
287
- remove_morph_methods
288
- @value = 'Morph'
289
- @morph.name = @value
290
- @attribute = 'name'
291
- @expected_morph_methods_count = 2
292
- end
293
-
294
- it_should_behave_like "class with generated accessor methods added"
295
-
296
- it 'should return assigned value when reader method called' do
297
- @morph.name.should == @value
298
- end
299
- end
300
-
301
-
302
- describe "when class= is called" do
303
-
304
- include MorphSpecHelperMethods
305
- before :all do initialize_morph; end
306
- after :all do remove_morph_methods; end
307
-
308
- it 'should throw exception if non nil object is passed' do
309
- lambda { @morph.class = 'Red' }.should raise_error(/cannot create accessor methods/)
310
- end
311
-
312
- it 'should throw exception if nil object is passed' do
313
- lambda { @morph.class = nil }.should raise_error(/cannot create accessor methods/)
314
- end
315
- end
316
-
317
- describe 'when passing block to morph_method_missing' do
318
-
319
- include MorphSpecHelperMethods
320
- before :all do initialize_morph; end
321
- after :each do remove_morph_methods; end
322
-
323
- it 'should class_eval the block' do
324
- @morph.morph_method_missing(:chunky, 'bacon') do |base, attribute|
325
- base.class_eval "def #{attribute}; 'spinach'; end"
326
- end
327
- @morph.respond_to?(:chunky).should == true
328
- @morph.chunky.should == 'spinach'
329
- @morphed_class.class_eval "remove_method :chunky"
330
- lambda { @morph.chunky }.should raise_error
331
- end
332
-
333
- it 'should class_eval the block' do
334
- @morph.morph_method_missing :chunky, 'bacon' do |base, attribute|
335
- base.class_def(attribute) { 'spinach' }
336
- end
337
- @morph.respond_to?(:chunky).should == true
338
- @morph.chunky.should == 'spinach'
339
- @morphed_class.class_eval "remove_method :chunky"
340
- lambda { @morph.chunky }.should raise_error
341
- end
342
-
343
- end
344
-
345
- describe "when converting label text to morph method name" do
346
-
347
- include MorphSpecHelperMethods
348
-
349
- it 'should covert dash to underscore' do
350
- check_convert_to_morph_method_name 'hi-time', 'hi_time'
351
- end
352
- it 'should upper case to lower case' do
353
- check_convert_to_morph_method_name 'CaSe', 'case'
354
- end
355
- it 'should convert single space to underscorce' do
356
- check_convert_to_morph_method_name 'First reading', 'first_reading'
357
- end
358
- it 'should convert multiple spaces to single underscorce' do
359
- check_convert_to_morph_method_name "First reading", 'first_reading'
360
- end
361
- it 'should convert tabs to single underscorce' do
362
- check_convert_to_morph_method_name "First\t\treading", 'first_reading'
363
- end
364
- it 'should convert new line chars to single underscorce' do
365
- check_convert_to_morph_method_name "First\r\nreading", 'first_reading'
366
- end
367
- it 'should remove leading and trailing whitespace new line chars to single underscorce' do
368
- check_convert_to_morph_method_name " \t\r\nFirst reading \t\r\n", 'first_reading'
369
- end
370
- it 'should remove trailing colon surrounded by whitespace' do
371
- check_convert_to_morph_method_name "First reading : ", 'first_reading'
372
- end
373
- it 'should remove parenthesis' do
374
- check_convert_to_morph_method_name 'Nav(GBX)', 'nav_gbx'
375
- end
376
- it 'should remove *' do
377
- check_convert_to_morph_method_name 'Change**', 'change'
378
- end
379
- it 'should convert % character to the text "percentage"' do
380
- check_convert_to_morph_method_name '% Change', 'percentage_change'
381
- end
382
- it 'should precede leading digit with an underscore character' do
383
- check_convert_to_morph_method_name '52w_high', '_52w_high'
384
- end
385
- it 'should handle unicode name' do
386
- check_convert_to_morph_method_name '年龄', '年龄'
387
- end
388
- end
389
-
390
- describe 'creating from hash' do
391
- it 'should create classes and object instances with array of hashes' do
392
- h = {
393
- "CompanyDetails"=> {
394
- "SearchItems"=> [
395
- { "CompanyDate"=> '',
396
- "CompanyIndexStatus"=> '',
397
- "DataSet"=>"LIVE",
398
- "CompanyName"=>"CANONGROVE LIMITED",
399
- "CompanyNumber"=>"SC244777" },
400
- { "CompanyDate"=>"",
401
- "CompanyIndexStatus"=>"",
402
- "DataSet"=>"LIVE",
403
- "CompanyName"=>"CANONHALL ACCOUNTANCY LTD",
404
- "CompanyNumber"=>"05110715" }
405
- ]
406
- }
407
- }
408
- company_details = Morph.from_hash(h)
409
- company_details.search_items.first.class.name.should == 'Morph::SearchItem'
410
- company_details.search_items.first.data_set.should == 'LIVE'
411
- company_details.search_items.first.company_name.should == 'CANONGROVE LIMITED'
412
- end
413
-
414
- it 'should create classes and object instances' do
415
- h = {
416
- "CompanyDetails"=> {
417
- :RegAddress=> {
418
- "AddressLine"=>["ST DAVID'S HOUSE", "WEST WING", "WOOD STREET", "CARDIFF CF10 1ES"]},
419
- "LastFullMemDate"=>"2002-03-25",
420
- "xsi:schemaLocation"=>"xmlgwdev.companieshouse.gov.uk/v1-0/schema/CompanyDetails.xsd",
421
- "HasBranchInfo"=>"0",
422
- "Mortgages"=> {
423
- "NumMortSatisfied"=>"0",
424
- "MortgageInd"=>"LT300",
425
- "NumMortOutstanding"=>"7",
426
- "NumMortPartSatisfied"=>"0",
427
- "NumMortCharges"=>"7"},
428
- "CompanyCategory"=>"Public Limited Company",
429
- "HasAppointments"=>"1",
430
- "SICCodes"=> {
431
- "SicText"=>"stadiums"},
432
- "Returns"=> {
433
- "Overdue"=>"NO",
434
- "DocumentAvailable"=>"1",
435
- "NextDueDate"=>"2003-04-22",
436
- "LastMadeUpDate"=>"2002-03-25"
437
- },
438
- "CountryOfOrigin"=>"United Kingdom",
439
- "CompanyStatus"=>"Active",
440
- "CompanyName"=>"MILLENNIUM STADIUM PLC",
441
- "InLiquidation"=>"0",
442
- "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
443
- "Accounts"=>{
444
- "Overdue"=>"NO",
445
- "DocumentAvailable"=>"1",
446
- "AccountCategory"=>"FULL",
447
- "NextDueDate"=>"2002-11-30",
448
- "LastMadeUpDate"=>"2001-04-30",
449
- "AccountRefDate"=>"0000-30-04"},
450
- "IncorporationDate"=>"1996-03-25",
451
- "CompanyNumber"=>"03176906",
452
- "xmlns"=>"http://xmlgw.companieshouse.gov.uk/v1-0"
453
- }
454
- }
455
- Object.const_set 'Company', Module.new
456
- Company.const_set 'House', Module.new
457
-
458
- company_details = Morph.from_hash(h, Company::House)
459
- company_details.class.name.should == 'Company::House::CompanyDetails'
460
- morph_methods = company_details.class.morph_methods
461
- if RUBY_VERSION >= "1.9"
462
- morph_methods.include?(:last_full_mem_date).should be_true
463
- morph_methods.include?(:accounts).should be_true
464
- morph_methods.delete(:accounts)
465
- morph_methods.include?(:accounts).should be_false
466
- morph_methods = company_details.class.morph_methods
467
- morph_methods.include?(:accounts).should be_true
468
- else
469
- morph_methods.include?('last_full_mem_date').should be_true
470
- morph_methods.include?('accounts').should be_true
471
- morph_methods.delete('accounts')
472
- morph_methods.include?('accounts').should be_false
473
- morph_methods = company_details.class.morph_methods
474
- morph_methods.include?('accounts').should be_true
475
- end
476
-
477
- company_details.accounts.class.name.should == 'Company::House::Accounts'
478
- company_details.accounts.overdue.should == 'NO'
479
- company_details.last_full_mem_date.should == "2002-03-25"
480
- company_details.sic_codes.sic_text.should == 'stadiums'
481
- company_details.reg_address.address_lines.should == ["ST DAVID'S HOUSE", "WEST WING", "WOOD STREET", "CARDIFF CF10 1ES"]
482
-
483
- list = Morph.generate_migrations company_details, :ignore=>['xmlns','xmlns_xsi','xsi_schema_location']
484
- list.size.should == 7
485
- list[0].should == "./script/generate model company_details company_category:string company_name:string company_number:string company_status:string country_of_origin:string has_appointments:string has_branch_info:string in_liquidation:string incorporation_date:date last_full_mem_date:date"
486
- list[1].should == './script/generate model accounts company_details_id:integer account_category:string account_ref_date:date document_available:string last_made_up_date:date next_due_date:date overdue:string'
487
- list[2].should == './script/generate model mortgages company_details_id:integer mortgage_ind:string num_mort_charges:string num_mort_outstanding:string num_mort_part_satisfied:string num_mort_satisfied:string'
488
- list[3].should == './script/generate model reg_address company_details_id:integer'
489
- list[4].should == './script/generate model address_lines reg_address_id:integer'
490
- list[5].should == './script/generate model returns company_details_id:integer document_available:string last_made_up_date:date next_due_date:date overdue:string'
491
- list[6].should == './script/generate model sic_codes company_details_id:integer sic_text:string'
492
-
493
- yaml = %Q|--- !ruby/object:Company::House::CompanyDetails
494
- accounts: !ruby/object:Company::House::Accounts
495
- account_category: FULL
496
- account_ref_date: "0000-30-04"
497
- document_available: "1"
498
- last_made_up_date: "2001-04-30"
499
- next_due_date: "2002-11-30"
500
- overdue: "NO"
501
- company_category: Public Limited Company
502
- company_name: MILLENNIUM STADIUM PLC
503
- company_number: 03176906
504
- company_status: Active
505
- country_of_origin: United Kingdom
506
- has_appointments: "1"
507
- has_branch_info: "0"
508
- in_liquidation: "0"
509
- incorporation_date: "1996-03-25"
510
- last_full_mem_date: "2002-03-25"
511
- mortgages: !ruby/object:Company::House::Mortgages
512
- mortgage_ind: LT300
513
- num_mort_charges: "7"
514
- num_mort_outstanding: "7"
515
- num_mort_part_satisfied: "0"
516
- num_mort_satisfied: "0"
517
- reg_address: !ruby/object:Company::House::RegAddress
518
- address_lines:
519
- - ST DAVID'S HOUSE
520
- - WEST WING
521
- - WOOD STREET
522
- - CARDIFF CF10 1ES
523
- returns: !ruby/object:Company::House::Returns
524
- document_available: "1"
525
- last_made_up_date: "2002-03-25"
526
- next_due_date: "2003-04-22"
527
- overdue: "NO"
528
- sic_codes: !ruby/object:Company::House::SICCodes
529
- sic_text: stadiums
530
- xmlns: http://xmlgw.companieshouse.gov.uk/v1-0
531
- xmlns_xsi: http://www.w3.org/2001/XMLSchema-instance
532
- xsi_schema_location: xmlgwdev.companieshouse.gov.uk/v1-0/schema/CompanyDetails.xsd|
533
- end
534
- end
535
-
536
- describe 'creating from xml' do
537
-
538
- def check_councils councils, class_name
539
- councils.class.should == Array
540
- councils.size.should == 2
541
- councils.first.class.name.should == class_name
542
- councils.first.name.should == 'Aberdeen City Council'
543
- councils.last.name.should == 'Allerdale Borough Council'
544
- end
545
-
546
- it 'should create classes and object instances' do
547
- councils = Morph.from_xml(xml)
548
- check_councils councils, 'Morph::Council'
549
- end
550
-
551
- describe 'when module name is supplied' do
552
- it 'should create classes and object instances' do
553
- Object.const_set 'Ppc', Module.new
554
- councils = Morph.from_xml(xml, Ppc)
555
- check_councils councils, 'Ppc::Council'
556
- end
557
- end
558
-
559
- def xml
560
- %Q[<?xml version="1.0" encoding="UTF-8"?>
561
- <councils type="array">
562
- <council code='1'>
563
- <name>Aberdeen City Council</name>
564
- </council>
565
- <council code='2'>
566
- <name>Allerdale Borough Council</name>
567
- </council>
568
- </councils>]
569
- end
570
- end
571
-
572
- describe 'creating from' do
573
-
574
- def check_councillors councillors, class_name, nil_value=''
575
- councillors.class.should == Array
576
- councillors.size.should == 2
577
- councillor = councillors.first
578
- councillor.class.name.should == class_name
579
- councillor.name.should == 'Ted Roe'
580
- councillor.party.should == 'labour'
581
- councillor.councillors.should == 'Councillor for Stretford Ward'
582
- councillor.councils.should == 'Trafford Council'
583
- councillor.respond_to?(:council_experience).should be_false
584
-
585
- councillor = councillors.last
586
- councillor.name.should == 'Ali Davidson'
587
- councillor.party.should == 'labour'
588
- councillor.councillors.should == nil_value
589
- councillor.councils.should == 'Basildon District Council'
590
- councillor.respond_to?(:council_experience).should be_false
591
- end
592
-
593
- describe 'tsv (tab separated value)' do
594
- describe 'when class name is supplied' do
595
- it 'should create classes and object instances' do
596
- councillors = Morph.from_tsv(tsv, 'Councillor')
597
- check_councillors councillors, 'Morph::Councillor'
598
- end
599
- end
600
-
601
- describe 'when class name and module name is supplied' do
602
- it 'should create classes and object instances' do
603
- Object.const_set 'Ppc', Module.new unless defined? Ppc
604
- councillors = Morph.from_tsv(tsv, 'Councillor', Ppc)
605
- check_councillors councillors, 'Ppc::Councillor'
606
- end
607
- end
608
-
609
- def tsv
610
- %Q[name party councillors councils council_experience
611
- Ted Roe labour Councillor for Stretford Ward Trafford Council
612
- Ali Davidson labour Basildon District Council
613
- ]
614
- end
615
- end
616
-
617
- describe 'csv (comma separated value)' do
618
- describe 'when class name is supplied' do
619
- it 'should create classes and object instances' do
620
- councillors = Morph.from_csv(csv, 'Councillor')
621
- check_councillors councillors, 'Morph::Councillor', nil
622
- end
623
- end
624
-
625
- describe 'when class name and module name is supplied' do
626
- it 'should create classes and object instances' do
627
- Object.const_set 'Ppc', Module.new unless defined? Ppc
628
- councillors = Morph.from_csv(csv, 'Councillor', Ppc)
629
- check_councillors councillors, 'Ppc::Councillor', nil
630
- end
631
- end
632
-
633
- def csv
634
- %Q[name,party,councillors,councils,council_experience
635
- Ted Roe,labour,Councillor for Stretford Ward,Trafford Council,
636
- Ali Davidson,labour,,Basildon District Council,
637
- ]
638
- end
639
- end
640
- end
641
-
642
- end
@@ -1,147 +0,0 @@
1
- # encoding: utf-8
2
- require File.dirname(__FILE__) + '/../lib/morph'
3
-
4
- module MorphSpecHelperMethods
5
-
6
- def initialize_morph_class code=nil
7
- code = 'class ExampleMorph; include Morph; end' unless code
8
- eval code
9
- @morphed_class = ExampleMorph
10
- end
11
-
12
- def initialize_second_morph_class code=nil
13
- code = 'class AnotherMorph; include Morph; end' unless code
14
- eval code
15
- @another_morphed_class = AnotherMorph
16
- end
17
-
18
- def initialize_morph code=nil
19
- initialize_morph_class code
20
- @original_instance_methods = @morphed_class.instance_methods
21
- @morph = @morphed_class.new
22
- end
23
-
24
- def initialize_another_morph
25
- initialize_second_morph_class
26
- @more_original_instance_methods = @another_morphed_class.instance_methods
27
- @another_morph = @another_morphed_class.new
28
- end
29
-
30
- def remove_morph_methods
31
- @morphed_class.instance_methods.each do |method|
32
- begin
33
- unless method.to_s[/received_message\?|should_not_receive|rspec_verify|unstub|rspec_reset|should_receive|as_null_object|stub_chain|stub\!|null_object?|stub/]
34
- remove_cmd = "remove_method :#{method}"
35
- @morphed_class.class_eval remove_cmd unless @original_instance_methods.include?(method)
36
- end
37
- rescue Exception => e
38
- raise e.to_s + '------' + @original_instance_methods.sort.inspect
39
- end
40
-
41
- end if @morphed_class
42
- end
43
-
44
- def remove_another_morph_methods
45
- @another_morphed_class.instance_methods.each do |method|
46
- @another_morphed_class.class_eval "remove_method :#{method}" unless @more_original_instance_methods.include?(method)
47
- end
48
- end
49
-
50
- def instance_methods
51
- @morphed_class.instance_methods
52
- end
53
-
54
- def morph_methods
55
- @morphed_class.morph_methods
56
- end
57
-
58
- def check_convert_to_morph_method_name label, method_name
59
- code = 'class ExampleMorph; include Morph; def convert_to_morph_method_name label; super; end; end'
60
- eval code
61
- ExampleMorph.new.convert_to_morph_method_name(label).should == method_name
62
- end
63
-
64
- def each_attribute
65
- if @attribute
66
- yield @attribute
67
- elsif @attributes
68
- @attributes.each {|a| yield a }
69
- end
70
- end
71
- end
72
-
73
- shared_examples_for "class with generated accessor methods added" do
74
-
75
- include MorphSpecHelperMethods
76
- before :all do initialize_morph; end
77
- after :all do remove_morph_methods; end
78
-
79
- it 'should add reader method to class instance_methods list' do
80
- if RUBY_VERSION >= "1.9"
81
- each_attribute { |a| instance_methods.should include(a.to_s.to_sym) }
82
- else
83
- each_attribute { |a| instance_methods.should include(a.to_s) }
84
- end
85
- end
86
-
87
- it 'should add writer method to class instance_methods list' do
88
- if RUBY_VERSION >= "1.9"
89
- each_attribute { |a| instance_methods.should include("#{a}=".to_sym) }
90
- else
91
- each_attribute { |a| instance_methods.should include("#{a}=") }
92
- end
93
- end
94
-
95
- it 'should add reader method to class morph_methods list' do
96
- if RUBY_VERSION >= "1.9"
97
- each_attribute { |a| morph_methods.should include(a.to_s.to_sym) }
98
- else
99
- each_attribute { |a| morph_methods.should include(a.to_s) }
100
- end
101
- end
102
-
103
- it 'should add writer method to class morph_methods list' do
104
- if RUBY_VERSION >= "1.9"
105
- each_attribute { |a| morph_methods.should include("#{a}=".to_sym) }
106
- else
107
- each_attribute { |a| morph_methods.should include("#{a}=") }
108
- end
109
- end
110
-
111
- it 'should only have generated accessor methods in morph_methods list' do
112
- morph_methods.size.should == @expected_morph_methods_count
113
- end
114
-
115
- end
116
-
117
- shared_examples_for "class without generated accessor methods added" do
118
- include MorphSpecHelperMethods
119
-
120
- before :all do
121
- initialize_morph
122
- end
123
-
124
- after :all do
125
- remove_morph_methods
126
- end
127
-
128
- it 'should not add reader method to class instance_methods list' do
129
- instance_methods.should_not include(@attribute)
130
- end
131
-
132
- it 'should not add writer method to class instance_methods list' do
133
- instance_methods.should_not include("#{@attribute}=")
134
- end
135
-
136
- it 'should not add reader method to class morph_methods list' do
137
- morph_methods.should_not include(@attribute)
138
- end
139
-
140
- it 'should not add writer method to class morph_methods list' do
141
- morph_methods.should_not include("#{@attribute}=")
142
- end
143
-
144
- it 'should have empty morph_methods list' do
145
- morph_methods.size.should == 0
146
- end
147
- end
data/spec/spec_helper.rb DELETED
@@ -1,3 +0,0 @@
1
- RSpec.configure do |config|
2
- config.mock_with :rspec
3
- end