entity-storage 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ === 1.0.4 2009-09-23
2
+ * Fixed edge case bug with defaults and accessors with underscores
3
+
4
+ === 1.0.3 2009-09-23
5
+ * updated tests and example docs
6
+
7
+ === 1.0.2 2009-09-21
8
+ * changed method of table discovery for auto table creation
9
+
10
+ === 1.0.1 2009-09-20
11
+ * documentation update
12
+
13
+ === 1.0.0 2009-09-19
14
+
15
+ * 1 major enhancement:
16
+ * Initial release
17
+
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/entity_storage.rb
6
+ script/console
7
+ script/destroy
8
+ script/generate
9
+ config/database.yml
10
+ test/test_entity_storage.rb
11
+ test/test_helper.rb
@@ -0,0 +1,99 @@
1
+ = entity_storage
2
+
3
+ http://github.com/eatenbyagrue/entity_storage
4
+
5
+ == DESCRIPTION:
6
+
7
+ An easy to use Key/Value store for any Ruby on Rails project. Like Memcache, only persistent. Stores config values & application wide state in the database in order to survive server restarts.
8
+
9
+ Designed to allow you to add persistent value storage to any Rails project in about 5 minutes.
10
+
11
+ Additionally, allows users to set a list of default keys that auto-initializes baseline key/value pairs in the database for easy initialization.
12
+
13
+ == SYNOPSIS:
14
+
15
+ You can use the entity store like so:
16
+
17
+ # Get key value.
18
+ e = EntityStore["testkey"]
19
+ e = EntityStore.testkey
20
+ e = EntityStore[:testkey]
21
+
22
+ # sets key named 'happened' to a Time object of now
23
+ EntityStore[:happened] = Time.now
24
+ EntityStore["happened"] = Time.now
25
+ EntityStore.happened = Time.now
26
+
27
+ # find out it's default, even if it's been changed
28
+ e = EntityStore.default(:testkey)
29
+
30
+ # or
31
+ e = EntityStore.defaults[:testkey]
32
+
33
+ # set it back to default
34
+ EntityStore.default!(:testkey)
35
+
36
+ # delete an item
37
+ EntityStore.delete(key)
38
+
39
+ All EntityStorage operations sync immediately with the database, so a server shutdown will not impact stored values.
40
+
41
+ If you access a key that doesn't exist, and is specified in default list, will be initialized and returned. If not in default list, will return nil.
42
+
43
+ Keys can be up to 512 characters in length. Values can be practically any size, and consist of any object. Objects are marshalled back and forth between database.
44
+
45
+ == REQUIREMENTS:
46
+ As of 1.0.5, requires ActiveRecord 3.0.0.beta4 or greater.
47
+
48
+ Version up to 1.0.4 requires ActiveRecord 2.2.3 or above (probably works with earlier versions, but has not been tested.)
49
+
50
+ == INSTALL:
51
+ To install from github:
52
+
53
+ Run the following if you haven't already:
54
+
55
+ gem sources -a http://gems.github.com
56
+
57
+ Install the gem(s):
58
+
59
+ sudo gem install eatenbyagrue-entity_storage
60
+
61
+ Or download the souce above and run, customized for version and environment:
62
+
63
+ sudo gem install PATH/entity_storage.#.#.#.gem
64
+
65
+ Put the following at the bottom of your environment.rb file, or in an initializer.
66
+
67
+ require 'entity_storage'
68
+ DEFAULT_KEYS = { "testkey" => DateTime.parse("1-1-900"), "also test" => 2, "long ass key that I probably wouldn't use" => false }
69
+ EntityStore = EntityStorage::Storage.new(DEFAULT_KEYS)
70
+
71
+ On initialization, if the table "entity_storage" doesn't exist, it will be created. If you already have a table with that name, it must be in the correct format (previously created by this gem.)
72
+
73
+ You can pass a hash full of default key/value pairs. If the application accesses one of the keys, and it doesn't already exist, it will initiliaze that key with the default value. Good for getting your app to an intial starting state.
74
+
75
+
76
+ == LICENSE:
77
+
78
+ (The MIT License)
79
+
80
+ Copyright (c) 2009 Joshua Siler
81
+
82
+ Permission is hereby granted, free of charge, to any person obtaining
83
+ a copy of this software and associated documentation files (the
84
+ 'Software'), to deal in the Software without restriction, including
85
+ without limitation the rights to use, copy, modify, merge, publish,
86
+ distribute, sublicense, and/or sell copies of the Software, and to
87
+ permit persons to whom the Software is furnished to do so, subject to
88
+ the following conditions:
89
+
90
+ The above copyright notice and this permission notice shall be
91
+ included in all copies or substantial portions of the Software.
92
+
93
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
94
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
95
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
96
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
97
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
98
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
99
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/entity_storage'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'entity-storage' do
14
+ self.developer 'Joshua Siler', 'joshua.siler@gmail.com'
15
+ # self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
+ self.rubyforge_name = 'entity-storage' #self.name # TODO this is default value
17
+ self.extra_deps = [['activerecord','>= 3.0.0.beta4']]
18
+ end
19
+
20
+ require 'newgem/tasks'
21
+ Dir['tasks/**/*.rake'].each { |t| load t }
22
+
23
+ # TODO - want other tests/tasks run by default? Add them to the list
24
+ # remove_task :default
25
+ # task :default => [:spec, :features]
@@ -0,0 +1,8 @@
1
+
2
+ adapter: mysql
3
+ database: entity_test
4
+ username: root
5
+ password: sillier2
6
+ host: localhost
7
+
8
+
@@ -0,0 +1,149 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'active_record'
6
+ # require 'active_record/migration'
7
+
8
+ module EntityStorage
9
+ VERSION = '1.0.5'
10
+
11
+ class Storage
12
+ attr_accessor :defaults
13
+
14
+ # Checks for the existence of the necessary Entities table... if not here, creates it.
15
+ def initialize(defaults={})
16
+ unless ActiveRecord::Base.connection.table_exists?('entity_storage')
17
+ AddEntitiesTable.create
18
+ end
19
+
20
+ self.defaults = defaults
21
+ end
22
+
23
+ # Read a value.
24
+ def [](index)
25
+ Entity.get_value(index,@defaults[index.to_s])
26
+ end
27
+
28
+ # Write a value.
29
+ def []=(index,value)
30
+ Entity.set_value(index,value)
31
+ end
32
+
33
+ # Deletes a key and associated data from store.
34
+ def delete(index)
35
+ Entity.remove_item(index)
36
+ end
37
+
38
+ # Returns the default value of a key contained in DEFAULT_KEYS global constant.
39
+ # Does not change the stored value. Use default! to reset the value.
40
+ def default(index)
41
+ @defaults[index.to_s]
42
+ end
43
+
44
+ # Resets the default value of a key contained in DEFAULT_KEYS global constant and returns the value.
45
+ def default!(index)
46
+ Entity.reset_value(index,@defaults[index.to_s])
47
+ end
48
+
49
+ # Allows EntityStorage[:whatever] to be accessed via EntityStorage.whatever.
50
+ def method_missing(*args)
51
+ if args.length == 1
52
+ self[args[0]]
53
+ elsif args.length == 2 and args[0].to_s =~ /^(.*)=$/
54
+ self[$1.intern] = args[1]
55
+ else
56
+ super
57
+ end
58
+ end
59
+ end
60
+
61
+ # This migration is required for EntityStorage to work correctly
62
+ class AddEntitiesTable < ActiveRecord::Migration
63
+ # up and down functions call broken code in Rail3 migrations gem, called it 'create'
64
+ def self.create
65
+ create_table "entity_storage", :force => true do |t|
66
+ t.string "key", :limit => 512, :null => false
67
+ t.text "value"
68
+ t.datetime "created_at"
69
+ t.datetime "updated_at"
70
+ end
71
+
72
+ add_index "entity_storage", ["created_at"], :name => "created_at"
73
+ add_index "entity_storage", ["key"], :name => "key"
74
+ add_index "entity_storage", ["updated_at"], :name => "updated_at"
75
+ end
76
+
77
+ #def self.down
78
+ # drop_table :entities
79
+ #end
80
+ end
81
+
82
+
83
+ class Entity < ActiveRecord::Base
84
+ set_table_name "entity_storage"
85
+
86
+ # Entities should be used via class methods and not instantiated directly.
87
+ private_class_method :new
88
+
89
+ # Gets value based on specific key.`
90
+ # If not found, will initialize according to defaults set in DEFAULT_KEYS global constant.
91
+ def self.get_value(search_key,default_value)
92
+ e = Entity.find_by_key(search_key.to_s)
93
+ if e.nil? || e.value.nil?
94
+ e = initialize_value(search_key,default_value)
95
+ end
96
+ e.value rescue nil
97
+ end
98
+
99
+ # Sets value for a specific key. If key doesn't exist, creates with value.
100
+ def self.set_value(search_key, new_value)
101
+ e = Entity.find_by_key(search_key.to_s)
102
+ if e.nil?
103
+ e = new
104
+ end
105
+ e.key = search_key
106
+ e.value = new_value
107
+ e.save
108
+ end
109
+
110
+ # Resets a key contained in DEFAULT_KEYS global constant to it's default value
111
+ def self.reset_value(search_key,default_value)
112
+ Entity.remove_item(search_key)
113
+ initialize_value(search_key,default_value).value
114
+ end
115
+
116
+ # Deletes a record from key store.
117
+ def self.remove_item(search_key)
118
+ e = Entity.find_by_key(search_key.to_s)
119
+ e.destroy rescue 0
120
+ end
121
+
122
+ def value=(data)
123
+ write_attribute(:value,Marshal.dump(data))
124
+ end
125
+
126
+ def value
127
+ Marshal.load(read_attribute(:value))
128
+ end
129
+
130
+ def key=(newkey)
131
+ write_attribute(:key,newkey.to_s)
132
+ end
133
+
134
+ private
135
+
136
+ # Checks provided key against internal defaults list and initializes to default value.
137
+ # Defaults defined in DEFAULT_KEYS global constant.
138
+ def self.initialize_value(search_key,default_value)
139
+ en = new
140
+ en.key = search_key
141
+ en.value = default_value
142
+ en.save
143
+ en
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/entity_storage.rb'}"
9
+ puts "Loading entity_storage gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,107 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ ActiveRecord::Base.establish_connection(YAML::load(File.read(File.dirname(__FILE__) + '/../config/database.yml')))
3
+
4
+ class TestEntityStorage < Test::Unit::TestCase
5
+ DEFAULT_KEYS = { "test" => DateTime.parse("1-1-900"), "also test" => 2, "long ass key that I probably wouldn't use" => false,
6
+ # last time the hiring manager notifications have been run
7
+ "new_applicant_last_run" => DateTime.parse("1-1-1900"),
8
+ # last time the new job notifications have been run
9
+ "new_jobs_last_run" => DateTime.parse("1-1-1900"),
10
+ "email_test_address" => "joshuas@bnj.com" }
11
+
12
+ attr_accessor :EntityStore
13
+ EntityStore = EntityStorage::Storage.new(DEFAULT_KEYS)
14
+
15
+ def setup
16
+ ActiveRecord::Base.connection.execute("delete from entity_storage")
17
+ end
18
+
19
+ def test_instantiation
20
+ # test nasty weird bug with underscore characters
21
+ entityStore2 = EntityStorage::Storage.new(DEFAULT_KEYS)
22
+ assert_equal entityStore2.email_test_address, 'joshuas@bnj.com'
23
+ end
24
+
25
+ # tests value setting and getting functionality, along with default creation
26
+ def test_defaultkeys
27
+ DEFAULT_KEYS.each { |key,value|
28
+ EntityStore.delete(key)
29
+
30
+ # set key when it doesn't exist, should go to default
31
+ e = EntityStore[key]
32
+ assert_equal e, value
33
+
34
+ EntityStore.delete(key)
35
+
36
+ # set and try method missing access
37
+ if key[/\w/] == key
38
+ eval("e = EntityStore."+key)
39
+ assert_equal e, value
40
+ end
41
+
42
+ # change it to something else
43
+ EntityStore[key] = Time.now.to_s
44
+ e = EntityStore[key]
45
+ assert_not_equal e, value
46
+
47
+ # find out it's default
48
+ e = EntityStore.default(key)
49
+ assert_equal e, value
50
+
51
+ e = EntityStore.defaults[key]
52
+ assert_equal e, value
53
+
54
+ # set it back to default
55
+ EntityStore.default!(key)
56
+ e = EntityStore[key]
57
+ assert_equal e, value
58
+
59
+ # set it to something else using method missing
60
+ if key[/\w/] == key
61
+ eval("e = EntityStore."+key +" = Time.now.to_s")
62
+ assert_equal e, value
63
+ end
64
+ }
65
+ end
66
+
67
+ # tests setting values when no DEFAULT_KEY exists
68
+ def test_settingvalues
69
+ EntityStore.delete('test')
70
+
71
+ # key that can't be accessed via method missing
72
+ # set value and check it
73
+ EntityStore['big long key that cannot be accessed via method missing'] = 'what up'
74
+ e = EntityStore['big long key that cannot be accessed via method missing']
75
+ assert_equal e, 'what up'
76
+
77
+ # set another value and check it
78
+ EntityStore['big long key that cannot be accessed via method missing'] = 'another value'
79
+ e = EntityStore['big long key that cannot be accessed via method missing']
80
+ assert_equal e, 'another value'
81
+
82
+ EntityStore['test'] = 'what up'
83
+ e = EntityStore['test']
84
+ assert_equal e, 'what up'
85
+
86
+ EntityStore['test'] = 'another value'
87
+ e = EntityStore['test']
88
+ assert_equal e, 'another value'
89
+
90
+ # try the method missing version of the tests
91
+ e = EntityStore.test = 'what up'
92
+ e = EntityStore.test
93
+ assert_equal e, 'what up'
94
+
95
+ e = EntityStore.test = 'another value'
96
+ e = EntityStore.test
97
+ assert_equal e, 'another value'
98
+
99
+ end
100
+
101
+ def test_getunknownvalue
102
+ EntityStore.delete('does not exist')
103
+ e = EntityStore['does not exist']
104
+ assert_nil e
105
+ end
106
+
107
+ end
@@ -0,0 +1,6 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require 'rubygems'
4
+ require 'active_record'
5
+ require 'active_support'
6
+ require File.dirname(__FILE__) + '/../lib/entity_storage'
metadata ADDED
@@ -0,0 +1,134 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: entity-storage
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 5
10
+ version: 1.0.5
11
+ platform: ruby
12
+ authors:
13
+ - Joshua Siler
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-02 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 299253624
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ - beta4
35
+ version: 3.0.0.beta4
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: rubyforge
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 7
47
+ segments:
48
+ - 2
49
+ - 0
50
+ - 4
51
+ version: 2.0.4
52
+ type: :development
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: hoe
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 21
63
+ segments:
64
+ - 2
65
+ - 6
66
+ - 1
67
+ version: 2.6.1
68
+ type: :development
69
+ version_requirements: *id003
70
+ description: |-
71
+ An easy to use Key/Value store for any Ruby on Rails project. Like Memcache, only persistent. Stores config values &amp; application wide state in the database in order to survive server restarts.
72
+
73
+ Designed to allow you to add persistent value storage to any Rails project in about 5 minutes.
74
+
75
+ Additionally, allows users to set a list of default keys that auto-initializes baseline key/value pairs in the database for easy initialization.
76
+ email:
77
+ - joshua.siler@gmail.com
78
+ executables: []
79
+
80
+ extensions: []
81
+
82
+ extra_rdoc_files:
83
+ - History.txt
84
+ - Manifest.txt
85
+ files:
86
+ - History.txt
87
+ - Manifest.txt
88
+ - README.rdoc
89
+ - Rakefile
90
+ - lib/entity_storage.rb
91
+ - script/console
92
+ - script/destroy
93
+ - script/generate
94
+ - config/database.yml
95
+ - test/test_entity_storage.rb
96
+ - test/test_helper.rb
97
+ has_rdoc: true
98
+ homepage: http://github.com/eatenbyagrue/entity_storage
99
+ licenses: []
100
+
101
+ post_install_message:
102
+ rdoc_options:
103
+ - --main
104
+ - README.rdoc
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: 3
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project: entity-storage
128
+ rubygems_version: 1.3.7
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: An easy to use Key/Value store for any Ruby on Rails project
132
+ test_files:
133
+ - test/test_helper.rb
134
+ - test/test_entity_storage.rb