BrianTheCoder-cool_breeze 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 1.0.0 / 2009-03-21
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/README.txt ADDED
@@ -0,0 +1,56 @@
1
+ cool_breeze
2
+ by Brian Smith
3
+ http://brianthecoder.com
4
+ brian@46blocks.com
5
+
6
+ == DESCRIPTION:
7
+
8
+ The most awesomest thing ever
9
+
10
+ == FEATURES/PROBLEMS:
11
+
12
+ * need to write tests for queries
13
+ * uniqueness validator
14
+ * finish up indexes
15
+ * allow other data stores (bit table, simple db, couch?)
16
+
17
+ == SYNOPSIS:
18
+
19
+ * coming soon
20
+
21
+ == REQUIREMENTS:
22
+
23
+ * guid
24
+ * extlib
25
+ * validatable
26
+ * redis
27
+ * rufus-tokyo (ruby-tokyotyrant when its ready)
28
+
29
+ == INSTALL:
30
+
31
+ * its a gem on github, you should know the routine by now
32
+
33
+ == LICENSE:
34
+
35
+ (The MIT License)
36
+
37
+ Copyright (c) 2008 FIXME (different license?)
38
+
39
+ Permission is hereby granted, free of charge, to any person obtaining
40
+ a copy of this software and associated documentation files (the
41
+ 'Software'), to deal in the Software without restriction, including
42
+ without limitation the rights to use, copy, modify, merge, publish,
43
+ distribute, sublicense, and/or sell copies of the Software, and to
44
+ permit persons to whom the Software is furnished to do so, subject to
45
+ the following conditions:
46
+
47
+ The above copyright notice and this permission notice shall be
48
+ included in all copies or substantial portions of the Software.
49
+
50
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
51
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
52
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
53
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
54
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
55
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
56
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "cool_breeze"
8
+ gem.summary = %Q{A new type of orm utilizing two different storage mechanisms to the best of their abilities}
9
+ gem.email = "wbsmith83@gmail.com"
10
+ gem.homepage = "http://github.com/BrianTheCoder/cool_breeze"
11
+ gem.authors = ["brianthecoder"]
12
+
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ require 'rake/testtask'
20
+ Rake::TestTask.new(:test) do |test|
21
+ test.libs << 'lib' << 'test'
22
+ test.pattern = 'test/**/*_test.rb'
23
+ test.verbose = false
24
+ end
25
+
26
+ begin
27
+ require 'rcov/rcovtask'
28
+ Rcov::RcovTask.new do |test|
29
+ test.libs << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = true
32
+ end
33
+ rescue LoadError
34
+ task :rcov do
35
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
36
+ end
37
+ end
38
+
39
+
40
+ task :default => :test
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ if File.exist?('VERSION.yml')
45
+ config = YAML.load(File.read('VERSION.yml'))
46
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
47
+ else
48
+ version = ""
49
+ end
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "Cool Breeze #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
56
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 3
3
+ :patch: 0
4
+ :major: 0
data/bin/cool_breeze ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ puts "Its getting cold in here"
3
+
4
+ system("redis-server redis.conf")
5
+
6
+ puts "Redis started"
7
+ ROOT = File.expand_path(File.join(File.dirname(__FILE__)),'..')
8
+
9
+ TokyoConfig = {
10
+ :port => 45000,
11
+ :data_file => File.join(ROOT,'log','tokyo.tct'),
12
+ :pid_file => File.join(ROOT,'log','tokyo.pid'),
13
+ :log_file => File.join(ROOT,'log','tokyo.log')
14
+ }
15
+
16
+ system("ttserver -dmn -port #{TokyoConfig[:port]} -log #{TokyoConfig[:log_file]} -pid #{TokyoConfig[:pid_file]} #{TokyoConfig[:data_file]}")
17
+
18
+ puts "Tokyo server started"
19
+ puts "Lets rock and roll!"
data/bin/redis.conf ADDED
@@ -0,0 +1,66 @@
1
+ # Redis configuration file example
2
+
3
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
4
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
5
+ daemonize yes
6
+
7
+ # Accept connections on the specified port, default is 6379
8
+ port 6379
9
+
10
+ # If you want you can bind a single interface, if the bind option is not
11
+ # specified all the interfaces will listen for connections.
12
+ #
13
+ # bind 127.0.0.1
14
+
15
+ # Close the connection after a client is idle for N seconds
16
+ timeout 300
17
+
18
+ # Save the DB on disk:
19
+ #
20
+ # save <seconds> <changes>
21
+ #
22
+ # Will save the DB if both the given number of seconds and the given
23
+ # number of write operations against the DB occurred.
24
+ #
25
+ # In the example below the behaviour will be to save:
26
+ # after 900 sec (15 min) if at least 1 key changed
27
+ # after 300 sec (5 min) if at least 10 keys changed
28
+ # after 60 sec if at least 10000 keys changed
29
+ save 900 1
30
+ save 300 10
31
+ save 60 10000
32
+
33
+ # For default save/load DB in/from the working directory
34
+ # Note that you must specify a directory not a file name.
35
+ dir ./
36
+
37
+ # Set server verbosity to 'debug'
38
+ # it can be one of:
39
+ # debug (a lot of information, useful for development/testing)
40
+ # notice (moderately verbose, what you want in production probably)
41
+ # warning (only very important / critical messages are logged)
42
+ loglevel debug
43
+
44
+ # Specify the log file name. Also 'stdout' can be used to force
45
+ # the demon to log on the standard output. Note that if you use standard
46
+ # output for logging but daemonize, logs will be sent to /dev/null
47
+ logfile stdout
48
+
49
+ # Set the number of databases.
50
+ databases 16
51
+
52
+ ################################# REPLICATION #################################
53
+
54
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
55
+ # another Redis server. Note that the configuration is local to the slave
56
+ # so for example it is possible to configure the slave to save the DB with a
57
+ # different interval, or to listen to another port, and so on.
58
+
59
+ # slaveof <masterip> <masterport>
60
+
61
+ ############################### ADVANCED CONFIG ###############################
62
+
63
+ # Glue small output buffers together in order to send small replies in a
64
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
65
+ # in terms of number of queries per second. Use 'yes' if unsure.
66
+ glueoutputbuf yes
@@ -0,0 +1,52 @@
1
+ require 'extlib'
2
+ require 'guid'
3
+ require 'validatable'
4
+
5
+ module CoolBreeze
6
+
7
+ # :stopdoc:
8
+ VERSION = '0.2.0'
9
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
+ # :startdoc:
12
+
13
+ # Returns the version string for the library.
14
+ #
15
+ def self.version
16
+ VERSION
17
+ end
18
+
19
+ # Returns the library path for the module. If any arguments are given,
20
+ # they will be joined to the end of the libray path using
21
+ # <tt>File.join</tt>.
22
+ #
23
+ def self.libpath( *args )
24
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ end
34
+
35
+ # Utility method used to require all files ending in .rb that lie in the
36
+ # directory below this file that has the same name as the filename passed
37
+ # in. Optionally, a specific _directory_ name can be passed in such that
38
+ # the _filename_ does not have to be equivalent to the directory.
39
+ #
40
+ def self.require_all_libs_relative_to( fname, dir = nil )
41
+ dir ||= ::File.basename(fname, '.*')
42
+ search_me = ::File.expand_path(
43
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
44
+
45
+ Dir.glob(search_me).sort.each {|rb| require rb}
46
+ end
47
+
48
+ end # module CoolBreeze
49
+
50
+ CoolBreeze.require_all_libs_relative_to(__FILE__)
51
+
52
+ # EOF
@@ -0,0 +1,52 @@
1
+ module CoolBreeze
2
+ class Association
3
+ include Enumerable
4
+
5
+ def initialize(klass, name, options = {})
6
+ @list_name = "#{name}_list"
7
+ @klass = klass
8
+ klass.instance_index :"#{name}_list", :list
9
+ end
10
+
11
+ def for(instance)
12
+ @list = instance.method(@list_name)
13
+ self
14
+ end
15
+
16
+ def add(obj)
17
+ @list.call.push(obj.key)
18
+ end
19
+
20
+ def remove(obj)
21
+ @list.call.remove(1,obj.key)
22
+ end
23
+
24
+ def destroy(obj)
25
+ remove(obj)
26
+ obj.destroy
27
+ end
28
+
29
+ def get(start = 0, stop = -1)
30
+ keys = @list.call.range(start, stop)
31
+ return [] if keys.blank?
32
+ keys.map{|k| @klass.get k}
33
+ end
34
+
35
+ def size
36
+ @list.call.length
37
+ end
38
+
39
+ def first
40
+ key = @list.call.range(0,1)
41
+ @klass.get(key) unless key.blank?
42
+ end
43
+
44
+ def each
45
+ values = @list.call.range(0,-1)
46
+ return if values.blank?
47
+ values.each do |val|
48
+ yield @klass.get val
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,81 @@
1
+ class Symbol
2
+ def eq
3
+ [self.to_s,:eq]
4
+ end
5
+
6
+ def includes
7
+ [self.to_s,:includes]
8
+ end
9
+
10
+ def starts_with
11
+ [self.to_s,:starts_with]
12
+ end
13
+
14
+ def ends_with
15
+ [self.to_s,:ends_with]
16
+ end
17
+
18
+ def and
19
+ [self.to_s,:and]
20
+ end
21
+
22
+ def or
23
+ [self.to_s,:or]
24
+ end
25
+
26
+ def stroreq
27
+ [self.to_s,:stroreq]
28
+ end
29
+
30
+ def matches
31
+ [self.to_s,:matches]
32
+ end
33
+
34
+ def gt
35
+ [self.to_s,:gt]
36
+ end
37
+
38
+ def gte
39
+ [self.to_s,:gte]
40
+ end
41
+
42
+ def lt
43
+ [self.to_s,:lt]
44
+ end
45
+
46
+ def lte
47
+ [self.to_s,:lte]
48
+ end
49
+
50
+ def between
51
+ [self.to_s,:between]
52
+ end
53
+
54
+ def numoreq
55
+ [self.to_s,:numoreq]
56
+ end
57
+
58
+ def strasc
59
+ [self.to_s,:strasc]
60
+ end
61
+
62
+ def strdesc
63
+ [self.to_s,:strdesc]
64
+ end
65
+
66
+ def asc
67
+ [self.to_s,:asc]
68
+ end
69
+
70
+ def desc
71
+ [self.to_s,:desc]
72
+ end
73
+
74
+ def numasc
75
+ [self.to_s,:numasc]
76
+ end
77
+
78
+ def numdesc
79
+ [self.to_s,:numdesc]
80
+ end
81
+ end
@@ -0,0 +1,10 @@
1
+ module CoolBreeze
2
+ class Connections
3
+ class_inheritable_accessor(:adapters)
4
+ self.adapters ||= {}
5
+
6
+ def self.setup(name, instance)
7
+ adapters[name] = instance
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ module CoolBreeze
2
+ module Index
3
+ class Abstract
4
+ attr_accessor :name, :type
5
+ def initialize(name,type)
6
+ @name = name
7
+ @type = type
8
+ end
9
+
10
+ def get_key(klass)
11
+ @get_key ||= "#{klass.to_s.downcase}:#{@name}"
12
+ end
13
+
14
+ def type_klass
15
+ @type_klass ||= Module.find_const("CoolBreeze::Indices::#{@type.to_s.to_const_string}")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ module CoolBreeze
2
+ module Index
3
+ class ClassIndex < Abstract
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module CoolBreeze
2
+ module Index
3
+ class InstanceIndex < Abstract
4
+ def get_key(klass)
5
+ "#{klass.class.to_s.downcase}:#{klass.key}:#{@name}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ module CoolBreeze
2
+ module Mixins
3
+ module Associations
4
+ def self.included(base)
5
+ base.class_eval <<-EOS, __FILE__, __LINE__
6
+ class_inheritable_accessor(:associations)
7
+ self.associations = {}
8
+ EOS
9
+
10
+ base.extend(ClassMethods)
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def many(name, options = {})
16
+ associations[name] = CoolBreeze::Association.new(self,name,options = {})
17
+ class_eval <<-EOS, __FILE__, __LINE__
18
+ def #{name}
19
+ self.class.associations[:"#{name}"].for(self)
20
+ end
21
+ EOS
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,55 @@
1
+ module CoolBreeze
2
+ module Mixins
3
+ module Indices
4
+ def self.included(base)
5
+ base.class_eval <<-EOS, __FILE__, __LINE__
6
+ class_inheritable_accessor(:index_types)
7
+ class_inheritable_accessor(:class_indices)
8
+ class_inheritable_accessor(:instance_indices)
9
+ self.index_types = %w(value list set counter)
10
+ self.class_indices = {}
11
+ self.instance_indices = {}
12
+ EOS
13
+
14
+ base.extend(ClassMethods)
15
+
16
+ def destroy
17
+ instance_indices.each{|idx| idx.destroy }
18
+ super
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+ def class_indicies
24
+ @class_indicies
25
+ end
26
+
27
+ def instance_indicies
28
+ @instance_indicies
29
+ end
30
+
31
+ def class_index(name,type)
32
+ klass = Module.find_const("CoolBreeze::Types::#{type.to_s.to_const_string}")
33
+ instance_eval <<-RUBY, __FILE__, __LINE__
34
+ class_indices[name] = klass.new("#{self.to_s.downcase}:#{name}")
35
+ def #{name}(opts = {})
36
+ class_indices[:"#{name}"]
37
+ end
38
+ RUBY
39
+ end
40
+
41
+ def instance_index(name,type)
42
+ klass = Module.find_const("CoolBreeze::Types::#{type.to_s.to_const_string}")
43
+ class_eval do
44
+ define_method name do
45
+ if instance_indices[name].nil?
46
+ instance_indices[name] = klass.new("#{self.key}:#{name}")
47
+ end
48
+ instance_indices[name]
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,140 @@
1
+ module CoolBreeze
2
+ module Model
3
+ def self.included(model)
4
+ model.send(:include, InstanceMethods)
5
+ model.send(:include, Validatable)
6
+ model.send(:include, Extlib::Hook)
7
+ model.send(:include, CoolBreeze::Mixins::Indices)
8
+ model.send(:include, CoolBreeze::Mixins::Associations)
9
+ model.class_inheritable_accessor(:default_conditions)
10
+ model.extend(ClassMethods)
11
+ model.class_eval do
12
+ self.default_conditions = {:model_type => self.to_s.downcase}
13
+ end
14
+ end
15
+ module ClassMethods
16
+ def get(id)
17
+ attrs = data_store[id]
18
+ cast(attrs) unless attrs.blank?
19
+ end
20
+
21
+ alias :[] :get
22
+
23
+ def find(query = {})
24
+ rs = CoolBreeze::Query.new(self,query).run
25
+ l = LazyArray.new
26
+ l = rs.to_a
27
+ end
28
+
29
+ def first(query = {})
30
+ attrs = find(query.merge(default_conditions.merge(:limit => 1))).first
31
+ cast(attrs) unless attrs.blank?
32
+ end
33
+
34
+ def index_store
35
+ adapter(:redis)
36
+ end
37
+
38
+ def data_store
39
+ adapter(:tokyo)
40
+ end
41
+
42
+ def all(query = {})
43
+ attrs = find(query.merge(default_conditions))
44
+ attrs.map{|a| cast(a)} unless attrs.blank?
45
+ end
46
+
47
+ def adapter(name)
48
+ Connections.adapters[name]
49
+ end
50
+
51
+ def create(data = {})
52
+ m = self.new(data)
53
+ m.save
54
+ end
55
+
56
+ def timestamps!
57
+ before :save do
58
+ self.created_at = Time.now if new?
59
+ self.updated_at = Time.now
60
+ end
61
+ end
62
+
63
+ def count(query = {})
64
+ find(query.merge(default_conditions)).size
65
+ end
66
+
67
+ protected
68
+
69
+ def cast(attrs)
70
+ key = attrs.delete(:pk)
71
+ m = self.new(attrs)
72
+ m.key = key
73
+ m
74
+ end
75
+ end
76
+
77
+ module InstanceMethods
78
+ def initialize(data = {})
79
+ @index_store = self.class.index_store
80
+ @data_store = self.class.data_store
81
+ @data = {}
82
+ data.each do |k,v|
83
+ self.send(:"#{k}=",v.to_s)
84
+ end
85
+ end
86
+
87
+ def properties
88
+ @data.keys
89
+ end
90
+
91
+ def key
92
+ @key ||= "#{self.class.to_s.downcase}:#{Guid.new.to_s}"
93
+ end
94
+
95
+ def key=(k)
96
+ @key = k
97
+ end
98
+
99
+ def new?
100
+ @data_store[key].nil?
101
+ end
102
+
103
+ alias :new_record? :new?
104
+
105
+ def [](key)
106
+ @data[key]
107
+ end
108
+
109
+ def []=(key,val)
110
+ @data[key] = val.to_s
111
+ end
112
+
113
+ def save
114
+ unless @data.has_key?(:model_type)
115
+ self.model_type = self.class.to_s.downcase
116
+ end
117
+ @data_store[key] = @data
118
+ return @data_store[key] == @data
119
+ end
120
+
121
+ def destroy
122
+ @data_store.delete(key)
123
+ end
124
+
125
+ def method_missing(method_symbol, *arguments)
126
+ method_name = method_symbol.to_s
127
+
128
+ case method_name[-1..-1]
129
+ when "="
130
+ @data[method_name[0..-2]] = arguments.first.to_s
131
+ when "?"
132
+ @data[method_name[0..-2]] == true
133
+ else
134
+ # Returns nil on failure so forms will work
135
+ @data.has_key?(method_name) ? @data[method_name] : nil
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,36 @@
1
+ module CoolBreeze
2
+ class Query
3
+ def initialize(klass,conditions = {})
4
+ @klass = klass
5
+ @query = Rufus::Tokyo::TableQuery.new(CoolBreeze::Connections.adapters[:tokyo])
6
+ parse_conditions(conditions)
7
+ end
8
+
9
+ def parse_conditions(conds)
10
+ # check for order condtion
11
+ order = conds.delete(:order_by)
12
+ @query.order_by(*order) unless order.nil?
13
+ # check for limit condition
14
+ offset = conds.delete(:offset)
15
+ limit = conds.delete(:limit)
16
+ @query.limit(limit, offset || -1) unless limit.nil?
17
+ # take conditions from :prop.op => val to add(prop, op, value)
18
+ conds.each do |key, val|
19
+ key = [key,:eq] if key.is_a?(Symbol)
20
+ if key.last == :eq
21
+ if val.is_a? Numeric
22
+ key[1] = :numeq
23
+ else val.is_a? String
24
+ key[1] = :streq
25
+ end
26
+ end
27
+ key[0] = key.first.to_s
28
+ @query.add *(key + [val.to_s])
29
+ end
30
+
31
+ def run
32
+ @query.run
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module CoolBreeze
2
+ module Types
3
+ class Abstract
4
+ attr_accessor :key, :index_store
5
+ def initialize(key)
6
+ @key = key
7
+ @index_store = CoolBreeze::Connections.adapters[:redis]
8
+ end
9
+
10
+ def get
11
+ @index_store[@key]
12
+ end
13
+
14
+ def destroy
15
+ @index_store.delete(@key)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module CoolBreeze
2
+ module Types
3
+ class Counter < Abstract
4
+ def incr
5
+ @index_store.incr(@key)
6
+ end
7
+
8
+ def decr
9
+ @index_store.decr(@key)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ module CoolBreeze
2
+ module Types
3
+ class List < Abstract
4
+ def length
5
+ @index_store.list_length(@key)
6
+ end
7
+
8
+ def push(val)
9
+ @index_store.push_tail(@key, val)
10
+ end
11
+
12
+ def pop
13
+ @index_store.pop_tail(@key)
14
+ end
15
+
16
+ def unshift
17
+ @index_store.pop_head(@key)
18
+ end
19
+
20
+ def shift(val)
21
+ @index_store.push_head(@key, val)
22
+ end
23
+
24
+ def trim(start, stop)
25
+ @index_store.list_trim(@key, start, stop)
26
+ end
27
+
28
+ def range(start, stop)
29
+ @index_store.list_range(@key, start, stop)
30
+ end
31
+
32
+ def index(index)
33
+ @index_store.list_index(@key, index)
34
+ end
35
+
36
+ def remove(count, value)
37
+ @index_store.list_rm(@key, count, value)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ module CoolBreeze
2
+ module Types
3
+ class Set < Abstract
4
+ def get
5
+ @index_store.set_members(@key)
6
+ end
7
+
8
+ def add(val)
9
+ @index_store.set_add(@key,val)
10
+ end
11
+
12
+ def size
13
+ @index_store.set_count(@key)
14
+ end
15
+
16
+ def include?(val)
17
+ @index_store.set_member?(@key, val)
18
+ end
19
+
20
+ def remove(val)
21
+ @index_store.set_delete(@key, val)
22
+ end
23
+
24
+ def intersect(key)
25
+ @index_store.set_intersect(@key, key)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ module CoolBreeze
2
+ module Types
3
+ class Value < Abstract
4
+ def set(val)
5
+ @index_store[@key] = val
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
2
+
3
+ describe "Associations" do
4
+ before do
5
+ @user = User.new
6
+ end
7
+
8
+ it "defines the method on a instance" do
9
+ @user.respond_to?(:messages).should be_true
10
+ end
11
+
12
+ it "has a destroy method" do
13
+ @user.messages.respond_to?(:destroy).should be_true
14
+ end
15
+
16
+ it "has an add method" do
17
+ @user.messages.respond_to?(:add).should be_true
18
+ end
19
+
20
+ it "has a remove method" do
21
+ @user.messages.respond_to?(:remove).should be_true
22
+ end
23
+
24
+ it "has a get method" do
25
+ @user.messages.respond_to?(:get).should be_true
26
+ end
27
+
28
+ it "responds to each" do
29
+ @user.messages.respond_to?(:each).should be_true
30
+ end
31
+
32
+ it "responds to first" do
33
+ @user.messages.respond_to?(:first).should be_true
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
2
+
3
+ describe "Class Index" do
4
+ before do
5
+ end
6
+ end
7
+
8
+ describe "Instance Index" do
9
+ before do
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
2
+
3
+ describe "CoolBreeze::Model" do
4
+ before do
5
+ @data = {
6
+ "profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/74591615/01-30-09_2327_normal.jpg",
7
+ "created_at" => "Sun, 22 Mar 2009 00:13:11 +0000",
8
+ "from_user" => "pbrendel",
9
+ "text" => "first time i've noticed not having digital antenna. don't get austin cbs anymore, so no horns. (internet tv to the rescue)",
10
+ "to_user_id" => nil,
11
+ "id" => 1368224751,
12
+ "from_user_id" => 4205104,
13
+ "iso_language_code" => "en",
14
+ "source" => "&lt;a href=&quot;http://twitter.com/&quot;&gt;web&lt;/a&gt;"
15
+ }
16
+ end
17
+ it 'should take an optional paramter to new and set the data' do
18
+ m = Message.new(@data)
19
+ m.data.should == @data.each{|k,v| @data[k] = v.to_s}
20
+ end
21
+ end
22
+
23
+ # EOF
@@ -0,0 +1,12 @@
1
+ class Message
2
+ include CoolBreeze::Model
3
+
4
+ def key
5
+ @key ||= "message:#{self['id']}"
6
+ end
7
+
8
+ timestamps!
9
+
10
+ class_index :count, :counter
11
+ instance_index :tags, :set
12
+ end
@@ -0,0 +1,5 @@
1
+ class User
2
+ include CoolBreeze::Model
3
+
4
+ many :messages
5
+ end
@@ -0,0 +1,6 @@
1
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
2
+
3
+ describe "Queries" do
4
+ before do
5
+ end
6
+ end
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'spec' # Satisfies Autotest and anyone else not using the Rake tasks
3
+ require 'redis'
4
+ require 'rufus/tokyo'
5
+
6
+
7
+ require File.expand_path(
8
+ File.join(File.dirname(__FILE__), %w[.. lib cool_breeze]))
9
+
10
+ Dir[File.expand_path(File.join(File.dirname(__FILE__), 'models','*'))].each{|m| require m}
11
+
12
+ Spec::Runner.configure do |config|
13
+ CoolBreeze::Connections.setup(:redis, Redis.new)
14
+ CoolBreeze::Connections.setup(:tokyo, Rufus::Tokyo::Table.new('log/test.tct'))
15
+ # == Mock Framework
16
+ #
17
+ # RSpec uses it's own mocking framework by default. If you prefer to
18
+ # use mocha, flexmock or RR, uncomment the appropriate line:
19
+ #
20
+ # config.mock_with :mocha
21
+ # config.mock_with :flexmock
22
+ # config.mock_with :rr
23
+ end
24
+
25
+ # EOF
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: BrianTheCoder-cool_breeze
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - brianthecoder
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-15 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: wbsmith83@gmail.com
18
+ executables:
19
+ - cool_breeze
20
+ - redis.conf
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - README.txt
25
+ files:
26
+ - History.txt
27
+ - README.txt
28
+ - Rakefile
29
+ - VERSION.yml
30
+ - bin/cool_breeze
31
+ - bin/redis.conf
32
+ - lib/cool_breeze.rb
33
+ - lib/cool_breeze/association.rb
34
+ - lib/cool_breeze/conditions.rb
35
+ - lib/cool_breeze/connections.rb
36
+ - lib/cool_breeze/index/abstract.rb
37
+ - lib/cool_breeze/index/class_index.rb
38
+ - lib/cool_breeze/index/instance_index.rb
39
+ - lib/cool_breeze/mixins/associations.rb
40
+ - lib/cool_breeze/mixins/indices.rb
41
+ - lib/cool_breeze/model.rb
42
+ - lib/cool_breeze/query.rb
43
+ - lib/cool_breeze/types/abstract.rb
44
+ - lib/cool_breeze/types/counter.rb
45
+ - lib/cool_breeze/types/list.rb
46
+ - lib/cool_breeze/types/set.rb
47
+ - lib/cool_breeze/types/value.rb
48
+ - spec/association_spec.rb
49
+ - spec/index_spec.rb
50
+ - spec/model_spec.rb
51
+ - spec/models/message.rb
52
+ - spec/models/user.rb
53
+ - spec/query_spec.rb
54
+ - spec/spec_helper.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/BrianTheCoder/cool_breeze
57
+ post_install_message:
58
+ rdoc_options:
59
+ - --charset=UTF-8
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.2.0
78
+ signing_key:
79
+ specification_version: 2
80
+ summary: A new type of orm utilizing two different storage mechanisms to the best of their abilities
81
+ test_files:
82
+ - spec/association_spec.rb
83
+ - spec/index_spec.rb
84
+ - spec/model_spec.rb
85
+ - spec/models/message.rb
86
+ - spec/models/user.rb
87
+ - spec/query_spec.rb
88
+ - spec/spec_helper.rb