dm-serializer 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1,10 @@
1
+ === 0.9.8 / 2008-12-07
1
2
 
3
+ * 2 minor enhancements:
4
+
5
+ * to_yaml and to_xml now support :only and :exclude options
6
+ * to_yaml and to_xml now support serializing methods
7
+
8
+ * 1 bug fix:
9
+
10
+ * gem requires now preceded by gem() call
@@ -10,11 +10,14 @@ lib/dm-serializer.rb
10
10
  lib/dm-serializer/version.rb
11
11
  spec/fixtures/cow.rb
12
12
  spec/fixtures/planet.rb
13
- spec/fixtures/quatum_cat.rb
13
+ spec/fixtures/quan_tum_cat.rb
14
+ spec/lib/serialization_method_shared_spec.rb
15
+ spec/public/serializer_spec.rb
16
+ spec/public/to_csv_spec.rb
17
+ spec/public/to_json_spec.rb
18
+ spec/public/to_xml_spec.rb
19
+ spec/public/to_yaml_spec.rb
14
20
  spec/spec.opts
15
21
  spec/spec_helper.rb
16
- spec/unit/serializer_spec.rb
17
- spec/unit/to_csv_spec.rb
18
- spec/unit/to_json_spec.rb
19
- spec/unit/to_xml_spec.rb
20
- spec/unit/to_yaml_spec.rb
22
+ tasks/install.rb
23
+ tasks/spec.rb
data/Rakefile CHANGED
@@ -1,58 +1,25 @@
1
- require 'rubygems'
2
- require 'spec'
3
- require 'spec/rake/spectask'
4
1
  require 'pathname'
2
+ require 'rubygems'
3
+
4
+ ROOT = Pathname(__FILE__).dirname.expand_path
5
+ JRUBY = RUBY_PLATFORM =~ /java/
6
+ WINDOWS = Gem.win_platform?
7
+ SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
5
8
 
6
- ROOT = Pathname(__FILE__).dirname.expand_path
7
9
  require ROOT + 'lib/dm-serializer/version'
8
10
 
9
- AUTHOR = "Guy van den Berg"
10
- EMAIL = "vandenberg.guy@gmail.com"
11
- GEM_NAME = "dm-serializer"
11
+ AUTHOR = 'Guy van den Berg'
12
+ EMAIL = 'vandenberg.guy [a] gmail [d] com'
13
+ GEM_NAME = 'dm-serializer'
12
14
  GEM_VERSION = DataMapper::Serializer::VERSION
13
- GEM_DEPENDENCIES = [["dm-core", GEM_VERSION]]
14
- GEM_CLEAN = ["log", "pkg", "coverage"]
15
- GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.txt LICENSE TODO ] }
16
-
17
- PROJECT_NAME = "datamapper"
18
- PROJECT_URL = "http://github.com/sam/dm-more/tree/master/dm-serializer"
19
- PROJECT_DESCRIPTION = PROJECT_SUMMARY = "DataMapper plugin for serializing DataMapper objects"
20
-
21
- require ROOT.parent + 'tasks/hoe'
22
-
23
- task :default => [ :spec ]
24
-
25
- WIN32 = (RUBY_PLATFORM =~ /win32|mingw|cygwin/) rescue nil
26
- SUDO = WIN32 ? '' : ('sudo' unless ENV['SUDOLESS'])
27
-
28
- desc "Install #{GEM_NAME} #{GEM_VERSION} (default ruby)"
29
- task :install => [ :package ] do
30
- sh "#{SUDO} gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources", :verbose => false
31
- end
32
-
33
- desc "Uninstall #{GEM_NAME} #{GEM_VERSION} (default ruby)"
34
- task :uninstall => [ :clobber ] do
35
- sh "#{SUDO} gem uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x", :verbose => false
36
- end
37
-
38
- namespace :jruby do
39
- desc "Install #{GEM_NAME} #{GEM_VERSION} with JRuby"
40
- task :install => [ :package ] do
41
- sh %{#{SUDO} jruby -S gem install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources}, :verbose => false
42
- end
43
- end
15
+ GEM_DEPENDENCIES = [['dm-core', "~>#{GEM_VERSION}"]]
16
+ GEM_CLEAN = %w[ log pkg coverage ]
17
+ GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.txt LICENSE TODO History.txt ] }
44
18
 
45
- desc 'Run specifications'
46
- Spec::Rake::SpecTask.new(:spec) do |t|
47
- t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
48
- t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s)
19
+ PROJECT_NAME = 'datamapper'
20
+ PROJECT_URL = "http://github.com/sam/dm-more/tree/master/#{GEM_NAME}"
21
+ PROJECT_DESCRIPTION = PROJECT_SUMMARY = 'DataMapper plugin for serializing DataMapper objects'
49
22
 
50
- begin
51
- t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
52
- t.rcov_opts << '--exclude' << 'spec'
53
- t.rcov_opts << '--text-summary'
54
- t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
55
- rescue Exception
56
- # rcov not installed
57
- end
23
+ [ ROOT, ROOT.parent ].each do |dir|
24
+ Pathname.glob(dir.join('tasks/**/*.rb').to_s).each { |f| require f }
58
25
  end
data/TODO CHANGED
@@ -1,8 +0,0 @@
1
- TODO
2
- ====
3
-
4
-
5
-
6
- ---
7
- TODO tickets may also be found in the DataMapper Issue Tracker:
8
- http://wm.lighthouseapp.com/projects/4819-datamapper/overview
@@ -1,36 +1,31 @@
1
- require Pathname('rexml/document')
1
+ require 'rexml/document'
2
2
 
3
3
  begin
4
+ gem('fastercsv')
4
5
  require 'faster_csv'
5
6
  rescue LoadError
6
7
  nil
7
8
  end
8
9
 
9
10
  begin
10
- require Pathname('json/ext')
11
+ gem('json')
12
+ require 'json/ext'
11
13
  rescue LoadError
12
- require Pathname('json/pure')
14
+ gem('json_pure')
15
+ require 'json/pure'
13
16
  end
14
17
 
15
18
  module DataMapper
16
19
  module Serialize
17
-
18
20
  # Serialize a Resource to JavaScript Object Notation (JSON; RFC 4627)
19
21
  #
20
22
  # @return <String> a JSON representation of the Resource
21
- def to_json(options = {})
23
+ def to_json(*args)
24
+ options = args.first || {}
22
25
  result = '{ '
23
26
  fields = []
24
27
 
25
- # FIXME: this should go into bunch of protected methods shared with other serialization methods
26
- only_properties = Array(options[:only])
27
- excluded_properties = Array(options[:exclude])
28
- exclude_read_only = options[:without_read_only_attributes] || false
29
-
30
- propset = self.class.properties(repository.name).reject do |p|
31
- next if only_properties.include? p.name
32
- excluded_properties.include?(p.name) || !(only_properties.empty? || only_properties.include?(p.name))
33
- end
28
+ propset = properties_to_serialize(options)
34
29
 
35
30
  fields += propset.map do |property|
36
31
  "#{property.name.to_json}: #{send(property.getter).to_json}"
@@ -96,10 +91,17 @@ module DataMapper
96
91
  def to_yaml(opts = {})
97
92
  YAML::quick_emit(object_id,opts) do |out|
98
93
  out.map(nil,to_yaml_style) do |map|
99
- self.class.properties(repository.name).each do |property|
94
+ propset = properties_to_serialize(opts)
95
+ propset.each do |property|
100
96
  value = send(property.name.to_sym)
101
97
  map.add(property.name, value.is_a?(Class) ? value.to_s : value)
102
98
  end
99
+ # add methods
100
+ (opts[:methods] || []).each do |meth|
101
+ if self.respond_to?(meth)
102
+ map.add(meth.to_sym, send(meth))
103
+ end
104
+ end
103
105
  (instance_variable_get("@yaml_addes") || []).each do |k,v|
104
106
  map.add(k.to_s,v)
105
107
  end
@@ -109,12 +111,31 @@ module DataMapper
109
111
 
110
112
  protected
111
113
 
114
+ # Returns propreties to serialize based on :only or :exclude arrays, if provided
115
+ # :only takes precendence over :exclude
116
+ #
117
+ # @return <Array> properties that need to be serialized
118
+ def properties_to_serialize(options)
119
+ only_properties = Array(options[:only])
120
+ excluded_properties = Array(options[:exclude])
121
+ exclude_read_only = options[:without_read_only_attributes] || false
122
+
123
+ self.class.properties(repository.name).reject do |p|
124
+ if only_properties.include? p.name
125
+ false
126
+ else
127
+ excluded_properties.include?(p.name) || !(only_properties.empty? || only_properties.include?(p.name))
128
+ end
129
+ end
130
+ end
131
+
132
+
112
133
  # Return the name of this Resource - to be used as the root element name.
113
134
  # This can be overloaded.
114
135
  #
115
136
  # @return <String> name of this Resource
116
137
  def xml_element_name
117
- Extlib::Inflection.underscore(self.class.name)
138
+ Extlib::Inflection.underscore(self.class.name).tr("/", "-")
118
139
  end
119
140
 
120
141
  # Return a REXML::Document representing this Resource
@@ -126,7 +147,8 @@ module DataMapper
126
147
 
127
148
  #TODO old code base was converting single quote to double quote on attribs
128
149
 
129
- self.class.properties(repository.name).each do |property|
150
+ propset = properties_to_serialize(opts)
151
+ propset.each do |property|
130
152
  value = send(property.name)
131
153
  node = root.add_element(property.name.to_s)
132
154
  unless property.type == String
@@ -134,6 +156,16 @@ module DataMapper
134
156
  end
135
157
  node << REXML::Text.new(value.to_s) unless value.nil?
136
158
  end
159
+
160
+ # add methods
161
+ (opts[:methods] || []).each do |meth|
162
+ if self.respond_to?(meth)
163
+ xml_name = meth.to_s.gsub(/[^a-z0-9_]/, '')
164
+ node = root.add_element(xml_name)
165
+ value = send(meth)
166
+ node << REXML::Text.new(value.to_s, :raw => true) unless value.nil?
167
+ end
168
+ end
137
169
  doc
138
170
  end
139
171
 
@@ -143,12 +175,27 @@ module DataMapper
143
175
  include Serialize
144
176
  end # module Resource
145
177
 
178
+ # the json gem adds Object#to_json, which breaks the DM proxies, since it
179
+ # happens *after* the proxy has been blank slated. This code removes the added
180
+ # method, so it is delegated correctly to the Collection
181
+ [
182
+ Associations::OneToMany::Proxy,
183
+ (Associations::ManyToOne::Proxy if defined?(Associations::ManyToOne::Proxy)),
184
+ Associations::ManyToMany::Proxy
185
+ ].each do |proxy|
186
+ [:to_json].each do |method|
187
+ proxy.send(:undef_method, :to_json) rescue nil
188
+ end
189
+ end
190
+
146
191
  class Collection
147
192
  def to_yaml(opts = {})
148
- to_a.to_yaml(opts)
193
+ # FIXME: Don't double handle the YAML (remove the YAML.load)
194
+ to_a.collect {|x| YAML.load(x.to_yaml(opts)) }.to_yaml
149
195
  end
150
196
 
151
- def to_json(opts = {})
197
+ def to_json(*args)
198
+ opts = args.first || {}
152
199
  "[" << map {|e| e.to_json(opts)}.join(",") << "]"
153
200
  end
154
201
 
