redis-model-extension 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +50 -0
- data/Rakefile +90 -0
- data/VERSION +1 -0
- data/config/redis_config.yml.example +16 -0
- data/config/redis_setup.conf +9 -0
- data/lib/database.rb +19 -0
- data/lib/redis-model-extension.rb +295 -0
- data/lib/string_to_bool.rb +9 -0
- data/redis-model.gemspec +88 -0
- data/test/helper.rb +19 -0
- data/test/test_redis-model-extension.rb +123 -0
- metadata +209 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "redis"
|
4
|
+
gem "i18n", "~> 0.6.0"
|
5
|
+
gem "activesupport", "~> 3.1.0"
|
6
|
+
gem "rake"
|
7
|
+
gem "rack", "~> 1.3.0"
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem "shoulda", ">= 0"
|
11
|
+
gem 'shoulda-context'
|
12
|
+
gem "rdoc", "~> 3.12"
|
13
|
+
gem "bundler", "~> 1.0.0"
|
14
|
+
gem "jeweler", "~> 1.8.3"
|
15
|
+
gem "turn", "~> 0.8.2"
|
16
|
+
gem "minitest"
|
17
|
+
gem "ansi", "~> 1.2.5"
|
18
|
+
end
|
19
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Ondrej Bartas
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Redis Model
|
2
|
+
|
3
|
+
Redis model is basic implementation of few methods for creating model which store data in Redis
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
``` ruby
|
8
|
+
class TestRedisModel
|
9
|
+
REDIS_MODEL_CONF = {
|
10
|
+
:fields => {
|
11
|
+
:integer => :to_i,
|
12
|
+
:boolean => :to_bool,
|
13
|
+
:string => :to_s,
|
14
|
+
:symbol => :to_sym,
|
15
|
+
},
|
16
|
+
:required => [:integer, :string],
|
17
|
+
:redis_key => [:string],
|
18
|
+
:redis_aliases => {
|
19
|
+
:token => [:symbol]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
include RedisModel
|
23
|
+
initialize_redis_model_methods REDIS_MODEL_CONF
|
24
|
+
end
|
25
|
+
|
26
|
+
foo = TestRedisModel.new()
|
27
|
+
```
|
28
|
+
|
29
|
+
Now you can easily access all attributes from TestRedisModel by `foo.integer` or exists? `foo.integer?` or set value by `foo.integer = 1234`
|
30
|
+
|
31
|
+
You can initialize model by `foo = TestRedisModel.new(:integer => 123, :string => "bar")` and then access it same as above.
|
32
|
+
|
33
|
+
Saving is easy too: `foo.save` -> It will raise exception if :required attributes aren't filled. Error message says what is missing.
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
## Contributing to redis-model-extension
|
38
|
+
|
39
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
40
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
41
|
+
* Fork the project.
|
42
|
+
* Start a feature/bugfix branch.
|
43
|
+
* Commit and push until you are happy with your contribution.
|
44
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
45
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
46
|
+
|
47
|
+
## Copyright
|
48
|
+
|
49
|
+
Copyright (c) 2012 Ondrej Bartas. See LICENSE.txt for
|
50
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
ENV['RACK_ENV'] ||= "development"
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
begin
|
7
|
+
Bundler.setup(:default, :development)
|
8
|
+
rescue Bundler::BundlerError => e
|
9
|
+
$stderr.puts e.message
|
10
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
11
|
+
exit e.status_code
|
12
|
+
end
|
13
|
+
require 'rake'
|
14
|
+
|
15
|
+
require 'jeweler'
|
16
|
+
Jeweler::Tasks.new do |gem|
|
17
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
18
|
+
gem.name = "redis-model-extension"
|
19
|
+
gem.homepage = "http://github.com/ondrejbartas/redis-model-extension"
|
20
|
+
gem.license = "MIT"
|
21
|
+
gem.summary = %Q{Redis model is basic implementation of creating, finding, updating and deleting model which store data in Redis.}
|
22
|
+
gem.description = %Q{It provides functions as find, find_by_alias, get, exists?, validate, save etc.}
|
23
|
+
gem.email = "ondrej@bartas.cz"
|
24
|
+
gem.authors = ["Ondrej Bartas"]
|
25
|
+
# dependencies defined in Gemfile
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |test|
|
31
|
+
test.libs << 'lib' << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
task :default => :test
|
37
|
+
|
38
|
+
|
39
|
+
#get directories!
|
40
|
+
PIDS_DIR = File.expand_path(File.join("..", "tmp","pid"), __FILE__)
|
41
|
+
CONF_DIR = File.expand_path(File.join("..", "config"), __FILE__)
|
42
|
+
#create directory for pid files
|
43
|
+
FileUtils.mkdir_p(PIDS_DIR) unless File.exists?(PIDS_DIR)
|
44
|
+
REDIS_PID = File.join(PIDS_DIR, "redis.pid")
|
45
|
+
|
46
|
+
#copy example config files for redis and elastic if they don't exists
|
47
|
+
FileUtils.cp(File.join(CONF_DIR, "redis_config.yml.example"), File.join(CONF_DIR, "redis_config.yml") ) unless File.exists?(File.join(CONF_DIR, "redis_config.yml"))
|
48
|
+
|
49
|
+
#for testing purposes use
|
50
|
+
REDIS_CNF = File.join(File.expand_path(File.join("..","config"), __FILE__), "redis_setup.conf")
|
51
|
+
|
52
|
+
desc "Run tests and manage databases start/stop"
|
53
|
+
task :run => [:'redis:start', :test, :'redis:stop']
|
54
|
+
|
55
|
+
desc "Start databases"
|
56
|
+
task :startup => [:'redis:start']
|
57
|
+
|
58
|
+
desc "Teardown databases"
|
59
|
+
task :teardown => [:'redis:stop']
|
60
|
+
|
61
|
+
Rake::TestTask.new(:test) do |t|
|
62
|
+
t.test_files = FileList['test/functional/*_test.rb', 'test/unit/*_test.rb','test/integration/*_test.rb']
|
63
|
+
t.warning = false
|
64
|
+
t.verbose = false
|
65
|
+
end
|
66
|
+
|
67
|
+
namespace :redis do
|
68
|
+
desc "Start the Redis server"
|
69
|
+
task :start do
|
70
|
+
redis_running = \
|
71
|
+
begin
|
72
|
+
File.exists?(REDIS_PID) && Process.kill(0, File.read(REDIS_PID).to_i)
|
73
|
+
rescue Errno::ESRCH
|
74
|
+
FileUtils.rm REDIS_PID
|
75
|
+
false
|
76
|
+
end
|
77
|
+
system "pwd"
|
78
|
+
puts system "redis-server #{REDIS_CNF}" unless redis_running
|
79
|
+
puts "redis started"
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Stop the Redis server"
|
83
|
+
task :stop do
|
84
|
+
if File.exists?(REDIS_PID)
|
85
|
+
Process.kill "INT", File.read(REDIS_PID).to_i
|
86
|
+
FileUtils.rm REDIS_PID
|
87
|
+
puts "redis stopped"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/database.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
#Wrapper for redis connection
|
3
|
+
#============================
|
4
|
+
#Creates only one connection to redis per application in first time it needs to work with redis
|
5
|
+
module Database
|
6
|
+
|
7
|
+
def self.config
|
8
|
+
if File.exists?('config/redis_config.yml')
|
9
|
+
YAML.load_file('config/redis_config.yml')[ENV['RACK_ENV'] || 'development'].symbolize_keys
|
10
|
+
else
|
11
|
+
raise ArgumentError, "Redis configuration file does not exists -> 'config/redis_config.yml', please provide it"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.redis
|
16
|
+
@redis ||= Redis.new(Database.config)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'pp'
|
3
|
+
require 'redis'
|
4
|
+
require 'active_support'
|
5
|
+
require 'active_support/inflector'
|
6
|
+
require 'active_support/inflector/inflections'
|
7
|
+
require 'active_support/core_ext/hash/keys'
|
8
|
+
require 'active_support/core_ext/object/blank'
|
9
|
+
require 'active_support/core_ext/class/inheritable_attributes'
|
10
|
+
require 'string_to_bool'
|
11
|
+
require 'database'
|
12
|
+
|
13
|
+
module RedisModel
|
14
|
+
|
15
|
+
attr_accessor :args, :error, :old_key, :conf
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.send :extend, ClassMethods
|
19
|
+
base.send :include, InstanceMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
|
24
|
+
def initialize_redis_model_methods conf
|
25
|
+
@conf = conf
|
26
|
+
#take all fields and make methods for them
|
27
|
+
conf[:fields].each do |attr, action|
|
28
|
+
define_method "#{attr}" do
|
29
|
+
if self.args[attr] || self.args[attr] == false #== false is a fi for boolean variable
|
30
|
+
self.args[attr].to_s.send(action)
|
31
|
+
else
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
define_method "#{attr}=" do |item|
|
37
|
+
self.args[attr] = item
|
38
|
+
end
|
39
|
+
|
40
|
+
define_method "#{attr}?" do
|
41
|
+
!self.args[attr].nil?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def conf
|
47
|
+
@conf
|
48
|
+
end
|
49
|
+
|
50
|
+
#Generates redis key for storing object
|
51
|
+
def generate_key(args = {})
|
52
|
+
out = "#{self.name.to_s.downcase.to_sym}"
|
53
|
+
@conf[:redis_key].each do |key|
|
54
|
+
if args.has_key?(key)
|
55
|
+
out += ":#{args[key]}"
|
56
|
+
else
|
57
|
+
out += ":*"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
out
|
61
|
+
end
|
62
|
+
|
63
|
+
#Generates redis key for storing indexes for aliases
|
64
|
+
def generate_alias_key(alias_name, args = {})
|
65
|
+
out = "#{self.name.to_s.downcase.to_sym}:#{alias_name}"
|
66
|
+
@conf[:redis_aliases][alias_name.to_sym].each do |key|
|
67
|
+
if args.has_key?(key)
|
68
|
+
out += ":#{args[key]}"
|
69
|
+
else
|
70
|
+
out += ":*"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
out
|
74
|
+
end
|
75
|
+
|
76
|
+
#Validates if key by arguments is valid
|
77
|
+
def valid_key?(args = {})
|
78
|
+
full_key = true
|
79
|
+
@conf[:redis_key].each do |key|
|
80
|
+
full_key = false if !args.has_key?(key) || args[key].nil?
|
81
|
+
end
|
82
|
+
full_key
|
83
|
+
end
|
84
|
+
|
85
|
+
#Validates if key by alias name and arguments is valid
|
86
|
+
def valid_alias_key?(alias_name, args = {})
|
87
|
+
full_key = true
|
88
|
+
@conf[:redis_aliases][alias_name.to_sym].each do |key|
|
89
|
+
full_key = false if !args.has_key?(key) || args[key].nil?
|
90
|
+
end
|
91
|
+
full_key
|
92
|
+
end
|
93
|
+
|
94
|
+
#Check if key by arguments exists in db
|
95
|
+
def exists?(args = {})
|
96
|
+
Database.redis.exists(self.name.constantize.generate_key(args))
|
97
|
+
end
|
98
|
+
|
99
|
+
#Check if key by alias name and arguments exists in db
|
100
|
+
def alias_exists?(alias_name, args = {})
|
101
|
+
Database.redis.exists(self.name.constantize.generate_alias_key(alias_name, args))
|
102
|
+
end
|
103
|
+
|
104
|
+
#Wrapper around find to get all instances
|
105
|
+
def all
|
106
|
+
self.find({})
|
107
|
+
end
|
108
|
+
|
109
|
+
#Find method for searching in redis
|
110
|
+
def find(args = {})
|
111
|
+
args.symbolize_keys!
|
112
|
+
out = []
|
113
|
+
klass = self.name.constantize
|
114
|
+
|
115
|
+
#is key specified directly? -> no needs of looking for other keys! -> faster
|
116
|
+
if klass.valid_key?(args)
|
117
|
+
out << klass.new(args.merge(Database.redis.hgetall(klass.generate_key(args))).merge({:old_key => klass.generate_key(args)})) if klass.exists?(args)
|
118
|
+
else
|
119
|
+
Database.redis.keys(klass.generate_key(args)).each do |key|
|
120
|
+
out << klass.new(args.merge(Database.redis.hgetall(key)).merge({:old_key => key}))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
out
|
124
|
+
end
|
125
|
+
|
126
|
+
#Find method for searching in redis
|
127
|
+
def find_by_alias(alias_name, args = {})
|
128
|
+
args.symbolize_keys!
|
129
|
+
out = []
|
130
|
+
klass = self.name.constantize
|
131
|
+
|
132
|
+
#is key specified directly? -> no needs of looking for other keys! -> faster
|
133
|
+
if klass.valid_alias_key?(alias_name, args)
|
134
|
+
out << klass.get_by_alias(alias_name, args) if klass.alias_exists?(alias_name, args)
|
135
|
+
else
|
136
|
+
Database.redis.keys(klass.generate_alias_key(alias_name, args)).each do |key|
|
137
|
+
out << klass.get_by_alias_key(key)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
out
|
141
|
+
end
|
142
|
+
|
143
|
+
#fastest method to get object from redis by getting it by arguments
|
144
|
+
def get(args = {})
|
145
|
+
args.symbolize_keys!
|
146
|
+
klass = self.name.constantize
|
147
|
+
if klass.valid_key?(args)
|
148
|
+
klass.new(args.merge(Database.redis.hgetall(klass.generate_key(args))).merge({:old_key => klass.generate_key(args)})) if klass.exists?(args)
|
149
|
+
else
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
#fastest method to get object from redis by getting it by alias and arguments
|
155
|
+
def get_by_alias(alias_name, args = {})
|
156
|
+
args.symbolize_keys!
|
157
|
+
klass = self.name.constantize
|
158
|
+
if klass.valid_alias_key?(alias_name, args) && klass.alias_exists?(alias_name, args)
|
159
|
+
key = Database.redis.get(klass.generate_alias_key(alias_name, args))
|
160
|
+
if Database.redis.exists(key)
|
161
|
+
klass.new(args.merge(Database.redis.hgetall(key)).merge({:old_key => key}))
|
162
|
+
else
|
163
|
+
nil
|
164
|
+
end
|
165
|
+
else
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
#fastest method to get object from redis by getting it by alias and arguments
|
171
|
+
def get_by_alias_key(alias_key)
|
172
|
+
klass = self.name.constantize
|
173
|
+
if Database.redis.exists(alias_key)
|
174
|
+
key = Database.redis.get(alias_key)
|
175
|
+
if Database.redis.exists(key)
|
176
|
+
klass.new(args.merge(Database.redis.hgetall(key)).merge({:old_key => key}))
|
177
|
+
else
|
178
|
+
nil
|
179
|
+
end
|
180
|
+
else
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
module InstanceMethods
|
188
|
+
|
189
|
+
def initialize(args={})
|
190
|
+
args.symbolize_keys!
|
191
|
+
#if old_key is specified, don't usi it in args hash
|
192
|
+
if args[:old_key] && args[:old_key].size > 0
|
193
|
+
self.old_key = args[:old_key]
|
194
|
+
args.delete(:old_key)
|
195
|
+
end
|
196
|
+
self.args = clear_args(args)
|
197
|
+
return self
|
198
|
+
end
|
199
|
+
|
200
|
+
#Fixing some problems with saving nil into redis and clearing input arguments
|
201
|
+
def clear_args(args)
|
202
|
+
args.symbolize_keys!
|
203
|
+
out_args = {}
|
204
|
+
args.each do |key, value|
|
205
|
+
if self.class.conf[:fields].keys.include?(key) #don't use arguments wich aren't specified in :fields
|
206
|
+
if value.nil? || value.to_s.size == 0 #change nil and zero length string into nil
|
207
|
+
out_args[key] = nil
|
208
|
+
else
|
209
|
+
out_args[key] = value
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
out_args
|
214
|
+
end
|
215
|
+
|
216
|
+
#validates required attributes
|
217
|
+
def valid?
|
218
|
+
@error = []
|
219
|
+
self.class.conf[:required].each do |key|
|
220
|
+
if !self.args.has_key?(key) || self.args[key].nil?
|
221
|
+
@error.push("Required #{key}")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
@error.size == 0
|
225
|
+
end
|
226
|
+
|
227
|
+
#return error from validation
|
228
|
+
def errors
|
229
|
+
@errors
|
230
|
+
end
|
231
|
+
|
232
|
+
#take all arguments and send them out
|
233
|
+
def to_arg
|
234
|
+
self.args
|
235
|
+
end
|
236
|
+
|
237
|
+
#if this record exists in database
|
238
|
+
def exists?
|
239
|
+
Database.redis.exists(self.class.generate_key(self.args))
|
240
|
+
end
|
241
|
+
|
242
|
+
#remove record form database
|
243
|
+
def destroy!
|
244
|
+
if exists?
|
245
|
+
#destroy main object
|
246
|
+
Database.redis.del(generate_key)
|
247
|
+
destroy_aliases!
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
#remove all aliases
|
252
|
+
def destroy_aliases!
|
253
|
+
self.class.conf[:redis_aliases].each do |alias_name, fields|
|
254
|
+
Database.redis.del(self.class.generate_alias_key(alias_name, self.args)) if self.class.alias_exists?(alias_name, self.args)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
#Method for creating aliases
|
259
|
+
def create_aliases
|
260
|
+
main_key = redis_key
|
261
|
+
self.class.conf[:redis_aliases].each do |alias_name, fields|
|
262
|
+
Database.redis.set(self.class.generate_alias_key(alias_name, self.args), main_key)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
#get redis key for instance
|
267
|
+
def redis_key
|
268
|
+
self.class.generate_key(self.args)
|
269
|
+
end
|
270
|
+
|
271
|
+
#get redis key for instance alias
|
272
|
+
def redis_alias_key(alias_name)
|
273
|
+
self.class.generate_alias_key(alias_name, self.args)
|
274
|
+
end
|
275
|
+
|
276
|
+
#save method
|
277
|
+
def save
|
278
|
+
if valid?
|
279
|
+
#generate key (possibly new)
|
280
|
+
generated_key = redis_key
|
281
|
+
Database.redis.rename(self.old_key, generated_key) if self.old_key && generated_key != self.old_key
|
282
|
+
Database.redis.hmset(generated_key, *self.args.reject{|k,v| v.nil?}.inject([]){ |arr,kv| arr + [kv[0], kv[1].to_s]})
|
283
|
+
|
284
|
+
#destroy aliases
|
285
|
+
destroy_aliases!
|
286
|
+
create_aliases
|
287
|
+
#after save make new_key -> old_key
|
288
|
+
self.old_key = generated_key
|
289
|
+
return self
|
290
|
+
else
|
291
|
+
raise ArgumentError, @error.join(", ")
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
class String
|
4
|
+
def to_bool
|
5
|
+
return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
|
6
|
+
return false if self == false || self.blank? || self =~ (/(false|f|no|n|0)$/i)
|
7
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
|
8
|
+
end
|
9
|
+
end
|
data/redis-model.gemspec
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "redis-model-extension"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ondrej Bartas"]
|
12
|
+
s.date = "2012-02-26"
|
13
|
+
s.description = "It provides functions as find, find_by_alias, get, exists?, validate, save etc."
|
14
|
+
s.email = "ondrej@bartas.cz"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE.txt",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"config/redis_config.yml.example",
|
27
|
+
"config/redis_setup.conf",
|
28
|
+
"lib/database.rb",
|
29
|
+
"lib/redis-model-extension.rb",
|
30
|
+
"lib/string_to_bool.rb",
|
31
|
+
"test/helper.rb",
|
32
|
+
"test/test_redis-model-extension.rb"
|
33
|
+
]
|
34
|
+
s.homepage = "http://github.com/ondrejbartas/redis-model-extension"
|
35
|
+
s.licenses = ["MIT"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = "1.8.10"
|
38
|
+
s.summary = "Redis model is basic implementation of creating, finding, updating and deleting model which store data in Redis."
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_runtime_dependency(%q<redis>, [">= 0"])
|
45
|
+
s.add_runtime_dependency(%q<i18n>, ["~> 0.6.0"])
|
46
|
+
s.add_runtime_dependency(%q<activesupport>, ["~> 3.1.0"])
|
47
|
+
s.add_runtime_dependency(%q<rake>, [">= 0"])
|
48
|
+
s.add_runtime_dependency(%q<rack>, ["~> 1.3.0"])
|
49
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<shoulda-context>, [">= 0"])
|
51
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
52
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
53
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
54
|
+
s.add_development_dependency(%q<turn>, ["~> 0.8.2"])
|
55
|
+
s.add_development_dependency(%q<minitest>, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<ansi>, ["~> 1.2.5"])
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
59
|
+
s.add_dependency(%q<i18n>, ["~> 0.6.0"])
|
60
|
+
s.add_dependency(%q<activesupport>, ["~> 3.1.0"])
|
61
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
62
|
+
s.add_dependency(%q<rack>, ["~> 1.3.0"])
|
63
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
64
|
+
s.add_dependency(%q<shoulda-context>, [">= 0"])
|
65
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
66
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
68
|
+
s.add_dependency(%q<turn>, ["~> 0.8.2"])
|
69
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
70
|
+
s.add_dependency(%q<ansi>, ["~> 1.2.5"])
|
71
|
+
end
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
74
|
+
s.add_dependency(%q<i18n>, ["~> 0.6.0"])
|
75
|
+
s.add_dependency(%q<activesupport>, ["~> 3.1.0"])
|
76
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
77
|
+
s.add_dependency(%q<rack>, ["~> 1.3.0"])
|
78
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
79
|
+
s.add_dependency(%q<shoulda-context>, [">= 0"])
|
80
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
81
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
82
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
83
|
+
s.add_dependency(%q<turn>, ["~> 0.8.2"])
|
84
|
+
s.add_dependency(%q<minitest>, [">= 0"])
|
85
|
+
s.add_dependency(%q<ansi>, ["~> 1.2.5"])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'turn'
|
12
|
+
require 'shoulda-context'
|
13
|
+
|
14
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
16
|
+
require 'redis-model-extension'
|
17
|
+
|
18
|
+
class Test::Unit::TestCase
|
19
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'helper'
|
3
|
+
class RedisModelTest < Test::Unit::TestCase
|
4
|
+
context "RedisModel" do
|
5
|
+
setup do
|
6
|
+
Database.redis.flushdb
|
7
|
+
|
8
|
+
class TestRedisModel
|
9
|
+
REDIS_MODEL_CONF = {
|
10
|
+
:fields => {
|
11
|
+
:integer => :to_i,
|
12
|
+
:boolean => :to_bool,
|
13
|
+
:string => :to_s,
|
14
|
+
:symbol => :to_sym,
|
15
|
+
},
|
16
|
+
:required => [:integer, :string],
|
17
|
+
:redis_key => [:string],
|
18
|
+
:redis_aliases => {
|
19
|
+
:token => [:symbol]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
include RedisModel
|
23
|
+
initialize_redis_model_methods REDIS_MODEL_CONF
|
24
|
+
end
|
25
|
+
@args = {:integer => 12345, :string => "foo", :symbol => :bar, :boolean => true}
|
26
|
+
@test_model = TestRedisModel.new(@args)
|
27
|
+
@test_model_partial = TestRedisModel.new(:integer => 12345, :string => "foo")
|
28
|
+
end
|
29
|
+
|
30
|
+
context "define methods" do
|
31
|
+
should "be accessible" do
|
32
|
+
assert @test_model.respond_to?(:integer)
|
33
|
+
assert @test_model.respond_to?(:boolean)
|
34
|
+
assert @test_model.respond_to?(:string)
|
35
|
+
assert @test_model.respond_to?(:symbol)
|
36
|
+
end
|
37
|
+
|
38
|
+
should "get valid arguments" do
|
39
|
+
assert_equal @test_model.integer, 12345
|
40
|
+
assert_equal @test_model.string, "foo"
|
41
|
+
assert_equal @test_model.symbol, :bar
|
42
|
+
assert_equal @test_model.boolean, true
|
43
|
+
end
|
44
|
+
|
45
|
+
should "return valid exists?" do
|
46
|
+
assert_equal @test_model.integer?, true
|
47
|
+
assert_equal @test_model.string?, true
|
48
|
+
assert_equal @test_model.symbol?, true
|
49
|
+
assert_equal @test_model.boolean?, true
|
50
|
+
|
51
|
+
assert_equal @test_model_partial.integer?, true
|
52
|
+
assert_equal @test_model_partial.string?, true
|
53
|
+
assert_equal @test_model_partial.symbol?, false
|
54
|
+
assert_equal @test_model_partial.boolean?, false
|
55
|
+
end
|
56
|
+
|
57
|
+
should "be assign new values" do
|
58
|
+
@test_model.integer = 54321
|
59
|
+
@test_model.string = "bar"
|
60
|
+
@test_model.symbol = :foo
|
61
|
+
@test_model.boolean = false
|
62
|
+
assert_equal @test_model.integer, 54321
|
63
|
+
assert_equal @test_model.string, "bar"
|
64
|
+
assert_equal @test_model.symbol, :foo
|
65
|
+
assert_equal @test_model.boolean, false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "redis key" do
|
70
|
+
should "generate right key" do
|
71
|
+
assert_equal @test_model.redis_key, "redismodeltest::testredismodel:foo"
|
72
|
+
assert_equal TestRedisModel.generate_key(@args), "redismodeltest::testredismodel:foo"
|
73
|
+
end
|
74
|
+
should "generate right key alias" do
|
75
|
+
assert_equal @test_model.redis_alias_key(:token), "redismodeltest::testredismodel:token:bar"
|
76
|
+
assert_equal TestRedisModel.generate_alias_key(:token, @args), "redismodeltest::testredismodel:token:bar"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "after initialize" do
|
81
|
+
should "clear input arguments" do
|
82
|
+
test_model = TestRedisModel.new(@args.merge({:foor => :bar, :not_in_fields => "foo"}))
|
83
|
+
assert_same_elements test_model.args, @args
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "validation" do
|
88
|
+
should "not raise exeption on invalid initialize" do
|
89
|
+
assert_nothing_raised { TestRedisModel.new() }
|
90
|
+
end
|
91
|
+
|
92
|
+
should "raise exeption on save" do
|
93
|
+
test_model = TestRedisModel.new()
|
94
|
+
assert_raises ArgumentError do
|
95
|
+
test_model.save
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context "saving" do
|
101
|
+
setup do
|
102
|
+
@test_model.save
|
103
|
+
end
|
104
|
+
|
105
|
+
should "have same elements after get" do
|
106
|
+
@getted_model = TestRedisModel.get(@args)
|
107
|
+
assert_equal @getted_model.integer, @test_model.integer
|
108
|
+
assert_equal @getted_model.string, @test_model.string
|
109
|
+
assert_equal @getted_model.symbol, @test_model.symbol
|
110
|
+
assert_equal @getted_model.boolean, @test_model.boolean
|
111
|
+
end
|
112
|
+
|
113
|
+
should "be getted by alias" do
|
114
|
+
@getted_model = TestRedisModel.get_by_alias(:token ,@args)
|
115
|
+
assert_equal @getted_model.integer, @test_model.integer
|
116
|
+
assert_equal @getted_model.string, @test_model.string
|
117
|
+
assert_equal @getted_model.symbol, @test_model.symbol
|
118
|
+
assert_equal @getted_model.boolean, @test_model.boolean
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
metadata
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis-model-extension
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ondrej Bartas
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: redis
|
16
|
+
requirement: &70246417679280 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70246417679280
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: i18n
|
27
|
+
requirement: &70246417678780 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.6.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70246417678780
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activesupport
|
38
|
+
requirement: &70246417678100 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.1.0
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70246417678100
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: &70246417677380 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70246417677380
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rack
|
60
|
+
requirement: &70246417676820 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.3.0
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70246417676820
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: shoulda
|
71
|
+
requirement: &70246418084920 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70246418084920
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: shoulda-context
|
82
|
+
requirement: &70246418083780 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70246418083780
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rdoc
|
93
|
+
requirement: &70246418082640 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '3.12'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70246418082640
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: bundler
|
104
|
+
requirement: &70246418081620 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.0.0
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *70246418081620
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: jeweler
|
115
|
+
requirement: &70246418080920 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ~>
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 1.8.3
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *70246418080920
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: turn
|
126
|
+
requirement: &70246418080340 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.8.2
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *70246418080340
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: minitest
|
137
|
+
requirement: &70246418078980 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: *70246418078980
|
146
|
+
- !ruby/object:Gem::Dependency
|
147
|
+
name: ansi
|
148
|
+
requirement: &70246418078460 !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ~>
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 1.2.5
|
154
|
+
type: :development
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: *70246418078460
|
157
|
+
description: It provides functions as find, find_by_alias, get, exists?, validate,
|
158
|
+
save etc.
|
159
|
+
email: ondrej@bartas.cz
|
160
|
+
executables: []
|
161
|
+
extensions: []
|
162
|
+
extra_rdoc_files:
|
163
|
+
- LICENSE.txt
|
164
|
+
- README.markdown
|
165
|
+
files:
|
166
|
+
- .document
|
167
|
+
- Gemfile
|
168
|
+
- LICENSE.txt
|
169
|
+
- README.markdown
|
170
|
+
- Rakefile
|
171
|
+
- VERSION
|
172
|
+
- config/redis_config.yml.example
|
173
|
+
- config/redis_setup.conf
|
174
|
+
- lib/database.rb
|
175
|
+
- lib/redis-model-extension.rb
|
176
|
+
- lib/string_to_bool.rb
|
177
|
+
- redis-model.gemspec
|
178
|
+
- test/helper.rb
|
179
|
+
- test/test_redis-model-extension.rb
|
180
|
+
homepage: http://github.com/ondrejbartas/redis-model-extension
|
181
|
+
licenses:
|
182
|
+
- MIT
|
183
|
+
post_install_message:
|
184
|
+
rdoc_options: []
|
185
|
+
require_paths:
|
186
|
+
- lib
|
187
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
188
|
+
none: false
|
189
|
+
requirements:
|
190
|
+
- - ! '>='
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
segments:
|
194
|
+
- 0
|
195
|
+
hash: 1247064394902780429
|
196
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
|
+
none: false
|
198
|
+
requirements:
|
199
|
+
- - ! '>='
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
requirements: []
|
203
|
+
rubyforge_project:
|
204
|
+
rubygems_version: 1.8.10
|
205
|
+
signing_key:
|
206
|
+
specification_version: 3
|
207
|
+
summary: Redis model is basic implementation of creating, finding, updating and deleting
|
208
|
+
model which store data in Redis.
|
209
|
+
test_files: []
|