kvc 0.0.3 → 0.1.0

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.
@@ -1,3 +1,10 @@
1
+ === 0.1.0 / 2009-12-10
2
+
3
+ * 1 enhancement
4
+
5
+ * Reload database records by default.
6
+
7
+
1
8
  === 0.0.3 / 2009-06-27
2
9
 
3
10
  * 1 minor enhancement
@@ -61,14 +61,12 @@ If need be, validate specific key values in an initializer:
61
61
 
62
62
  Install:
63
63
 
64
- % gem install stephencelis-kvc --source=http://gems.github.com
64
+ % gem install kvc
65
65
 
66
66
 
67
67
  And configure:
68
68
 
69
- config.gem "stephencelis-kvc",
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.3"
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
@@ -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? 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 read_attribute(:value)
69
+ @value ||= KVC::Settings.deserialize YAML.load(read_attribute(:value))
47
70
  end
48
71
 
49
72
  # Serializes value for database.
@@ -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 @setting.send(method) if [:created_at, :updated_at].include? method
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
- return_value = @setting.value.send(method, *args, &block)
20
- if @setting.value != YAML.load(@setting.read_attribute(:value))
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
 
@@ -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
- :dbfile => ':memory:'
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.3
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-06-27 00:00:00 -05:00
12
+ date: 2009-12-10 00:00:00 -06:00
13
13
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
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.txt
26
+ - History.rdoc
36
27
  - Manifest.txt
37
- - README.txt
28
+ - README.rdoc
38
29
  files:
39
- - History.txt
30
+ - History.rdoc
40
31
  - Manifest.txt
41
- - README.txt
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.txt
47
+ - README.rdoc
57
48
  require_paths:
58
49
  - lib
59
50
  required_ruby_version: !ruby/object:Gem::Requirement