dm-xml-adapter 0.57 → 0.58

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/README CHANGED
@@ -1 +1,2 @@
1
1
  This is an XML adapter.
2
+ Set DataMapper::Adapters::XmlAdapter.threads = 2 or more in jruby...
@@ -9,25 +9,22 @@ require 'tempfile'
9
9
  require 'simple_memoize'
10
10
  require 'log4r'
11
11
 
12
-
12
+ # the XML adapter is an adapter for DataMapper that allows you to store
13
+ # data in XML files. beware, it's not transactionally safe.
13
14
  module DataMapper::Adapters
14
15
 
15
16
  class XmlAdapterCache
16
17
 
17
18
  def initialize
18
- #@@logger = Log4r::Logger.new 'cache'
19
- #@@logger.outputters = Log4r::Outputter.stdout
20
19
  @mtimes = Hash.new()
21
20
  @classes = Hash.new()
22
21
  end
23
22
 
24
23
  def set_mtime(file, mtime)
25
- #@@logger.info("Saved mtime, #{file} -> #{mtime}")
26
- @mtimes[file] = mtime
24
+ @mtimes[file] = mtime
27
25
  end
28
26
 
29
27
  def delete_mtime(file)
30
- #@@logger.info("deleting the following mtime: #{file}")
31
28
  @mtimes.delete(file)
32
29
  end
33
30
 
@@ -35,9 +32,7 @@ module DataMapper::Adapters
35
32
  return @mtimes[file]
36
33
  end
37
34
 
38
- def put(classname, id, object)
39
- #@@logger.info("CACHE INSERT: #{classname} #{id} #{object.inspect}")
40
-
35
+ def put(classname, id, object)
41
36
  # check to see if we have a classname entry
42
37
  if (@classes[classname] == nil)
43
38
  @classes[classname] = Hash.new
@@ -45,35 +40,31 @@ module DataMapper::Adapters
45
40
 
46
41
  hash = @classes[classname]
47
42
  hash[id.to_s] = object
48
- # @@logger.info("the hash is: #{hash.inspect}")
49
- end
43
+ end
50
44
 
51
45
  def delete(classname, id)
52
- #@@logger.info("deleted the following from cache: #{classname} #{id.to_s}")
53
46
  hash = @classes[classname]
54
- #@@logger.info("the hash is: #{hash.inspect}")
55
47
  unless hash == nil
56
48
  hash.delete(id.to_s)
57
49
  end
58
- #@@logger.info("the hash is: #{hash.inspect}")
59
- end
50
+ end
60
51
 
61
52
  def get(classname, id)
62
- #@@logger.info("CACHE FETCH: #{classname} #{id}")
63
- #@@logger.info("Master classes: #{@classes.inspect}")
64
53
  hash = @classes[classname]
65
- #@@logger.info("the hash is: #{hash.inspect}")
66
- object = hash[id]
67
- #@@logger.info("The object is: #{object}")
68
- return object
54
+ return hash[id]
69
55
  end
70
56
  end
71
57
 
72
58
  class XmlAdapter < AbstractAdapter
73
59
 
60
+ def self.threads=(count)
61
+ @@threadcount = count
62
+ end
63
+
74
64
  def initialize(name, options)
75
65
  super
76
66
 
67
+ @@threadcount = 1
77
68
  @options = Hash.new
78
69
  @options[:directory] = options[:directory]
79
70
  @options[:directory] ||= './db'
@@ -81,10 +72,7 @@ module DataMapper::Adapters
81
72
  @last_used_id = Hash.new
82
73
 
83
74
  @cache = XmlAdapterCache.new
84
-
85
- #@@logger = Log4r::Logger.new 'adapter'
86
- #@@logger.outputters = Log4r::Outputter.stdout
87
-
75
+
88
76
  end
89
77
 
90
78
  def destroy_model_storage(repository, model)
@@ -95,27 +83,27 @@ module DataMapper::Adapters
95
83
  FileUtils.mkdir_p(classname_to_dir(model.to_s))
96
84
  end
97
85
 
98
- def create(resources)
86
+ def create(resources)
87
+ key = resources.first.model.key.first.name
99
88
  resources.each do |resource|
100
- model = resource.model
101
- id = find_free_id_for(resource.class.to_s)
89
+ id = find_free_id_for(resources.first.class.to_s)
102
90
  # find name of key attribute
103
- key = model.key.first.name
104
91
  resource.attributes[key] = id
105
92
  resource.instance_variable_set("@" + key.to_s, id)
106
93
  save(resource)
107
- end
108
- return resources.size
94
+ end.size
109
95
  end
110
96
 
111
97
  def delete(collection)
112
98
  collection.each do |result|
113
- @last_used_id[result.class.to_s] = result.key.first
99
+ key = result.key.first
100
+ class_name = result.model.to_s
101
+ @last_used_id[class_name] = key
114
102
  xml_destroy(result)
115
103
  # also remove from cache
116
- @cache.delete(result.model.to_s, result.key.first)
104
+ @cache.delete(class_name, key)
117
105
  # also remove from mtimes
118
- @cache.delete_mtime(class_name_to_file(result.model.to_s, result.key.first))
106
+ @cache.delete_mtime(class_name_to_file(class_name, key))
119
107
  end
120
108
  return collection.size
121
109
  end
@@ -146,116 +134,101 @@ module DataMapper::Adapters
146
134
  # take an objects class and ID and figure
147
135
  # out what file it's in
148
136
  # and then remove that file
149
- class_name = resource.class.to_s
150
- id = resource.key.first
151
- file = class_name_to_file(class_name, id)
152
- File.unlink(file)
137
+ File.unlink class_name_to_file(resource.class.to_s, resource.key.first)
153
138
  end
154
139
 
155
140
  def filter_result_set(objects, query)
156
- #puts "before filter: #{objects.inspect}"
157
141
  result_set = objects.clone
158
- result_set = query.filter_records(result_set)
159
- #puts "After filter: #{result_set.inspect}"
160
142
  return query.filter_records(result_set)
161
143
  end
162
144
 
163
145
  def get_all(model)
164
- #@@logger.info("Trying to get all: #{model.to_s}")
165
- directory = classname_to_dir(model.to_s)
146
+ model_name = model.to_s
147
+ directory = classname_to_dir(model_name)
166
148
  if ! File.exists?(directory)
167
- #@@logger.error("The directory doesn't exist!")
168
149
  return []
169
150
  end
151
+
170
152
  objects = []
171
- Dir.entries(directory).select {|f| f.match(/\.xml$/) }.each do |filename|
172
- filename = directory + "/" + filename
153
+ Dir[directory + "/*.xml"].each do |filename|
173
154
  # see if we have a nice cached version
174
- mtime = File.mtime(filename)
175
- cache_mtime = @cache.get_mtime(filename)
176
- #puts "file mtime: #{mtime} cache mtime: #{@cache.get_mtime(filename)}"
177
- if (mtime != nil and cache_mtime != nil)
178
- #puts "comparing! #{mtime < cache_mtime}"
179
- end
180
- if (mtime != nil and cache_mtime != nil and mtime <= cache_mtime)
181
- # we hav ea nice cached object..
182
- objects << @cache.get(model.to_s, file_to_id(filename))
155
+ if has_cached_version?(filename)
156
+ # we have a nice cached object..
157
+ objects << @cache.get(model_name, file_to_id(filename))
183
158
  else
184
- #@@logger.info("CACHE MISS")
185
- # the file's newer, so we gotta load it up
159
+ # the file's newer OR older (aha!!), so we gotta load it up
186
160
  object = file_to_object(filename, model)
187
161
  objects << object
188
- @cache.put(model.to_s, object.key.first, object)
162
+ @cache.put(model_name, object.key.first, object)
189
163
  @cache.set_mtime(filename, File.mtime(filename))
190
164
  end
191
165
  end
192
166
  return objects
193
167
  end
168
+
169
+ def has_cached_version?(filename)
170
+ mtime = File.mtime(filename)
171
+ cache_mtime = @cache.get_mtime(filename)
172
+ return true if (mtime != nil and cache_mtime != nil and mtime == cache_mtime)
173
+ end
194
174
 
195
175
  def file_to_id(file)
196
176
  return file.match(/([0-9]+)\.xml/)[1]
197
177
  end
198
-
199
- def is_integer?(number)
200
- if number.class == String and number.match(/^\-*[0-9]+$/)
201
- return true
202
- end
203
- return false
204
- end
205
178
 
206
179
  def file_to_object(file, model)
