blendris 0.0.1
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.tar.gz.sig +0 -0
- data/History.txt +4 -0
- data/Manifest +32 -0
- data/PostInstall.txt +1 -0
- data/README.rdoc +79 -0
- data/Rakefile +22 -0
- data/autotest/discover.rb +3 -0
- data/blendris.gemspec +32 -0
- data/lib/blendris.rb +25 -0
- data/lib/blendris/accessor.rb +62 -0
- data/lib/blendris/errors.rb +3 -0
- data/lib/blendris/integer.rb +19 -0
- data/lib/blendris/list.rb +37 -0
- data/lib/blendris/model.rb +141 -0
- data/lib/blendris/node.rb +46 -0
- data/lib/blendris/reference.rb +51 -0
- data/lib/blendris/reference_base.rb +68 -0
- data/lib/blendris/reference_set.rb +65 -0
- data/lib/blendris/set.rb +39 -0
- data/lib/blendris/string.rb +19 -0
- data/lib/blendris/types.rb +14 -0
- data/lib/blendris/utils.rb +39 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/list_spec.rb +17 -0
- data/spec/model_spec.rb +180 -0
- data/spec/redis-tools_spec.rb +15 -0
- data/spec/ref_spec.rb +40 -0
- data/spec/set_spec.rb +20 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +85 -0
- data/spec/string_spec.rb +20 -0
- data/tasks/rspec.rake +21 -0
- metadata +128 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
Binary file
|
data/History.txt
ADDED
data/Manifest
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest
|
3
|
+
PostInstall.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
autotest/discover.rb
|
7
|
+
lib/blendris.rb
|
8
|
+
lib/blendris/accessor.rb
|
9
|
+
lib/blendris/errors.rb
|
10
|
+
lib/blendris/integer.rb
|
11
|
+
lib/blendris/list.rb
|
12
|
+
lib/blendris/model.rb
|
13
|
+
lib/blendris/node.rb
|
14
|
+
lib/blendris/reference.rb
|
15
|
+
lib/blendris/reference_base.rb
|
16
|
+
lib/blendris/reference_set.rb
|
17
|
+
lib/blendris/set.rb
|
18
|
+
lib/blendris/string.rb
|
19
|
+
lib/blendris/types.rb
|
20
|
+
lib/blendris/utils.rb
|
21
|
+
script/console
|
22
|
+
script/destroy
|
23
|
+
script/generate
|
24
|
+
spec/list_spec.rb
|
25
|
+
spec/model_spec.rb
|
26
|
+
spec/redis-tools_spec.rb
|
27
|
+
spec/ref_spec.rb
|
28
|
+
spec/set_spec.rb
|
29
|
+
spec/spec.opts
|
30
|
+
spec/spec_helper.rb
|
31
|
+
spec/string_spec.rb
|
32
|
+
tasks/rspec.rake
|
data/PostInstall.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
For more information on blendris, see http://github.com/alexmchale/blendris
|
data/README.rdoc
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
= blendris
|
2
|
+
|
3
|
+
* http://github.com/alexmchale/blendris
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Blendris is a Ruby interface to a Redis database.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
== SYNOPSIS:
|
12
|
+
|
13
|
+
== REQUIREMENTS:
|
14
|
+
|
15
|
+
* Blendris uses the redis RubyGem.
|
16
|
+
|
17
|
+
== INSTALL:
|
18
|
+
|
19
|
+
* gem install blendris
|
20
|
+
|
21
|
+
== EXAMPLES:
|
22
|
+
|
23
|
+
The following would create a Website model that knows its url and
|
24
|
+
paths within the website.
|
25
|
+
|
26
|
+
class Website < Blendris::Model
|
27
|
+
key "website", :title
|
28
|
+
|
29
|
+
string :title
|
30
|
+
string :url
|
31
|
+
set :paths
|
32
|
+
end
|
33
|
+
|
34
|
+
website = Website.create("One Fake Website")
|
35
|
+
website.url = "http://fakewebsite.com"
|
36
|
+
website.paths << "/blog/index"
|
37
|
+
website.paths << "/admin/index"
|
38
|
+
|
39
|
+
The above would create the following Redis keys:
|
40
|
+
|
41
|
+
website:One_Fake_Website => "Website" (This identifies the model type)
|
42
|
+
website:One_Fake_Website:name => "One Fake Website"
|
43
|
+
website:One_Fake_Website:url => "http://fakewebsite.com"
|
44
|
+
website:One_Fake_Website:paths => [ "/blog/index", "/admin/index" ]
|
45
|
+
|
46
|
+
Now suppose we want to open the Website model back up to add a concept of sister sites:
|
47
|
+
|
48
|
+
class Website
|
49
|
+
refs :sister_sites, :class => Website, :reverse => :sister_sites
|
50
|
+
end
|
51
|
+
|
52
|
+
This will cause the website to maintain a set of other websites. The reverse tag
|
53
|
+
causes the other website's sister_sites set to be updated when it is added or removed
|
54
|
+
from this site's list.
|
55
|
+
|
56
|
+
== LICENSE:
|
57
|
+
|
58
|
+
(The MIT License)
|
59
|
+
|
60
|
+
Copyright (c) 2010 Alexander Timothy McHale
|
61
|
+
|
62
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
63
|
+
a copy of this software and associated documentation files (the
|
64
|
+
'Software'), to deal in the Software without restriction, including
|
65
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
66
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
67
|
+
permit persons to whom the Software is furnished to do so, subject to
|
68
|
+
the following conditions:
|
69
|
+
|
70
|
+
The above copyright notice and this permission notice shall be
|
71
|
+
included in all copies or substantial portions of the Software.
|
72
|
+
|
73
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
74
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
75
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
76
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
77
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
78
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
79
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
gem "echoe", ">= 4.1"
|
4
|
+
gem "redis", ">= 0.1.2"
|
5
|
+
|
6
|
+
require "echoe"
|
7
|
+
|
8
|
+
require 'fileutils'
|
9
|
+
require './lib/blendris'
|
10
|
+
|
11
|
+
Echoe.new("blendris", "0.0.1") do |p|
|
12
|
+
|
13
|
+
p.description = "A redis library for Ruby"
|
14
|
+
p.url = "http://github.com/alexmchale/blendris"
|
15
|
+
p.author = "Alex McHale"
|
16
|
+
p.email = "alexmchale@gmail.com"
|
17
|
+
p.ignore_pattern = [ "tmp", "pkg", "script" ]
|
18
|
+
p.development_dependencies = []
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
data/blendris.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{blendris}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Alex McHale"]
|
9
|
+
s.cert_chain = ["/Users/amchale/Dropbox/Security/gem-public_cert.pem"]
|
10
|
+
s.date = %q{2010-02-11}
|
11
|
+
s.description = %q{A redis library for Ruby}
|
12
|
+
s.email = %q{alexmchale@gmail.com}
|
13
|
+
s.extra_rdoc_files = ["README.rdoc", "lib/blendris.rb", "lib/blendris/accessor.rb", "lib/blendris/errors.rb", "lib/blendris/integer.rb", "lib/blendris/list.rb", "lib/blendris/model.rb", "lib/blendris/node.rb", "lib/blendris/reference.rb", "lib/blendris/reference_base.rb", "lib/blendris/reference_set.rb", "lib/blendris/set.rb", "lib/blendris/string.rb", "lib/blendris/types.rb", "lib/blendris/utils.rb", "tasks/rspec.rake"]
|
14
|
+
s.files = ["History.txt", "Manifest", "PostInstall.txt", "README.rdoc", "Rakefile", "autotest/discover.rb", "lib/blendris.rb", "lib/blendris/accessor.rb", "lib/blendris/errors.rb", "lib/blendris/integer.rb", "lib/blendris/list.rb", "lib/blendris/model.rb", "lib/blendris/node.rb", "lib/blendris/reference.rb", "lib/blendris/reference_base.rb", "lib/blendris/reference_set.rb", "lib/blendris/set.rb", "lib/blendris/string.rb", "lib/blendris/types.rb", "lib/blendris/utils.rb", "script/console", "script/destroy", "script/generate", "spec/list_spec.rb", "spec/model_spec.rb", "spec/redis-tools_spec.rb", "spec/ref_spec.rb", "spec/set_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/string_spec.rb", "tasks/rspec.rake", "blendris.gemspec"]
|
15
|
+
s.homepage = %q{http://github.com/alexmchale/blendris}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Blendris", "--main", "README.rdoc"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{blendris}
|
19
|
+
s.rubygems_version = %q{1.3.5}
|
20
|
+
s.signing_key = %q{/Users/amchale/Dropbox/Security/gem-private_key.pem}
|
21
|
+
s.summary = %q{A redis library for Ruby}
|
22
|
+
|
23
|
+
if s.respond_to? :specification_version then
|
24
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
25
|
+
s.specification_version = 3
|
26
|
+
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
28
|
+
else
|
29
|
+
end
|
30
|
+
else
|
31
|
+
end
|
32
|
+
end
|
data/lib/blendris.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
module Blendris
|
5
|
+
VERSION = '0.0.1'
|
6
|
+
end
|
7
|
+
|
8
|
+
require "blendris/errors"
|
9
|
+
require "blendris/utils"
|
10
|
+
|
11
|
+
require "blendris/accessor"
|
12
|
+
require "blendris/node"
|
13
|
+
|
14
|
+
require "blendris/model"
|
15
|
+
|
16
|
+
require "blendris/string"
|
17
|
+
require "blendris/integer"
|
18
|
+
require "blendris/list"
|
19
|
+
require "blendris/set"
|
20
|
+
|
21
|
+
require "blendris/reference_base"
|
22
|
+
require "blendris/reference"
|
23
|
+
require "blendris/reference_set"
|
24
|
+
|
25
|
+
require "blendris/types"
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
module Blendris
|
4
|
+
|
5
|
+
module RedisAccessor
|
6
|
+
|
7
|
+
include Utils
|
8
|
+
|
9
|
+
def redis
|
10
|
+
RedisAccessor.redis
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.redis
|
14
|
+
$_redis_connection ||= Redis.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def prefix
|
18
|
+
RedisAccessor.prefix
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_key(klass, values)
|
22
|
+
value_index = 0
|
23
|
+
|
24
|
+
klass.local_parameters.map do |symbol|
|
25
|
+
case symbol
|
26
|
+
|
27
|
+
when String then symbol
|
28
|
+
|
29
|
+
when Symbol
|
30
|
+
value = values[value_index]
|
31
|
+
value_index += 1
|
32
|
+
|
33
|
+
raise ArgumentError.new("#{self.name} created without #{symbol}") unless value
|
34
|
+
|
35
|
+
klass.cast_value symbol, value
|
36
|
+
|
37
|
+
else
|
38
|
+
raise TypeError.new("only strings and symbols allowed in key definition for #{klass.name} (#{symbol.class.name})")
|
39
|
+
|
40
|
+
end
|
41
|
+
end.map do |segment|
|
42
|
+
sanitize_key segment
|
43
|
+
end.compact.join(":")
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.prefix
|
47
|
+
$_redis_prefix ||= ""
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.prefix=(prefix)
|
51
|
+
$_redis_prefix = prefix.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.flush_keys
|
55
|
+
redis.keys("#{prefix}*").each do |key|
|
56
|
+
redis.del key
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Blendris
|
2
|
+
|
3
|
+
class RedisInteger
|
4
|
+
|
5
|
+
include RedisNode
|
6
|
+
|
7
|
+
def self.cast_to_redis(value, options = {})
|
8
|
+
raise TypeError.new("#{value.class.name} is not an integer") unless value.kind_of? Fixnum
|
9
|
+
|
10
|
+
value
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.cast_from_redis(value, options = {})
|
14
|
+
value.to_i if value
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Blendris
|
2
|
+
|
3
|
+
class RedisList
|
4
|
+
|
5
|
+
include RedisNode
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(key, options = {})
|
9
|
+
@key = key.to_s
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
redis.lrange(key, 0, -1).each do |value|
|
15
|
+
yield value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def <<(value)
|
20
|
+
[ value ].flatten.compact.each do |v|
|
21
|
+
redis.rpush key, v
|
22
|
+
end
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def get
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete(value)
|
32
|
+
redis.lrem key, 0, value
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Blendris
|
2
|
+
|
3
|
+
class Model
|
4
|
+
|
5
|
+
include RedisAccessor
|
6
|
+
|
7
|
+
attr_reader :key
|
8
|
+
|
9
|
+
def initialize(new_key, options = {})
|
10
|
+
@key = sanitize_key(new_key)
|
11
|
+
actual_type = constantize(redis.get(prefix + key))
|
12
|
+
|
13
|
+
raise ArgumentError.new("#{self.class.name} second argument must be a hash") unless options.kind_of? Hash
|
14
|
+
raise TypeError.new("#{prefix + key} does not exist, not a #{self.class.name} - you may want create instead of new") if !actual_type
|
15
|
+
raise TypeError.new("#{prefix + key} is a #{actual_type}, not a #{self.class.name}") if actual_type != self.class
|
16
|
+
|
17
|
+
if options[:verify] != false
|
18
|
+
parameters = self.class.local_parameters.find_all {|s| s.kind_of? Symbol}
|
19
|
+
dne = parameters.find {|p| not self.send(p.to_s)}
|
20
|
+
|
21
|
+
raise ArgumentError.new("#{self.class.name} #{key} is missing its #{dne}") if dne
|
22
|
+
raise ArgumentError.new("blank keys are not allowed") if @key.length == 0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def id
|
27
|
+
Digest::SHA1.hexdigest key
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(method_sym, *arguments)
|
31
|
+
(name, setter) = method_sym.to_s.scan(/(.*[^=])(=)?/).first
|
32
|
+
|
33
|
+
if node = redis_symbol(name)
|
34
|
+
if setter
|
35
|
+
return node.set *arguments
|
36
|
+
else
|
37
|
+
return node.get
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
def redis_symbol(name)
|
45
|
+
subkey = self.subkey(name)
|
46
|
+
|
47
|
+
options = self.class.redis_symbols[name.to_s]
|
48
|
+
|
49
|
+
return unless options
|
50
|
+
|
51
|
+
options = options.merge(:model => self)
|
52
|
+
|
53
|
+
options[:type].new subkey, options
|
54
|
+
end
|
55
|
+
|
56
|
+
def subkey(key)
|
57
|
+
sanitize_key "#{self.key}:#{key}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def ==(other)
|
61
|
+
return false unless self.class == other.class
|
62
|
+
return self.key == other.key
|
63
|
+
end
|
64
|
+
|
65
|
+
class << self
|
66
|
+
|
67
|
+
include RedisAccessor
|
68
|
+
|
69
|
+
# This method will instantiate a new object with the correct key
|
70
|
+
# and assign the values passed to it.
|
71
|
+
def create(*args)
|
72
|
+
parameters = local_parameters.find_all {|s| s.kind_of? Symbol}
|
73
|
+
got = args.count
|
74
|
+
wanted = parameters.count
|
75
|
+
|
76
|
+
if got != wanted
|
77
|
+
msg = "wrong number of arguments for a new #{self.class.name} (%d for %d)" % [ got, wanted ]
|
78
|
+
raise ArgumentError.new(msg)
|
79
|
+
end
|
80
|
+
|
81
|
+
key = generate_key(self, args)
|
82
|
+
current_model = redis.get(prefix + key)
|
83
|
+
|
84
|
+
if current_model && current_model != self.name
|
85
|
+
raise ArgumentError.new("#{key} is a #{current_model}, not a #{self.name}")
|
86
|
+
end
|
87
|
+
|
88
|
+
redis.set(prefix + key, self.name)
|
89
|
+
|
90
|
+
obj = new(key, :verify => false)
|
91
|
+
|
92
|
+
parameters.each_with_index do |parm, i|
|
93
|
+
obj.redis_symbol(parm).set args[i]
|
94
|
+
end
|
95
|
+
|
96
|
+
obj
|
97
|
+
end
|
98
|
+
|
99
|
+
def key(*fields)
|
100
|
+
@local_parameters = fields
|
101
|
+
|
102
|
+
@local_parameters.flatten!
|
103
|
+
@local_parameters.compact!
|
104
|
+
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
|
108
|
+
# Defines a new data type for Blendris:Model construction.
|
109
|
+
def type(name, klass)
|
110
|
+
(class << self; self; end).instance_eval do
|
111
|
+
define_method name do |varname, options|
|
112
|
+
options ||= {}
|
113
|
+
options[:type] = klass
|
114
|
+
redis_symbols[varname.to_s] = options
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Variables stored in the Redis database.
|
120
|
+
def redis_symbols
|
121
|
+
@redis_symbols ||= {}
|
122
|
+
end
|
123
|
+
|
124
|
+
# Parameters used when creating a new copy of this model.
|
125
|
+
def local_parameters
|
126
|
+
@local_parameters ||= []
|
127
|
+
end
|
128
|
+
|
129
|
+
# Take a value and attempt to make it fit the given field.
|
130
|
+
def cast_value(symbol, value)
|
131
|
+
options = redis_symbols[symbol.to_s]
|
132
|
+
raise ArgumentError.new("#{self.name} is missing its #{symbol}") unless options
|
133
|
+
|
134
|
+
options[:type].cast_to_redis value, options
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|