store_configurable 3.2.4 → 3.2.5

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/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: