redis_hash 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14c0920d865fbe1f15499c0c50876cef5f72d179c49ad352ad61cae430722c06
4
- data.tar.gz: cc78b095bd8043d381832900daad5ae60fcdf7b3ae0bdac2c354d604cca151e9
3
+ metadata.gz: d3131d41ea67e65aa544a9ebdb7da08c0b0611a0f1439715af115e8c33ff9c96
4
+ data.tar.gz: 3dc68b7eaf87c5730073d4f4eb71c64d7369220f9c334e7d89fe495a1b4538af
5
5
  SHA512:
6
- metadata.gz: b092d1ca79de529e0e8ab93aa738c173d6719c1f01ffa2a5a35cd16376befa11fcbeaf2f4ea3b136c24d545fca2446b7464ef836cf4e0dacd679dcd4a3e047aa
7
- data.tar.gz: 1e40e8fa91ee20f8c5160d0ac33b4a99e85c12e8ff758448240364e2339526afe3aee03964c943b80666cdf210cee3de23ff9436cad0fc5c65c1f1a572203251
6
+ metadata.gz: a636758a36b3167865640201ac84227360d441be44b441ea17586681ed7167145b31e3e0d497783ee770840de87c3ed9b6aea58c483da140d39581a6beb0e315
7
+ data.tar.gz: f8c94d4d75e2c9bbc17a658d66c898dfb863955360779e5480973f9f5dd810124a513e5fc9af56dc0194d819c4da3d45118e7d9d5809662992d4e3ba92b61473
data/lib/redis_hash.rb CHANGED
@@ -2,8 +2,10 @@ require "active_support"
2
2
 
3
3
  require "redis"
4
4
 
5
- require "technologic"
6
-
7
5
  require "redis_hash/version"
8
6
 
9
- module RedisHash; end
7
+ require "redis_hash/base"
8
+
9
+ module RedisHash
10
+ class AlreadyDefinedError < StandardError; end
11
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "concerns/adapter"
4
+ require_relative "concerns/default"
5
+ require_relative "concerns/callbacks"
6
+ require_relative "concerns/core"
7
+ require_relative "concerns/identity"
8
+ require_relative "concerns/accessors"
9
+ require_relative "concerns/comparisons"
10
+ require_relative "concerns/predicates"
11
+ require_relative "concerns/insertions"
12
+ require_relative "concerns/deletions"
13
+ require_relative "concerns/enumerators"
14
+ require_relative "concerns/mutations"
15
+ require_relative "concerns/converters"
16
+ require_relative "concerns/counters"
17
+ require_relative "concerns/expiration"
18
+
19
+ module RedisHash
20
+ class Base
21
+ include RedisHash::Adapter
22
+ include RedisHash::Default
23
+ include RedisHash::Callbacks
24
+ include RedisHash::Core
25
+ include RedisHash::Identity
26
+ include RedisHash::Accessors
27
+ include RedisHash::Comparisons
28
+ include RedisHash::Predicates
29
+ include RedisHash::Insertions
30
+ include RedisHash::Deletions
31
+ include RedisHash::Enumerators
32
+ include RedisHash::Mutations
33
+ include RedisHash::Converters
34
+ include RedisHash::Counters
35
+ include RedisHash::Expiration
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Accessors allow for the retrieval of data from the Hash.
4
+ module RedisHash
5
+ module Accessors
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :hget, :hkeys, :hlen, :hmget, :hvals, to: :redis
10
+ delegate :assoc, :compact, :dig, :fetch_values, :flatten, :key, :rassoc, :rehash, to: :to_h
11
+ end
12
+
13
+ def [](field)
14
+ hget(redis_key, field) || default(field)
15
+ end
16
+
17
+ def fetch(field, default = nil)
18
+ value = self[field]
19
+ return value if value.present?
20
+ return yield(field) if block_given?
21
+ return default unless default.nil?
22
+
23
+ raise KeyError, "key not found: \"#{field}\""
24
+ end
25
+
26
+ def keys
27
+ hkeys(redis_key)
28
+ end
29
+
30
+ def length
31
+ hlen(redis_key)
32
+ end
33
+ alias_method :size, :length
34
+
35
+ def values
36
+ hvals(redis_key)
37
+ end
38
+
39
+ def values_at(*fields)
40
+ hmget(*fields.flatten.unshift(redis_key))
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Adapter which handles the storage and retrieval of hash data in Redis.
4
+ module RedisHash
5
+ module Adapter
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_reader :redis, :redis_key, :redis_ttl
10
+
11
+ delegate :default_redis, :default_redis_key, :default_redis_ttl, to: :class
12
+
13
+ private
14
+
15
+ def initialize_redis(redis, redis_key, redis_ttl)
16
+ @redis = redis || default_redis
17
+ @redis_key = redis_key || default_redis_key
18
+ @redis_ttl = redis_ttl || default_redis_ttl
19
+ end
20
+ end
21
+
22
+ class_methods do
23
+ def default_redis
24
+ Redis.new
25
+ end
26
+
27
+ def default_redis_key
28
+ SecureRandom.hex
29
+ end
30
+
31
+ def default_redis_ttl
32
+ nil
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Callbacks provide an extensible mechanism for hooking into a RedisHash.
4
+ module RedisHash
5
+ module Callbacks
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include ActiveSupport::Callbacks
10
+ define_callbacks :initialize, :insertion, :deletion
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Comparisons encompasses equality and set inclusion.
4
+ module RedisHash
5
+ module Comparisons
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :<, :<=, :>, :>=, :compare_by_identity, :compare_by_identity?, to: :to_h
10
+ end
11
+
12
+ def eql?(other)
13
+ other.hash == hash
14
+ end
15
+ alias_method :==, :eql?
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Converters allow for other objects to be coerced into a RedisHash.
4
+ module RedisHash
5
+ module Converters
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def [](*arguments)
10
+ options = block_given? ? yield({}) : {}
11
+ new(**options).merge!(Hash[*arguments])
12
+ end
13
+
14
+ def try_convert(object, &block)
15
+ return object if object.is_a?(RedisHash)
16
+
17
+ self[object, &block] if object.respond_to?(:to_hash)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A RedisHash is a wrapper around a h<key> stored in Redis.
4
+ module RedisHash
5
+ module Core
6
+ extend ActiveSupport::Concern
7
+
8
+ def initialize(default = nil, redis: nil, redis_key: nil, redis_ttl: nil, &block)
9
+ run_callbacks(:initialize) do
10
+ initialize_default(default, &block)
11
+ initialize_redis(redis, redis_key, redis_ttl)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Counters allow for the incrementing and decrementing of numeric values into the RedisHash.
4
+ module RedisHash
5
+ module Counters
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :hincrby, :hincrbyfloat, to: :redis
10
+
11
+ private
12
+
13
+ def increment_field_by(field, by, modifier: 1)
14
+ raise ArgumentError, "by must be greater than or equal to 0" if by < 0
15
+
16
+ by *= modifier
17
+
18
+ return hincrbyfloat(redis_key, field, by) if by.is_a?(Float)
19
+
20
+ hincrby(redis_key, field, by)
21
+ end
22
+ end
23
+
24
+ def increment(field, by: 1)
25
+ increment_field_by(field, by)
26
+ end
27
+
28
+ def decrement(field, by: 1)
29
+ increment_field_by(field, by, modifier: -1)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A Default allows a static or procedurally generated value to be returned on failed lookups.
4
+ module RedisHash
5
+ module Default
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_reader :default_proc
10
+
11
+ private
12
+
13
+ def initialize_default(default, &block)
14
+ raise ArgumentError, "cannot specify both block and static default" if block_given? && default.present?
15
+
16
+ set_default(default, &block)
17
+ end
18
+
19
+ def set_default(default, &block)
20
+ self.default = default if default.present?
21
+ self.default_proc = block if block_given?
22
+ end
23
+
24
+ def to_default(field = nil, allow_nil_field: true)
25
+ @default.presence || (default_proc&.call(self, field) if !field.nil? || allow_nil_field)
26
+ end
27
+
28
+ def validate_proc(proc)
29
+ raise TypeError, "wrong default_proc type #{proc.class.name} (expected Proc)" unless proc.is_a? Proc
30
+
31
+ validate_lambda_arity(proc.arity) if proc.lambda?
32
+ end
33
+
34
+ def validate_lambda_arity(arity)
35
+ raise TypeError, "default_proc takes two arguments (2 for #{arity})" if arity >= 0 && arity != 2
36
+ end
37
+ end
38
+
39
+ def default=(value)
40
+ @default = value
41
+ @default_proc = nil
42
+ end
43
+
44
+ def default_proc=(value)
45
+ validate_proc(value) unless value.nil?
46
+
47
+ @default = nil
48
+ @default_proc = value
49
+ end
50
+
51
+ def default(field = nil)
52
+ to_default(field, allow_nil_field: false)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Deletions allow for the removal of data from the Hash.
4
+ module RedisHash
5
+ module Deletions
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :del, :hdel, to: :redis
10
+ end
11
+
12
+ def clear
13
+ del(redis_key) and {}
14
+ end
15
+
16
+ def delete(field)
17
+ run_callbacks(:deletion) do
18
+ value = self[field]
19
+ result = hdel(redis_key, field)
20
+ (result == 0 && block_given?) ? yield(field) : value
21
+ end
22
+ end
23
+
24
+ def shift
25
+ return to_default if empty?
26
+
27
+ field = keys.first
28
+ [ field, delete(field) ]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Enumerators allow for the traversal and manipulation of data in the Hash.
4
+ module RedisHash
5
+ module Enumerators
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :each, :each_pair, :each_key, :each_value, :reject, :select, :transform_values, to: :to_h
10
+ end
11
+
12
+ def delete_if
13
+ return enum_for(__method__) unless block_given?
14
+
15
+ each { |field, value| delete(field) if yield(field, value) }
16
+
17
+ to_h
18
+ end
19
+
20
+ def keep_if
21
+ return enum_for(__method__) unless block_given?
22
+
23
+ delete_if { |field, value| !yield(field, value) }
24
+ end
25
+
26
+ def reject!(&block)
27
+ return enum_for(__method__) unless block_given?
28
+
29
+ original = to_h
30
+ delete_if(&block)
31
+ current = to_h
32
+
33
+ (original == current) ? nil : current
34
+ end
35
+
36
+ def select!
37
+ return enum_for(__method__) unless block_given?
38
+
39
+ reject! { |*arguments| !yield(*arguments) }
40
+ end
41
+
42
+ def transform_values!
43
+ return enum_for(__method__) unless block_given?
44
+
45
+ each { |field, value| store(field, yield(value)) }
46
+
47
+ to_h
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Expiration ensures that volatile hashes are properly configured to expire in Redis.
4
+ module RedisHash
5
+ module Expiration
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ set_callback :insertion, :before, :before_insertion
10
+ set_callback :insertion, :after, :after_insertion
11
+
12
+ private
13
+
14
+ attr_writer :was_empty_before_insertion
15
+
16
+ def before_insertion
17
+ self.was_empty_before_insertion = empty?
18
+ end
19
+
20
+ def after_insertion
21
+ expire(redis_ttl) if redis_ttl.present? && empty_before_insertion?
22
+ end
23
+ end
24
+
25
+ def empty_before_insertion?
26
+ @was_empty_before_insertion.present?
27
+ end
28
+
29
+ def expire(seconds)
30
+ redis.expire(redis_key, seconds)
31
+ end
32
+
33
+ def ttl
34
+ redis.ttl(redis_key)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Identity relates to the specific object instance.
4
+ module RedisHash
5
+ module Identity
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :hgetall, to: :redis
10
+ delegate :inspect, :to_proc, :to_s, to: :to_h
11
+ end
12
+
13
+ def hash
14
+ { redis_id: redis.id, redis_key: redis_key }.hash
15
+ end
16
+
17
+ def to_hash
18
+ to_h
19
+ end
20
+
21
+ def to_h
22
+ hgetall(redis_key)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Insertions allow for the addition of data into the RedisHash.
4
+ module RedisHash
5
+ module Insertions
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :hmset, :hset, :hsetnx, to: :redis
10
+ delegate :merge, to: :to_h
11
+ end
12
+
13
+ def merge!(other_hash)
14
+ run_callbacks(:insertion) { hmset(*other_hash.to_a.unshift(redis_key)) }
15
+
16
+ self
17
+ end
18
+ alias_method :update, :merge!
19
+
20
+ def store(field, value)
21
+ run_callbacks(:insertion) { hset(redis_key, field, value) }
22
+ end
23
+ alias_method :[]=, :store
24
+
25
+ def setnx!(field, value)
26
+ run_callbacks(:insertion) do
27
+ success = hsetnx(redis_key, field, value)
28
+
29
+ raise RedisHash::AlreadyDefinedError, "#{field} already defined" unless success
30
+ end
31
+
32
+ true
33
+ end
34
+
35
+ def setnx(field, value)
36
+ setnx!(field, value)
37
+ rescue RedisHash::AlreadyDefinedError
38
+ false
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Mutations allow for the manipulation of data in the Hash.
4
+ module RedisHash
5
+ module Mutations
6
+ extend ActiveSupport::Concern
7
+
8
+ def compact!
9
+ delete_if { |_, value| value.blank? }
10
+ end
11
+
12
+ def invert
13
+ inversion = to_h.invert
14
+ clear
15
+ inversion.each { |key, value| self[key] = value }
16
+ end
17
+
18
+ def replace(other_hash)
19
+ clear and merge!(other_hash)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Predicates enable querying the Hash for data.
4
+ module RedisHash
5
+ module Predicates
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ delegate :hexists, to: :redis
10
+ end
11
+
12
+ def any?(&block)
13
+ return length > 0 unless block_given?
14
+
15
+ to_h.any?(&block)
16
+ end
17
+
18
+ def empty?
19
+ length == 0
20
+ end
21
+
22
+ def include?(field)
23
+ hexists(redis_key, field)
24
+ end
25
+ alias_method :has_key?, :include?
26
+ alias_method :key?, :include?
27
+ alias_method :member?, :include?
28
+
29
+ def value?(value)
30
+ values.include? value
31
+ end
32
+ alias_method :has_value?, :value?
33
+ end
34
+ end
@@ -1,4 +1,4 @@
1
1
  module RedisHash
2
2
  # This constant is managed by spicerack
3
- VERSION = "0.9.0"
3
+ VERSION = "0.9.1"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_hash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Garside
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.2.1
27
- - !ruby/object:Gem::Dependency
28
- name: technologic
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '='
32
- - !ruby/object:Gem::Version
33
- version: 0.9.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '='
39
- - !ruby/object:Gem::Version
40
- version: 0.9.0
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: redis
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -63,6 +49,22 @@ files:
63
49
  - LICENSE.txt
64
50
  - README.md
65
51
  - lib/redis_hash.rb
52
+ - lib/redis_hash/base.rb
53
+ - lib/redis_hash/concerns/accessors.rb
54
+ - lib/redis_hash/concerns/adapter.rb
55
+ - lib/redis_hash/concerns/callbacks.rb
56
+ - lib/redis_hash/concerns/comparisons.rb
57
+ - lib/redis_hash/concerns/converters.rb
58
+ - lib/redis_hash/concerns/core.rb
59
+ - lib/redis_hash/concerns/counters.rb
60
+ - lib/redis_hash/concerns/default.rb
61
+ - lib/redis_hash/concerns/deletions.rb
62
+ - lib/redis_hash/concerns/enumerators.rb
63
+ - lib/redis_hash/concerns/expiration.rb
64
+ - lib/redis_hash/concerns/identity.rb
65
+ - lib/redis_hash/concerns/insertions.rb
66
+ - lib/redis_hash/concerns/mutations.rb
67
+ - lib/redis_hash/concerns/predicates.rb
66
68
  - lib/redis_hash/version.rb
67
69
  homepage: https://github.com/Freshly/spicerack/tree/master/redis_hash
68
70
  licenses: