store_configurable 3.2.4 → 3.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,9 @@
1
1
 
2
+ = 3.2.5
3
+
4
+ * Bypass ActiveRecord forcing all serialized attributes be saved.
5
+
6
+
2
7
  = 3.2.4
3
8
 
4
9
  * The loader will just not send to key names but always use :[] and :[]= for safety.
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  # StoreConfigurable
3
3
 
4
- A zero-configuration recursive Hash for storing a tree of options in a serialized ActiveRecord column. Includes self aware hooks that delegate dirty/changed state to your configs owner.
4
+ A zero-configuration recursive Hash for storing a tree of options in a serialized ActiveRecord column. Includes self aware hooks that delegate dirty/changed state to your configs owner. Read my article [*A Lesson In Recursion In Ruby*](http://metaskills.net/2012/03/12/store-configurable-a-lesson-in-recursion-in-ruby/) if you are interested in how this library works.
5
5
 
6
6
  <img src="http://cdn.actionmoniker.com/share/recursive_kitty_small.jpg" alt="Recursive Github Kitty" width="260" height="160" style="float:right; margin:-20px 35px 15px 15px; background-color:#fff; padding:13px; -moz-box-shadow: 5px 5px 5px rgba(0,0,0,0.5); -webkit-box-shadow: 5px 5px 5px rgba(0,0,0,0.5); box-shadow: 5px 5px 5px rgba(0,0,0,0.5); -moz-transform: rotate(-2deg); -webkit-transform: rotate(-2deg); transform: rotate(-2deg);">
7
7
 
@@ -18,7 +18,7 @@ gem 'store_configurable', '~> 3.2.0'
18
18
 
19
19
  ## Setup
20
20
 
21
- To use StoreConfigurable, you must create create a `_config` colun in the model's table. Make sure that you declare this column as a text type, so there's plenty of room.
21
+ To use StoreConfigurable, you must create a `_config` column in the model's table. Make sure that you declare this column as a text type, so there's plenty of room.
22
22
 
23
23
  ```ruby
24
24
  class AddStoreConfigurableField < ActiveRecord::Migration
@@ -115,6 +115,15 @@ StoreConfigurable persists your configuration data in YAML format to the `_confi
115
115
  - :this: deep_value
116
116
  ```
117
117
 
118
+ ## Todo
119
+
120
+ * Incorporate an option to compress serialized data. Gzip, [MessagePack](http://msgpack.org/), Etc...
121
+
122
+
123
+ ## Other Solutions
124
+
125
+ * [StoreField](https://github.com/kenn/store_field) - Similar approach but no dirty tracking and still requires manual key configs.
126
+
118
127
 
119
128
  ## License
120
129
 
@@ -1,6 +1,6 @@
1
1
  module StoreConfigurable
2
2
  module Read
3
-
3
+
4
4
  # Our main syntatic interface to the underlying +_config+ store. This method ensures that
5
5
  # +self+, the store's owner, will allways be set in the config object. Hence allowing all
6
6
  # other recursive options to get a handle back to the owner.
@@ -55,6 +55,12 @@ module StoreConfigurable
55
55
  config
56
56
  super
57
57
  end
58
+
59
+ # We never want the `_config` key in the list of attributes. This keeps practically keeps
60
+ # ActiveRecord from always saving this serialized column too
61
+ def attributes
62
+ super.tap { |x| x.delete('_config') }
63
+ end
58
64
 
59
65
  end
60
66
  end
@@ -1,6 +1,6 @@
1
1
  module StoreConfigurable
2
2
 
3
3
  # We track ActiveRecord's major and minor version and follow semantic versioning.
4
- VERSION = '3.2.4'
4
+ VERSION = '3.2.5'
5
5
 
6
6
  end
@@ -46,7 +46,7 @@ class StoreConfigurable::BaseTest < StoreConfigurable::TestCase
46
46
  user_ken.config[:sortable_tables][:column].must_equal 'updated_at'
47
47
  end
48
48
 
49
- it 'must be mark owner as dirty after missing getter since that inits a new namespace' do
49
+ it 'must mark owner as dirty after missing getter since that inits a new namespace' do
50
50
  user_ken.config.bar
51
51
  user_ken.must_be :config_changed?
52
52
  end
@@ -78,9 +78,22 @@ class StoreConfigurable::BaseTest < StoreConfigurable::TestCase
78
78
  user_ken.save!
79
79
  @user = User.find(user_ken.id)
80
80
  end
81
-
81
+
82
82
  it 'wont be dirty after loading' do
83
83
  @user.wont_be :config_changed?
84
+ @user.wont_be :changed?
85
+ end
86
+
87
+ it 'does not update the _config column when not dirty, bypassing ActiveRecords always save serialized columns' do
88
+ assert_queries(0) { @user.save! }
89
+ end
90
+
91
+ it 'allows the dirty _config value to be persisted' do
92
+ new_color = '#f1f1f1'
93
+ @user.config.color = new_color
94
+ @user.must_be :changed?
95
+ assert_queries(1) { @user.save! }
96
+ User.find(@user.id).config.color.must_equal new_color
84
97
  end
85
98
 
86
99
  it 'can reconsitute saved values' do
data/test/helper.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
- require "bundler/setup"
3
+ require 'bundler/setup'
4
4
  Bundler.require
5
5
  require 'store_configurable'
6
6
  require 'active_record/base'
7
+ require 'support/activerecord'
7
8
  require 'minitest/autorun'
8
9
  require 'logger'
9
10
 
@@ -14,11 +15,14 @@ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':me
14
15
 
15
16
  module StoreConfigurable
16
17
  class TestCase < MiniTest::Spec
18
+
19
+ include ActiveRecordTestHelper
17
20
 
18
21
  before { setup_environment }
19
22
 
20
23
  let(:new_user) { User.new }
21
24
  let(:user_ken) { User.find_by_email('ken@metaskills.net') }
25
+ let(:post_sc) { Post.find_by_title('StoreConfigurable') }
22
26
 
23
27
  def setup_environment
24
28
  setup_database
@@ -34,12 +38,16 @@ module StoreConfigurable
34
38
  t.string :name, :email
35
39
  t.text :_config
36
40
  end
41
+ connection.create_table :posts, :force => true do |t|
42
+ t.string :title, :body
43
+ end
37
44
  end
38
45
  end
39
46
  end
40
47
 
41
48
  def setup_data
42
49
  User.create :name => 'Ken Collins', :email => 'ken@metaskills.net'
50
+ Post.create :title => 'StoreConfigurable', :body => 'test'
43
51
  end
44
52
 
45
53
  end
@@ -54,3 +62,6 @@ end
54
62
  class User < ActiveRecord::Base
55
63
  store_configurable
56
64
  end
65
+
66
+ class Post < ActiveRecord::Base
67
+ end
@@ -0,0 +1,51 @@
1
+ module StoreConfigurable
2
+ module ActiveRecordTestHelper
3
+
4
+ protected
5
+
6
+ class SQLCounter
7
+
8
+ class << self
9
+ attr_accessor :ignored_sql, :log
10
+ end
11
+
12
+ self.log = []
13
+ self.ignored_sql = [/^PRAGMA (?!(table_info))/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^SHOW max_identifier_length/, /^BEGIN/i, /^COMMIT/i]
14
+
15
+ attr_reader :ignore
16
+
17
+ def initialize(ignore = Regexp.union(self.class.ignored_sql))
18
+ @ignore = ignore
19
+ end
20
+
21
+ def call(name, start, finish, message_id, values)
22
+ sql = values[:sql]
23
+ return if 'CACHE' == values[:name] || ignore =~ sql
24
+ self.class.log << sql
25
+ end
26
+
27
+ end
28
+
29
+ def assert_sql(*patterns_to_match)
30
+ SQLCounter.log = []
31
+ yield
32
+ SQLCounter.log
33
+ ensure
34
+ failed_patterns = []
35
+ patterns_to_match.each do |pattern|
36
+ failed_patterns << pattern unless SQLCounter.log.any?{ |sql| pattern === sql }
37
+ end
38
+ assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}"
39
+ end
40
+
41
+ def assert_queries(num = 1)
42
+ SQLCounter.log = []
43
+ yield
44
+ ensure
45
+ assert_equal num, SQLCounter.log.size, "#{SQLCounter.log.size} instead of #{num} queries were executed.#{SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{SQLCounter.log.join("\n")}"}"
46
+ end
47
+
48
+ ActiveSupport::Notifications.subscribe 'sql.active_record', SQLCounter.new
49
+
50
+ end
51
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store_configurable
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.4
4
+ version: 3.2.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-01 00:00:00.000000000 Z
12
+ date: 2012-09-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &70330795216880 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 3.2.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70330795216880
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.0
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: sqlite3
27
- requirement: &70330795216380 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ~>
@@ -32,10 +37,15 @@ dependencies:
32
37
  version: '1.3'
33
38
  type: :development
34
39
  prerelease: false
35
- version_requirements: *70330795216380
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.3'
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: rake
38
- requirement: &70330795215920 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ~>
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: 0.9.2
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *70330795215920
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.2
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: minitest
49
- requirement: &70330795215420 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ~>
@@ -54,7 +69,12 @@ dependencies:
54
69
  version: 2.8.1
55
70
  type: :development
56
71
  prerelease: false
57
- version_requirements: *70330795215420
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.8.1
58
78
  description: Grown up ActiveRecord::Store config options!
59
79
  email:
60
80
  - ken@metaskills.net
@@ -78,6 +98,7 @@ files:
78
98
  - lib/store_configurable/version.rb
79
99
  - test/cases/base_test.rb
80
100
  - test/helper.rb
101
+ - test/support/activerecord.rb
81
102
  homepage: http://github.com/metaskills/store_configurable/
82
103
  licenses: []
83
104
  post_install_message:
@@ -99,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
120
  version: '0'
100
121
  requirements: []
101
122
  rubyforge_project:
102
- rubygems_version: 1.8.17
123
+ rubygems_version: 1.8.23
103
124
  signing_key:
104
125
  specification_version: 3
105
126
  summary: A zero-configuration recursive Hash for storing a tree of options in a serialized
@@ -107,3 +128,5 @@ summary: A zero-configuration recursive Hash for storing a tree of options in a
107
128
  test_files:
108
129
  - test/cases/base_test.rb
109
130
  - test/helper.rb
131
+ - test/support/activerecord.rb
132
+ has_rdoc: