georgepalmer-couch_foo 0.7.3 → 0.7.4

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.rdoc CHANGED
@@ -35,7 +35,7 @@ Basic operations are the same as ActiveRecord:
35
35
  class Address < CouchFoo::Base
36
36
  property :number, Integer
37
37
  property :street, String
38
- property :postcode # Any generic type is fine as long as .to_json can be called on it
38
+ property :postcode # Any generic type is fine as long as .to_json and class.from_json(json) can be called on it
39
39
  end
40
40
 
41
41
  address1 = Address.create(:number => 3, :street => "My Street", :postcode => "secret") # Create address
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 7
4
- :patch: 3
4
+ :patch: 4
@@ -191,15 +191,7 @@ module CouchFoo
191
191
  # Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
192
192
  # "2004-12-12" in a data type is cast to a date object, like Date.new(2004, 12, 12)).
193
193
  def read_attribute(attr_name)
194
- if !(value = @attributes[attr_name.to_s]).nil?
195
- if type = type_for_property(attr_name.to_sym)
196
- convert_to_type(value, type)
197
- else
198
- value
199
- end
200
- else
201
- nil
202
- end
194
+ convert_to_type(@attributes[attr_name.to_s], type_for_property(attr_name.to_sym))
203
195
  end
204
196
 
205
197
  def read_attribute_before_type_cast(attr_name)
@@ -211,7 +203,7 @@ module CouchFoo
211
203
  def write_attribute(attr_name, value)
212
204
  attr_name = attr_name.to_s
213
205
  @attributes_cache.delete(attr_name)
214
- @attributes[attr_name] = value
206
+ @attributes[attr_name] = convert_to_json(value, type_for_property(attr_name.to_sym))
215
207
  end
216
208
 
217
209
  def query_attribute(attr_name)
@@ -259,15 +251,46 @@ module CouchFoo
259
251
  end
260
252
 
261
253
  protected
262
- # Converts a value to its type, or if not specified tries calling to_json on the value before
254
+ def convert_to_json(value, type)
255
+ return nil if value.nil?
256
+
257
+ #Not keen on type hack for case statement
258
+ case type.to_s
259
+ when "String"
260
+ value.to_s
261
+ when "Integer"
262
+ value.to_i
263
+ when "Float"
264
+ value.to_f
265
+ when "DateTime"
266
+ DateTime.parse(value.to_s).strftime("%Y/%m/%d %H:%M:%S +0000")
267
+ when "Time"
268
+ Time.at(value.to_f).strftime("%Y/%m/%d %H:%M:%S +0000")
269
+ when "Date"
270
+ Date.new(value.year, value.month, value.day).strftime("%Y/%m/%d %H:%M:%S +0000")
271
+ when "TrueClass"
272
+ convert_boolean(value)
273
+ when "Boolean"
274
+ convert_boolean(value)
275
+ else
276
+ # Calling to_json on Array or Hash makes them strings = bad
277
+ if value.is_a?(Array) || value.is_a?(Hash)
278
+ value
279
+ else
280
+ value.to_json rescue value
281
+ end
282
+ end
283
+ end
284
+
285
+ # Converts a value to its type, or if not specified tries calling from_json on the value before
263
286
  # falling back on just using the value
264
287
  def convert_to_type(value, type)
265
288
  return nil if value.nil?
266
-
289
+
267
290
  #Not keen on type hack for case statement
268
291
  case type.to_s
269
292
  when "String"
270
- value
293
+ value.to_s
271
294
  when "Integer"
272
295
  value.to_i
273
296
  when "Float"
@@ -283,7 +306,7 @@ module CouchFoo
283
306
  when "Boolean"
284
307
  convert_boolean(value)
285
308
  else
286
- value.to_json rescue value
309
+ type.from_json(value) rescue value
287
310
  end
288
311
  end
289
312
 
@@ -109,7 +109,7 @@ module CouchFoo
109
109
  # class Address < CouchFoo::Base
110
110
  # property :number, Integer
111
111
  # property :street, String
112
- # property :postcode # Any generic type is fine as long as .to_json can be called on it
112
+ # property :postcode # Any generic type is fine as long as .to_json and class.from_json(json) can be called on it
113
113
  # end
114
114
  #
115
115
  # Documents have three more properties that get added automatically. _id and _rev are CouchDB
@@ -1030,9 +1030,11 @@ module CouchFoo
1030
1030
 
1031
1031
  # Set a property for the document. These can be passed a type and options hash. If no type
1032
1032
  # is passed a #to_json method is called on the ruby object and the result stored in the
1033
- # database. If a type is passed then the object is cast before storing in the database. This
1034
- # does not guarantee that the object is the correct type (use the validaters for that), it
1035
- # merely tries to convert the current type to the desired one - for example:
1033
+ # database. When it is retrieved from the database a class.from_json(json) method is called
1034
+ # on it or if that doesn't exist it just uses the value. If a type is passed then the object
1035
+ # is cast before storing in the database. This does not guarantee that the object is the
1036
+ # correct type (use the validaters for that), it merely tries to convert the current type to
1037
+ # the desired one - for example:
1036
1038
  # '123' => 123 # useful
1037
1039
  # 'a' => 0 # probably not desired behaviour
1038
1040
  # The later would fail with a validator
@@ -1046,10 +1048,11 @@ module CouchFoo
1046
1048
  # property :number, Integer
1047
1049
  # property :paid, TrueClass, :default => false
1048
1050
  # property :notes, String
1049
- # property :acl
1051
+ # property :acl # or acl, Object is equivalent
1052
+ # property :price, Price
1050
1053
  # end
1051
- def property(name, type = nil, options = {})
1052
- logger.warn("Using type as a column name may issue unexpected behaviour") if name == :type
1054
+ def property(name, type = Object, options = {})
1055
+ logger.warn("Using type as a property name may issue unexpected behaviour") if name == :type
1053
1056
  properties.delete_if{|e| e.name == name} # Subset properties override
1054
1057
  properties << Property.new(name, type, options[:default])
1055
1058
  end
@@ -1295,25 +1298,17 @@ module CouchFoo
1295
1298
  allocate
1296
1299
  end
1297
1300
 
1298
- object.instance_variable_set("@attributes", check_document_types(document))
1301
+ object.instance_variable_set("@attributes", check_document_attributes(document))
1299
1302
  object.instance_variable_set("@attributes_cache", Hash.new)
1300
1303
  object
1301
1304
  end
1302
1305
 
1303
- # Checks that the document only contains types that are listed as properties. Also converts
1304
- # Date, DateTime and Time types into ruby objects (as we write them to the database in a JSON
1305
- # format suitable for sorting)
1306
- def check_document_types(record)
1307
- property_types.each do |property, type|
1308
- value = record[property.to_s]
1309
- if (type == Date || type == DateTime || type == Time)
1310
- record[property.to_s] = type.send(:parse, value) rescue nil
1311
- else
1312
- # Seems pointless but ensures we get attributes for properties that have been added to
1313
- # model since document last saved
1314
- record[property.to_s] = value
1315
- end
1316
- end
1306
+ # Checks that the document only contains types that are listed as properties
1307
+ def check_document_attributes(record)
1308
+ # Add new properties
1309
+ (property_names.map{|p| p.to_s} - record.keys).each {|k| record[k] = nil}
1310
+
1311
+ # Remove old properties
1317
1312
  record.reject!{|key, value| !(unchangeable_property_names + property_names).include?(key.to_sym)}
1318
1313
  record
1319
1314
  end
@@ -1941,7 +1936,7 @@ module CouchFoo
1941
1936
 
1942
1937
  def update
1943
1938
  begin
1944
- response = self.class.database.save(attributes_for_save)
1939
+ response = self.class.database.save(attributes_before_type_cast)
1945
1940
  @attributes["_rev"] = response['rev']
1946
1941
  1
1947
1942
  rescue Exception => e
@@ -1953,7 +1948,7 @@ module CouchFoo
1953
1948
  def create
1954
1949
  @attributes["_id"] = self.class.get_uuid
1955
1950
  begin
1956
- response = self.class.database.save(attributes_for_save.reject{|key,value| key == "_rev"})
1951
+ response = self.class.database.save(attributes_before_type_cast.reject{|key,value| key == "_rev"})
1957
1952
  @attributes["_rev"] = response['rev']
1958
1953
  @new_record = false
1959
1954
  @attributes["_id"]
@@ -1964,18 +1959,6 @@ module CouchFoo
1964
1959
  end
1965
1960
  end
1966
1961
 
1967
- # Attributes but with date/time types convert to JSON sortable format. This creates a copy of
1968
- # the original attributes for saving so doesn't alter the attributes accessible to the user
1969
- def attributes_for_save
1970
- attrs = attributes
1971
- self.class.property_types.each do |name, type|
1972
- if (type == Date || type == DateTime || type == Time)
1973
- attrs[name.to_s] = attrs[name.to_s].strftime("%Y/%m/%d %H:%M:%S +0000") if attrs[name.to_s]
1974
- end
1975
- end
1976
- attrs
1977
- end
1978
-
1979
1962
  # Sets the attribute used for inheritance to this class name if this is not the CouchFoo::Base
1980
1963
  # descendent. Considering the hierarchy Reply < Message < ActiveRecord::Base, this makes it
1981
1964
  # possible to do Reply.new without having to set <tt>Reply[Reply.inheritance_column] = "Reply"</tt>
@@ -122,6 +122,7 @@ module CouchFoo
122
122
  search_fields = options.delete(:use_key)
123
123
  if search_fields
124
124
  search_fields = [search_fields] unless search_fields.is_a?(Array)
125
+ search_fields = search_fields.sort_by{|f| f.to_s}
125
126
  else
126
127
  search_fields = options[:conditions].to_a.sort_by{|f| f.first.to_s}.map(&:first)
127
128
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: georgepalmer-couch_foo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - George Palmer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-02-05 00:00:00 -08:00
12
+ date: 2009-02-06 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency