redpear 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,27 +0,0 @@
1
- module Redpear::Expiration
2
-
3
- # Expires the record.
4
- # @param [Time, Integer] either a Time or an Integer period (in seconds)
5
- def expire(value)
6
- return false unless persisted?
7
-
8
- case value
9
- when Time
10
- nest.expireat(value.to_i)
11
- when Integer
12
- nest.expire(value)
13
- when String
14
- value = Kernel::Integer(value) rescue nil
15
- expire(value)
16
- else
17
- false
18
- end
19
- end
20
-
21
- # @return [Integer] the period this record has to live.
22
- # May return -1 for non-expiring records and nil for non-persisted records.
23
- def ttl
24
- nest.ttl if persisted?
25
- end
26
-
27
- end
@@ -1,59 +0,0 @@
1
- module Redpear::Finders
2
- extend Redpear::Concern
3
-
4
- module ClassMethods
5
-
6
- # @return [Array] the IDs of all existing records
7
- def members
8
- Redpear::Members.new(mb_nest)
9
- end
10
-
11
- # @return [Integer] the number of total records
12
- def count
13
- members.count
14
- end
15
-
16
- # @return [Array] all records
17
- def all
18
- members.map {|id| find(id) }.compact
19
- end
20
-
21
- # @yield [Model] applies a block to each object
22
- def find_each(&block)
23
- members.each do |id|
24
- record = find(id)
25
- yield(record) if record
26
- end
27
- end
28
-
29
- # Finds a single record.
30
- #
31
- # @param id the ID of the record to retrieve
32
- # @param [Hash] options additional options
33
- # @option :lazy defaults to true, set to false to load the record instantly
34
- # @return [Redpear::Model] a record, or nil when not found
35
- def find(id, options = {})
36
- record = instantiate('id' => id.to_s) # Initialize
37
- if record.nest.exists # Do we have a record key?
38
- record.refresh_attributes if options[:lazy] == false
39
- record
40
- else # Must be an expired or orphaned one
41
- record.destroy # Destroy (removes from mb_nest set)
42
- nil
43
- end
44
- end
45
-
46
- # @param id the ID to check
47
- # @return [Boolean] true or false
48
- def exists?(id)
49
- members.include?(id)
50
- end
51
-
52
- def instantiate(*a)
53
- new(*a).tap do |instance|
54
- instance.send :instance_variable_set, :@__loaded__, false
55
- end
56
- end
57
-
58
- end
59
- end
data/lib/redpear/index.rb DELETED
@@ -1,31 +0,0 @@
1
- class Redpear::Index < Redpear::Column
2
-
3
- # @return [Redpear::Nest] the namespace of the index. Example:
4
- #
5
- # index = Comment.columns.lookup["post_id"]
6
- # index.namespace # => "comments:[post_id]"
7
- #
8
- def namespace
9
- model.namespace["[#{to_s}]"]
10
- end
11
-
12
- # @param [String] value the index value
13
- # @return [Redpear::Nest] the nest for a specific value. Example:
14
- #
15
- # index = Comment.columns.lookup["post_id"]
16
- # index.nest(123) # => "comments:[post_id]:123"
17
- # index.nest(nil) # => "comments:[post_id]:_"
18
- # index.nest("") # => "comments:[post_id]:_"
19
- #
20
- def nest(value)
21
- value = "_" if value.nil? || (value.respond_to?(:empty?) && value.empty?)
22
- namespace[value]
23
- end
24
-
25
- # @param [String] value the index value
26
- # @return [Array] the IDs of all existing records for a given index value
27
- def members(value)
28
- Redpear::Members.new nest(value)
29
- end
30
-
31
- end
@@ -1,51 +0,0 @@
1
- require 'redpear'
2
- require 'machinist'
3
-
4
- # Machinist module for your tests/specs. Example:
5
- #
6
- # # spec/support/blueprints.rb
7
- # require "redpear/machinist"
8
- #
9
- # Post.blueprint do
10
- # title { "A Title" }
11
- # created_at { 2.days.ago }
12
- # end
13
- #
14
- module Redpear::Machinist
15
-
16
- class Blueprint < Machinist::Blueprint
17
-
18
- def make!(attributes = {})
19
- make(attributes).tap &:save
20
- end
21
-
22
- def lathe_class #:nodoc:
23
- Lathe
24
- end
25
-
26
- end
27
-
28
- class Lathe < Machinist::Lathe
29
- protected
30
-
31
- def make_one_value(attribute, args)
32
- return unless block_given?
33
- raise_argument_error(attribute) unless args.empty?
34
- yield
35
- end
36
-
37
- def assign_attribute(key, value) #:nodoc:
38
- @assigned_attributes[key.to_sym] = value
39
- @object.load key => value
40
- end
41
-
42
- end
43
- end
44
-
45
- class Redpear::Model #:nodoc:
46
- extend Machinist::Machinable
47
-
48
- def self.blueprint_class
49
- Redpear::Machinist::Blueprint
50
- end
51
- end
@@ -1,83 +0,0 @@
1
- class Redpear::Members
2
- include Enumerable
3
-
4
- attr_reader :nest
5
-
6
- # Constructor
7
- # @param [Redpear::Nest] nest
8
- # the nest object
9
- def initialize(nest)
10
- @nest = nest
11
- end
12
-
13
- # @return [Boolean] true if member have been loaded
14
- def loaded?
15
- !@members.nil?
16
- end
17
-
18
- # @yield [String] do something with each member
19
- def each(&block)
20
- members.each(&block)
21
- end
22
-
23
- # @param [String] value
24
- # check if this value is a member
25
- # @return [Boolean] true if members contain the value
26
- def include?(value)
27
- loaded? ? @members.include?(value.to_s) : is_member?(value)
28
- end
29
-
30
- # @return [Set] the actual members
31
- def members
32
- @members ||= nest.smembers.to_set
33
- end
34
-
35
- # @return [Integer] then count of members
36
- def count
37
- @count ||= loaded? ? @members.size : cardinality
38
- end
39
- alias_method :size, :count
40
-
41
- # Compares members
42
- # @param [Object] other the object to compare with
43
- # @return [Boolean] true if same as other
44
- def ==(other)
45
- case other
46
- when Redpear::Members
47
- other.members == members
48
- when Set
49
- other == members
50
- when Array
51
- other.to_set == members
52
- else
53
- super
54
- end
55
- end
56
-
57
- # Is the value a member? This method is not cached, try using #include? instead.
58
- # @param [String] value
59
- def is_member?(value)
60
- nest.sismember(value)
61
- end
62
-
63
- # @return [Integer] the cardinaliry of this set.
64
- # This method is not cached, try using #count instead.
65
- def cardinality
66
- nest.scard
67
- end
68
-
69
- # Add a member to this set
70
- # @param [Model] record
71
- def add(record)
72
- @members << record.id if loaded?
73
- nest.sadd(record.id)
74
- end
75
-
76
- # Remove a member from this set
77
- # @param [Model] record
78
- def remove(record)
79
- @members.delete(record.id) if loaded?
80
- nest.srem(record.id)
81
- end
82
-
83
- end
@@ -1,79 +0,0 @@
1
- # Namespace organization for models. Example:
2
- #
3
- # class Comment < Model
4
- # index :post_id
5
- # end
6
- # instance = Comment.save(:post_id => 2)
7
- #
8
- # Comment.namespace.keys
9
- # # => ['comments:1', 'comments:+', 'comments:*', 'comments:post_id:2']
10
- #
11
- # # Instance nesting
12
- # instance.nest # => 'comments:1'
13
- # instance.nest.hgetall # => { "post_id" => "2" }
14
- #
15
- # # Member nesting
16
- # Comment.mb_nest # "comments:[~]"
17
- # Comment.mb_nest.smembers # => #<Set: {1}>
18
- #
19
- # # PK nesting
20
- # Comment.pk_nest # "comments:[+]"
21
- # Comment.pk_nest.get # 1 = last ID
22
- #
23
- # # Index nesting
24
- # Comment.columns["post_id"].nest(2) # "comments:post_id:2"
25
- # Comment.columns["post_id"].nest(2).smembers # #<Set: {1}>
26
- #
27
- module Redpear::Namespace
28
- extend Redpear::Concern
29
-
30
- module ClassMethods
31
-
32
- # @return [Redpear::Nest] the namespace of this model, Example:
33
- #
34
- # Comment.namespace # => "comments":Redpear::Nest
35
- #
36
- def namespace
37
- @namespace ||= Redpear::Nest.new(scope, master_connection, slave_connection)
38
- end
39
-
40
- # @return [String] the scope of this model. Example:
41
- #
42
- # Comment.scope # => "comments"
43
- #
44
- # Override if you want to use a differnet scope schema.
45
- def scope
46
- @scope ||= "#{name.split('::').last.downcase}s"
47
- end
48
-
49
- # @return [Redpear::Nest] the nest for the members store. Example:
50
- #
51
- # Comment.mb_nest # => 'comments:*'
52
- # Comment.mb_nest.smembers # => [1, 2, 3]
53
- #
54
- def mb_nest
55
- @mb_nest ||= namespace["[~]"]
56
- end
57
-
58
- # @return [Redpear::Nest] the nest for the primary-key incrementor. Example:
59
- #
60
- # Comment.pk_nest # => 'comments:+'
61
- # Comment.pk_nest.get # => 0
62
- # Comment.pk_nest.incr # => 1
63
- #
64
- def pk_nest
65
- @pk_nest ||= namespace["[+]"]
66
- end
67
-
68
- end
69
-
70
- # @return [Redpear::Nest] the nest for the current record. Example:
71
- #
72
- # comment.nest # => 'comments:123'
73
- # Comment.new.nest # => 'comments:_'
74
- #
75
- def nest
76
- self.class.namespace[id || '_']
77
- end
78
-
79
- end
data/lib/redpear/nest.rb DELETED
@@ -1,100 +0,0 @@
1
- # Nested redis key-value store, with master slave support
2
- # Heavily "inspired" by the nest library
3
- # Original copyright: Michel Martens & Damian Janowski
4
- class Redpear::Nest < ::String
5
-
6
- MASTER_METHODS = %w|
7
- append auth
8
- bgrewriteaof bgsave blpop brpop brpoplpush
9
- config
10
- decr decrby del discard
11
- exec expire expireat
12
- flushall flushdb getset
13
- hset hsetnx hincrby hmset hdel
14
- incr incrby
15
- linsert lpop lpush lpushx lrem lset ltrim
16
- mapped_hmset mapped_mset mapped_msetnx
17
- move mset msetnx multi
18
- persist pipelined psubscribe punsubscribe quit
19
- rename renamenx rpop rpoplpush rpush rpushx
20
- sadd save sdiffstore set setbit
21
- setex setnx setrange sinterstore
22
- shutdown smove spop srem subscribe
23
- sunionstore sync synchronize
24
- unsubscribe unwatch watch
25
- zadd zincrby zinterstore zrem
26
- zremrangebyrank zremrangebyscore zunionstore
27
- |.freeze
28
-
29
- SLAVE_METHODS = %w|
30
- dbsize debug get getbit getrange
31
- echo exists
32
- hget hmget hexists hlen hkeys hvals hgetall
33
- info keys lastsave lindex llen lrange
34
- mapped_hmget mapped_mget mget monitor
35
- object ping publish randomkey
36
- scard sdiff select sinter sismember slaveof
37
- smembers sort srandmember strlen substr sunion
38
- ttl type
39
- zcard zcount zrange zrangebyscore zrank
40
- zrevrange zrevrangebyscore zrevrank zscore
41
- |.freeze
42
-
43
- attr_reader :master, :slave, :current
44
-
45
- # Constructor
46
- # @param [String] key
47
- # The redis key
48
- # @param [Redis::Client|Redis::Namespace|ConnectionPool] master
49
- # The master connection, optional, defaults to the current connection
50
- # @param [Redis::Client|Redis::Namespace|ConnectionPool] slave
51
- # The slave connection, optional, defaults to master
52
- def initialize(key, master = Redis.current, slave = nil)
53
- super(key)
54
- @master = master
55
- @slave = slave || master
56
- end
57
-
58
- # @param [multiple] keys
59
- # Nest within these keys
60
- # @return [Redpear::Nest]
61
- # The nested key
62
- def [](*keys)
63
- self.class.new [self, *keys].join(':'), master, slave
64
- end
65
-
66
- # @param [Symbol] name
67
- # Either :master or :slave
68
- # @yield
69
- # Perform a block with the given connection
70
- def with_connection(name)
71
- @current = send(name)
72
- yield
73
- ensure
74
- @current = nil
75
- end
76
- alias_method :with, :with_connection
77
-
78
- MASTER_METHODS.each do |meth|
79
- define_method(meth) do |*args, &block|
80
- client = current || master
81
- if Redis.instance_method(meth).arity.zero?
82
- client.send(meth, &block)
83
- else
84
- client.send(meth, self, *args, &block)
85
- end
86
- end
87
- end
88
-
89
- SLAVE_METHODS.each do |meth|
90
- define_method(meth) do |*args, &block|
91
- client = current || slave
92
- if Redis.instance_method(meth).arity.zero?
93
- client.send(meth, &block)
94
- else
95
- client.send(meth, self, *args, &block)
96
- end
97
- end
98
- end
99
-
100
- end
@@ -1,147 +0,0 @@
1
- # Redpear's persistence methods
2
- module Redpear::Persistence
3
- extend Redpear::Concern
4
-
5
- module ClassMethods
6
-
7
- # Runs a bulk-operation.
8
- # @yield [] operations that should be run in the transaction
9
- def transaction(&block)
10
- namespace.multi(&block)
11
- end
12
-
13
- # Create or update a record. Example:
14
- #
15
- # Post.save :body => "Hello World!" # => creates a new Post
16
- # Post.save :id => 3, :body => "Hello World!" # => updates an existing Post
17
- #
18
- def save(*args)
19
- new(*args).tap(&:save)
20
- end
21
- alias_method :save!, :save
22
-
23
- # Destroys a record. Example:
24
- # @param id the ID of the record to destroy
25
- # @return [Redpear::Model] the destroyed record
26
- def destroy(id)
27
- new('id' => id).tap(&:destroy)
28
- end
29
-
30
- # Generates the next ID
31
- def next_id
32
- pk_nest.incr.to_s
33
- end
34
-
35
- end
36
-
37
- # Returns true for new records
38
- def new_record?
39
- !id
40
- end
41
-
42
- # Returns true for existing records
43
- def persisted?
44
- !new_record?
45
- end
46
-
47
- # Reloads the record (destructive)
48
- def reload
49
- replace self.class.find(id, :lazy => false) if persisted?
50
- self
51
- end
52
-
53
- # Load attributes from DB (destructive)
54
- def refresh_attributes
55
- update nest.hgetall if persisted?
56
- @__loaded__ = true
57
- self
58
- end
59
-
60
- # Saves the record.
61
- #
62
- # @param [Hash] options additional options
63
- # @option options [Integer|Date] :expire expiration period or timestamp
64
- # @yield [record] Additional block, applied as part of the save transaction
65
- # @return [Redpear::Model] the saved record
66
- def save(options = {}, &block)
67
- before_save
68
- update "id" => self.class.next_id unless persisted?
69
-
70
- transaction do
71
- nest.mapped_hmset __persistable_attributes__
72
- __relevant_member_sets__.each {|s| s.add(self) }
73
- expire options[:expire]
74
- yield(self) if block
75
- end
76
- ensure
77
- after_save
78
- end
79
- alias_method :save!, :save
80
-
81
- # Destroy the record.
82
- # @return [Boolean] true or false
83
- def destroy
84
- return false unless persisted?
85
- before_destroy
86
-
87
- transaction do
88
- nest.del
89
- __relevant_member_sets__.each {|s| s.remove(self) }
90
- end
91
-
92
- true
93
- ensure
94
- after_destroy
95
- end
96
-
97
- protected
98
-
99
- # Run in a DB transaction, returns self
100
- def transaction(&block)
101
- self.class.transaction(&block)
102
- self
103
- end
104
-
105
- # "Cheap" callback, override in subclasses
106
- def before_save
107
- end
108
-
109
- # "Cheap" callback, override in subclasses
110
- def after_save
111
- end
112
-
113
- # "Cheap" callback, override in subclasses
114
- def before_destroy
115
- end
116
-
117
- # "Cheap" callback, override in subclasses
118
- def after_destroy
119
- end
120
-
121
- protected
122
-
123
- # Attributes that can be persisted
124
- def __persistable_attributes__
125
- result = {}
126
- each do |key, value|
127
- next unless self.class.columns.include?(key)
128
- result[key] = __persistable_value__(value)
129
- end
130
- result
131
- end
132
-
133
- def __persistable_value__(value)
134
- case value
135
- when Time
136
- value.to_i
137
- else
138
- value
139
- end
140
- end
141
-
142
- # Return relevant set nests
143
- def __relevant_member_sets__
144
- @__relevant_member_sets__ ||= [self.class.members] + self.class.columns.indices.map {|i| i.members(self[i]) if self[i] }.compact
145
- end
146
-
147
- end
@@ -1,26 +0,0 @@
1
- class Redpear::ZIndex < Redpear::Index
2
-
3
- attr_reader :callback
4
-
5
- # Creates a new ZIndex.
6
- # @param [Redpear::Model] model
7
- # the model the column is associated with
8
- # @param [String] name
9
- # the column name
10
- # @param [Symbol] callback
11
- # method to be call on the object, to determine the score
12
- # @param [Symbol] type
13
- # the column type (:string (default), :counter, :integer, :float, :timestamp)
14
- def initialize(model, name, callback, type = nil)
15
- super(model, name, type)
16
- @callback = callback
17
- end
18
-
19
- # @param [String] value
20
- # the index value
21
- # @return [Redpear::SortedMembers] the IDs of all existing records for a given index value
22
- def members(value)
23
- Redpear::ZMembers.new nest(value), callback
24
- end
25
-
26
- end
@@ -1,68 +0,0 @@
1
- class Redpear::ZMembers < Redpear::Members
2
-
3
- # Constructor
4
- # @param [Redpear::Nest] nest
5
- # the nest object
6
- # @param [Symbol] callback
7
- # the method to use for scoring when members are added
8
- def initialize(nest, callback)
9
- super(nest)
10
- @callback = callback.to_sym
11
- end
12
-
13
- # @return [Hash] the actual members
14
- def members
15
- @members ||= range.to_set
16
- end
17
-
18
- # @param [Hash] options
19
- # @option [Integer] start, start index, defaults to 0
20
- # @option [Integer] stop, stop index, defaults to -1
21
- # @returns [Hash] range of members, lowest rank first
22
- def range(options = {})
23
- options = options.merge(:start => 0, :stop => -1)
24
- nest.zrange options.delete(:start), options.delete(:stop), options
25
- end
26
-
27
- # @param [Hash] options
28
- # @option [Integer] start, start index, defaults to 0
29
- # @option [Integer] stop, stop index, defaults to -1
30
- # @returns [Hash] range or members, highest rank first
31
- def reverse_range(options = {})
32
- options = options.merge(:start => 0, :stop => -1)
33
- nest.zrevrange options.delete(:start), options.delete(:stop), options
34
- end
35
-
36
- # Is the value a member? This method is not cached, try using #include? instead.
37
- # @param [String] value
38
- def is_member?(value)
39
- !!nest.zscore(value)
40
- end
41
-
42
- # @return [Integer] the cardinality of this set.
43
- # This method is not cached, try using #count instead.
44
- def cardinality
45
- nest.zcard
46
- end
47
-
48
- # @return [Integer] the score for a member
49
- # This method is not cached.
50
- def score(value)
51
- nest.zscore(value)
52
- end
53
-
54
- # Add a member to this set
55
- # @param [Model] record
56
- def add(record)
57
- @members << record.id if loaded?
58
- nest.zadd(record.send(@callback), record.id)
59
- end
60
-
61
- # Remove a member from this set
62
- # @param [Model] record
63
- def remove(record, score = 0)
64
- @members.delete(record.id) if loaded?
65
- nest.zrem(record.id)
66
- end
67
-
68
- end