blendris 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2010-02-06
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -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
@@ -0,0 +1 @@
1
+ For more information on blendris, see http://github.com/alexmchale/blendris
@@ -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.
@@ -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 }
@@ -0,0 +1,3 @@
1
+ Autotest.add_discovery do
2
+ "rspec"
3
+ end
@@ -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
@@ -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,3 @@
1
+ module Blendris
2
+
3
+ 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