207
-
180
+ model_name = model.to_s
208
181
  # allocate new object to receive these fields
209
- if (model.to_s.match(/\:\:/))
210
- modname, clazz = model.to_s.split("::")
182
+ if (model_name.match(/(.*)\:\:(.*)/))
183
+ modname, clazz = [$1, $2]
211
184
  new_obj = Kernel.const_get(modname).const_get(clazz).new
212
185
  else
213
- clazz = model.to_s
214
- new_obj = Kernel.const_get(clazz).new
186
+ new_obj = Kernel.const_get(model_name).new
215
187
  end
216
188
 
217
- # file is our XML file
218
- string = IO.read(file)
219
- parser = XML::Parser.string(string)
220
- doc = parser.parse
221
- root_node = doc.root
222
189
  # iterate over children
223
- root_node.children.each do |child|
190
+ XML::Parser.string(IO.read(file)).parse.root.children.each do |child|
224
191
  child_class = child.attributes["class"]
225
192
  if child_class != nil
226
193
  # this means we have an attribute
227
- if (child_class == "Integer")
228
- new_obj.instance_variable_set("@#{child.name}", child.content.to_i)
229
- elsif (child_class == "String")
230
- new_obj.instance_variable_set("@#{child.name}", child.content)
231
- elsif (child_class == "TrueClass")
232
- new_obj.instance_variable_set("@#{child.name}", true)
233
- elsif (child_class == "FalseClass")
234
- new_obj.instance_variable_set("@#{child.name}", false)
235
- elsif (child_class == "BigDecimal")
236
- new_obj.instance_variable_set("@#{child.name}", BigDecimal.new(child.content))
237
- elsif (child_class == "DateTime")
238
- new_obj.instance_variable_set("@#{child.name}", DateTime.parse(child.content))
239
- end
194
+ populate_instance(new_obj, child, child_class)
240
195
  end
241
196
  end
242
197
 
243
198
  return new_obj
244
199
  end
200
+
201
+ def populate_instance(new_obj, child, child_class)
202
+ if (child_class == "String")
203
+ new_obj.instance_variable_set("@#{child.name}", child.content)
204
+ elsif (child_class == "Integer")
205
+ new_obj.instance_variable_set("@#{child.name}", child.content.to_i)
206
+ elsif (child_class == "TrueClass")
207
+ new_obj.instance_variable_set("@#{child.name}", true)
208
+ elsif (child_class == "FalseClass")
209
+ new_obj.instance_variable_set("@#{child.name}", false)
210
+ elsif (child_class == "BigDecimal")
211
+ new_obj.instance_variable_set("@#{child.name}", BigDecimal.new(child.content))
212
+ elsif (child_class == "DateTime")
213
+ new_obj.instance_variable_set("@#{child.name}", DateTime.parse(child.content))
214
+ elsif (child_class == "Date")
215
+ new_obj.instance_variable_set("@#{child.name}", Date.parse(child.content))
216
+ end
217
+ end
245
218
 
246
- def find_free_id_for(class_name)
219
+ def find_free_id_for(class_name)
247
220
  # if there are no entries in the directory
248
221
  # or the directory doesn't exist
249
222
  # we need to create it...
250
223
  if ! File.exists?(classname_to_dir(class_name))
251
224
  # default ID
252
- return 0
225
+ return 1
253
226
  end
254
227
  directory = Dir.new(classname_to_dir(class_name))
255
228
  if directory.entries.size == 0
256
- return 0
229
+ return 1
257
230
  end
258
- id = @last_used_id[class_name] || 0
231
+ id = @last_used_id[class_name] || 1
259
232
  while true do
260
233
  if ! File.exists?(File.join(directory.path, id.to_s + ".xml"))
261
234
  @last_used_id[class_name] = id
@@ -266,43 +239,39 @@ module DataMapper::Adapters
266
239
  end
267
240
 
268
241
  def save(resource)
269
-
270
242
  # since we're saving, purge the cache
271
- @cache.delete(resource.class.to_s, resource.key.first)
272
- @cache.delete_mtime(class_name_to_file(resource.class.to_s, resource.key.first))
243
+ resource_class = resource.class.to_s
244
+ resource_key = resource.key.first
245
+ @cache.delete(resource_class, resource_key)
246
+ @cache.delete_mtime(class_name_to_file(resource_class, resource_key))
273
247
 