@@ -166,7 +213,7 @@ module DataMapper
166
213
 
167
214
  protected
168
215
  def xml_element_name
169
- Extlib::Inflection.tableize(self.model.to_s)
216
+ Extlib::Inflection.pluralize(Extlib::Inflection.underscore(self.model.to_s)).tr("/", "-")
170
217
  end
171
218
 
172
219
  def to_xml_document(opts={})
@@ -1,5 +1,5 @@
1
1
  module DataMapper
2
2
  module Serializer
3
- VERSION = "0.9.7"
3
+ VERSION = '0.9.8'
4
4
  end
5
5
  end
@@ -6,6 +6,9 @@ class Cow
6
6
  property :name, String
7
7
  property :breed, String
8
8
 
9
+ has n, :baby_cows, :class_name => 'Cow'
10
+ belongs_to :mother_cow, :class_name => 'Cow'
11
+
9
12
  def serialize_properties
10
13
  {:extra => "Extra", :another => 42}
11
14
  end
@@ -4,6 +4,11 @@ class Planet
4
4
  property :name, String, :key => true
5
5
  property :aphelion, Float
6
6
 
7
+ # Sorry these associations don't make any sense
8
+ # I just needed a many-to-many association to test against
9
+ has n, :friended_planets
10
+ has n, :friend_planets, :through => :friended_planets, :class_name => 'Planet'
11
+
7
12
  def category
8
13
  case self.name.downcase
9
14
  when "mercury", "venus", "earth", "mars" then "terrestrial"
@@ -16,3 +21,13 @@ class Planet
16
21
  self.name.downcase == "earth"
17
22
  end
18
23
  end
24
+
25
+ class FriendedPlanet
26
+ include DataMapper::Resource
27
+
28
+ property :planet_name, String, :key => true
29
+ property :friend_planet_name, String, :key => true
30
+
31
+ belongs_to :planet, :child_key => [:planet_name]
32
+ belongs_to :friend_planet, :class_name => 'Planet', :child_key => [:friend_planet_name]
33
+ end
@@ -0,0 +1,15 @@
1
+ # Yes, this crazy capitalization is intentional,
2
+ # to test xml root element name generation
3
+ module QuanTum
4
+ class Cat
5
+ include DataMapper::Resource
6
+
7
+ property :id, Serial
8
+ property :name, String
9
+ property :location, String
10
+
11
+ repository(:alternate) do
12
+ property :is_dead, Boolean
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,193 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ share_examples_for 'A serialization method' do
5
+ before(:all) do
6
+ %w[ @harness ].each do |ivar|
7
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_get(ivar)
8
+ end
9
+
10
+ DataMapper.auto_migrate!
11
+ end
12
+
13
+ before(:each) do
14
+ Cow.all.destroy!
15
+ Planet.all.destroy!
16
+ FriendedPlanet.all.destroy!
17
+ end
18
+
19
+ describe '(serializing single resources)' do
20
+ it 'should serialize Model.first' do
21
+ # At the moment this is implied by serializing a resource, but this
22
+ # test ensures the contract even if dm-core changes
23
+ Cow.create(
24
+ :id => 89,
25
+ :composite => 34,
26
+ :name => 'Berta',
27
+ :breed => 'Guernsey'
28
+ )
29
+ result = @harness.test(Cow.first)
30
+ result.values_at("name", "breed").should == ["Berta", "Guernsey"]
31
+ end
32
+
33
+ it 'should serialize a resource' do
34
+ cow = Cow.new(
35
+ :id => 89,
36
+ :composite => 34,
37
+ :name => 'Berta',
38
+ :breed => 'Guernsey'
39
+ )
40
+
41
+ result = @harness.test(cow)
42
+ result.values_at("id", "composite", "name", "breed").should == [89, 34, 'Berta', 'Guernsey']
43
+ end
44
+
45
+ it 'should exclude nil properties' do
46
+ cow = Cow.new(
47
+ :id => 89,
48
+ :name => nil
49
+ )
50
+
51
+ result = @harness.test(cow)
52
+ result.values_at("id", "composite").should == [89, nil]
53
+ end
54
+
55
+ it "should only includes properties given to :only option" do
56
+ planet = Planet.new(
57
+ :name => "Mars",
58
+ :aphelion => 249_209_300.4
59
+ )
60
+
61
+ result = @harness.test(planet, :only => [:name])
62
+ result.values_at("name", "aphelion").should == ["Mars", nil]
63
+ end
64
+
65
+ it "should serialize values returned by methods given to :methods option" do
66
+ planet = Planet.new(
67
+ :name => "Mars",
68
+ :aphelion => 249_209_300.4
69
+ )
70
+
71
+ result = @harness.test(planet, :methods => [:category, :has_known_form_of_life?])
72
+ # XML currently can't serialize ? at the end of method names
73
+ boolean_method_name = @harness.method_name == :to_xml ? "has_known_form_of_life" : "has_known_form_of_life?"
74
+ result.values_at("category", boolean_method_name).should == ["terrestrial", false]
75
+ end
76
+
77
+ it "should only include properties given to :only option" do
78
+ planet = Planet.new(
79
+ :name => "Mars",
80
+ :aphelion => 249_209_300.4
81
+ )
82
+
83
+ result = @harness.test(planet, :only => [:name])
84
+ result.values_at("name", "aphelion").should == ["Mars", nil]
85
+ end
86
+
87
+ it "should exclude properties given to :exclude option" do
88
+ planet = Planet.new(
89
+ :name => "Mars",
90
+ :aphelion => 249_209_300.4
91
+ )
92
+
93
+ result = @harness.test(planet, :exclude => [:aphelion])
94
+ result.values_at("name", "aphelion").should == ["Mars", nil]
95
+ end
96
+
97
+ it "should give higher precendence to :only option over :exclude" do
98
+ planet = Planet.new(
99
+ :name => "Mars",
100
+ :aphelion => 249_209_300.4
101
+ )
102
+
103
+ result = @harness.test(planet, :only => [:name], :exclude => [:name])
104
+ result.values_at("name", "aphelion").should == ["Mars", nil]
105
+ end
106
+ end
107
+
108
+ describe "(collections and proxies)" do
109
+ it 'should serialize Model.all' do
110
+ # At the moment this is implied by serializing a collection, but this
111
+ # test ensures the contract even if dm-core changes
112
+ Cow.create(
113
+ :id => 89,
114
+ :composite => 34,
115
+ :name => 'Berta',
116
+ :breed => 'Guernsey'
117
+ )
118
+ result = @harness.test(Cow.all)
119
+ result[0].values_at("name", "breed").should == ["Berta", "Guernsey"]
120
+ end
121
+
122
+ it 'should serialize a collection' do
123
+ query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
124
+ collection = DataMapper::Collection.new(query) do |c|
125
+ c.load([1, 2, 'Betsy', 'Jersey'])
126
+ c.load([10, 20, 'Berta', 'Guernsey'])
127
+ end
128
+
129
+ result = @harness.test(collection)
130
+ result[0].values_at("id", "composite", "name", "breed").should == [1, 2, 'Betsy', 'Jersey']
131
+ result[1].values_at("id", "composite", "name", "breed").should == [10, 20, 'Berta', 'Guernsey']
132
+ end
133
+
134
+ it 'should serialize an empty collection' do
135
+ query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
136
+ collection = DataMapper::Collection.new(query) {}
137
+
138
+ result = @harness.test(collection)
139
+ result.should be_empty
140
+ end
141
+
142
+ it "serializes a one to many relationship" do
143
+ parent = Cow.new(:id => 1, :composite => 322, :name => "Harry", :breed => "Angus")
144
+ baby = Cow.new(:mother_cow => parent, :id => 2, :composite => 321, :name => "Felix", :breed => "Angus")
145
+
146
+ parent.save
147
+ baby.save
148
+
149
+ result = @harness.test(parent.baby_cows)
150
+ result.should be_kind_of(Array)
151
+
152
+ result[0].values_at(*%w{id composite name breed}).should == [2, 321, "Felix", "Angus"]
153
+ end
154
+
155
+ it "serializes a many to one relationship" do
156
+ parent = Cow.new(:id => 1, :composite => 322, :name => "Harry", :breed => "Angus")
157
+ baby = Cow.new(:mother_cow => parent, :id => 2, :composite => 321, :name => "Felix", :breed => "Angus")
158
+
159
+ parent.save
160
+ baby.save
161
+
162
+ result = @harness.test(baby.mother_cow)
163
+ result.should be_kind_of(Hash)
164
+ result.values_at(*%w{id composite name breed}).should == [1, 322, "Harry", "Angus"]
165
+ end
166
+
167
+ it "serializes a many to many relationship" do
168
+ p1 = Planet.create(:name => 'earth')
169
+ p2 = Planet.create(:name => 'mars')
170
+
171
+ FriendedPlanet.create(:planet => p1, :friend_planet => p2)
172
+
173
+ result = @harness.test(p1.reload.friend_planets)
174
+ result.should be_kind_of(Array)
175
+
176
+ result[0]["name"].should == "mars"
177
+ end
178
+ end
179
+
180
+ describe "(multiple repositories)" do
181
+ before(:all) do
182
+ QuanTum::Cat.auto_migrate!
183
+ repository(:alternate){QuanTum::Cat.auto_migrate!}
184
+ end
185
+
186
+ it "should use the repsoitory for the model" do
187
+ gerry = QuanTum::Cat.create(:name => "gerry")
188
+ george = repository(:alternate){QuanTum::Cat.create(:name => "george", :is_dead => false)}
189
+ @harness.test(gerry )['is_dead'].should be(nil)
190
+ @harness.test(george)['is_dead'].should be(false)
191
+ end
192
+ end
193
+ end
File without changes
@@ -23,24 +23,24 @@ describe DataMapper::Serialize, '#to_csv' do
23
23
  peter.composite = 344
24
24
  peter.name = 'Peter'
25
25
  peter.breed = 'Long Horn'
26
- peter.to_csv.chomp.should == '44,344,Peter,Long Horn'
26
+ peter.to_csv.chomp.split(',')[0..3].should == ['44','344','Peter','Long Horn']
27
27
  end
28
28
 
29
29
  it "should serialize a collection to CSV" do
30
- @collection.to_csv.gsub(/[[:space:]]+\n/, "\n").should ==
31
- "1,2,Betsy,Jersey\n" +
32
- "10,20,Berta,Guernsey\n"
30
+ result = @collection.to_csv.gsub(/[[:space:]]+\n/, "\n")
31
+ result.to_a[0].split(',')[0..3].should == ['1','2','Betsy','Jersey']
32
+ result.to_a[1].split(',')[0..3].should == ['10','20','Berta','Guernsey']
33
33
  end
34
34
 
35
35
  describe "multiple repositories" do
36
36
  before(:all) do
37
- QuantumCat.auto_migrate!
38
- repository(:alternate){QuantumCat.auto_migrate!}
37
+ QuanTum::Cat.auto_migrate!
38
+ repository(:alternate){QuanTum::Cat.auto_migrate!}
39
39
  end
40
40
 
41
41
  it "should use the repsoitory for the model" do
42
- gerry = QuantumCat.create(:name => "gerry")
43
- george = repository(:alternate){QuantumCat.create(:name => "george", :is_dead => false)}
42
+ gerry = QuanTum::Cat.create(:name => "gerry")
43
+ george = repository(:alternate){QuanTum::Cat.create(:name => "george", :is_dead => false)}
44
44
  gerry.to_csv.should_not match(/false/)
45
45
  george.to_csv.should match(/false/)
46
46
  end
@@ -0,0 +1,94 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Serialize, '#to_json' do
5
+ #
6
+ # ==== ajaxy JSON
7
+ #
8
+
9
+ before(:all) do
10
+ DataMapper.auto_migrate!
11
+ query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
12
+
13
+ @collection = DataMapper::Collection.new(query) do |c|
14
+ c.load([1, 2, 'Betsy', 'Jersey'])
15
+ c.load([10, 20, 'Berta', 'Guernsey'])
16
+ end
17
+
18
+ @harness = Class.new(SerializerTestHarness) do
19
+ def method_name
20
+ :to_json
21
+ end
22
+
23
+ protected
24
+
25
+ def deserialize(result)
26
+ JSON.parse(result)
27
+ end
28
+ end.new
29
+ end
30
+
31
+ it_should_behave_like "A serialization method"
32
+
33
+ it "should serialize an array of collections" do
34
+ deserialized_collection = JSON.parse([@collection].to_json).first
35
+ betsy = deserialized_collection.first
36
+ berta = deserialized_collection.last
37
+
38
+ betsy["id"].should == 1
39
+ betsy["composite"].should == 2
40
+ betsy["name"].should == "Betsy"
41
+ betsy["breed"].should == "Jersey"
42
+
43
+ berta["id"].should == 10
44
+ berta["composite"].should == 20
45
+ berta["name"].should == "Berta"
46
+ berta["breed"].should == "Guernsey"
47
+ end
48
+
49
+ it "should serialize an array of extended objects" do
50
+ deserialized_collection = JSON.parse(@collection.to_a.to_json)
51
+ betsy = deserialized_collection.first
52
+ berta = deserialized_collection.last
53
+
54
+ betsy["id"].should == 1
55
+ betsy["composite"].should == 2
56
+ betsy["name"].should == "Betsy"
57
+ betsy["breed"].should == "Jersey"
58
+
59
+ berta["id"].should == 10
60
+ berta["composite"].should == 20
61
+ berta["name"].should == "Berta"
62
+ berta["breed"].should == "Guernsey"
63
+ end
64
+
65
+ it "handles extra properties" do
66
+ deserialized_hash = JSON.parse(Cow.new(:id => 1, :name => "Harry", :breed => "Angus").to_json)
67
+
68
+ deserialized_hash["extra"].should == "Extra"
69
+ deserialized_hash["another"].should == 42
70
+ end
71
+
72
+ it "handles options given to a collection properly" do
73
+ deserialized_collection = JSON.parse(@collection.to_json(:only => [:composite]))
74
+ betsy = deserialized_collection.first
75
+ berta = deserialized_collection.last
76
+
77
+ betsy["id"].should be_nil
78
+ betsy["composite"].should == 2
79
+ betsy["name"].should be_nil
80
+ betsy["breed"].should be_nil
81
+
82
+ berta["id"].should be_nil
83
+ berta["composite"].should == 20
84
+ berta["name"].should be_nil
85
+ berta["breed"].should be_nil
86
+ end
87
+
88
+ it "supports :include option for one level depth"
89
+
90
+ it "supports :include option for more than one level depth"
91
+
92
+ it "has :repository option to override used repository"
93
+
94
+ end
@@ -0,0 +1,89 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Serialize, '#to_xml' do
5
+ #
6
+ # ==== enterprisey XML
7
+ #
8
+
9
+ before(:all) do
10
+ @harness = Class.new(SerializerTestHarness) do
11
+ def method_name
12
+ :to_xml
13
+ end
14
+
15
+ protected
16
+
17
+ def deserialize(result)
18
+ doc = REXML::Document.new(result)
19
+ root = doc.elements[1]
20
+ if root.attributes["type"] == "array"
21
+ root.elements.collect do |element|
22
+ a = {}
23
+ element.elements.each do |v|
24
+ a.update(v.name => cast(v.text, v.attributes["type"]))
25
+ end
26
+ a
27
+ end
28
+ else
29
+ a = {}
30
+ root.elements.each do |v|
31
+ a.update(v.name => cast(v.text, v.attributes["type"]))
32
+ end
33
+ a
34
+ end
35
+ end
36
+
37
+ def cast(value, type)
38
+ boolean_conversions = {"true" => true, "false" => false}
39
+ value = boolean_conversions[value] if boolean_conversions.has_key?(value)
40
+ value = value.to_i if value && type == "integer"
41
+ value
42
+ end
43
+ end.new
44
+ end
45
+
46
+ it_should_behave_like "A serialization method"
47
+
48
+ describe 'Resource#xml_element_name' do
49
+ it 'should return the class name underscored and with slashes replaced with dashes' do
50
+ QuanTum::Cat.new.send(:xml_element_name).should == 'quan_tum-cat'
51
+ end
52
+
53
+ it 'should be used as the root node name by #to_xml' do
54
+ planet = Planet.new
55
+ class << planet
56
+ def xml_element_name
57
+ "aplanet"
58
+ end
59
+ end
60
+
61
+ xml = planet.to_xml
62
+ REXML::Document.new(xml).elements[1].name.should == "aplanet"
63
+ end
64
+ end
65
+
66
+ describe 'Collection#xml_element_name' do
67
+ before(:each) do
68
+ query = DataMapper::Query.new(DataMapper::repository(:default), QuanTum::Cat)
69
+ @collection = DataMapper::Collection.new(query) {}
70
+ end
71
+
72
+ it 'should return the class name tableized and with slashes replaced with dashes' do
73
+ @collection.send(:xml_element_name).should == 'quan_tum-cats'
74
+ end
75
+
76
+ it 'should be used as the root node name by #to_xml' do
77
+ planet = Planet.new
78
+ @collection.load([1])
79
+ class << @collection
80
+ def xml_element_name
81
+ "somanycats"
82
+ end
83
+ end
84
+
85
+ xml = @collection.to_xml
86
+ REXML::Document.new(xml).elements[1].name.should == "somanycats"
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,32 @@
1
+ require 'pathname'
2
+ require 'yaml'
3
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
4
+
5
+ describe DataMapper::Serialize, '#to_yaml' do
6
+ #
7
+ # ==== yummy YAML
8
+ #
9
+
10
+ before(:all) do
11
+ @harness = Class.new(SerializerTestHarness) do
12
+ def method_name
13
+ :to_yaml
14
+ end
15
+
16
+ protected
17
+
18
+ def deserialize(result)
19
+ stringify_keys = lambda {|hash| hash.inject({}) {|a, (key, value)| a.update(key.to_s => value) }}
20
+ result = YAML.load(result)
21
+ if result.is_a?(Array)
22
+ result.collect(&stringify_keys)
23
+ else
24
+ stringify_keys[result]
25
+ end
26
+ end
27
+ end.new
28
+ end
29
+
30
+ it_should_behave_like "A serialization method"
31
+
32
+ end
@@ -1,2 +1 @@
1
- --format specdoc
2
1
  --colour
@@ -1,7 +1,7 @@
1
- require 'rubygems'
2
1
  require 'pathname'
2
+ require 'rubygems'
3
3
 
4
- gem 'dm-core', '~>0.9.7'
4
+ gem 'dm-core', '~>0.9.8'
5
5
  require 'dm-core'
6
6
 
7
7
  spec_dir_path = Pathname(__FILE__).dirname.expand_path
@@ -10,17 +10,13 @@ require spec_dir_path.parent + 'lib/dm-serializer'
10
10
  def load_driver(name, default_uri)
11
11
  return false if ENV['ADAPTER'] != name.to_s
12
12
 
13
- lib = "do_#{name}"
14
-
15
13
  begin
16
- gem lib, '~>0.9.7'
17
- require lib
18
14
  DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
19
15
  DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
20
16
  DataMapper::Repository.adapters[:alternate] = DataMapper::Repository.adapters[name]
21
17
  true
22
- rescue Gem::LoadError => e
23
- warn "Could not load #{lib}: #{e}"
18
+ rescue LoadError => e
19
+ warn "Could not load do_#{name}: #{e}"
24
20
  false
25
21
  end
26
22
  end
@@ -31,6 +27,13 @@ HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
31
27
  HAS_MYSQL = load_driver(:mysql, 'mysql://localhost/dm_core_test')
32
28
  HAS_POSTGRES = load_driver(:postgres, 'postgres://postgres@localhost/dm_core_test')
33
29
 
30
+ class SerializerTestHarness
31
+ def test(object, *args)
32
+ deserialize(object.send(method_name, *args))
33
+ end
34
+ end
35
+
36
+ require spec_dir_path + 'lib/serialization_method_shared_spec'
34
37
 
35
38
  # require fixture resources
36
39
  Dir[spec_dir_path + "fixtures/*.rb"].each do |fixture_file|
@@ -0,0 +1,13 @@
1
+ def sudo_gem(cmd)
2
+ sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
3
+ end
4
+
5
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
6
+ task :install => [ :package ] do
7
+ sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
8
+ end
9
+
10
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
11
+ task :uninstall => [ :clobber ] do
12
+ sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -Ix"
13
+ end
@@ -0,0 +1,25 @@
1
+ begin
2
+ gem 'rspec', '~>1.1.11'
3
+ require 'spec'
4
+ require 'spec/rake/spectask'
5
+
6
+ task :default => [ :spec ]
7
+
8
+ desc 'Run specifications'
9
+ Spec::Rake::SpecTask.new(:spec) do |t|
10
+ t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
11
+ t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s)
12
+
13
+ begin
14
+ gem 'rcov', '~>0.8'
15
+ t.rcov = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
16
+ t.rcov_opts << '--exclude' << 'spec'
17
+ t.rcov_opts << '--text-summary'
18
+ t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
19
+ rescue LoadError
20
+ # rcov not installed
21
+ end
22
+ end
23
+ rescue LoadError
24
+ # rspec not installed
25
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-serializer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guy van den Berg
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-18 00:00:00 -08:00
12
+ date: 2008-12-07 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -18,23 +18,13 @@ dependencies:
18
18
  version_requirement:
19
19
  version_requirements: !ruby/object:Gem::Requirement
20
20
  requirements:
21
- - - "="
21
+ - - ~>
22
22
  - !ruby/object:Gem::Version
23
- version: 0.9.7
24
- version:
25
- - !ruby/object:Gem::Dependency
26
- name: hoe
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.8.2
23
+ version: 0.9.8
34
24
  version:
35
25
  description: DataMapper plugin for serializing DataMapper objects
36
26
  email:
37
- - vandenberg.guy@gmail.com
27
+ - vandenberg.guy [a] gmail [d] com
38
28
  executables: []
39
29
 
40
30
  extensions: []
@@ -43,6 +33,7 @@ extra_rdoc_files:
43
33
  - README.txt
44
34
  - LICENSE
45
35
  - TODO
36
+ - History.txt
46
37
  files:
47
38
  - History.txt
48
39
  - LICENSE
@@ -56,14 +47,17 @@ files:
56
47
  - lib/dm-serializer/version.rb
57
48
  - spec/fixtures/cow.rb
58
49
  - spec/fixtures/planet.rb
59
- - spec/fixtures/quatum_cat.rb
50
+ - spec/fixtures/quan_tum_cat.rb
51
+ - spec/lib/serialization_method_shared_spec.rb
52
+ - spec/public/serializer_spec.rb
53
+ - spec/public/to_csv_spec.rb
54
+ - spec/public/to_json_spec.rb
55
+ - spec/public/to_xml_spec.rb
56
+ - spec/public/to_yaml_spec.rb
60
57
  - spec/spec.opts
61
58
  - spec/spec_helper.rb
62
- - spec/unit/serializer_spec.rb
63
- - spec/unit/to_csv_spec.rb
64
- - spec/unit/to_json_spec.rb
65
- - spec/unit/to_xml_spec.rb
66
- - spec/unit/to_yaml_spec.rb
59
+ - tasks/install.rb
60
+ - tasks/spec.rb
67
61
  has_rdoc: true
68
62
  homepage: http://github.com/sam/dm-more/tree/master/dm-serializer
69
63
  post_install_message:
@@ -1,11 +0,0 @@
1
- class QuantumCat
2
- include DataMapper::Resource
3
-
4
- property :id, Serial
5
- property :name, String
6
- property :location, String
7
-
8
- repository(:alternate) do
9
- property :is_dead, Boolean
10
- end
11
- end
@@ -1,130 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
-
4
- describe DataMapper::Serialize, '#to_json' do
5
- #
6
- # ==== ajaxy JSON
7
- #
8
-
9
- before(:all) do
10
- query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
11
-
12
- @collection = DataMapper::Collection.new(query) do |c|
13
- c.load([1, 2, 'Betsy', 'Jersey'])
14
- c.load([10, 20, 'Berta', 'Guernsey'])
15
- end
16
-
17
- @empty_collection = DataMapper::Collection.new(query) {}
18
- end
19
-
20
- it "serializes resource to JSON" do
21
- deserialized_hash = JSON.parse(Cow.new(:id => 1, :composite => 322, :name => "Harry", :breed => "Angus").to_json)
22
-
23
- deserialized_hash["id"].should == 1
24
- deserialized_hash["composite"].should == 322
25
- deserialized_hash["name"].should == "Harry"
26
- deserialized_hash["breed"].should == "Angus"
27
- end
28
-
29
- it "excludes nil attributes" do
30
- deserialized_hash = JSON.parse(Cow.new(:id => 1, :name => "Harry", :breed => "Angus").to_json)
31
-
32
- deserialized_hash["id"].should == 1
33
- deserialized_hash["composite"].should be(nil)
34
- deserialized_hash["name"].should == "Harry"
35
- deserialized_hash["breed"].should == "Angus"
36
- end
37
-
38
- it "serializes collections to JSON by serializing each member" do
39
- deserialized_collection = JSON.parse(@collection.to_json)
40
- betsy = deserialized_collection.first
41
- berta = deserialized_collection.last
42
-
43
- betsy["id"].should == 1
44
- betsy["composite"].should == 2
45
- betsy["name"].should == "Betsy"
46
- betsy["breed"].should == "Jersey"
47
-
48
- berta["id"].should == 10
49
- berta["composite"].should == 20
50
- berta["name"].should == "Berta"
51
- berta["breed"].should == "Guernsey"
52
- end
53
-
54
- it "handles extra properties" do
55
- deserialized_hash = JSON.parse(Cow.new(:id => 1, :name => "Harry", :breed => "Angus").to_json)
56
-
57
- deserialized_hash["extra"].should == "Extra"
58
- deserialized_hash["another"].should == 42
59
- end
60
-
61
- it "handles empty collections just fine" do
62
- deserialized_collection = JSON.parse(@empty_collection.to_json)
63
- deserialized_collection.should be_empty
64
- end
65
-
66
- it "handles options given to a collection properly" do
67
- deserialized_collection = JSON.parse(@collection.to_json(:only => [:composite]))
68
- betsy = deserialized_collection.first
69
- berta = deserialized_collection.last
70
-
71
- betsy["id"].should be_nil
72
- betsy["composite"].should == 2
73
- betsy["name"].should be_nil
74
- betsy["breed"].should be_nil
75
-
76
- berta["id"].should be_nil
77
- berta["composite"].should == 20
78
- berta["name"].should be_nil
79
- berta["breed"].should be_nil
80
- end
81
-
82
- it "serializes values returned by methods given to :methods option" do
83
- deserialized_hash = JSON.parse(Planet.new(:name => "Mars", :aphelion => 249_209_300.4).to_json(:methods => [:category, :has_known_form_of_life?]))
84
-
85
- deserialized_hash["category"].should == "terrestrial"
86
- deserialized_hash["has_known_form_of_life?"].should be(false)
87
- end
88
-
89
- it "only includes properties given to :only option" do
90
- deserialized_hash = JSON.parse(Planet.new(:name => "Mars", :aphelion => 249_209_300.4).to_json(:only => [:name]))
91
-
92
- deserialized_hash["name"].should == "Mars"
93
- deserialized_hash["aphelion"].should be(nil)
94
- end
95
-
96
- it "only includes properties given to :only option" do
97
- deserialized_hash = JSON.parse(Planet.new(:name => "Mars", :aphelion => 249_209_300.4).to_json(:exclude => [:aphelion]))
98
-
99
- deserialized_hash["name"].should == "Mars"
100
- deserialized_hash["aphelion"].should be(nil)
101
- end
102
-
103
- it "has higher presedence for :only option" do
104
- deserialized_hash = JSON.parse(Planet.new(:name => "Mars", :aphelion => 249_209_300.4).to_json(:only => [:aphelion], :exclude => [:aphelion]))
105
-
106
- deserialized_hash["name"].should be(nil)
107
- deserialized_hash["aphelion"].should == 249_209_300.4
108
- end
109
-
110
- describe "multiple repositories" do
111
- before(:all) do
112
- QuantumCat.auto_migrate!
113
- repository(:alternate){QuantumCat.auto_migrate!}
114
- end
115
-
116
- it "should use the repsoitory for the model" do
117
- gerry = QuantumCat.create(:name => "gerry")
118
- george = repository(:alternate){QuantumCat.create(:name => "george", :is_dead => false)}
119
- gerry.to_json.should_not match(/is_dead/)
120
- george.to_json.should match(/is_dead/)
121
- end
122
- end
123
-
124
- it "supports :include option for one level depth"
125
-
126
- it "supports :include option for more than one level depth"
127
-
128
- it "has :repository option to override used repository"
129
-
130
- end
@@ -1,73 +0,0 @@
1
- require 'pathname'
2
- require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
-
4
- describe DataMapper::Serialize, '#to_xml' do
5
- #
6
- # ==== enterprisey XML
7
- #
8
-
9
- before(:all) do
10
- query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
11
-
12
- @time = DateTime.now
13
-
14
-
15
- @collection = DataMapper::Collection.new(query) do |c|
16
- c.load([1, 2, 'Betsy', 'Jersey'])
17
- c.load([10, 20, 'Berta', 'Guernsey'])
18
- end
19
-
20
- @empty_collection = DataMapper::Collection.new(query) {}
21
- end
22
-
23
- it "should serialize a resource to XML" do
24
- berta = Cow.new
25
- berta.id = 89
26
- berta.composite = 34
27
- berta.name = 'Berta'
28
- berta.breed = 'Guernsey'
29
-
30
- berta.to_xml.should == <<-EOS.compress_lines(false)
31
- <cow>
32
- <id type='integer'>89</id>
33
- <composite type='integer'>34</composite>
34
- <name>Berta</name>
35
- <breed>Guernsey</breed>
36
- </cow>
37
- EOS
38
- end
39
-
40
- it "should serialize a collection to XML" do
41
- @collection.to_xml.should == <<-EOS.compress_lines(false)
42
- <#{Extlib::Inflection.tableize("Cow")} type='array'>
43
- <cow>
44
- <id type='integer'>1</id>
45
- <composite type='integer'>2</composite>
46
- <name>Betsy</name>
47
- <breed>Jersey</breed>
48
- </cow>
49
- <cow>
50
- <id type='integer'>10</id>
51
- <composite type='integer'>20</composite>
52
- <name>Berta</name>
53
- <breed>Guernsey</breed>
54
- </cow>
55
- </#{Extlib::Inflection.tableize("Cow")}>
56
- EOS
57
- end
58
-
59
- describe "multiple repositories" do
60
- before(:all) do
61
- QuantumCat.auto_migrate!
62
- repository(:alternate){QuantumCat.auto_migrate!}
63
- end
64
-
65
- it "should use the repsoitory for the model" do
66
- gerry = QuantumCat.create(:name => "gerry")
67
- george = repository(:alternate){QuantumCat.create(:name => "george", :is_dead => false)}
68
- gerry.to_xml.should_not match(/is_dead/)
69
- george.to_xml.should match(/is_dead/)
70
- end
71
- end
72
-
73
- end
@@ -1,76 +0,0 @@
1
- require 'pathname'
2
- require 'yaml'
3
- require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
4
-
5
- describe DataMapper::Serialize, '#to_yaml' do
6
- #
7
- # ==== yummy YAML
8
- #
9
-
10
- before(:all) do
11
- query = DataMapper::Query.new(DataMapper::repository(:default), Cow)
12
-
13
- @collection = DataMapper::Collection.new(query) do |c|
14
- c.load([1, 2, 'Betsy', 'Jersey'])
15
- c.load([10, 20, 'Berta', 'Guernsey'])
16
- end
17
-
18
- @empty_collection = DataMapper::Collection.new(query) {}
19
- end
20
-
21
- it "serializes single resource to YAML" do
22
- betsy = Cow.new(:id => 230, :composite => 22, :name => "Betsy", :breed => "Jersey")
23
- deserialized_hash = YAML.load(betsy.to_yaml)
24
-
25
- deserialized_hash[:id].should == 230
26
- deserialized_hash[:name].should == "Betsy"
27
- deserialized_hash[:composite].should == 22
28
- deserialized_hash[:breed].should == "Jersey"
29
- end
30
-
31
- it "leaves out nil properties" do
32
- betsy = Cow.new(:id => 230, :name => "Betsy", :breed => "Jersey")
33
- deserialized_hash = YAML.load(betsy.to_yaml)
34
-
35
- deserialized_hash[:id].should == 230
36
- deserialized_hash[:name].should == "Betsy"
37
- deserialized_hash[:composite].should be(nil)
38
- deserialized_hash[:breed].should == "Jersey"
39
- end
40
-
41
- it "serializes a collection to YAML" do
42
- deserialized_collection = YAML.load(@collection.to_yaml)
43
-
44
- betsy = deserialized_collection.first
45
- berta = deserialized_collection.last
46
-
47
- betsy[:id].should == 1
48
- betsy[:name].should == "Betsy"
49
- betsy[:composite].should == 2
50
- betsy[:breed].should == "Jersey"
51
-
52
- berta[:id].should == 10
53
- berta[:name].should == "Berta"
54
- berta[:composite].should == 20
55
- berta[:breed].should == "Guernsey"
56
- end
57
-
58
- it "handles empty collections just fine" do
59
- YAML.load(@empty_collection.to_yaml).should be_empty
60
- end
61
-
62
- describe "multiple repositories" do
63
- before(:all) do
64
- QuantumCat.auto_migrate!
65
- repository(:alternate){QuantumCat.auto_migrate!}
66
- end
67
-
68
- it "should use the repsoitory for the model" do
69
- gerry = QuantumCat.create(:name => "gerry")
70
- george = repository(:alternate){QuantumCat.create(:name => "george", :is_dead => false)}
71
- gerry.to_yaml.should_not match(/is_dead/)
72
- george.to_yaml.should match(/is_dead/)
73
- end
74
- end
75
-
76
- end