property_sets 0.6.2 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -49,6 +49,7 @@ module PropertySets
49
49
  define_method "#{key}=" do |value|
50
50
  instance = lookup(key)
51
51
  instance.value = PropertySets::Casting.write(property_class.type(key), value)
52
+ instance.value
52
53
  end
53
54
 
54
55
  define_method "#{key}_record" do
@@ -56,6 +57,10 @@ module PropertySets
56
57
  end
57
58
  end
58
59
 
60
+ define_method :property_serialized? do |key|
61
+ property_class.type(key) == :serialized
62
+ end
63
+
59
64
  def save(*args)
60
65
  each { |p| p.save(*args) }
61
66
  end
@@ -88,6 +93,7 @@ module PropertySets
88
93
  def lookup(arg)
89
94
  instance = lookup_without_default(arg)
90
95
  instance ||= build_default(arg)
96
+ instance.value_serialized = property_serialized?(arg)
91
97
 
92
98
  if ActiveRecord::VERSION::MAJOR == 3
93
99
  owner = proxy_association.owner
@@ -102,7 +108,7 @@ module PropertySets
102
108
  # This finder method returns the property if present, otherwise a new instance with the default value.
103
109
  # It does not have the side effect of adding a new setting object.
104
110
  def lookup_or_default(arg)
105
- instance = detect { |property| property.name.to_sym == arg.to_sym }
111
+ instance = lookup_without_default(arg)
106
112
  instance ||= begin
107
113
  if ActiveRecord::VERSION::MAJOR == 3
108
114
  association_class = proxy_association.klass
@@ -111,6 +117,8 @@ module PropertySets
111
117
  end
112
118
  association_class.new(:value => default(arg))
113
119
  end
120
+ instance.value_serialized = property_serialized?(arg)
121
+ instance
114
122
  end
115
123
  end
116
124
  end
@@ -1,3 +1,5 @@
1
+ require 'json'
2
+
1
3
  module PropertySets
2
4
  module Casting
3
5
 
@@ -15,6 +17,9 @@ module PropertySets
15
17
  value.to_i
16
18
  when :boolean
17
19
  ![ "false", "0", "", "off", "n" ].member?(value.to_s.downcase)
20
+ when :serialized
21
+ # deserialization happens in the model
22
+ value
18
23
  end
19
24
  end
20
25
 
@@ -28,6 +33,9 @@ module PropertySets
28
33
  else
29
34
  value.in_time_zone("UTC").to_s
30
35
  end
36
+ when :serialized
37
+ # write the object directly.
38
+ value
31
39
  else
32
40
  value.to_s
33
41
  end
@@ -24,10 +24,36 @@ module PropertySets
24
24
  self.class.protected?(name.to_sym)
25
25
  end
26
26
 
27
+ def value
28
+ if value_serialized
29
+ v = read_attribute(:value)
30
+ return nil if v == "null"
31
+ @deserialized_value ||= JSON.parse(v)
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ def value=(v)
38
+ if value_serialized
39
+ @deserialized_value = v
40
+ write_attribute(:value, v.to_json)
41
+ else
42
+ super(v)
43
+ end
44
+ end
45
+
46
+ def reload(*args, &block)
47
+ @deserialized_value = nil
48
+ super
49
+ end
50
+
27
51
  def to_s
28
52
  value.to_s
29
53
  end
30
54
 
55
+ attr_accessor :value_serialized
56
+
31
57
  private
32
58
 
33
59
  def validate_format_of_name
@@ -38,10 +64,17 @@ module PropertySets
38
64
  end
39
65
  end
40
66
 
41
- def coerce_value
42
- self.value = value.to_s unless value.nil?
67
+ def validate_length_of_serialized_data
68
+ if value_serialized && self.read_attribute(:value).to_s.size > self.class.columns_hash["value"].limit
69
+ errors.add(:value, :invalid)
70
+ end
43
71
  end
44
72
 
73
+ def coerce_value
74
+ if value && !value_serialized
75
+ self.value = value.to_s
76
+ end
77
+ end
45
78
 
46
79
  def owner_class_instance
47
80
  send(self.class.owner_class_sym)
@@ -51,6 +84,7 @@ module PropertySets
51
84
  module ClassMethods
52
85
  def self.extended(base)
53
86
  base.validate :validate_format_of_name
87
+ base.validate :validate_length_of_serialized_data
54
88
  base.before_create :coerce_value
55
89
  end
56
90
 
data/lib/property_sets.rb CHANGED
@@ -3,7 +3,7 @@ require 'property_sets/active_record_extension'
3
3
  require 'property_sets/action_view_extension'
4
4
 
5
5
  module PropertySets
6
- VERSION = "0.6.2"
6
+ VERSION = "0.7.1"
7
7
 
8
8
  def self.ensure_property_set_class(association, owner_class)
9
9
  const_name = "#{owner_class.name}#{association.to_s.singularize.capitalize}".to_sym
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'property_sets'
16
- s.version = '0.6.2'
17
- s.date = '2012-03-22'
16
+ s.version = '0.7.1'
17
+ s.date = '2012-04-09'
18
18
  s.rubyforge_project = 'property_sets'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -50,6 +50,7 @@ Gem::Specification.new do |s|
50
50
  s.add_runtime_dependency("activesupport", ">= 2.3.14", "< 3.3")
51
51
  s.add_runtime_dependency("activerecord", ">= 2.3.14", "< 3.3")
52
52
  s.add_runtime_dependency("actionpack", ">= 2.3.14", "< 3.3")
53
+ s.add_runtime_dependency("json")
53
54
 
54
55
  ## List your development dependencies here. Development dependencies are
55
56
  ## those that are only needed during development
data/test/helper.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
2
4
  require 'active_support'
3
5
  require 'test/unit'
4
6
  require 'active_record'
@@ -69,5 +71,6 @@ class Account < ActiveRecord::Base
69
71
  property :datetime_prop, :type => :datetime
70
72
  property :float_prop, :type => :float
71
73
  property :int_prop, :type => :integer
74
+ property :serialized_prop, :type => :serialized
72
75
  end
73
76
  end
data/test/test_casting.rb CHANGED
@@ -8,6 +8,10 @@ class TestCasting < ActiveSupport::TestCase
8
8
  assert_equal nil, PropertySets::Casting.read(:string, nil)
9
9
  assert_equal nil, PropertySets::Casting.read(:hello, nil)
10
10
  end
11
+
12
+ should "leave serialized data alone" do
13
+ assert_equal [1,2,3], PropertySets::Casting.read(:serialized, [1, 2, 3])
14
+ end
11
15
  end
12
16
 
13
17
  context "Casting#write" do
@@ -24,6 +28,11 @@ class TestCasting < ActiveSupport::TestCase
24
28
  should "convert integers to strings" do
25
29
  assert_equal "123", PropertySets::Casting.write(:integer, 123)
26
30
  end
31
+
32
+ should "leave serialized data alone for the record to deal with" do
33
+ a = [123]
34
+ assert_equal a, PropertySets::Casting.write(:serialized, a)
35
+ end
27
36
  end
28
37
 
29
38
  end
@@ -302,6 +302,34 @@ class TestPropertySets < ActiveSupport::TestCase
302
302
  assert_equal string_rep, @account.typed_data.lookup("datetime_prop").value
303
303
  end
304
304
  end
305
+
306
+ context "serialized data" do
307
+ should "store data in json" do
308
+ value = {:a => 1, :b => 2}
309
+ @account.typed_data.serialized_prop = value
310
+ @account.save!
311
+ @account.reload
312
+ assert_equal({'a' => 1, 'b' => 2}, @account.typed_data.serialized_prop)
313
+ end
314
+
315
+ should "not overflow the column" do
316
+ @account.typed_data.serialized_prop = (1..100_000).to_a
317
+ assert !@account.typed_data.lookup(:serialized_prop).valid?
318
+ assert !@account.save
319
+ end
320
+
321
+ should "allow for destructive operators" do
322
+ value = {:a => 1, :b => 2}
323
+ @account.typed_data.serialized_prop = value
324
+ @account.typed_data.serialized_prop[:c] = 3
325
+ assert_equal 3, @account.typed_data.serialized_prop[:c]
326
+ end
327
+
328
+ should "deal with nil values properly" do
329
+ @account.typed_data.serialized_prop = nil
330
+ @account.save!
331
+ end
332
+ end
305
333
  end
306
334
  end
307
335
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: property_sets
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 1
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 6
9
- - 2
10
- version: 0.6.2
8
+ - 7
9
+ - 1
10
+ version: 0.7.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Morten Primdahl
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-03-22 00:00:00 Z
18
+ date: 2012-04-09 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activesupport
@@ -87,7 +87,7 @@ dependencies:
87
87
  type: :runtime
88
88
  version_requirements: *id003
89
89
  - !ruby/object:Gem::Dependency
90
- name: rake
90
+ name: json
91
91
  prerelease: false
92
92
  requirement: &id004 !ruby/object:Gem::Requirement
93
93
  none: false
@@ -98,10 +98,10 @@ dependencies:
98
98
  segments:
99
99
  - 0
100
100
  version: "0"
101
- type: :development
101
+ type: :runtime
102
102
  version_requirements: *id004
103
103
  - !ruby/object:Gem::Dependency
104
- name: bundler
104
+ name: rake
105
105
  prerelease: false
106
106
  requirement: &id005 !ruby/object:Gem::Requirement
107
107
  none: false
@@ -115,7 +115,7 @@ dependencies:
115
115
  type: :development
116
116
  version_requirements: *id005
117
117
  - !ruby/object:Gem::Dependency
118
- name: shoulda
118
+ name: bundler
119
119
  prerelease: false
120
120
  requirement: &id006 !ruby/object:Gem::Requirement
121
121
  none: false
@@ -129,7 +129,7 @@ dependencies:
129
129
  type: :development
130
130
  version_requirements: *id006
131
131
  - !ruby/object:Gem::Dependency
132
- name: mocha
132
+ name: shoulda
133
133
  prerelease: false
134
134
  requirement: &id007 !ruby/object:Gem::Requirement
135
135
  none: false
@@ -143,7 +143,7 @@ dependencies:
143
143
  type: :development
144
144
  version_requirements: *id007
145
145
  - !ruby/object:Gem::Dependency
146
- name: appraisal
146
+ name: mocha
147
147
  prerelease: false
148
148
  requirement: &id008 !ruby/object:Gem::Requirement
149
149
  none: false
@@ -156,6 +156,20 @@ dependencies:
156
156
  version: "0"
157
157
  type: :development
158
158
  version_requirements: *id008
159
+ - !ruby/object:Gem::Dependency
160
+ name: appraisal
161
+ prerelease: false
162
+ requirement: &id009 !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ hash: 3
168
+ segments:
169
+ - 0
170
+ version: "0"
171
+ type: :development
172
+ version_requirements: *id009
159
173
  description: This gem is an ActiveRecord extension which provides a convenient interface for managing per row properties.
160
174
  email: primdahl@me.com
161
175
  executables: []