datamapper4rail 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,5 +18,11 @@ lib/datamapper4rails/adapters/base_adapter.rb
18
18
  lib/datamapper4rails/adapters/restful_adapter.rb
19
19
  lib/datamapper4rails/database_config.rb
20
20
  lib/datamapper4rails/datamapper_store.rb
21
+ lib/datamapper4rails/identity_maps.rb
22
+ lib/datamapper4rails/preload_models.rb
21
23
  lib/datamapper4rails/restful_transactions.rb
22
24
  lib/datamapper4rails/version.rb
25
+ spec/datamapper_store_spec.rb
26
+ spec/restful_adapter_spec.rb
27
+ spec/spec.opts
28
+ spec/spec_helper.rb
data/Rakefile CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
+
6
+ require 'spec'
7
+ require 'spec/rake/spectask'
8
+ require 'pathname'
9
+
5
10
  require './lib/datamapper4rails/version.rb'
6
11
 
7
12
  Hoe.new('datamapper4rail', Datamapper4rails::VERSION) do |p|
@@ -17,16 +22,16 @@ task :install => [:clean, :package] do
17
22
  sh "gem install --local #{gem} --no-ri --no-rdoc"
18
23
  end
19
24
 
20
- # desc 'Run specifications'
21
- # Spec::Rake::SpecTask.new(:spec) do |t|
22
- # if File.exists?('spec/spec.opts')
23
- # t.spec_opts << '--options' << 'spec/spec.opts'
24
- # end
25
- # t.spec_files = Pathname.glob('./spec/**/*_spec.rb')
26
- # end
25
+ desc 'Run specifications'
26
+ Spec::Rake::SpecTask.new(:spec) do |t|
27
+ if File.exists?('spec/spec.opts')
28
+ t.spec_opts << '--options' << 'spec/spec.opts'
29
+ end
30
+ t.spec_files = Pathname.glob('./spec/**/*_spec.rb')
31
+ end
27
32
 
28
- # require 'yard'
33
+ require 'yard'
29
34
 
30
- # YARD::Rake::YardocTask.new
35
+ YARD::Rake::YardocTask.new
31
36
 
32
37
  # vim: syntax=Ruby
@@ -2,13 +2,13 @@ require 'rails_generator/generators/components/model/model_generator'
2
2
  require 'active_record'
3
3
  require File.dirname(__FILE__) + '/../rspec_default_values'
4
4
 
5
- class RspecDmModelExtendedGenerator <ModelGenerator
5
+ class RspecDmModelGenerator <ModelGenerator
6
6
 
7
7
  def manifest
8
8
  record do |m|
9
9
 
10
10
  # Check for class naming collisions.
11
- m.class_collisions class_path, class_name
11
+ #m.class_collisions class_path, class_name
12
12
 
13
13
  # Model, spec, and fixture directories.
14
14
  m.directory File.join('app/models', class_path)
@@ -1,16 +1,19 @@
1
1
  class <%= class_name %>
2
2
  include DataMapper::Resource
3
+ <% if options[:add_constraints] -%>
4
+ include DataMapper::Constraints
5
+ <% end -%>
6
+
3
7
  property :id, Serial
4
8
 
5
9
  <% for attribute in attributes -%>
6
- property :<%= attribute.name %>, <%= attribute.type.to_s.camelize %>, :nullable => false <% if attribute.type == :string or attribute.type == :text -%>, :format => /^[^<'&">]*$/<% if attribute.type == :string %>, :length => 50<% end -%>
7
- <% else -%>
10
+ property :<%= attribute.name %>, <%= attribute.type.to_s.camelize %>, :nullable => false <% if attribute.type == :string or attribute.type == :text -%>, :format => /^[^<'&">]*$/<% if attribute.type == :string %>, :length => 255<% end -%>
11
+ <% #else -%>
8
12
 
9
13
  <% end -%>
10
14
  <% end -%>
11
15
  <% unless options[:skip_timestamps] %>
12
- property :created_at, DateTime, :nullable => false
13
- property :updated_at, DateTime, :nullable => false
16
+ timestamps :at
14
17
 
15
18
  <% end -%>
16
19
  end
@@ -1,53 +1 @@
1
- require 'dm-core'
2
- def config_file()
3
- RAILS_ROOT + "/config/database.yml"
4
- end
5
-
6
- def create_connection()
7
- conf = config.dup
8
- if repositories = conf.delete(:repositories)
9
- repositories.each do |repo, conf|
10
- ::DataMapper.setup(repo, conf) unless conf.empty?
11
- end
12
- else
13
- ::DataMapper.setup(:default, conf) unless conf.empty?
14
- end
15
- end
16
-
17
- def get_config_for_environment
18
- if hash = full_config[RAILS_ENV]
19
- symbolize_keys(hash)
20
- elsif hash = full_config[RAILS_ENV.to_sym]
21
- hash
22
- else
23
- raise ArgumentError, "missing environment '#{RAILS_ENV}' in config file #{config_file}"
24
- end
25
- end
26
-
27
- def full_config
28
- @full_config ||= YAML::load(ERB.new(IO.read(config_file)).result)
29
- end
30
-
31
- def config
32
- @config ||= get_config_for_environment
33
- end
34
-
35
- def symbolize_keys(h)
36
- config = {}
37
-
38
- h.each do |k, v|
39
- if k == 'port'
40
- config[k.to_sym] = v.to_i
41
- elsif k == 'adapter' && v == 'postgresql'
42
- config[k.to_sym] = 'postgres'
43
- elsif v.is_a?(Hash)
44
- config[k.to_sym] = symbolize_keys(v)
45
- else
46
- config[k.to_sym] = v
47
- end
48
- end
49
-
50
- config
51
- end
52
-
53
- create_connection()
1
+ require 'datamapper4rails/database_config'
@@ -1,7 +1,8 @@
1
- require 'adapters/restful_adapter'
1
+ require 'datamapper4rails/adapters/base_adapter'
2
2
  require 'net/http'
3
3
  require 'extlib/inflection'
4
4
  require 'extlib/module'
5
+ require 'dm-serializer'
5
6
 
6
7
  module DataMapper
7
8
  module Adapters
@@ -44,6 +45,18 @@ module DataMapper
44
45
  raise "compound keys are not supported"
45
46
  end
46
47
  end
48
+
49
+ def single_entity_query?(query)
50
+ query.conditions.count {|c| c[1].key? and c[0] == :eql} == query.model.key.size
51
+ end
52
+
53
+ def attributes_to_xml(name, attributes)
54
+ xml = "<#{name}>"
55
+ attributes.each do |attr, val|
56
+ xml += "<#{attr.name}>#{val}</#{attr.name}>"
57
+ end
58
+ xml += "</#{name}>"
59
+ end
47
60
 
48
61
  def http_get(uri)
49
62
  send_request do |http|
@@ -66,13 +79,16 @@ module DataMapper
66
79
  end
67
80
  end
68
81
 
69
- def http_put(uri, data = {})
82
+ def http_put(uri, data = nil)
70
83
  send_request do |http|
71
- request = Net::HTTP::Put.new(uri)
84
+ request = Net::HTTP::Put.new(uri, {
85
+ 'content-type' => 'application/xml',
86
+ 'content-length' => data.length.to_s
87
+ })
72
88
  request.basic_auth(@uri[:login],
73
89
  @uri[:password]) unless @uri[:login].blank?
74
- request.set_form_data(data)
75
- http.request(request)
90
+ # request.set_form_data(data)
91
+ http.request(request, data)
76
92
  end
77
93
  end
78
94
 
@@ -112,14 +128,25 @@ module DataMapper
112
128
  #puts
113
129
  #puts "elements"
114
130
  #p elements
131
+ #p query
132
+ #p model
115
133
  resource = model.load(model.properties.collect do |f|
116
134
  elements[f.name]
117
135
  end, query)
118
136
  resource.send("#{keys_from_query(query)[0].name}=".to_sym, elements[keys_from_query(query)[0].name] )
119
- #p resource
120
- associations.each do |name, association|
121
- model =
137
+ # p resource
138
+ #p associations
139
+ associations.each do |name, association|
140
+ # puts "asso"
141
+ # p model
142
+ # p name
143
+ # p association
144
+ #p model.relationships
145
+ is_one_to_one = false
146
+ asso_model =
122
147
  if rel = model.relationships[name]
148
+ #puts "rel"
149
+ #p rel
123
150
  if rel.child_model == model
124
151
  rel.parent_model
125
152
  else
@@ -129,17 +156,38 @@ module DataMapper
129
156
  #::Extlib::Inflection.constantize(::Extlib::Inflection.classify(name))
130
157
  # model.find_const(::Extlib::Inflection.classify(name))
131
158
  end
159
+ # p asso_model
132
160
  if resource.respond_to? "#{name}=".to_sym
161
+ # puts
162
+ # puts "association"
163
+ # puts name
164
+ # p model
165
+ # p asso_model
133
166
  resource.send("#{name}=".to_sym,
134
- parse_resource(association, model,
135
- ::DataMapper::Query.new(query.repository, model )))
167
+ parse_resource(association, asso_model,
168
+ ::DataMapper::Query.new(query.repository, asso_model ))) unless asso_model.nil?
136
169
  else
137
170
  resource.send(("#{name.to_s.pluralize}<" + "<").to_sym,
138
- parse_resource(association, model,
139
- ::DataMapper::Query.new(query.repository, model )))
171
+ parse_resource(association, asso_model,
172
+ ::DataMapper::Query.new(query.repository, asso_model ))) unless asso_model.nil?
173
+ end
174
+ end
175
+
176
+ #puts "many 2 many"
177
+ #p many_to_many
178
+ many_to_many.each do |name, many|
179
+ if model.relationships[name]
180
+ # TODO
181
+ else
182
+ # p ::Extlib::Inflection.classify(name.to_s.singularize)
183
+ many_model = Object.const_get(::Extlib::Inflection.classify(name.to_s.singularize))
184
+ resource.send(name).send(("<" + "<").to_sym,
185
+ parse_resource(many, many_model,
186
+ ::DataMapper::Query.new(query.repository, many_model ))) unless many_model.nil?
140
187
  end
141
188
  end
142
189
  resource.instance_variable_set(:@new_record, false)
190
+ #p resource
143
191
  resource
144
192
  end
145
193
 
@@ -168,65 +216,70 @@ module DataMapper
168
216
 
169
217
  # @see BaseAdapter
170
218
  def read_resource(query)
171
- if(query.conditions.empty?)
172
- raise "not implemented"
219
+ key = key_value_from_query(query)
220
+ uri = "/#{resource_name_from_query(query).pluralize}/#{key}.xml"
221
+ logger.debug { "get #{uri}" }
222
+ response = http_get(uri)
223
+ if response.kind_of?(Net::HTTPSuccess)
224
+ logger.debug { response.body.to_s }
225
+ parse_resource(REXML::Document::new(response.body).root,
226
+ query.model,
227
+ query)
173
228
  else
174
- key = key_value_from_query(query)
175
- uri = "/#{resource_name_from_query(query).pluralize}/#{key}.xml"
229
+ #TODO may act on different response codes differently
230
+ end
231
+ end
232
+
233
+ # @see BaseAdapter
234
+ def read_resources(query)
235
+ if single_entity_query?(query)
236
+ [read_resource(query)]
237
+ else
238
+ uri = "/#{resource_name_from_query(query).pluralize}.xml"
176
239
  logger.debug { "get #{uri}" }
177
240
  response = http_get(uri)
178
241
  if response.kind_of?(Net::HTTPSuccess)
179
- parse_resource(REXML::Document::new(response.body).root,
180
- query.model,
181
- query)
242
+ result = []
243
+ logger.debug { response.body.to_s }
244
+ REXML::Document::new(response.body).root.each do |element|
245
+ result << parse_resource(element,
246
+ query.model,
247
+ query)
248
+ end
249
+ result
182
250
  else
183
251
  #TODO may act on different response codes differently
184
252
  end
185
253
  end
186
254
  end
187
255
 
188
- # @see BaseAdapter
189
- def read_resources(query)
190
- # raise "not implemented"
191
- [read_resource(query)]
192
- end
193
-
194
256
  # @overwrite BaseAdapter
195
257
  def update(attributes, query)
196
- name = resource_name_from_query(query)
197
- params = {}
198
- attributes.each do |attr, val|
199
- params["#{name}[#{attr.name}]"]=val
258
+ if query.limit == 1 or single_entity_query?(query)
259
+ xml = attributes_to_xml(resource_name_from_query(query), attributes)
260
+ key = key_value_from_query(query)
261
+ uri = "/#{resource_name_from_query(query).pluralize}/#{key}.xml"
262
+ logger.debug { "put #{uri}" }
263
+ response = http_put(uri, xml)
264
+ response.kind_of?(Net::HTTPSuccess)
265
+ else
266
+ super
200
267
  end
201
- key = key_value_from_query(query)
202
- uri = "/#{name.pluralize}/#{key}.xml"
203
- logger.debug { "put #{uri}" }
204
- response = http_put(uri, params)
205
- response.kind_of?(Net::HTTPSuccess)
206
268
  end
207
269
 
208
270
  # @see BaseAdapter
209
271
  def update_resource(resource, attributes)
210
272
  query = resource.to_query
211
- if(query.conditions.empty?)
212
- raise "not implemented"
213
- else
214
- name = resource.name
215
- params = {}
216
- attributes.each do |attr, val|
217
- params["#{name}[#{attr.name}]"]=val
218
- end
219
- key = key_value_from_query(query)
220
- logger.debug {resource.to_xml}
221
- response = http_put("/#{resource_name_from_query(query).pluralize}/#{key}.xml", params)
222
- response.kind_of?(Net::HTTPSuccess)
223
- end
273
+ xml = attributes_to_xml(resource.name, attributes)
274
+ key = key_value_from_query(query)
275
+ logger.debug {resource.to_xml}
276
+ response = http_put("/#{resource_name_from_query(query).pluralize}/#{key}.xml", xml)
277
+ response.kind_of?(Net::HTTPSuccess)
224
278
  end
225
-
279
+
226
280
  # @overwrite BaseAdapter
227
281
  def delete(query)
228
- # TODO limit == 1 is NOT sufficient ONLY necessary
229
- if query.limit == 1
282
+ if query.limit == 1 or single_entity_query?(query)
230
283
  name = resource_name_from_query(query)
231
284
  key = key_value_from_query(query)
232
285
  uri = "/#{name.pluralize}/#{key}.xml"
@@ -241,7 +294,7 @@ module DataMapper
241
294
  # @see BaseAdapter
242
295
  def delete_resource(resource)
243
296
  name = resource.name
244
- key = key_value_from_query(resource.to_queryquery)
297
+ key = key_value_from_query(resource.to_query)
245
298
  uri = "/#{name.pluralize}/#{key}.xml"
246
299
  logger.debug { "delete #{uri}" }
247
300
  response = http_delete(uri)
@@ -6,8 +6,13 @@ end
6
6
 
7
7
  def create_connection()
8
8
  conf = config.dup
9
- repositories = conf.delete(:repositories)
10
- ::DataMapper.setup(:default, conf) unless conf.empty?
9
+ if repositories = conf.delete(:repositories)
10
+ repositories.each do |repo, conf|
11
+ ::DataMapper.setup(repo, conf) unless conf.empty?
12
+ end
13
+ else
14
+ ::DataMapper.setup(:default, conf) unless conf.empty?
15
+ end
11
16
  end
12
17
 
13
18
  def get_config_for_environment
@@ -8,8 +8,10 @@ module ActionController
8
8
  super
9
9
  if options.delete(:cache)
10
10
  @@cache = {}
11
+ else
12
+ @@cache = nil unless self.class.class_variable_defined? :@@cache
11
13
  end
12
- @@session_class = ::DatamapperStore::Session
14
+ @@session_class = options.delete(:session_class) || ::DatamapperStore::Session unless (self.class.class_variable_defined? :@@session_class and @@session_class)
13
15
  end
14
16
 
15
17
  private
@@ -32,10 +34,8 @@ module ActionController
32
34
  @@session_class.get(sid)
33
35
  end || @@session_class.new(:session_id => sid)
34
36
  session.data = session_data || {}
35
- if session.new_record?
36
- session.updated_at = Time.now
37
- @@cache[sid] = session if @@cache
38
- end
37
+ session.updated_at = Time.now if session.dirty?
38
+ @@cache[sid] = session if @@cache
39
39
  session.save
40
40
  end
41
41
  end
@@ -60,6 +60,7 @@ module DatamapperStore
60
60
  def data=(data)
61
61
  attribute_set(:data, ::Base64.encode64(Marshal.dump(data)))
62
62
  end
63
+
63
64
  def data
64
65
  Marshal.load(::Base64.decode64(attribute_get(:data)))
65
66
  end
@@ -0,0 +1,23 @@
1
+ module Datamapper4rails
2
+ module IdentityMaps
3
+
4
+ module Base
5
+ def self.included(base)
6
+ base.prepend_around_filter(IdentityMapFilter)
7
+ end
8
+ end
9
+
10
+ class IdentityMapFilter
11
+
12
+ def self.filter(controller)
13
+ DataMapper.repository(:default) do |*block_args|
14
+ if block_given?
15
+ yield (*block_args)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ ::ActionController::Base.send(:include, Datamapper4rails::IdentityMaps::Base)
@@ -0,0 +1,26 @@
1
+ # load all models before each request so relations in datamapper find their classes
2
+ MODELS = []
3
+ Dir[RAILS_ROOT + "/app/models/**/*.rb"].each do |model|
4
+ model.sub!(/.*models\//, '').sub!(/.rb/, '')
5
+ m = ::Extlib::Inflection.classify(model.to_s)
6
+ MODELS << m
7
+ Object.const_get(m)
8
+ end
9
+
10
+ module ModelLoader
11
+ module Base
12
+ def self.included(base)
13
+ base.prepend_before_filter(ModelLoaderFilter)
14
+ end
15
+ end
16
+
17
+ class ModelLoaderFilter
18
+ def self.filter(controller)
19
+ MODELS.each do |model|
20
+ Object.const_get(model)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ ::ActionController::Base.send(:include, ModelLoader::Base)
@@ -11,17 +11,18 @@ module Datamapper4rails
11
11
  end
12
12
 
13
13
  class TransactionFilter
14
+
14
15
  def self.filter(controller)
15
16
  case controller.request.method
16
17
  when :post, :put, :delete then
17
18
  begin
19
+ # TODO remove the :default repository and make it more general
18
20
  DataMapper::Transaction.new(DataMapper.repository(:default)) do |*block_args|
19
21
  if block_given?
20
22
  yield (*block_args)
21
23
  # added rollback for all actions which just render
22
- # a page with validation errors and do not redirect to new idem potent
23
- # page (http-method get is idem potent within the
24
- # restful paradigma
24
+ # a page (with validation errors) and do not redirect to
25
+ # another page
25
26
  unless controller.response.redirected_to
26
27
  raise Datamapper4rails::RestfulTransactions::Rollback
27
28
  end
@@ -1,3 +1,3 @@
1
1
  class Datamapper4rails
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -0,0 +1,127 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require 'spec_helper'
3
+ require 'datamapper4rails/datamapper_store'
4
+
5
+ describe DatamapperStore do
6
+
7
+ before :each do
8
+ load 'lib/datamapper4rails/datamapper_store.rb'
9
+ ActionController::Session::DatamapperStore.send(:class_variable_set, :@@session_class, nil)
10
+ end
11
+
12
+ it 'should initialize with no cache and default session class' do
13
+ store = ActionController::Session::DatamapperStore.new(nil)
14
+ store.class.send(:class_variable_get, :@@cache).should be_nil
15
+ store.class.send(:class_variable_get, :@@session_class).should == DatamapperStore::Session
16
+
17
+ store = ActionController::Session::DatamapperStore.new(nil, :session_class => :some_class)
18
+ store.class.send(:class_variable_get, :@@cache).should be_nil
19
+ store.class.send(:class_variable_get, :@@session_class).should == DatamapperStore::Session
20
+ end
21
+
22
+ it 'should initialize with cache and default session class' do
23
+ store = ActionController::Session::DatamapperStore.new(nil, :cache => true)
24
+ store.class.send(:class_variable_get, :@@cache).instance_of?(Hash).should be_true
25
+
26
+ store = ActionController::Session::DatamapperStore.new(nil)
27
+ store.class.send(:class_variable_get, :@@cache).instance_of?(Hash).should be_true
28
+ end
29
+
30
+ it 'should initialize with custom session class' do
31
+ store = ActionController::Session::DatamapperStore.new(nil, :session_class => Session)
32
+ store.class.send(:class_variable_get, :@@session_class).should == Session
33
+
34
+ store = ActionController::Session::DatamapperStore.new(nil, :session_class => :some_class)
35
+ store.class.send(:class_variable_get, :@@session_class).should == Session
36
+ end
37
+ end
38
+
39
+ describe 'DatamapperStore without cache' do
40
+
41
+ def mock_session(stubs={})
42
+ @mock_session ||= mock(Session, stubs)
43
+ end
44
+
45
+ before :each do
46
+ load 'lib/datamapper4rails/datamapper_store.rb'
47
+ ActionController::Session::DatamapperStore.send(:class_variable_set, :@@cache, nil)
48
+ ActionController::Session::DatamapperStore.send(:class_variable_set, :@@session_class, nil)
49
+ @store = ActionController::Session::DatamapperStore.new(nil, :session_class => Session)
50
+ end
51
+
52
+ it 'should get the session data' do
53
+ Session.stub!(:get)
54
+ @store.send(:get_session, nil, "sid").should == ["sid",{}]
55
+ Session.stub!(:get).and_return(mock_session)
56
+ mock_session.should_receive(:data).and_return({:id => "id"})
57
+ @store.send(:get_session, nil, "sid").should == ["sid",{:id => "id"}]
58
+ end
59
+
60
+ it 'should set the session data on new session' do
61
+ Session.should_receive(:get)
62
+ Session.should_receive(:new).with(:session_id => "sid").and_return(mock_session)
63
+ mock_session.should_receive(:data=).with({})
64
+ mock_session.should_receive(:dirty?).and_return(true)
65
+ mock_session.should_receive(:updated_at=)
66
+ mock_session.should_receive(:save).and_return(true)
67
+ @store.send(:set_session, nil, "sid", {}).should == true
68
+ end
69
+
70
+ it 'should set the session data' do
71
+ Session.should_receive(:get).and_return(mock_session)
72
+ mock_session.should_receive(:data=).with({})
73
+ mock_session.should_receive(:dirty?).and_return(true)
74
+ mock_session.should_receive(:updated_at=)
75
+ mock_session.should_receive(:save).and_return(true)
76
+ @store.send(:set_session, nil, "sid", {}).should == true
77
+ end
78
+ end
79
+
80
+ describe 'DatamapperStore with cache' do
81
+
82
+ def mock_session(stubs={})
83
+ @mock_session ||= mock(Session, stubs)
84
+ end
85
+
86
+ before :each do
87
+ load 'lib/datamapper4rails/datamapper_store.rb'
88
+ ActionController::Session::DatamapperStore.send(:class_variable_set, :@@cache, nil)
89
+ ActionController::Session::DatamapperStore.send(:class_variable_set, :@@session_class, nil)
90
+ @store = ActionController::Session::DatamapperStore.new(nil, :cache => true, :session_class => Session)
91
+ end
92
+
93
+ it 'should get the session data from storage' do
94
+ Session.stub!(:get)
95
+ @store.send(:get_session, nil, "sid").should == ["sid",{}]
96
+ Session.stub!(:get).and_return(mock_session)
97
+ mock_session.should_receive(:data).and_return({:id => "id"})
98
+ @store.send(:get_session, nil, "sid").should == ["sid",{:id => "id"}]
99
+ end
100
+
101
+ it 'should get the session data from cache' do
102
+ ActionController::Session::DatamapperStore.send(:class_variable_get, :@@cache)["sid"] = mock_session
103
+ mock_session.should_receive(:data).and_return({:id => "id"})
104
+ @store.send(:get_session, nil, "sid").should == ["sid",{:id => "id"}]
105
+ end
106
+
107
+ it 'should set the session data on new session' do
108
+ Session.should_receive(:get)
109
+ Session.should_receive(:new).with(:session_id => "sid").and_return(mock_session)
110
+ mock_session.should_receive(:data=).with({})
111
+ mock_session.should_receive(:dirty?).and_return(true)
112
+ mock_session.should_receive(:updated_at=)
113
+ mock_session.should_receive(:save).and_return(true)
114
+ @store.send(:set_session, nil, "sid", {}).should == true
115
+ ActionController::Session::DatamapperStore.send(:class_variable_get, :@@cache)["sid"].should == mock_session
116
+
117
+ end
118
+
119
+ it 'should set the session data' do
120
+ Session.should_receive(:get).and_return(mock_session)
121
+ mock_session.should_receive(:data=).with({})
122
+ mock_session.should_receive(:dirty?).and_return(false)
123
+ mock_session.should_receive(:save).and_return(true)
124
+ @store.send(:set_session, nil, "sid", {}).should == true
125
+ ActionController::Session::DatamapperStore.send(:class_variable_get, :@@cache)["sid"].should == mock_session
126
+ end
127
+ end
@@ -0,0 +1,187 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require 'spec_helper'
3
+ require 'datamapper4rails/adapters/restful_adapter'
4
+ require 'slf4r/ruby_logger'
5
+
6
+ class Item
7
+ include DataMapper::Resource
8
+
9
+ property :id, Serial
10
+ property :name, String
11
+
12
+ belongs_to :container
13
+ end
14
+ class User
15
+ include DataMapper::Resource
16
+
17
+ property :id, Serial
18
+
19
+ belongs_to :container
20
+ has n, :groups, :through => Resource
21
+ end
22
+ class Group
23
+ include DataMapper::Resource
24
+
25
+ property :id, Serial
26
+
27
+ has n, :users, :through => Resource
28
+ end
29
+
30
+ class Container
31
+ include DataMapper::Resource
32
+
33
+ property :id, Serial
34
+
35
+ has 1, :user
36
+ has n, :items
37
+ end
38
+
39
+ def mock_attribute(name)
40
+ attr = Object.new
41
+ def attr.name
42
+ @name
43
+ end
44
+ def attr.name=(name)
45
+ @name = name
46
+ end
47
+ attr.name= name
48
+ attr
49
+ end
50
+
51
+ def mock_item(stubs={})
52
+ @mock_item ||= mock(Item, stubs)
53
+ end
54
+
55
+ def mock_query(stubs={})
56
+ @mock_query ||= mock(DataMapper::Query, stubs)
57
+ end
58
+
59
+ describe DataMapper::Adapters::RestfulAdapter do
60
+
61
+ before :each do
62
+ @adapter = DataMapper::Adapters::RestfulAdapter.new(:name, "uri://")
63
+
64
+ def @adapter.key_value_from_query(query)
65
+ 432
66
+ end
67
+ def @adapter.resource_name_from_query(query)
68
+ "item"
69
+ end
70
+ def @adapter.http_put(uri, data)
71
+ @uri = uri
72
+ @data = data
73
+ end
74
+ def @adapter.http_delete(uri)
75
+ @uri = uri
76
+ end
77
+ def @adapter.data
78
+ @data
79
+ end
80
+ def @adapter.uri
81
+ @uri
82
+ end
83
+ def @adapter.body=(b)
84
+ @body = b
85
+ end
86
+ def @adapter.send_request
87
+ res = Object.new
88
+ def res.body=(b)
89
+ @body = b
90
+ end
91
+ def res.body
92
+ @body
93
+ end
94
+ def res.kind_of?(clazz)
95
+ true
96
+ end
97
+ res.body= @body
98
+ res
99
+ end
100
+
101
+ end
102
+
103
+ it 'should create an Item' do
104
+ @adapter.body = "<item><id>123</id><name>zappa</name></item>"
105
+
106
+ item = Item.new
107
+ @adapter.create_resource(item).should == item
108
+ item.id.should == 123
109
+ item.name.should == 'zappa'
110
+ end
111
+
112
+ it 'should update an Item' do
113
+ mock_item.should_receive(:to_query)
114
+ mock_item.should_receive(:name).and_return("item")
115
+ mock_item.should_receive(:to_xml)
116
+
117
+ @adapter.update_resource(mock_item, mock_attribute(:name) => "frank zappa")
118
+
119
+ @adapter.data.should == "<item><name>frank zappa</name></item>"
120
+ end
121
+
122
+ it 'should update Items' do
123
+ mock_query.should_receive(:limit).and_return(1)
124
+ @adapter.update({mock_attribute(:name) => "frank zappa"}, mock_query)
125
+
126
+ @adapter.data.should == "<item><name>frank zappa</name></item>"
127
+ end
128
+
129
+ it 'should delete an Item' do
130
+ mock_item.should_receive(:name).and_return("item")
131
+ mock_item.should_receive(:to_query)
132
+ @adapter.delete_resource(mock_item)
133
+ @adapter.uri.should == "/items/432.xml"
134
+ end
135
+
136
+ it 'should delete Items' do
137
+ mock_query.should_receive(:limit).and_return(1)
138
+ @adapter.delete(mock_query)
139
+
140
+ @adapter.uri.should == "/items/432.xml"
141
+ end
142
+
143
+ it 'should read an Item' do
144
+ @adapter.body = "<item><id>123</id><name>zappa</name></item>"
145
+
146
+ query = DataMapper::Query.new(Item.new.repository, Item)
147
+ item = @adapter.read_resource(query)
148
+ item.id.should == 123
149
+ item.name.should == 'zappa'
150
+ end
151
+
152
+ it 'should read Items' do
153
+ @adapter.body = "<items type='array'><item><id>123</id><name>zappa</name></item></items>"
154
+
155
+ query = DataMapper::Query.new(Item.new.repository, Item)
156
+ items = @adapter.read_resources(query)
157
+ items.size.should == 1
158
+ items[0].id.should == 123
159
+ items[0].name.should == 'zappa'
160
+ end
161
+ #end
162
+
163
+
164
+ #describe 'associations of ' + DataMapper::Adapters::RestfulAdapter.to_s do
165
+ it 'should read nested resource (belongs_to)' do
166
+ @adapter.body = "<item><id>123</id><name>zappa</name>" +
167
+ "<container><id>342</id>" + #<items tpye='array'><item><id>1234</id><name>frank zappa</name></item></items>" +
168
+ "</container>" +
169
+ "</item>"
170
+
171
+ query = DataMapper::Query.new(Item.new.repository, Item)
172
+ item = @adapter.read_resource(query)
173
+ item.id.should == 123
174
+ item.name.should == 'zappa'
175
+ item.container.id.should == 342
176
+ end
177
+
178
+ # it 'should read nested resource (has 1)' do
179
+ # @adapter.body = "<container><id>342</id>" +
180
+ # "<user><id>543</id></user>" +
181
+ # "</container>"
182
+
183
+ # query = DataMapper::Query.new(Container.new.repository, Container)
184
+ # c = @adapter.read_resource(query)
185
+ # c.id.should == 342
186
+ # end
187
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'dm-core'
3
+ $LOAD_PATH << Pathname(__FILE__).dirname.parent.expand_path + 'lib'
4
+
5
+ # just define a empty abstract store
6
+ module ActionController
7
+ module Session
8
+ class AbstractStore
9
+ def initialize(app, options = {})
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ class Session
16
+
17
+ include ::DataMapper::Resource
18
+
19
+ property :session_id, String, :key => true
20
+
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datamapper4rail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - mkristian
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-21 00:00:00 +05:30
12
+ date: 2009-03-28 00:00:00 +05:30
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -64,8 +64,14 @@ files:
64
64
  - lib/datamapper4rails/adapters/restful_adapter.rb
65
65
  - lib/datamapper4rails/database_config.rb
66
66
  - lib/datamapper4rails/datamapper_store.rb
67
+ - lib/datamapper4rails/identity_maps.rb
68
+ - lib/datamapper4rails/preload_models.rb
67
69
  - lib/datamapper4rails/restful_transactions.rb
68
70
  - lib/datamapper4rails/version.rb
71
+ - spec/datamapper_store_spec.rb
72
+ - spec/restful_adapter_spec.rb
73
+ - spec/spec.opts
74
+ - spec/spec_helper.rb
69
75
  has_rdoc: true
70
76
  homepage: http://datamapper4rail.rubyforge.org
71
77
  post_install_message: