readthis 1.3.0 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3fc72dc492c9faadf1cdb788cffc7cc7f884b718
4
- data.tar.gz: 9f3953c2e151c2533518c58deb434d0018cfa898
3
+ metadata.gz: ff00fddcb5af28ee6566f8f9d95e69b842adbb4c
4
+ data.tar.gz: cf57c791dbf2d3c9bb4b0fe3cb3f541df00b9385
5
5
  SHA512:
6
- metadata.gz: 4773d7f739dce07c3ee5f193f6966599d9dd12619bf8bfe1ad9d325563b1d00c70fcac0014e9b0d408167b929e6629401d44332bded3facc4b2581c3cb78ae7b
7
- data.tar.gz: 709e8fdbfab3668d51e8a428223e8e976e9e49e60c1e3e10fa397dc6bf0d8445127466830472c203f8e3e663c42d789db474e2acecfc91d61f9d69148ef50f81
6
+ metadata.gz: 378c680e372e985903972f569b4402e11f1dde8b9ce1805e3bc1b78e21428fd0290f9896d186aab1014f7cc2aa0ed1c75001573e0a90dd3cfa3bdb7c11cc16f1
7
+ data.tar.gz: c41dbbf2eea8a564975510066e6ed881c1940497cd04249ed676faf935314eafd9a26b1e76c98633c69bcf8cd67d8df766730e97f3f9877d2e3c03ed600fa155
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
  [![Build Status](https://travis-ci.org/sorentwo/readthis.svg?branch=master)](https://travis-ci.org/sorentwo/readthis)
3
3
  [![Code Climate](https://codeclimate.com/github/sorentwo/readthis/badges/gpa.svg)](https://codeclimate.com/github/sorentwo/readthis)
4
4
  [![Coverage Status](https://coveralls.io/repos/sorentwo/readthis/badge.svg?branch=master&service=github)](https://coveralls.io/github/sorentwo/readthis?branch=master)
5
+ [![Inline Docs](http://inch-ci.org/github/sorentwo/readthis.svg?branch=master)](http://inch-ci.org/github/sorentwo/readthis)
5
6
 
6
7
  # Readthis
7
8
 
@@ -184,7 +185,8 @@ Readthis supports all of standard cache methods except for the following:
184
185
  * `cleanup` - Redis does this with TTL or LRU already.
185
186
  * `delete_matched` - You really don't want to perform key matching operations in
186
187
  Redis. They are linear time and only support basic globbing.
187
- * `mute` and `silence!` - You can subscribe to the events `/cache*+active_support/` with `ActiveSupport::Notifications` to [log cache calls manually][notifications].
188
+ * `mute` and `silence!` - You can subscribe to the events `/cache*.active_support/`
189
+ with `ActiveSupport::Notifications` to [log cache calls manually][notifications].
188
190
 
189
191
  [notifications]: https://github.com/sorentwo/readthis/issues/22#issuecomment-142595938
190
192
 
@@ -1,6 +1,9 @@
1
1
  require 'readthis'
2
2
 
3
3
  module ActiveSupport
4
+ # Provided for compatibility with ActiveSupport's cache lookup behavior. When
5
+ # the ActiveSupport `cache_store` is set to `:readthis_store` it will resolve
6
+ # to `Readthis::Cache`.
4
7
  module Cache
5
8
  ReadthisStore ||= Readthis::Cache # rubocop:disable Style/ConstantName
6
9
  end
@@ -1,12 +1,13 @@
1
1
  require 'readthis/entity'
2
2
  require 'readthis/expanders'
3
3
  require 'readthis/passthrough'
4
+ require 'readthis/scripts'
4
5
  require 'redis'
5
6
  require 'connection_pool'
6
7
 
7
8
  module Readthis
8
9
  class Cache
9
- attr_reader :entity, :notifications, :options, :pool
10
+ attr_reader :entity, :notifications, :options, :pool, :scripts
10
11
 
11
12
  # Provide a class level lookup of the proper notifications module.
12
13
  # Instrumention is expected to occur within applications that have
@@ -18,15 +19,15 @@ module Readthis
18
19
 
19
20
  # Creates a new Readthis::Cache object with the given options.
20
21
  #
21
- # @option [Hash] :redis Options that will be passed to the redis connection
22
- # @option [Boolean] :compress (false) Enable or disable automatic compression
23
- # @option [Number] :compression_threshold (8k) Minimum string size for compression
24
- # @option [Number] :expires_in The number of seconds until an entry expires
25
- # @option [Boolean] :refresh (false) Automatically refresh key expiration
26
- # @option [Module] :marshal (Marshal) Module that responds to `dump` and `load`
27
- # @option [String] :namespace Prefix used to namespace entries
28
- # @option [Number] :pool_size (5) The number of threads in the pool
29
- # @option [Number] :pool_timeout (5) How long before a thread times out
22
+ # @option options [Hash] :redis Options that will be passed to the redis connection
23
+ # @option options [Boolean] :compress (false) Enable or disable automatic compression
24
+ # @option options [Number] :compression_threshold (8k) Minimum string size for compression
25
+ # @option options [Number] :expires_in The number of seconds until an entry expires
26
+ # @option options [Boolean] :refresh (false) Automatically refresh key expiration
27
+ # @option options [Module] :marshal (Marshal) Module that responds to `dump` and `load`
28
+ # @option options [String] :namespace Prefix used to namespace entries
29
+ # @option options [Number] :pool_size (5) The number of threads in the pool
30
+ # @option options [Number] :pool_timeout (5) How long before a thread times out
30
31
  #
31
32
  # @example Create a new cache instance
32
33
  # Readthis::Cache.new(namespace: 'cache',
@@ -47,14 +48,16 @@ module Readthis
47
48
  @pool = ConnectionPool.new(pool_options(options)) do
48
49
  Redis.new(options.fetch(:redis, {}))
49
50
  end
51
+
52
+ @scripts = Readthis::Scripts.new
50
53
  end
51
54
 
52
55
  # Fetches data from the cache, using the given key. If there is data in
53
56
  # the cache with the given key, then that data is returned. Otherwise, nil
54
57
  # is returned.
55
58
  #
56
- # @param [String] Key for lookup
57
- # @param [Hash] Optional overrides
59
+ # @param [String] key Key for lookup
60
+ # @param [Hash] options Optional overrides
58
61
  #
59
62
  # @example
60
63
  #
@@ -76,8 +79,8 @@ module Readthis
76
79
  # Writes data to the cache using the given key. Will overwrite whatever
77
80
  # value is already stored at that key.
78
81
  #
79
- # @param [String] Key for lookup
80
- # @param [Hash] Optional overrides
82
+ # @param [String] key Key for lookup
83
+ # @param [Hash] options Optional overrides
81
84
  #
82
85
  # @example
83
86
  #
@@ -96,8 +99,8 @@ module Readthis
96
99
  # Delete the value stored at the specified key. Returns `true` if
97
100
  # anything was deleted, `false` otherwise.
98
101
  #
99
- # @params [String] The key for lookup
100
- # @params [Hash] Optional overrides
102
+ # @param [String] key The key for lookup
103
+ # @param [Hash] options Optional overrides
101
104
  #
102
105
  # @example
103
106
  #
@@ -121,10 +124,11 @@ module Readthis
121
124
  # the block will be written to the cache under the given cache key, and
122
125
  # that return value will be returned.
123
126
  #
124
- # @param [String] Key for lookup
125
- # @param [Block] Optional block for generating the value when missing
127
+ # @param [String] key Key for lookup
126
128
  # @param options [Hash] Optional overrides
127
129
  # @option options [Boolean] :force Force a cache miss
130
+ # @yield [String] Gives a missing key to the block, which is used to
131
+ # generate the missing value
128
132
  #
129
133
  # @example Typical
130
134
  #
@@ -137,6 +141,7 @@ module Readthis
137
141
  # cache.fetch('city') do
138
142
  # 'Duckburgh'
139
143
  # end
144
+ #
140
145
  # cache.fetch('city') # => "Duckburgh"
141
146
  #
142
147
  # @example Cache Miss
@@ -161,9 +166,9 @@ module Readthis
161
166
  # If the key doesn't exist it will be initialized at 0. If the key exists
162
167
  # but it isn't a Fixnum it will be initialized at 0.
163
168
  #
164
- # @param [String] Key for lookup
165
- # @param [Fixnum] Value to increment by
166
- # @param [Hash] Optional overrides
169
+ # @param [String] key Key for lookup
170
+ # @param [Fixnum] amount Value to increment by
171
+ # @param [Hash] options Optional overrides
167
172
  #
168
173
  # @example
169
174
  #
@@ -182,9 +187,9 @@ module Readthis
182
187
  # If the key doesn't exist it will be initialized at 0. If the key exists
183
188
  # but it isn't a Fixnum it will be initialized at 0.
184
189
  #
185
- # @param [String] Key for lookup
186
- # @param [Fixnum] Value to decrement by
187
- # @param [Hash] Optional overrides
190
+ # @param [String] key Key for lookup
191
+ # @param [Fixnum] amount Value to decrement by
192
+ # @param [Hash] options Optional overrides
188
193
  #
189
194
  # @example
190
195
  #
@@ -233,8 +238,8 @@ module Readthis
233
238
  #
234
239
  # This is a non-standard, but useful, cache method.
235
240
  #
236
- # @param [Hash] Key value hash to write
237
- # @param [Hash] Optional overrides
241
+ # @param [Hash] hash Key value hash to write
242
+ # @param [Hash] options Optional overrides
238
243
  #
239
244
  # @example
240
245
  #
@@ -291,8 +296,8 @@ module Readthis
291
296
 
292
297
  # Returns `true` if the cache contains an entry for the given key.
293
298
  #
294
- # @param [String] Key for lookup
295
- # @param [Hash] Optional overrides
299
+ # @param [String] key Key for lookup
300
+ # @param [Hash] options Optional overrides
296
301
  #
297
302
  # @example
298
303
  #
@@ -308,11 +313,12 @@ module Readthis
308
313
  # Clear the entire cache. This flushes the current database, no
309
314
  # globbing is applied.
310
315
  #
311
- # @param [Hash] Options, only present for compatibility.
316
+ # @param [Hash] _options Options, only present for compatibility
312
317
  #
313
318
  # @example
314
319
  #
315
320
  # cache.clear #=> 'OK'
321
+ #
316
322
  def clear(_options = nil)
317
323
  invoke(:clear, '*', &:flushdb)
318
324
  end
@@ -322,11 +328,9 @@ module Readthis
322
328
  def refresh_entity(keys, store, options)
323
329
  return unless options[:refresh] && options[:expires_in]
324
330
 
325
- store.multi do
326
- Array(keys).each do |key|
327
- store.expire(key, coerce_expiration(options[:expires_in]))
328
- end
329
- end
331
+ expiration = coerce_expiration(options[:expires_in])
332
+
333
+ scripts.run('mexpire', store, keys, expiration)
330
334
  end
331
335
 
332
336
  def write_entity(key, value, store, options)
@@ -1,13 +1,19 @@
1
1
  require 'zlib'
2
2
 
3
3
  module Readthis
4
+ # An instance of the Entity class is used to handle `load` and `dump`
5
+ # operations on cached values.
4
6
  class Entity
7
+ # Unless they are overridden, these are the options used to load and unload
8
+ # every value.
5
9
  DEFAULT_OPTIONS = {
6
10
  compress: false,
7
11
  marshal: Marshal,
8
12
  threshold: 8 * 1024
9
13
  }.freeze
10
14
 
15
+ # A hexidecimal compression flag. When it is present within the magic bit
16
+ # of an entity that entity is considered compressed.
11
17
  COMPRESSED_FLAG = 0x8
12
18
 
13
19
  # Creates a Readthis::Entity with default options. Each option can be
@@ -17,9 +23,12 @@ module Readthis
17
23
  # automatically be used again when loading, regardless of how current
18
24
  # options are set.
19
25
  #
20
- # @option [Boolean] :compress (false) Enable or disable automatic compression
21
- # @option [Module] :marshal (Marshal) Any module that responds to `dump` and `load`
22
- # @option [Number] :threshold (8k) The size a string must be for compression
26
+ # @option [Boolean] :compress (false) Enable or disable automatic
27
+ # compression
28
+ # @option [Module] :marshal (Marshal) Any module that responds to `dump`
29
+ # and `load`
30
+ # @option [Number] :threshold (8k) The size a string must be for
31
+ # compression
23
32
  #
24
33
  def initialize(options = {})
25
34
  @options = DEFAULT_OPTIONS.merge(options)
@@ -28,10 +37,13 @@ module Readthis
28
37
  # Output a value prepared for cache storage. Passed options will override
29
38
  # whatever has been specified for the instance.
30
39
  #
31
- # @param [String] String to dump
32
- # @option [Boolean] :compress Enable or disable automatic compression
33
- # @option [Module] :marshal Any module that responds to `dump` and `load`
34
- # @option [Number] :threshold The size a string must be for compression
40
+ # @param [String] value String to dump
41
+ # @option options [Boolean] :compress Enable or disable automatic
42
+ # compression
43
+ # @option options [Module] :marshal Any module that responds to `dump` and
44
+ # `load`
45
+ # @option options [Number] :threshold The size a string must be for
46
+ # compression
35
47
  # @return [String] The prepared, possibly compressed, string
36
48
  #
37
49
  # @example Dumping a value using defaults
@@ -54,7 +66,7 @@ module Readthis
54
66
 
55
67
  # Parse a dumped value using the embedded options.
56
68
  #
57
- # @param [String] Option embedded string to load
69
+ # @param [String] string Option embedded string to load
58
70
  # @return [String] The original dumped string, restored
59
71
  #
60
72
  # @example
@@ -77,9 +89,9 @@ module Readthis
77
89
  # Where there are four unused bits, 1 compression bit, and 3 bits for the
78
90
  # serializer. This allows up to 8 different serializers for marshaling.
79
91
  #
80
- # @param [String] String to prefix with flags
81
- # @param [Module] The marshal module to be used
82
- # @param [Boolean] Flag determining whether the value is compressed
92
+ # @param [String] value String to prefix with flags
93
+ # @param [Module] marshal The marshal module to be used
94
+ # @param [Boolean] compress Flag determining whether the value is compressed
83
95
  # @return [String] The original string with a single byte prefixed
84
96
  #
85
97
  # @example Compose an option embedded string
@@ -96,7 +108,7 @@ module Readthis
96
108
 
97
109
  # Decompose an option embedded string into marshal, compression and value.
98
110
  #
99
- # @param [String] Option embedded string to
111
+ # @param [String] string Option embedded string to
100
112
  # @return [Array<Module, Boolean, String>] An array comprised of the
101
113
  # marshal, compression flag, and the base string.
102
114
  #
@@ -1,7 +1,22 @@
1
1
  module Readthis
2
+ # This is the base error that all other specific errors inherit from,
3
+ # making it possible to rescue the `ReadthisError` superclass.
4
+ #
5
+ # This isn't raised by itself.
2
6
  ReadthisError = Class.new(StandardError)
3
7
 
8
+ # Raised when attempting to modify the serializers after they have been
9
+ # frozen.
4
10
  SerializersFrozenError = Class.new(ReadthisError)
11
+
12
+ # Raised when attempting to add a new serializer after the limit of 7 is
13
+ # reached.
5
14
  SerializersLimitError = Class.new(ReadthisError)
15
+
16
+ # Raised when an unknown script is called.
17
+ UnknownCommandError = Class.new(ReadthisError)
18
+
19
+ # Raised when a serializer was specified, but hasn't been configured for
20
+ # usage.
6
21
  UnknownSerializerError = Class.new(ReadthisError)
7
22
  end
@@ -7,7 +7,10 @@ module Readthis
7
7
  when key.is_a?(Array)
8
8
  key.flat_map { |elem| expand_key(elem) }.join('/')
9
9
  when key.is_a?(Hash)
10
- key.sort_by { |hkey, _| hkey.to_s }.map { |hkey, val| "#{hkey}=#{val}" }.join('/')
10
+ key
11
+ .sort_by { |hkey, _| hkey.to_s }
12
+ .map { |hkey, val| "#{hkey}=#{val}" }
13
+ .join('/')
11
14
  when key.respond_to?(:to_param)
12
15
  key.to_param
13
16
  else
@@ -3,7 +3,7 @@
3
3
  module Readthis
4
4
  module Passthrough
5
5
  def self.dump(value)
6
- value
6
+ value.dup
7
7
  end
8
8
 
9
9
  def self.load(value)
@@ -0,0 +1,50 @@
1
+ module Readthis
2
+ # The `Scripts` class is used to conveniently execute lua scripts. The first
3
+ # time a command is run it is stored on the server and subsequently referred
4
+ # to by its SHA. Each instance tracks SHAs separately, they are not global.
5
+ class Scripts
6
+ attr_reader :loaded
7
+
8
+ # Creates a new Readthis::Scripts instance.
9
+ def initialize
10
+ @loaded = {}
11
+ end
12
+
13
+ # Run a named lua script with the provided keys and arguments.
14
+ #
15
+ # @param [String] command The script to run, without a `.lua` extension
16
+ # @param [#Store] store A Redis client for storing and evaluating the script
17
+ # @param [Array] keys One or more keys to pass to the command
18
+ # @param [Array] args One or more args to pass to the command
19
+ #
20
+ # @return [Any] The Redis converted value returned on the script
21
+ #
22
+ # @example
23
+ #
24
+ # scripts.run('mexpire', store, %w[a b c], 1) # => 'OK'
25
+ #
26
+ def run(command, store, keys, args = [])
27
+ store.evalsha(
28
+ sha(command, store),
29
+ Array(keys),
30
+ Array(args)
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ def sha(command, store)
37
+ loaded[command] ||= load_script!(command, store)
38
+ end
39
+
40
+ def load_script!(command, store)
41
+ path = File.join('script', "#{command}.lua")
42
+
43
+ File.open(path) do |file|
44
+ loaded[command] = store.script(:load, file.read)
45
+ end
46
+ rescue Errno::ENOENT
47
+ raise Readthis::UnknownCommandError, "unknown command '#{command}'"
48
+ end
49
+ end
50
+ end
@@ -4,12 +4,16 @@ require 'readthis/passthrough'
4
4
 
5
5
  module Readthis
6
6
  class Serializers
7
+ # Defines the default set of three serializers: Marshal, Passthrough, and
8
+ # JSON. With a hard limit of 7 that leaves 4 additional slots.
7
9
  BASE_SERIALIZERS = {
8
10
  Marshal => 0x1,
9
11
  Passthrough => 0x2,
10
12
  JSON => 0x3
11
13
  }.freeze
12
14
 
15
+ # The hard serializer limit, based on the number of possible values within
16
+ # a single 3bit integer.
13
17
  SERIALIZER_LIMIT = 7
14
18
 
15
19
  attr_reader :serializers, :inverted
@@ -25,7 +29,7 @@ module Readthis
25
29
  # any single application be configured for any single application. This
26
30
  # limit is based on the number of bytes available in the option flag.
27
31
  #
28
- # @param [Module] Any object that responds to `dump` and `load`
32
+ # @param [Module] serializer Any object that responds to `dump` and `load`
29
33
  # @return [self] Returns itself for possible chaining
30
34
  #
31
35
  # @example
@@ -37,7 +41,7 @@ module Readthis
37
41
  case
38
42
  when serializers.frozen?
39
43
  raise SerializersFrozenError
40
- when serializers.length > SERIALIZER_LIMIT
44
+ when serializers.length >= SERIALIZER_LIMIT
41
45
  raise SerializersLimitError
42
46
  else
43
47
  @serializers[serializer] = flags.max.succ
@@ -63,7 +67,7 @@ module Readthis
63
67
 
64
68
  # Find a flag for a serializer object.
65
69
  #
66
- # @param [Object] Look up a flag by object
70
+ # @param [Object] serializer Look up a flag by object
67
71
  # @return [Number] Corresponding flag for the serializer object
68
72
  # @raise [UnknownSerializerError] Indicates that a serializer was
69
73
  # specified, but hasn't been configured for usage.
@@ -84,7 +88,7 @@ module Readthis
84
88
 
85
89
  # Find a serializer object by flag value.
86
90
  #
87
- # @param [Number] Flag to look up the serializer object by
91
+ # @param [Number] flag Integer to look up the serializer object by
88
92
  # @return [Module] The serializer object
89
93
  #
90
94
  # @example
@@ -92,7 +96,7 @@ module Readthis
92
96
  # serializers.rassoc(1) #=> Marshal
93
97
  #
94
98
  def rassoc(flag)
95
- inverted[flag & inverted.length]
99
+ inverted[flag & SERIALIZER_LIMIT]
96
100
  end
97
101
 
98
102
  # @private
@@ -1,3 +1,3 @@
1
1
  module Readthis
2
- VERSION = '1.3.0'.freeze
2
+ VERSION = '1.4.0'.freeze
3
3
  end
data/lib/readthis.rb CHANGED
@@ -7,7 +7,7 @@ module Readthis
7
7
  # The current, global, instance of serializers that is used by all cache
8
8
  # instances.
9
9
  #
10
- # @returns [Readthis::Serializers] An cached Serializers instance
10
+ # @return [Readthis::Serializers] An cached Serializers instance
11
11
  #
12
12
  # @see readthis/serializers
13
13
  #
@@ -18,7 +18,7 @@ module Readthis
18
18
  # Indicates whether connection error tolerance is enabled. With tolerance
19
19
  # enabled every operation will return a `nil` value.
20
20
  #
21
- # @returns [Boolean] True for enabled, false for disabled
21
+ # @return [Boolean] True for enabled, false for disabled
22
22
  #
23
23
  def fault_tolerant?
24
24
  @fault_tolerant
@@ -26,7 +26,7 @@ module Readthis
26
26
 
27
27
  # Toggle fault tolerance for connection errors.
28
28
  #
29
- # @param [Boolean] The new value for fault tolerance
29
+ # @param [Boolean] value The new value for fault tolerance
30
30
  #
31
31
  def fault_tolerant=(value)
32
32
  @fault_tolerant = value
@@ -0,0 +1,7 @@
1
+ local expire = ARGV[1]
2
+
3
+ for index = 1, #KEYS do
4
+ redis.call('EXPIRE', KEYS[index], expire)
5
+ end
6
+
7
+ return true
@@ -1,4 +1,3 @@
1
- require 'readthis'
2
1
  require 'matchers/redis_matchers'
3
2
 
4
3
  RSpec.describe Readthis::Cache do
@@ -173,6 +172,12 @@ RSpec.describe Readthis::Cache do
173
172
  expect(cache.read('missing-key')).to eq(value)
174
173
  end
175
174
 
175
+ it 'returns computed value when using passthrough marshalling' do
176
+ cache = Readthis::Cache.new(marshal: Readthis::Passthrough)
177
+ result = cache.fetch('missing-key') { 'value for you' }
178
+ expect(result).to eq('value for you')
179
+ end
180
+
176
181
  it 'does not set for a missing key without a block' do
177
182
  expect(cache.fetch('missing-key')).to be_nil
178
183
  end
@@ -1,4 +1,3 @@
1
- require 'readthis'
2
1
  require 'json'
3
2
 
4
3
  RSpec.describe Readthis::Entity do
@@ -1,5 +1,3 @@
1
- require 'readthis/expanders'
2
-
3
1
  RSpec.describe Readthis::Expanders do
4
2
  def expand(key, namespace = nil)
5
3
  Readthis::Expanders.namespace_key(key, namespace)
@@ -1,17 +1,16 @@
1
- require 'readthis/passthrough'
2
-
3
1
  RSpec.describe Readthis::Passthrough do
2
+ let(:value) { 'skywalker' }
3
+
4
4
  describe '.load' do
5
5
  it 'passes through the provided value' do
6
- value = Object.new
7
6
  expect(Readthis::Passthrough.load(value)).to eq(value)
8
7
  end
9
8
  end
10
9
 
11
10
  describe '.dump' do
12
11
  it 'passes through the provided value' do
13
- value = Object.new
14
12
  expect(Readthis::Passthrough.dump(value)).to eq(value)
13
+ expect(Readthis::Passthrough.dump(value)).not_to be(value)
15
14
  end
16
15
  end
17
16
  end
@@ -0,0 +1,31 @@
1
+ RSpec.describe Readthis::Scripts do
2
+ let(:scripts) { Readthis::Scripts.new }
3
+
4
+ describe '#run' do
5
+ it 'raises an error with an unknown command' do
6
+ expect do
7
+ scripts.run('unknown', nil, [])
8
+ end.to raise_error(Readthis::UnknownCommandError)
9
+ end
10
+
11
+ it 'runs the script command with a single key' do
12
+ store = Redis.new
13
+
14
+ store.set('alpha', 'content')
15
+ scripts.run('mexpire', store, 'alpha', 1)
16
+
17
+ expect(store.ttl('alpha')).to eq(1)
18
+ end
19
+
20
+ it 'runs the script command with multiple keys' do
21
+ store = Redis.new
22
+
23
+ store.set('beta', 'content')
24
+ store.set('gamma', 'content')
25
+ scripts.run('mexpire', store, %w[beta gamma], 1)
26
+
27
+ expect(store.ttl('beta')).to eq(1)
28
+ expect(store.ttl('gamma')).to eq(1)
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,3 @@
1
- require 'readthis/serializers'
2
-
3
1
  RSpec.describe Readthis::Serializers do
4
2
  CustomSerializer = Class.new
5
3
  AnotherSerializer = Class.new
@@ -24,9 +22,9 @@ RSpec.describe Readthis::Serializers do
24
22
 
25
23
  it 'prevents more than seven serializers' do
26
24
  serializers = Readthis::Serializers.new
27
-
25
+ serializers << Class.new until serializers.flags.length >= 7
28
26
  expect do
29
- 10.times { serializers << Class.new }
27
+ serializers << Class.new
30
28
  end.to raise_error(Readthis::SerializersLimitError)
31
29
  end
32
30
  end
@@ -48,18 +46,29 @@ RSpec.describe Readthis::Serializers do
48
46
  end
49
47
 
50
48
  describe '#rassoc' do
51
- it 'inverts the current set of serializers' do
52
- serializers = Readthis::Serializers.new
49
+ let(:serializers) { Readthis::Serializers.new }
53
50
 
51
+ it 'inverts the current set of serializers' do
54
52
  expect(serializers.rassoc(1)).to eq(Marshal)
55
53
  end
56
54
 
57
55
  it 'returns custom serializers' do
58
- serializers = Readthis::Serializers.new
59
56
  serializers << CustomSerializer
60
-
61
57
  expect(serializers.rassoc(4)).to eq(CustomSerializer)
62
58
  end
59
+
60
+ it 'inverts default serializers after adding custom one' do
61
+ serializers << CustomSerializer
62
+ expect(serializers.rassoc(1)).to eq(Marshal)
63
+ expect(serializers.rassoc(3)).to eq(JSON)
64
+ end
65
+
66
+ it 'takes into account only first 3 bytes of passed integer' do
67
+ expect(serializers.rassoc(1)).to eq(Marshal)
68
+ expect(serializers.rassoc(11)).to eq(JSON)
69
+ serializers << CustomSerializer
70
+ expect(serializers.rassoc(12)).to eq(CustomSerializer)
71
+ end
63
72
  end
64
73
 
65
74
  describe '#freeze!' do
@@ -1,5 +1,3 @@
1
- require 'readthis'
2
-
3
1
  RSpec.describe Readthis do
4
2
  describe '#serializers' do
5
3
  it 'lists currently configured serializers' do
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'coveralls'
2
+ require 'readthis'
2
3
 
3
4
  Coveralls.wear!
4
5
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: readthis
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Parker Selbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-08 00:00:00.000000000 Z
11
+ date: 2016-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -123,13 +123,16 @@ files:
123
123
  - lib/readthis/errors.rb
124
124
  - lib/readthis/expanders.rb
125
125
  - lib/readthis/passthrough.rb
126
+ - lib/readthis/scripts.rb
126
127
  - lib/readthis/serializers.rb
127
128
  - lib/readthis/version.rb
129
+ - script/mexpire.lua
128
130
  - spec/matchers/redis_matchers.rb
129
131
  - spec/readthis/cache_spec.rb
130
132
  - spec/readthis/entity_spec.rb
131
133
  - spec/readthis/expanders_spec.rb
132
134
  - spec/readthis/passthrough_spec.rb
135
+ - spec/readthis/scripts_spec.rb
133
136
  - spec/readthis/serializers_spec.rb
134
137
  - spec/readthis_spec.rb
135
138
  - spec/spec_helper.rb
@@ -163,6 +166,8 @@ test_files:
163
166
  - spec/readthis/entity_spec.rb
164
167
  - spec/readthis/expanders_spec.rb
165
168
  - spec/readthis/passthrough_spec.rb
169
+ - spec/readthis/scripts_spec.rb
166
170
  - spec/readthis/serializers_spec.rb
167
171
  - spec/readthis_spec.rb
168
172
  - spec/spec_helper.rb
173
+ has_rdoc: