morph 0.2.8 → 0.2.9

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.2.9. added from_csv(); require fastercsv; added morph_attributes() class method
2
+
1
3
  v0.2.8. added from_xml() and from_tsv(); updated for active_support; fixed from_hash() when hash root is an array
2
4
 
3
5
  v0.2.7. handle dash when converting to method name, reported by danwrong
data/README CHANGED
@@ -1,12 +1,51 @@
1
1
  Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.
2
2
 
3
3
 
4
+ == Morph creating classes +from_xml+
5
+
6
+ Here's example code showing Morph playing with XML:
7
+
8
+ require 'rubygems'; require 'morph'
9
+
10
+ xml = %Q[<?xml version="1.0" encoding="UTF-8"?>
11
+ <councils type="array">
12
+ <council code='1'>
13
+ <name>Aberdeen City Council</name>
14
+ </council>
15
+ <council code='2'>
16
+ <name>Allerdale Borough Council</name>
17
+ </council>
18
+ </councils>]
19
+
20
+ councils = Morph.from_xml(xml)
21
+ # => [#<Morph::Council @code="1", @name="Aberdeen City Council">,
22
+ #<Morph::Council @code="2", @name="Allerdale Borough Council">]
23
+
24
+ councils.first.name
25
+ # => "Aberdeen City Council"
26
+
27
+ == Morph creating classes +from_tsv+
28
+
29
+ Here's example code showing Morph playing with TSV (tab-separated values):
30
+
31
+ require 'rubygems'; require 'morph'
32
+
33
+ tsv = %Q[name\tparty\nTed Roe\tred\nAli Davidson\tblue\nSue Smith\tgreen]
34
+
35
+ people = Morph.from_tsv(tsv, 'person')
36
+ # => [#<Morph::Person @name="Ted Roe", @party="red">,
37
+ #<Morph::Person @name="Ali Davidson", @party="blue">,
38
+ #<Morph::Person @name="Sue Smith", @party="green">]
39
+
40
+ people.last.party
41
+ # => "green"
4
42
 
5
43
  == Morph playing with +Hpricot+
6
44
 
7
45
  Here's example code showing Morph playing with Hpricot:
8
46
 
9
- require 'hpricot'; require 'open-uri'; require 'morph'
47
+ require 'rubygems'; require 'hpricot'; require 'open-uri'
48
+ require 'morph'
10
49
 
11
50
  class Hubbit
12
51
  include Morph # allows class to morph
data/Rakefile CHANGED
@@ -18,6 +18,7 @@ begin
18
18
  m.rubyforge_name = "morph"
19
19
  m.rdoc_options << '--inline-source'
20
20
  m.dependencies = ["activesupport >=2.0.2"]
21
+ m.dependencies = ["fastercsv >=1.5.0"]
21
22
  m.rdoc_pattern = ["README", "CHANGELOG", "LICENSE"]
22
23
  end
23
24
 
data/lib/morph.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'fastercsv'
1
2
  begin
2
3
  require 'active_support/core_ext/object/blank'
3
4
  require 'active_support/inflector'
@@ -13,7 +14,7 @@ rescue Exception => e
13
14
  end
14
15
 
15
16
  module Morph
16
- VERSION = "0.2.8"
17
+ VERSION = "0.2.9"
17
18
 
18
19
  class << self
19
20
  def generate_migrations object, options={}
@@ -24,6 +25,18 @@ module Morph
24
25
  add_migration name, object.morph_attributes, migrations, options
25
26
  end
26
27
 
28
+ def from_csv csv, class_name, namespace=Morph
29
+ objects = []
30
+ FasterCSV.parse(csv, { :headers => true }) do |row|
31
+ object = object_from_name class_name, namespace
32
+ row.each do |key, value|
33
+ object.morph(key, value)
34
+ end
35
+ objects << object
36
+ end
37
+ objects
38
+ end
39
+
27
40
  def from_tsv tsv, class_name, namespace=Morph
28
41
  lines = tsv.split("\n")
29
42
  attributes = lines[0].split("\t")
@@ -85,8 +98,7 @@ module Morph
85
98
  type = attribute_name[/date$/] ? 'date' : 'string'
86
99
  attribute_def = "#{attribute}:#{type}"
87
100
  migration.sub!(migration, "#{migration} #{attribute_def}")
88
- end
89
- when Array
101
+ end when Array
90
102
  options[:belongs_to_id] = " #{name}_id:integer"
91
103
  migrations = add_migration(attribute, '', migrations, options)
92
104
  when Hash
@@ -155,6 +167,11 @@ module Morph
155
167
 
156
168
  @@adding_morph_method = Hash.new {|hash,klass| hash[klass] = false }
157
169
  @@morph_methods = Hash.new {|hash,klass| hash[klass] = {} }
170
+ @@morph_attributes = Hash.new {|hash,klass| hash[klass] = [] }
171
+
172
+ def morph_attributes
173
+ @@morph_attributes[self] + []
174
+ end
158
175
 
159
176
  def morph_methods
160
177
  @@morph_methods[self].keys.sort
@@ -189,11 +206,19 @@ module Morph
189
206
  protected
190
207
 
191
208
  def method_added symbol
192
- @@morph_methods[self][symbol.to_s] = true if @@adding_morph_method[self]
209
+ if @@adding_morph_method[self]
210
+ @@morph_methods[self][symbol.to_s] = true
211
+ is_writer = symbol.to_s =~ /=$/
212
+ @@morph_attributes[self] << symbol unless is_writer
213
+ end
193
214
  end
194
215
 
195
216
  def method_removed symbol
196
- @@morph_methods[self].delete symbol.to_s if @@morph_methods[self].has_key? symbol.to_s
217
+ if @@morph_methods[self].has_key? symbol.to_s
218
+ @@morph_methods[self].delete symbol.to_s
219
+ is_writer = symbol.to_s =~ /=$/
220
+ @@morph_attributes[self].delete(symbol) unless is_writer
221
+ end
197
222
  end
198
223
 
199
224
  end
@@ -282,7 +307,7 @@ module Morph
282
307
  end
283
308
 
284
309
  def convert_to_morph_method_name label
285
- name = label.to_s.downcase.tr('()\-*',' ').gsub('%','percentage').strip.chomp(':').strip.gsub(/\s/,'_').squeeze('_')
310
+ name = label.to_s.downcase.tr('()\-*',' ').gsub("'",' ').gsub('/',' ').gsub('%','percentage').strip.chomp(':').strip.gsub(/\s/,'_').squeeze('_')
286
311
  name = '_'+name if name =~ /^\d/
287
312
  name
288
313
  end
data/morph.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{morph}
5
- s.version = "0.2.8"
5
+ s.version = "0.2.9"
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 = %q{2010-02-09}
9
+ s.date = %q{2010-04-04}
10
10
  s.description = %q{Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.
11
11
  }
12
12
  s.email = ["rob ~@nospam@~ rubyforge.org"]
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
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 = %q{morph}
19
- s.rubygems_version = %q{1.3.5}
19
+ s.rubygems_version = %q{1.3.6}
20
20
  s.summary = %q{Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.}
21
21
 
22
22
  if s.respond_to? :specification_version then
@@ -24,11 +24,11 @@ Gem::Specification.new do |s|
24
24
  s.specification_version = 3
25
25
 
26
26
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
- s.add_runtime_dependency(%q<activesupport>, [">= 2.0.2"])
27
+ s.add_runtime_dependency(%q<fastercsv>, [">= 1.5.0"])
28
28
  else
29
- s.add_dependency(%q<activesupport>, [">= 2.0.2"])
29
+ s.add_dependency(%q<fastercsv>, [">= 1.5.0"])
30
30
  end
31
31
  else
32
- s.add_dependency(%q<activesupport>, [">= 2.0.2"])
32
+ s.add_dependency(%q<fastercsv>, [">= 1.5.0"])
33
33
  end
34
34
  end
@@ -91,6 +91,15 @@ describe Morph do
91
91
  attributes = @morph.morph_attributes
92
92
  attributes[:every].should == 'which'
93
93
  attributes[:loose].should == { :honky_tonk => {:way => 'but'} }
94
+ attributes.delete(:every)
95
+ attributes = @morph.morph_attributes
96
+ attributes[:every].should == 'which'
97
+
98
+ attributes = @morph.class.morph_attributes
99
+ attributes.should == [:every, :loose]
100
+ attributes.delete(:every)
101
+ attributes = @morph.class.morph_attributes
102
+ attributes.should == [:every, :loose]
94
103
  end
95
104
 
96
105
  after :each do
@@ -424,9 +433,15 @@ describe Morph do
424
433
 
425
434
  company_details = Morph.from_hash(h, Company::House)
426
435
  company_details.class.name.should == 'Company::House::CompanyDetails'
427
- company_details.class.morph_methods.include?('last_full_mem_date').should be_true
428
- company_details.class.morph_methods.include?('accounts').should be_true
429
-
436
+ morph_methods = company_details.class.morph_methods
437
+ morph_methods.include?('last_full_mem_date').should be_true
438
+ morph_methods.include?('accounts').should be_true
439
+
440
+ morph_methods.delete('accounts')
441
+ morph_methods.include?('accounts').should be_false
442
+ morph_methods = company_details.class.morph_methods
443
+ morph_methods.include?('accounts').should be_true
444
+
430
445
  company_details.accounts.class.name.should == 'Company::House::Accounts'
431
446
  company_details.accounts.overdue.should == 'NO'
432
447
  company_details.last_full_mem_date.should == "2002-03-25"
@@ -512,19 +527,19 @@ xsi_schema_location: xmlgwdev.companieshouse.gov.uk/v1-0/schema/CompanyDetails.x
512
527
  def xml
513
528
  %Q[<?xml version="1.0" encoding="UTF-8"?>
514
529
  <councils type="array">
515
- <council>
530
+ <council code='1'>
516
531
  <name>Aberdeen City Council</name>
517
532
  </council>
518
- <council>
533
+ <council code='2'>
519
534
  <name>Allerdale Borough Council</name>
520
535
  </council>
521
536
  </councils>]
522
537
  end
523
538
  end
524
539
 
525
- describe 'creating from tsv (tab separated value)' do
540
+ describe 'creating from' do
526
541
 
527
- def check_councillors councillors, class_name
542
+ def check_councillors councillors, class_name, nil_value=''
528
543
  councillors.class.should == Array
529
544
  councillors.size.should == 2
530
545
  councillor = councillors.first
@@ -538,31 +553,57 @@ xsi_schema_location: xmlgwdev.companieshouse.gov.uk/v1-0/schema/CompanyDetails.x
538
553
  councillor = councillors.last
539
554
  councillor.name.should == 'Ali Davidson'
540
555
  councillor.party.should == 'labour'
541
- councillor.councillors.should == ''
556
+ councillor.councillors.should == nil_value
542
557
  councillor.councils.should == 'Basildon District Council'
543
558
  councillor.respond_to?(:council_experience).should be_false
544
559
  end
545
560
 
546
- describe 'when class name is supplied' do
547
- it 'should create classes and object instances' do
548
- councillors = Morph.from_tsv(tsv, 'Councillor')
549
- check_councillors councillors, 'Morph::Councillor'
561
+ describe 'tsv (tab separated value)' do
562
+ describe 'when class name is supplied' do
563
+ it 'should create classes and object instances' do
564
+ councillors = Morph.from_tsv(tsv, 'Councillor')
565
+ check_councillors councillors, 'Morph::Councillor'
566
+ end
550
567
  end
551
- end
552
-
553
- describe 'when class name and module name is supplied' do
554
- it 'should create classes and object instances' do
555
- Object.const_set 'Ppc', Module.new
556
- councillors = Morph.from_tsv(tsv, 'Councillor', Ppc)
557
- check_councillors councillors, 'Ppc::Councillor'
568
+
569
+ describe 'when class name and module name is supplied' do
570
+ it 'should create classes and object instances' do
571
+ Object.const_set 'Ppc', Module.new
572
+ councillors = Morph.from_tsv(tsv, 'Councillor', Ppc)
573
+ check_councillors councillors, 'Ppc::Councillor'
574
+ end
558
575
  end
559
- end
560
576
 
561
- def tsv
562
- %Q[name party councillors councils council_experience
577
+ def tsv
578
+ %Q[name party councillors councils council_experience
563
579
  Ted Roe labour Councillor for Stretford Ward Trafford Council
564
580
  Ali Davidson labour Basildon District Council
565
581
  ]
582
+ end
583
+ end
584
+
585
+ describe 'csv (comma separated value)' do
586
+ describe 'when class name is supplied' do
587
+ it 'should create classes and object instances' do
588
+ councillors = Morph.from_csv(csv, 'Councillor')
589
+ check_councillors councillors, 'Morph::Councillor', nil
590
+ end
591
+ end
592
+
593
+ describe 'when class name and module name is supplied' do
594
+ it 'should create classes and object instances' do
595
+ Object.const_set 'Ppc', Module.new
596
+ councillors = Morph.from_csv(csv, 'Councillor', Ppc)
597
+ check_councillors councillors, 'Ppc::Councillor', nil
598
+ end
599
+ end
600
+
601
+ def csv
602
+ %Q[name,party,councillors,councils,council_experience
603
+ Ted Roe,labour,Councillor for Stretford Ward,Trafford Council,
604
+ Ali Davidson,labour,,Basildon District Council,
605
+ ]
606
+ end
566
607
  end
567
608
  end
568
609
 
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 9
9
+ version: 0.2.9
5
10
  platform: ruby
6
11
  authors:
7
12
  - Rob McKinnon
@@ -9,19 +14,23 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-09 00:00:00 +00:00
17
+ date: 2010-04-04 00:00:00 +01:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
- name: activesupport
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
21
+ name: fastercsv
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
20
24
  requirements:
21
25
  - - ">="
22
26
  - !ruby/object:Gem::Version
23
- version: 2.0.2
24
- version:
27
+ segments:
28
+ - 1
29
+ - 5
30
+ - 0
31
+ version: 1.5.0
32
+ type: :runtime
33
+ version_requirements: *id001
25
34
  description: |
26
35
  Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.
27
36
 
@@ -67,18 +76,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
76
  requirements:
68
77
  - - ">="
69
78
  - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
70
81
  version: "0"
71
- version:
72
82
  required_rubygems_version: !ruby/object:Gem::Requirement
73
83
  requirements:
74
84
  - - ">="
75
85
  - !ruby/object:Gem::Version
86
+ segments:
87
+ - 1
88
+ - 2
76
89
  version: "1.2"
77
- version:
78
90
  requirements: []
79
91
 
80
92
  rubyforge_project: morph
81
- rubygems_version: 1.3.5
93
+ rubygems_version: 1.3.6
82
94
  signing_key:
83
95
  specification_version: 3
84
96
  summary: Morph allows you to emerge class definitions via calling assignment methods; mix with Hpricot for screen scrapping fun.