easy_key_value 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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +110 -0
- data/Rakefile +8 -0
- data/easy_key_value.gemspec +21 -0
- data/lib/easy_key_value/class_methods.rb +14 -0
- data/lib/easy_key_value/easy_key_value.rb +22 -0
- data/lib/easy_key_value/key_value_store.rb +102 -0
- data/lib/easy_key_value/model_extensions.rb +20 -0
- data/lib/easy_key_value/version.rb +3 -0
- data/lib/easy_key_value.rb +9 -0
- data/lib/generators/ekv/migrations/migrations_generator.rb +26 -0
- data/lib/generators/ekv/migrations/templates/migrations/1_easy_key_value_migration.rb +16 -0
- data/test/init_tests.rb +5 -0
- data/test/models/Foo.rb +10 -0
- data/test/schema.rb +24 -0
- data/test/test_ekv.rb +75 -0
- metadata +86 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Intrepidd
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# EasyKeyValue
|
2
|
+
|
3
|
+
This gem provides a handy key/value store for your ActiveRecord models.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'easy_key_value'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install easy_key_value
|
18
|
+
|
19
|
+
|
20
|
+
Once installed, please run the following commands :
|
21
|
+
|
22
|
+
```
|
23
|
+
rails generate ekv:migrations
|
24
|
+
```
|
25
|
+
|
26
|
+
This will generate a new migration used by easy_key_value
|
27
|
+
|
28
|
+
Don't forget to run ```rake db:migrate``` in order to apply the new migration.
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
Because an example is better than a precept :
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class MyModel < ActiveRecord::base
|
36
|
+
|
37
|
+
acts_as_key_value_store # Add this line in order to use the key/value store
|
38
|
+
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
You have now access to methods that will help you manipulate the data stored for objects of this class.
|
43
|
+
|
44
|
+
### Adding / Updating a key
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
model = MyModel.find(42)
|
48
|
+
|
49
|
+
model.key('foo', 'bar') # The key will be created if it does not exist
|
50
|
+
|
51
|
+
model.key('foo', 'baz') # The key will be updated if it exists
|
52
|
+
```
|
53
|
+
|
54
|
+
### Fetching the value of a key
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
model.key('foo') # => 'baz'
|
58
|
+
```
|
59
|
+
|
60
|
+
### Destroying a key
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
model.del_key('foo')
|
64
|
+
|
65
|
+
model.key('foo') # => nil
|
66
|
+
```
|
67
|
+
|
68
|
+
### Playing with default values
|
69
|
+
|
70
|
+
You can specify default values for a given model.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
|
74
|
+
class MyModel < ActiveRecord::base
|
75
|
+
|
76
|
+
acts_as_key_value_store # Add this line in order to use the key/value store
|
77
|
+
|
78
|
+
key_value_store_defaults {
|
79
|
+
'author' => 'Intrepidd',
|
80
|
+
'language' => 'ruby'
|
81
|
+
}
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
```
|
86
|
+
|
87
|
+
Then, if the key is not set, the default value will be returned.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
|
91
|
+
model = MyModel.new
|
92
|
+
model.save
|
93
|
+
|
94
|
+
model.key('author') # => 'Intrepidd'
|
95
|
+
|
96
|
+
model.key('language') # => 'ruby'
|
97
|
+
|
98
|
+
model.key('language', 'whatever')
|
99
|
+
|
100
|
+
model.key('language') => 'whatever'
|
101
|
+
|
102
|
+
```
|
103
|
+
|
104
|
+
## Contributing
|
105
|
+
|
106
|
+
1. Fork it
|
107
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
108
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
109
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
110
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/easy_key_value/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Adrien Siami(Intrepidd)"]
|
6
|
+
gem.email = ["adrien.siami@gmail.com"]
|
7
|
+
gem.description = "A simple gem that allows active record models to contain a key / value store for configuration"
|
8
|
+
gem.summary = "A simple gem that allows active record models to contain a key / value store for configuration"
|
9
|
+
gem.homepage = "https://github.com/WizVille/easy_key_value"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "easy_key_value"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = EKV::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'activerecord', '>= 3.1.0'
|
19
|
+
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module EKV
|
2
|
+
module ModelExtensions
|
3
|
+
module ClassMethods
|
4
|
+
|
5
|
+
# Sets default values for this model
|
6
|
+
#
|
7
|
+
# @param [Hash] defaults A hash containing default values
|
8
|
+
def key_value_store_defaults(defaults)
|
9
|
+
class_variable_set(:@@ekv_defaults, defaults)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
class EasyKeyValue < ActiveRecord::Base
|
4
|
+
|
5
|
+
# The key must be unique for a given instance
|
6
|
+
validates :key, :uniqueness => {:scope => [:ekv_id, :ekv_type]}
|
7
|
+
|
8
|
+
# Adds a key with a given value for a given object
|
9
|
+
#
|
10
|
+
# @param [ActiveRecord::Base] object An Active Record instance
|
11
|
+
# @param [String] key The key
|
12
|
+
# @param [String] value The value of this key
|
13
|
+
def self.add_key(object, key, value)
|
14
|
+
ekv = EasyKeyValue.new
|
15
|
+
ekv.ekv_id = object.id
|
16
|
+
ekv.ekv_type = object.class.to_s
|
17
|
+
ekv.key = key
|
18
|
+
ekv.value = value
|
19
|
+
ekv.save
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module EKV
|
2
|
+
module ModelExtensions
|
3
|
+
module KeyValueStore
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
class_variable_set(:@@ekv_defaults, {})
|
7
|
+
base.send(:extend, ModelExtensions::ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Accesses a key, or sets / updates it depending on its existence
|
11
|
+
#
|
12
|
+
# @param [String] key The name of the key
|
13
|
+
# @param [String, nil] value The value to be set or nil if we just want to read the value
|
14
|
+
# @return [String, boolean] The value of the key if value is nil
|
15
|
+
def key(key, value = nil)
|
16
|
+
return self.get_key(key) if value.nil?
|
17
|
+
|
18
|
+
if @ekv.key? key
|
19
|
+
#Update
|
20
|
+
self.update_key(key, value)
|
21
|
+
else
|
22
|
+
# Add a key
|
23
|
+
self.add_key(key, value)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
# Adds a key with its value
|
29
|
+
#
|
30
|
+
# @param [String] key The key
|
31
|
+
# @param [String] value The value
|
32
|
+
def add_key(key, value)
|
33
|
+
self.load_ekv
|
34
|
+
if EasyKeyValue.add_key(self, key, value) == true
|
35
|
+
@ekv[key] = value
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the value of a given key
|
42
|
+
#
|
43
|
+
# @param [String] key The key we want the value of
|
44
|
+
# @return [String, nil] The value or nil if it does not exist
|
45
|
+
def get_key(key)
|
46
|
+
self.load_ekv
|
47
|
+
@ekv[key] || @@ekv_defaults[key]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Removes a given key
|
51
|
+
#
|
52
|
+
# @param [String] key The key we want to destroy
|
53
|
+
# @return [Boolean] Wether or not the key was destroyed
|
54
|
+
def del_key(key)
|
55
|
+
self.load_ekv
|
56
|
+
return false unless @ekv.key? key
|
57
|
+
ekv = EasyKeyValue.find_by_ekv_id_and_ekv_type_and_key(self.id, self.class.to_s, key)
|
58
|
+
return false if ekv.nil?
|
59
|
+
ekv.destroy
|
60
|
+
@ekv.delete key
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
# Updates a given key with the given value
|
65
|
+
#
|
66
|
+
# @param [String] key The key we want to change
|
67
|
+
# @param [String] value The new value for this key
|
68
|
+
# @return [Boolean] true if the key was updated, false if the key did not exist
|
69
|
+
def update_key(key, value)
|
70
|
+
return false unless @ekv.key? key
|
71
|
+
ekv = EasyKeyValue.find_by_ekv_id_and_ekv_type_and_key(self.id, self.class.to_s, key)
|
72
|
+
return false if ekv.nil?
|
73
|
+
ekv.value = value
|
74
|
+
ekv.save
|
75
|
+
@ekv[key] = value
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
# Gets a hash containing the key and values
|
80
|
+
#
|
81
|
+
# @return [Hash] The hash containing key and values for this object
|
82
|
+
def kv_store
|
83
|
+
self.load_ekv
|
84
|
+
@ekv.clone.freeze
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
# Loads The key and values for the current model
|
90
|
+
def load_ekv
|
91
|
+
return if defined? @ekv and !@ekv.nil?
|
92
|
+
|
93
|
+
keys = EasyKeyValue.find_all_by_ekv_id_and_ekv_type(self.id, self.class.to_s)
|
94
|
+
@ekv = {}
|
95
|
+
keys.each do |k|
|
96
|
+
@ekv[k.key] = k.value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "easy_key_value/key_value_store"
|
2
|
+
require "easy_key_value/class_methods"
|
3
|
+
|
4
|
+
module EKV
|
5
|
+
module ModelExtensions
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.send(:extend, EKV::ClassMethods)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
# Marks the model as a key / value store
|
15
|
+
def acts_as_key_value_store
|
16
|
+
include ModelExtensions::KeyValueStore
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Ekv
|
2
|
+
module Generators
|
3
|
+
class MigrationsGenerator < Rails::Generators::Base
|
4
|
+
desc "Generates the default migrations for easy_key_value"
|
5
|
+
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
@_ekv_source_root ||= File.expand_path("../templates", __FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.next_migration_number(dirname)
|
13
|
+
Time.now.strftime("%Y%m%d%H%M%S")
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_migrations
|
17
|
+
Dir["#{self.class.source_root}/migrations/*.rb"].sort.each do |filepath|
|
18
|
+
name = File.basename(filepath)
|
19
|
+
migration_template "migrations/#{name}", "db/migrate/#{name.gsub(/^\d+_/,'')}"
|
20
|
+
sleep 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class EasyKeyValueMigration < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def change
|
4
|
+
create_table :easy_key_values do |t|
|
5
|
+
t.integer :ekv_id
|
6
|
+
t.string :ekv_type
|
7
|
+
|
8
|
+
t.string :key
|
9
|
+
t.text :value
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :easy_key_values, :ekv_id, :name => 'ekv_id_ix'
|
13
|
+
add_index :easy_key_values, :value, :name => 'value_ix'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/test/init_tests.rb
ADDED
data/test/models/Foo.rb
ADDED
data/test/schema.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'foos'")
|
3
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'easy_key_values'")
|
4
|
+
|
5
|
+
ActiveRecord::Schema.define(:version => 0) do
|
6
|
+
|
7
|
+
create_table :foos do |t|
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :easy_key_values do |t|
|
12
|
+
|
13
|
+
t.integer :ekv_id
|
14
|
+
t.string :ekv_type
|
15
|
+
|
16
|
+
t.string :key
|
17
|
+
t.text :value
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
add_index :easy_key_values, :ekv_id, :name => 'ekv_id_ix'
|
22
|
+
add_index :easy_key_values, :value, :name => 'value_ix'
|
23
|
+
|
24
|
+
end
|
data/test/test_ekv.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'init_tests'
|
2
|
+
require 'easy_key_value'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'models/Foo'
|
5
|
+
|
6
|
+
load 'schema.rb'
|
7
|
+
|
8
|
+
class EayKeyValueTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
|
11
|
+
def test_get_set_del
|
12
|
+
foo = Foo.new
|
13
|
+
foo.save
|
14
|
+
|
15
|
+
assert_equal true, foo.add_key('foo', 'bar')
|
16
|
+
assert_equal false, foo.add_key('foo', 'bar')
|
17
|
+
|
18
|
+
assert_equal 'bar', foo.get_key('foo')
|
19
|
+
assert_equal true, foo.del_key('foo')
|
20
|
+
assert_equal false, foo.del_key('foo')
|
21
|
+
assert_equal false, foo.del_key('bar')
|
22
|
+
assert_equal nil, foo.get_key('foo')
|
23
|
+
|
24
|
+
foo.add_key('toto', 'tata')
|
25
|
+
|
26
|
+
foo = Foo.last
|
27
|
+
|
28
|
+
assert_equal 'tata', foo.get_key('toto')
|
29
|
+
|
30
|
+
assert_equal 'tata', foo.kv_store['toto']
|
31
|
+
|
32
|
+
assert_equal true, foo.kv_store.frozen?
|
33
|
+
|
34
|
+
assert_equal true, foo.update_key('toto', 'tutu')
|
35
|
+
assert_equal false, foo.update_key('totu', 'tutu')
|
36
|
+
|
37
|
+
assert_equal 'tutu', foo.get_key('toto')
|
38
|
+
foo = Foo.last
|
39
|
+
assert_equal 'tutu', foo.get_key('toto')
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_key
|
44
|
+
foo = Foo.new
|
45
|
+
foo.save
|
46
|
+
|
47
|
+
assert_equal nil, foo.key('foo')
|
48
|
+
|
49
|
+
assert_equal true, foo.key('foo', 'bar')
|
50
|
+
assert_equal 'bar', foo.key('foo')
|
51
|
+
|
52
|
+
foo = Foo.last
|
53
|
+
|
54
|
+
assert_equal 'bar', foo.key('foo')
|
55
|
+
assert_equal true, foo.key('foo', 'baz')
|
56
|
+
assert_equal 'baz', foo.key('foo')
|
57
|
+
|
58
|
+
foo = Foo.last
|
59
|
+
assert_equal 'baz', foo.key('foo')
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_default_values
|
64
|
+
foo = Foo.new
|
65
|
+
foo.save
|
66
|
+
|
67
|
+
assert_equal 'mia', foo.key('mama')
|
68
|
+
|
69
|
+
foo.key('mama', 'nomia')
|
70
|
+
|
71
|
+
assert_equal 'nomia', foo.key('mama')
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easy_key_value
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Adrien Siami(Intrepidd)
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.1.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.1.0
|
30
|
+
description: A simple gem that allows active record models to contain a key / value
|
31
|
+
store for configuration
|
32
|
+
email:
|
33
|
+
- adrien.siami@gmail.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- easy_key_value.gemspec
|
44
|
+
- lib/easy_key_value.rb
|
45
|
+
- lib/easy_key_value/class_methods.rb
|
46
|
+
- lib/easy_key_value/easy_key_value.rb
|
47
|
+
- lib/easy_key_value/key_value_store.rb
|
48
|
+
- lib/easy_key_value/model_extensions.rb
|
49
|
+
- lib/easy_key_value/version.rb
|
50
|
+
- lib/generators/ekv/migrations/migrations_generator.rb
|
51
|
+
- lib/generators/ekv/migrations/templates/migrations/1_easy_key_value_migration.rb
|
52
|
+
- test/init_tests.rb
|
53
|
+
- test/models/Foo.rb
|
54
|
+
- test/schema.rb
|
55
|
+
- test/test_ekv.rb
|
56
|
+
homepage: https://github.com/WizVille/easy_key_value
|
57
|
+
licenses: []
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.8.24
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: A simple gem that allows active record models to contain a key / value store
|
80
|
+
for configuration
|
81
|
+
test_files:
|
82
|
+
- test/init_tests.rb
|
83
|
+
- test/models/Foo.rb
|
84
|
+
- test/schema.rb
|
85
|
+
- test/test_ekv.rb
|
86
|
+
has_rdoc:
|