redpear 0.6.4 → 0.7.0

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.
@@ -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