Class: Readthis::Cache

Inherits:
Object
  • Object
show all
Defined in:
lib/readthis/cache.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Cache

Creates a new Readthis::Cache object with the given options.

Examples:

Create a new cache instance

Readthis::Cache.new(namespace: 'cache', redis: { url: 'redis://localhost:6379/0' })

Create a compressed cache instance

Readthis::Cache.new(compress: true, compression_threshold: 2048)

Parameters:

  • [Hash] (Hash)

    a customizable set of options

  • [Boolean] (Hash)

    a customizable set of options

  • [Number] (Hash)

    a customizable set of options

  • [Module] (Hash)

    a customizable set of options

  • [String] (Hash)

    a customizable set of options



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/readthis/cache.rb', line 41

def initialize(options = {})
  @options    = options
  @expires_in = options.fetch(:expires_in, nil)
  @namespace  = options.fetch(:namespace, nil)

  @entity = Readthis::Entity.new(
    marshal:   options.fetch(:marshal, Marshal),
    compress:  options.fetch(:compress, false),
    threshold: options.fetch(:compression_threshold, 1024)
  )

  @pool = ConnectionPool.new(pool_options(options)) do
    Redis.new(options.fetch(:redis, {}))
  end
end

Instance Attribute Details

#entityObject (readonly)

Returns the value of attribute entity.



10
11
12
# File 'lib/readthis/cache.rb', line 10

def entity
  @entity
end

#expires_inObject (readonly)

Returns the value of attribute expires_in.



10
11
12
# File 'lib/readthis/cache.rb', line 10

def expires_in
  @expires_in
end

#namespaceObject (readonly)

Returns the value of attribute namespace.



10
11
12
# File 'lib/readthis/cache.rb', line 10

def namespace
  @namespace
end

#optionsObject (readonly)

Returns the value of attribute options.



10
11
12
# File 'lib/readthis/cache.rb', line 10

def options
  @options
end

#poolObject (readonly)

Returns the value of attribute pool.



10
11
12
# File 'lib/readthis/cache.rb', line 10

def pool
  @pool
end

Class Method Details

.notificationsObject

Provide a class level lookup of the proper notifications module. Instrumention is expected to occur within applications that have ActiveSupport::Notifications available, but needs to work even when it isn’t.



16
17
18
19
20
21
22
# File 'lib/readthis/cache.rb', line 16

def self.notifications
  if defined?(ActiveSupport::Notifications)
    ActiveSupport::Notifications
  else
    Readthis::Notifications
  end
end

Instance Method Details

#clear(options = {}) ⇒ Object

Clear the entire cache. This flushes the current database, no globbing is applied.

Examples:


cache.clear #=> 'OK'

Parameters:

  • Options, (Hash)

    only present for compatibility.



313
314
315
# File 'lib/readthis/cache.rb', line 313

def clear(options = {})
  invoke(:clear, '*', &:flushdb)
end

#decrement(key, amount = 1, options = {}) ⇒ Object

Decrement a key in the store.

If the key doesn’t exist it will be initialized at 0. If the key exists but it isn’t a Fixnum it will be initialized at 0.

Examples:


cache.write('counter', 20) # => 20
cache.decrement('counter') # => 19
cache.decrement('counter', 2) # => 17

Parameters:

  • Key (String)

    for lookup

  • Value (Fixnum)

    to decrement by

  • Optional (Hash)

    overrides



194
195
196
197
198
# File 'lib/readthis/cache.rb', line 194

def decrement(key, amount = 1, options = {})
  invoke(:decrement, key) do |store|
    alter(key, amount * -1, options)
  end
end

#delete(key, options = {}) ⇒ Object

Delete the value stored at the specified key. Returns ‘true` if anything was deleted, `false` otherwise.

Examples:


cache.delete('existing-key') # => true
cache.delete('random-key')   # => false


107
108
109
110
111
112
113
# File 'lib/readthis/cache.rb', line 107

def delete(key, options = {})
  namespaced = namespaced_key(key, merged_options(options))

  invoke(:delete, key) do |store|
    store.del(namespaced) > 0
  end
end

#exist?(key, options = {}) ⇒ Boolean

Returns ‘true` if the cache contains an entry for the given key.

Examples:


cache.exist?('some-key') # => false
cache.exist?('some-key', namespace: 'cache') # => true

Parameters:

  • Key (String)

    for lookup

  • Optional (Hash)

    overrides

Returns:

  • (Boolean)


299
300
301
302
303
# File 'lib/readthis/cache.rb', line 299

def exist?(key, options = {})
  invoke(:exist?, key) do |store|
    store.exists(namespaced_key(key, merged_options(options)))
  end
end

#fetch(key, options = {}) ⇒ Object

Fetches data from the cache, using the given key. If there is data in the cache with the given key, then that data is returned.

If there is no such data in the cache (a cache miss), then ‘nil` will be returned. However, if a block has been passed, that block will be passed the key and executed in the event of a cache miss. The return value of the block will be written to the cache under the given cache key, and that return value will be returned.

Examples:

Typical


cache.write('today', 'Monday')
cache.fetch('today') # => "Monday"
cache.fetch('city')  # => nil

With a block


cache.fetch('city') do
  'Duckburgh'
end
cache.fetch('city')   # => "Duckburgh"

Cache Miss


cache.write('today', 'Monday')
cache.fetch('today', force: true) # => nil

Parameters:

  • Key (String)

    for lookup

  • Optional (Block)

    block for generating the value when missing

  • options (Hash) (defaults to: {})

    Optional overrides

Options Hash (options):

  • :force (Boolean)

    Force a cache miss



147
148
149
150
151
152
153
154
155
156
# File 'lib/readthis/cache.rb', line 147

def fetch(key, options = {})
  value = read(key, options) unless options[:force]

  if value.nil? && block_given?
    value = yield(key)
    write(key, value, options)
  end

  value
end

#fetch_multi(keys) ⇒ Object

Fetches multiple keys from the cache using a single call to the server and filling in any cache misses. All read and write operations are executed atomically.

Examples:


cache.fetch_multi('alpha', 'beta') do |key|
  "#{key}-was-missing"
end

cache.fetch_multi('a', 'b', expires_in: 60) do |key|
  key * 2
end

Return all values for the given keys, applying the block to the key when a value is missing.

Parameters:

  • One (String)

    or more keys to fetch



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/readthis/cache.rb', line 269

def fetch_multi(*keys)
  results   = read_multi(*keys)
  extracted = extract_options!(keys)
  missing   = {}

  invoke(:fetch_multi, keys) do |store|
    results.each do |key, value|
      if value.nil?
        value = yield(key)
        missing[key] = value
        results[key] = value
      end
    end
  end

  write_multi(missing, extracted) if missing.any?

  results
end

#increment(key, amount = 1, options = {}) ⇒ Object

Increment a key in the store.

If the key doesn’t exist it will be initialized at 0. If the key exists but it isn’t a Fixnum it will be initialized at 0.

Examples:


cache.increment('counter') # => 0
cache.increment('counter') # => 1
cache.increment('counter', 2) # => 3

Parameters:

  • Key (String)

    for lookup

  • Value (Fixnum)

    to increment by

  • Optional (Hash)

    overrides



173
174
175
176
177
# File 'lib/readthis/cache.rb', line 173

def increment(key, amount = 1, options = {})
  invoke(:incremenet, key) do |store|
    alter(key, amount, options)
  end
end

#read(key, options = {}) ⇒ Object

Fetches data from the cache, using the given key. If there is data in the cache with the given key, then that data is returned. Otherwise, nil is returned.

Examples:


cache.read('missing') # => nil
cache.read('matched') # => 'some value'

Parameters:

  • Key (String)

    for lookup

  • Optional (Hash)

    overrides



69
70
71
72
73
74
75
# File 'lib/readthis/cache.rb', line 69

def read(key, options = {})
  invoke(:read, key) do |store|
    value = store.get(namespaced_key(key, merged_options(options)))

    entity.load(value)
  end
end

#read_multi(keys) ⇒ Hash

Read multiple values at once from the cache. Options can be passed in the last argument.

Examples:


cache.write('a', 1)
cache.read_multi('a', 'b') # => { 'a' => 1, 'b' => nil }

Return all values for the given keys.

Parameters:

  • One (String)

    or more keys to fetch

Returns:

  • (Hash)

    A hash mapping keys to the values found.



214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/readthis/cache.rb', line 214

def read_multi(*keys)
  options = merged_options(extract_options!(keys))
  mapping = keys.map { |key| namespaced_key(key, options) }

  return {} if keys.empty?

  invoke(:read_multi, keys) do |store|
    values = store.mget(mapping).map { |value| entity.load(value) }

    keys.zip(values).to_h
  end
end

#write(key, value, options = {}) ⇒ Object

Writes data to the cache using the given key. Will overwrite whatever value is already stored at that key.

Examples:


cache.write('some-key', 'a bunch of text')                     # => 'OK'
cache.write('some-key', 'short lived', expires_in: 60)         # => 'OK'
cache.write('some-key', 'lives elsehwere', namespace: 'cache') # => 'OK'

Parameters:

  • Key (String)

    for lookup

  • Optional (Hash)

    overrides



89
90
91
92
93
94
95
# File 'lib/readthis/cache.rb', line 89

def write(key, value, options = {})
  options = merged_options(options)

  invoke(:write, key) do |store|
    write_entity(key, value, store, options)
  end
end

#write_multi(hash, options = {}) ⇒ Object

Write multiple key value pairs simultaneously. This is an atomic operation that will always succeed and will overwrite existing values.

This is a non-standard, but useful, cache method.

Examples:


cache.write_multi({ 'a' => 1, 'b' => 2 }) # => true

Parameters:

  • Key (Hash)

    value hash to write

  • Optional (Hash)

    overrides



240
241
242
243
244
245
246
247
248
# File 'lib/readthis/cache.rb', line 240

def write_multi(hash, options = {})
  options = merged_options(options)

  invoke(:write_multi, hash.keys) do |store|
    store.multi do
      hash.each { |key, value| write_entity(key, value, store, options) }
    end
  end
end