274
- # file = File.join(class_name_to_file(resource.class.to_s, resource.key.first))
275
248
  # see if the directory exists, if it doesn't, we need to create it
276
- if ! File.exists?(classname_to_dir(resource.class.to_s))
277
- FileUtils.mkdir_p(classname_to_dir(resource.class.to_s))
249
+ if ! File.exists?(classname_to_dir(resource_class))
250
+ FileUtils.mkdir_p(classname_to_dir(resource_class))
278
251
  end
279
252
 
280
- # puts resource.model.properties.inspect
281
-
282
253
  # set up builder
283
254
  out_string = ""
284
255
  xml = Builder::XmlMarkup.new(:target => out_string, :indent => 1)
285
256
 
286
257
  # iterate over the resource and figure out the fields
287
- # class_name = resource.model.to_s.gsub(/\:/, "_")
288
258
  xml.tag!("RubyObject", :class => resource.model.to_s) do
289
259
  resource.model.properties.each do |property|
290
- #puts "saving prop: #{property.name}"
291
- #puts "primitive: #{property.primitive}"
292
- value = resource.instance_variable_get("@" + property.name.to_s)
260
+ property_name = property.name.to_s
261
+ value = resource.instance_variable_get("@" + property_name)
293
262
  # special case for false
294
263
  if property.primitive == TrueClass and value == false
295
- xml.tag!(property.name.to_s, false, :class => FalseClass.to_s)
296
- elsif (value != nil and property.primitive == BigDecimal)
297
- xml.tag!(property.name.to_s, value.to_s("F"), :class => BigDecimal)
264
+ xml.tag!(property_name, false, :class => FalseClass.to_s)
265
+ elsif (property.primitive == BigDecimal and value != nil)
266
+ xml.tag!(property_name, value.to_s("F"), :class => BigDecimal)
298
267
  elsif (value != nil)
299
- xml.tag!(property.name.to_s, value, :class => property.primitive)
268
+ xml.tag!(property_name, value, :class => property.primitive)
300
269
  end
301
270
  end
302
271
  end
303
272
 
304
- xmlfile = File.new(class_name_to_file(resource.class.to_s, resource.key.first), "w")
305
- tempfile = Tempfile.new("dm-xml-adapter", "/tmp")
273
+ xmlfile = File.new(class_name_to_file(resource_class, resource_key), "w")
274
+ tempfile = Tempfile.new("dm-xml-adapter", Dir.tmpdir())
306
275
  tempfile.puts out_string
307
276
  tempfile.close
308
277
  FileUtils.mv(tempfile.path,xmlfile.path)
@@ -3,6 +3,8 @@ require 'dm-core'
3
3
  require 'pathname'
4
4
  require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
5
5
 
6
+ DataMapper::Adapters::XmlAdapter.threads = 2
7
+
6
8
  describe DataMapper::Adapters::XmlAdapter do
7
9
  before(:each) do
8
10
  @adapter = DataMapper.setup(:default, {:adapter => 'xml', :directory => 'db'})
@@ -49,6 +51,17 @@ describe DataMapper::Adapters::XmlAdapter do
49
51
  end
50
52
  end
51
53
 
54
+ describe "date" do
55
+ it "should do date" do
56
+ u1 = XMLTest::User.new
57
+ u1.name = "cool!"
58
+ u1.date = Date.parse("01/01/2001")
59
+ u1.save
60
+ u2 = XMLTest::User.first(:name => "cool!")
61
+ u2.date.class.should == Date
62
+ end
63
+ end
64
+
52
65
  describe "boolean" do
53
66
  it "should be boolean" do
54
67
  u1 = XMLTest::User.new
data/spec/spec_helper.rb CHANGED
@@ -45,6 +45,7 @@ class User
45
45
  property :created, DateTime
46
46
  property :cool, Boolean
47
47
  property :content, String
48
+ property :date, Date
48
49
 
49
50
  has n, :posts, :model => "Post"
50
51
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-xml-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.57"
4
+ version: "0.58"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Harding
@@ -9,7 +9,7 @@ autorequire: dm-xml-adapter
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-07 00:00:00 -05:00
12
+ date: 2010-07-01 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -42,6 +42,26 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: "0"
44
44
  version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: log4r
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: peach
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
45
65
  description:
46
66
  email: josh@statewidesoftware.com
47
67
  executables: []