easy_key_value 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.sqlite3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in easy_key_value.gemspec
4
+ gemspec
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,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -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,3 @@
1
+ module EKV
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ require "easy_key_value/version"
2
+ require "easy_key_value/easy_key_value"
3
+ require "easy_key_value/model_extensions"
4
+
5
+
6
+ if defined? ActiveRecord::Base
7
+ ActiveRecord::Base.send(:include, EKV::ModelExtensions)
8
+ end
9
+
@@ -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
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'active_record'
3
+ require 'active_support'
4
+
5
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'test.sqlite3')
@@ -0,0 +1,10 @@
1
+ require 'active_record'
2
+ require 'easy_key_value'
3
+
4
+ class Foo < ActiveRecord::Base
5
+
6
+ acts_as_key_value_store
7
+
8
+ key_value_store_defaults 'mama' => 'mia'
9
+
10
+ end
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: