property_sets 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/benchmark/read.rb ADDED
@@ -0,0 +1,82 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test/helper')
2
+
3
+ class Account < ActiveRecord::Base
4
+ # Benchmark reading from an object with many settings when:
5
+ # 1. Settings are undefined and use the default value (empty)
6
+ # 2. Settings are defined and use the database value (fully defined)
7
+
8
+ # This is a fairly realastic example of an object that has a lot of settings
9
+ property_set :benchmark_settings do
10
+ # 30 simple objects
11
+ 10.times do |i|
12
+ property "float_prop_#{i}", :type => :float, :default => 3.1415
13
+ property "int_prop_#{i}", :type => :integer, :default => 22
14
+ property "string_prop_#{i}", :type => :string, :default => "Sausalito, CA"
15
+ end
16
+
17
+ # 10 complex
18
+ 5.times do |i|
19
+ property "datetime_prop_#{i}", :type => :datetime, :default => Time.now.to_s
20
+ property "serialized_prop_#{i}", :type => :serialized, :default => { "Hello" => "There" }
21
+ end
22
+
23
+ # 60 booleans
24
+ 60.times do |i|
25
+ property "boolean_prop_#{i}", :type => :boolean, :default => true
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ class BenchmarkRead < ActiveSupport::TestCase
32
+
33
+ context "property sets" do
34
+
35
+ setup do
36
+ @account = Account.create(:name => "Name")
37
+ end
38
+
39
+ should "benchmark fully defined settings" do
40
+ # Most settings are defined and will come from the database
41
+ @account.benchmark_settings.keys.each do |key|
42
+ @account.benchmark_settings.build_default(key)
43
+ end
44
+ @account.save!
45
+ @account.reload
46
+ assert_equal 100, @account.benchmark_settings.count
47
+
48
+ GC.start
49
+ full_timing = Benchmark.ms do
50
+ 1_000.times do
51
+ read_settings(@account)
52
+ end
53
+ end
54
+ puts "Reading fully defined settings: #{full_timing}ms"
55
+ end
56
+
57
+ should "benchmark defaults" do
58
+ assert_equal 0, @account.benchmark_settings.count
59
+ # Most settings are undefined and will use the default value
60
+ GC.start
61
+ empty_timing = Benchmark.ms do
62
+ 1_000.times do
63
+ read_settings(@account)
64
+ end
65
+ end
66
+ puts "Reading empty settings: #{empty_timing}ms"
67
+ end
68
+
69
+ end
70
+
71
+ def read_settings(account)
72
+ account.benchmark_settings.float_prop_1
73
+ account.benchmark_settings.int_prop_1
74
+ account.benchmark_settings.string_prop_1
75
+ account.benchmark_settings.datetime_prop_1
76
+ account.benchmark_settings.boolean_prop_20?
77
+ account.benchmark_settings.boolean_prop_30?
78
+ account.benchmark_settings.boolean_prop_40?
79
+ account.benchmark_settings.boolean_prop_50?
80
+ end
81
+
82
+ end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/primdahl/Git/property_sets
3
3
  specs:
4
- property_sets (2.0.0)
4
+ property_sets (2.0.1)
5
5
  activerecord (>= 2.3.14, < 3.3)
6
6
  activesupport (>= 2.3.14, < 3.3)
7
7
  json
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/primdahl/Git/property_sets
3
3
  specs:
4
- property_sets (2.0.0)
4
+ property_sets (2.0.1)
5
5
  activerecord (>= 2.3.14, < 3.3)
6
6
  activesupport (>= 2.3.14, < 3.3)
7
7
  json
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/primdahl/Git/property_sets
3
3
  specs:
4
- property_sets (2.0.0)
4
+ property_sets (2.0.1)
5
5
  activerecord (>= 2.3.14, < 3.3)
6
6
  activesupport (>= 2.3.14, < 3.3)
7
7
  json
@@ -38,12 +38,15 @@ module PropertySets
38
38
 
39
39
  # Reports the coerced truth value of the property
40
40
  define_method "#{key}?" do
41
- lookup_or_default(key).true?
41
+ type = property_class.type(key)
42
+ value = lookup_value(type, key)
43
+ ![ "false", "0", "", "off", "n" ].member?(value.to_s.downcase)
42
44
  end
43
45
 
44
46
  # Returns the value of the property
45
47
  define_method "#{key}" do
46
- PropertySets::Casting.read(property_class.type(key), lookup(key).value)
48
+ type = property_class.type(key)
49
+ lookup_value(type, key)
47
50
  end
48
51
 
49
52
  # Assigns a new value to the property
@@ -83,13 +86,47 @@ module PropertySets
83
86
  end
84
87
 
85
88
  def build_default(arg)
86
- build(:name => arg.to_s, :value => default(arg))
89
+ build(:name => arg.to_s, :value => raw_default(arg))
87
90
  end
88
91
 
89
92
  def lookup_without_default(arg)
90
93
  detect { |property| property.name.to_sym == arg.to_sym }
91
94
  end
92
95
 
96
+ if ActiveRecord::VERSION::STRING < "3.2.0"
97
+ def lookup_value(type, key)
98
+ serialized = property_serialized?(key)
99
+
100
+ if instance = lookup_without_default(key)
101
+ instance.value_serialized = serialized
102
+ PropertySets::Casting.read(type, instance.value)
103
+ else
104
+ value = default(key)
105
+ if serialized
106
+ PropertySets::Casting.deserialize(value)
107
+ else
108
+ PropertySets::Casting.read(type, value)
109
+ end
110
+ end
111
+ end
112
+ else
113
+ def lookup_value(type, key)
114
+ serialized = property_serialized?(key)
115
+
116
+ if instance = lookup_without_default(key)
117
+ instance.value_serialized = serialized
118
+ PropertySets::Casting.read(type, instance.value)
119
+ else
120
+ value = proxy_association.klass.default(key)
121
+ if serialized
122
+ PropertySets::Casting.deserialize(value)
123
+ else
124
+ PropertySets::Casting.read(type, value)
125
+ end
126
+ end
127
+ end
128
+ end
129
+
93
130
  # The finder method which returns the property if present, otherwise a new instance with defaults
94
131
  def lookup(arg)
95
132
  instance = lookup_without_default(arg)
@@ -116,7 +153,7 @@ module PropertySets
116
153
  else
117
154
  association_class = @reflection.klass
118
155
  end
119
- association_class.new(:value => default(arg))
156
+ association_class.new(:value => raw_default(arg))
120
157
  end
121
158
  instance.value_serialized = property_serialized?(arg)
122
159
  instance
@@ -41,5 +41,10 @@ module PropertySets
41
41
  end
42
42
  end
43
43
 
44
+ def self.deserialize(value)
45
+ return nil if value.nil? || value == "null"
46
+ JSON.parse(value)
47
+ end
48
+
44
49
  end
45
50
  end
@@ -29,8 +29,7 @@ module PropertySets
29
29
  def value
30
30
  if value_serialized
31
31
  v = read_attribute(:value)
32
- return nil if v.nil? || v == "null"
33
- @deserialized_value ||= JSON.parse(v)
32
+ @deserialized_value ||= PropertySets::Casting.deserialize(v)
34
33
  else
35
34
  super
36
35
  end
@@ -100,6 +99,12 @@ module PropertySets
100
99
  end
101
100
 
102
101
  def default(key)
102
+ if @properties[key] && @properties[key].key?(:default)
103
+ PropertySets::Casting.read(type(key), @properties[key][:default])
104
+ end
105
+ end
106
+
107
+ def raw_default(key)
103
108
  @properties[key] && @properties[key].key?(:default) ? @properties[key][:default] : nil
104
109
  end
105
110
 
@@ -1,4 +1,4 @@
1
- Gem::Specification.new "property_sets", "2.0.0" do |s|
1
+ Gem::Specification.new "property_sets", "2.0.1" do |s|
2
2
  s.summary = "Property sets for ActiveRecord."
3
3
  s.description = "This gem is an ActiveRecord extension which provides a convenient interface for managing per row properties."
4
4
  s.authors = ["Morten Primdahl"]
data/test/database.rb CHANGED
@@ -65,6 +65,16 @@ ActiveRecord::Schema.define(:version => 1) do
65
65
 
66
66
  add_index :account_typed_data, [ :account_id, :name ], :unique => true
67
67
 
68
+ create_table "account_benchmark_settings", :force => true do |t|
69
+ t.integer "account_id"
70
+ t.string "name"
71
+ t.string "value"
72
+ t.datetime "created_at"
73
+ t.datetime "updated_at"
74
+ end
75
+
76
+ add_index :account_benchmark_settings, [ :account_id, :name ], :unique => true
77
+
68
78
  create_table "accounts", :force => true do |t|
69
79
  t.string "name"
70
80
  t.datetime "created_at"
data/test/helper.rb CHANGED
@@ -30,6 +30,12 @@ end
30
30
  ActiveSupport::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
31
31
  $LOAD_PATH.unshift(ActiveSupport::TestCase.fixture_path)
32
32
 
33
+ class ActsLikeAnInteger
34
+ def to_i
35
+ 123
36
+ end
37
+ end
38
+
33
39
  class Account < ActiveRecord::Base
34
40
  property_set :settings do
35
41
  property :foo
@@ -58,5 +64,7 @@ class Account < ActiveRecord::Base
58
64
  property :float_prop, :type => :float
59
65
  property :int_prop, :type => :integer
60
66
  property :serialized_prop, :type => :serialized
67
+ property :default_prop, :type => :integer, :default => ActsLikeAnInteger.new
68
+ property :serialized_prop_with_default, :type => :serialized, :default => "[]"
61
69
  end
62
70
  end
@@ -270,6 +270,11 @@ class TestPropertySets < ActiveSupport::TestCase
270
270
  end
271
271
 
272
272
  context "typed columns" do
273
+
274
+ should "typecast the default value" do
275
+ assert_equal 123, @account.typed_data.default(:default_prop)
276
+ end
277
+
273
278
  context "string data" do
274
279
  should "be writable and readable" do
275
280
  @account.typed_data.string_prop = "foo"
@@ -301,6 +306,7 @@ class TestPropertySets < ActiveSupport::TestCase
301
306
  should "be writable and readable" do
302
307
  ts = Time.at(Time.now.to_i)
303
308
  @account.typed_data.datetime_prop = ts
309
+
304
310
  assert_equal ts, @account.typed_data.datetime_prop
305
311
  @account.save!
306
312
  assert_equal ts, @account.typed_data.datetime_prop
@@ -324,6 +330,10 @@ class TestPropertySets < ActiveSupport::TestCase
324
330
  assert_equal({'a' => 1, 'b' => 2}, @account.typed_data.serialized_prop)
325
331
  end
326
332
 
333
+ should "retrieve default values from JSON" do
334
+ assert_equal([], @account.typed_data.serialized_prop_with_default)
335
+ end
336
+
327
337
  should "not overflow the column" do
328
338
  @account.typed_data.serialized_prop = (1..100_000).to_a
329
339
  assert !@account.typed_data.lookup(:serialized_prop).valid?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: property_sets
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-15 00:00:00.000000000 Z
12
+ date: 2013-07-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -204,6 +204,7 @@ files:
204
204
  - LICENSE
205
205
  - README.md
206
206
  - Rakefile
207
+ - benchmark/read.rb
207
208
  - gemfiles/rails2.3.gemfile
208
209
  - gemfiles/rails2.3.gemfile.lock
209
210
  - gemfiles/rails3.0.gemfile
@@ -245,7 +246,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
245
246
  version: '0'
246
247
  requirements: []
247
248
  rubyforge_project:
248
- rubygems_version: 1.8.23
249
+ rubygems_version: 1.8.25
249
250
  signing_key:
250
251
  specification_version: 3
251
252
  summary: Property sets for ActiveRecord.