kvc 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.txt → History.rdoc} +7 -0
- data/{README.txt → README.rdoc} +7 -9
- data/Rakefile +0 -6
- data/lib/kvc.rb +6 -2
- data/lib/kvc/settings.rb +25 -2
- data/lib/kvc/settings_proxy.rb +8 -4
- data/test/kvc_test.rb +70 -1
- metadata +9 -18
data/{README.txt → README.rdoc}
RENAMED
@@ -61,14 +61,12 @@ If need be, validate specific key values in an initializer:
|
|
61
61
|
|
62
62
|
Install:
|
63
63
|
|
64
|
-
% gem install
|
64
|
+
% gem install kvc
|
65
65
|
|
66
66
|
|
67
67
|
And configure:
|
68
68
|
|
69
|
-
config.gem "
|
70
|
-
:lib => "kvc",
|
71
|
-
:source => "http://gems.github.com"
|
69
|
+
config.gem "kvc"
|
72
70
|
|
73
71
|
|
74
72
|
=== As a plugin
|
@@ -98,11 +96,11 @@ the table at any time, execute the "kvc:drop_table" Rake task).
|
|
98
96
|
|
99
97
|
(c) 2009-* Stephen Celis, stephen@stephencelis.com.
|
100
98
|
|
101
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
102
|
-
of this software and associated documentation files (the "Software"), to deal
|
103
|
-
in the Software without restriction, including without limitation the rights
|
104
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
105
|
-
copies of the Software, and to permit persons to whom the Software is
|
99
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
100
|
+
of this software and associated documentation files (the "Software"), to deal
|
101
|
+
in the Software without restriction, including without limitation the rights
|
102
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
103
|
+
copies of the Software, and to permit persons to whom the Software is
|
106
104
|
furnished to do so, subject to the following conditions:
|
107
105
|
|
108
106
|
The above copyright notice and this permission notice shall be included in all
|
data/Rakefile
CHANGED
@@ -1,14 +1,8 @@
|
|
1
1
|
$: << File.dirname(__FILE__) + "/lib"
|
2
2
|
require "rubygems"
|
3
|
-
require "hoe"
|
4
3
|
require "active_record"
|
5
4
|
require "kvc"
|
6
5
|
|
7
|
-
Hoe.new("kvc", KVC::VERSION) do |p|
|
8
|
-
p.developer("Stephen Celis", "stephen@stephencelis.com")
|
9
|
-
p.remote_rdoc_dir = ''
|
10
|
-
end
|
11
|
-
|
12
6
|
require 'rake'
|
13
7
|
require 'rake/testtask'
|
14
8
|
require 'rake/rdoctask'
|
data/lib/kvc.rb
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
# Or get creative:
|
19
19
|
#
|
20
20
|
# KVC["Chad's expensive guitar"] = Fender::Stratocaster.new(1957)
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# By default, nonexistent keys return +nil+ values, but you can be stricter if
|
23
23
|
# you want to avoid typo-based bugs:
|
24
24
|
#
|
@@ -35,7 +35,7 @@
|
|
35
35
|
#
|
36
36
|
# Failed validations will raise <tt>ActiveRecord::RecordInvalid</tt>.
|
37
37
|
module KVC
|
38
|
-
VERSION = "0.0
|
38
|
+
VERSION = "0.1.0"
|
39
39
|
|
40
40
|
class << self
|
41
41
|
def [](key)
|
@@ -65,3 +65,7 @@ module KVC
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
def KVC(key)
|
70
|
+
KVC[key]
|
71
|
+
end
|
data/lib/kvc/settings.rb
CHANGED
@@ -13,10 +13,16 @@ class KVC::Settings < ActiveRecord::Base
|
|
13
13
|
@@strict_keys = false
|
14
14
|
cattr_accessor :strict_keys
|
15
15
|
|
16
|
+
# Reload serialized <tt>ActiveRecord::Base</tt> records.
|
17
|
+
@@reload_records = true
|
18
|
+
cattr_accessor :reload_records
|
19
|
+
|
16
20
|
@@validations = HashWithIndifferentAccess.new []
|
17
21
|
cattr_reader :validations
|
22
|
+
|
18
23
|
class << self
|
19
|
-
alias strict_keys?
|
24
|
+
alias strict_keys? strict_keys
|
25
|
+
alias reload_records? reload_records
|
20
26
|
|
21
27
|
# Config takes a block for configuration. For now, this provides
|
22
28
|
# rudimentary validation. E.g.:
|
@@ -33,6 +39,23 @@ class KVC::Settings < ActiveRecord::Base
|
|
33
39
|
self
|
34
40
|
end.instance_eval(&block)
|
35
41
|
end
|
42
|
+
|
43
|
+
# Recursively reload saved records. To short-circuit record reloading, set
|
44
|
+
# <tt>KVC::Settings.reload_records = false</tt>.
|
45
|
+
def deserialize(object)
|
46
|
+
return object unless reload_records?
|
47
|
+
|
48
|
+
case object
|
49
|
+
when ActiveRecord::Base
|
50
|
+
object.new_record? ? object : object.reload
|
51
|
+
when Array
|
52
|
+
object.map { |o| deserialize(o) }
|
53
|
+
when Hash
|
54
|
+
object.each { |k, v| object[k] = deserialize(v) }
|
55
|
+
else
|
56
|
+
object
|
57
|
+
end
|
58
|
+
end
|
36
59
|
end
|
37
60
|
|
38
61
|
# Active Record does not automatically namespace tables.
|
@@ -43,7 +66,7 @@ class KVC::Settings < ActiveRecord::Base
|
|
43
66
|
|
44
67
|
# Deserializes value from database.
|
45
68
|
def value
|
46
|
-
@value ||= YAML.load
|
69
|
+
@value ||= KVC::Settings.deserialize YAML.load(read_attribute(:value))
|
47
70
|
end
|
48
71
|
|
49
72
|
# Serializes value for database.
|
data/lib/kvc/settings_proxy.rb
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
class KVC::SettingsProxy
|
8
8
|
undef_method *instance_methods.grep(/^(?!__|nil\?|send)/)
|
9
9
|
|
10
|
+
attr_reader :setting
|
11
|
+
|
10
12
|
def initialize(setting)
|
11
13
|
@setting = setting
|
12
14
|
end
|
@@ -14,11 +16,13 @@ class KVC::SettingsProxy
|
|
14
16
|
private
|
15
17
|
|
16
18
|
def method_missing(method, *args, &block)
|
17
|
-
return
|
19
|
+
return setting.send(method) if [:created_at, :updated_at].include? method
|
20
|
+
|
21
|
+
return_value = setting.value.send(method, *args, &block)
|
22
|
+
stored_value = KVC::Settings.deserialize YAML.load(setting[:value])
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
@setting.update_attribute :value, @setting.value
|
24
|
+
if setting.value != stored_value
|
25
|
+
setting.update_attribute :value, setting.value
|
22
26
|
return self # Allow for chaining.
|
23
27
|
end
|
24
28
|
|
data/test/kvc_test.rb
CHANGED
@@ -3,12 +3,25 @@ require 'rubygems'
|
|
3
3
|
require 'active_record'
|
4
4
|
require 'active_support'
|
5
5
|
require 'active_support/test_case'
|
6
|
+
ActiveRecord::Migration.verbose = false
|
6
7
|
|
7
8
|
$: << File.expand_path(File.dirname(__FILE__) + "/../lib") <<
|
8
9
|
File.expand_path(File.dirname(__FILE__) + "/../app/models")
|
9
10
|
|
10
11
|
ActiveRecord::Base.establish_connection :adapter => 'sqlite3',
|
11
|
-
:
|
12
|
+
:database => ':memory:'
|
13
|
+
|
14
|
+
ActiveRecord::Schema.define(:version => 1) do
|
15
|
+
create_table :guitars do |t|
|
16
|
+
t.string :make, :model
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :keyboards do |t|
|
21
|
+
t.string :make, :model
|
22
|
+
t.timestamps
|
23
|
+
end
|
24
|
+
end
|
12
25
|
|
13
26
|
require "kvc"
|
14
27
|
require "kvc/settings"
|
@@ -16,6 +29,13 @@ require "kvc/settings_proxy"
|
|
16
29
|
|
17
30
|
logger = Logger.new(STDOUT)
|
18
31
|
|
32
|
+
class Guitar < ActiveRecord::Base
|
33
|
+
end
|
34
|
+
|
35
|
+
class Keyboard < ActiveRecord::Base
|
36
|
+
validates_presence_of :make
|
37
|
+
end
|
38
|
+
|
19
39
|
class KVCTest < ActiveSupport::TestCase
|
20
40
|
teardown do
|
21
41
|
KVC::Settings.destroy_all
|
@@ -80,6 +100,55 @@ class KVCTest < ActiveSupport::TestCase
|
|
80
100
|
assert_kind_of Integer, KVC.favorite_year
|
81
101
|
end
|
82
102
|
|
103
|
+
test "models should serialize and deserialize updated versions" do
|
104
|
+
instruments = {
|
105
|
+
:guitars => {
|
106
|
+
:favorites => [
|
107
|
+
Guitar.create(:make => "Gibson", :model => "Melody Maker"),
|
108
|
+
Guitar.create(:make => "Epiphone", :model => "Les Paul"),
|
109
|
+
],
|
110
|
+
:not_so_good => [
|
111
|
+
Guitar.create(:make => "Samick")
|
112
|
+
]
|
113
|
+
},
|
114
|
+
:keyboard => Keyboard.create(:make => "Yamaha")
|
115
|
+
}
|
116
|
+
|
117
|
+
KVC.instruments = Marshal.load Marshal.dump(instruments) # Deep copy.
|
118
|
+
instruments[:keyboard].update_attribute(:model, "Privia PX-130")
|
119
|
+
|
120
|
+
assert_equal instruments, KVC.instruments
|
121
|
+
assert_equal instruments[:keyboard].model, KVC.instruments[:keyboard].model
|
122
|
+
end
|
123
|
+
|
124
|
+
test "should not reload records if record reloading is off" do
|
125
|
+
begin
|
126
|
+
KVC::Settings.reload_records = false
|
127
|
+
KVC.guitar = Guitar.create(:make => "Yamaha")
|
128
|
+
guitar = Guitar.last
|
129
|
+
guitar.update_attribute :make, "Yamahahaha"
|
130
|
+
assert_not_equal guitar.make, KVC.guitar.make
|
131
|
+
ensure
|
132
|
+
KVC::Settings.reload_records = true
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
test "unsaved models should deserialize" do
|
137
|
+
keyboard = Keyboard.new :model => "Some kind of synthesizer."
|
138
|
+
assert_nil keyboard.id
|
139
|
+
KVC["Which make was it again?"] = keyboard.clone # Unsaved copy.
|
140
|
+
assert_equal keyboard, KVC["Which make was it again?"]
|
141
|
+
end
|
142
|
+
|
143
|
+
test "missing models should raise exceptions" do
|
144
|
+
guitar = Guitar.create
|
145
|
+
KVC.ghost_guitar = guitar
|
146
|
+
guitar.destroy
|
147
|
+
assert_raise ActiveRecord::RecordNotFound do
|
148
|
+
KVC.ghost_guitar.touch
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
83
152
|
test "can set attributes with whitespace and symbols" do
|
84
153
|
assert KVC["uses_git?"] = true
|
85
154
|
assert KVC.uses_git?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kvc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Celis
|
@@ -9,19 +9,10 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-10 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: hoe
|
17
|
-
type: :development
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 2.0.0
|
24
|
-
version:
|
14
|
+
dependencies: []
|
15
|
+
|
25
16
|
description: |-
|
26
17
|
KVC (Key-Value Configuration) provides a powerful, transparent way to maintain
|
27
18
|
mutable app settings in the database.
|
@@ -32,13 +23,13 @@ executables: []
|
|
32
23
|
extensions: []
|
33
24
|
|
34
25
|
extra_rdoc_files:
|
35
|
-
- History.
|
26
|
+
- History.rdoc
|
36
27
|
- Manifest.txt
|
37
|
-
- README.
|
28
|
+
- README.rdoc
|
38
29
|
files:
|
39
|
-
- History.
|
30
|
+
- History.rdoc
|
40
31
|
- Manifest.txt
|
41
|
-
- README.
|
32
|
+
- README.rdoc
|
42
33
|
- Rakefile
|
43
34
|
- lib/kvc.rb
|
44
35
|
- lib/kvc/settings.rb
|
@@ -53,7 +44,7 @@ licenses: []
|
|
53
44
|
post_install_message:
|
54
45
|
rdoc_options:
|
55
46
|
- --main
|
56
|
-
- README.
|
47
|
+
- README.rdoc
|
57
48
|
require_paths:
|
58
49
|
- lib
|
59
50
|
required_ruby_version: !ruby/object:Gem::Requirement
|