Class: Dalli::KeyManager
- Inherits:
-
Object
- Object
- Dalli::KeyManager
- Defined in:
- lib/dalli/key_manager.rb
Overview
This class manages and validates keys sent to Memcached, ensuring that they meet Memcached key length requirements, and supporting the implementation of optional namespaces on a per-Dalli client basis.
Constant Summary collapse
- MAX_KEY_LENGTH =
250
- NAMESPACE_SEPARATOR =
':'
- TRUNCATED_KEY_SEPARATOR =
This is a hard coded md5 for historical reasons
':md5:'
- TRUNCATED_KEY_TARGET_SIZE =
This is 249 for historical reasons
249
- DEFAULTS =
{ digest_class: ::Digest::MD5 }.freeze
- OPTIONS =
%i[digest_class namespace].freeze
Instance Attribute Summary collapse
-
#namespace ⇒ Object
readonly
Returns the value of attribute namespace.
Instance Method Summary collapse
- #digest_class ⇒ Object
- #evaluate_namespace ⇒ Object
-
#initialize(client_options) ⇒ KeyManager
constructor
A new instance of KeyManager.
-
#key_with_namespace(key) ⇒ Object
Returns the key with the namespace prefixed, if a namespace is defined.
- #key_without_namespace(key) ⇒ Object
- #namespace_from_options ⇒ Object
- #namespace_regexp ⇒ Object
- #prefix_length(digest) ⇒ Object
-
#truncated_key(key) ⇒ Object
Produces a truncated key, if the raw key is longer than the maximum allowed length.
- #validate_digest_class_option(opts) ⇒ Object
-
#validate_key(key) ⇒ Object
Validates the key, and transforms as needed.
Constructor Details
#initialize(client_options) ⇒ KeyManager
Returns a new instance of KeyManager.
31 32 33 34 35 36 37 |
# File 'lib/dalli/key_manager.rb', line 31 def initialize() @key_options = DEFAULTS.merge(.select { |k, _| OPTIONS.include?(k) }) validate_digest_class_option(@key_options) @namespace = end |
Instance Attribute Details
#namespace ⇒ Object (readonly)
Returns the value of attribute namespace.
29 30 31 |
# File 'lib/dalli/key_manager.rb', line 29 def namespace @namespace end |
Instance Method Details
#digest_class ⇒ Object
73 74 75 |
# File 'lib/dalli/key_manager.rb', line 73 def digest_class @digest_class ||= @key_options[:digest_class] end |
#evaluate_namespace ⇒ Object
97 98 99 100 101 |
# File 'lib/dalli/key_manager.rb', line 97 def evaluate_namespace return namespace.call.to_s if namespace.is_a?(Proc) namespace end |
#key_with_namespace(key) ⇒ Object
Returns the key with the namespace prefixed, if a namespace is defined. Otherwise just returns the key
61 62 63 64 65 |
# File 'lib/dalli/key_manager.rb', line 61 def key_with_namespace(key) return key if namespace.nil? "#{evaluate_namespace}#{NAMESPACE_SEPARATOR}#{key}" end |
#key_without_namespace(key) ⇒ Object
67 68 69 70 71 |
# File 'lib/dalli/key_manager.rb', line 67 def key_without_namespace(key) return key if namespace.nil? key.sub(namespace_regexp, '') end |
#namespace_from_options ⇒ Object
89 90 91 92 93 94 95 |
# File 'lib/dalli/key_manager.rb', line 89 def raw_namespace = @key_options[:namespace] return nil unless raw_namespace return raw_namespace.to_s unless raw_namespace.is_a?(Proc) raw_namespace end |
#namespace_regexp ⇒ Object
77 78 79 80 81 |
# File 'lib/dalli/key_manager.rb', line 77 def namespace_regexp return /\A#{Regexp.escape(evaluate_namespace)}:/ if namespace.is_a?(Proc) @namespace_regexp ||= /\A#{Regexp.escape(namespace)}:/.freeze unless namespace.nil? end |
#prefix_length(digest) ⇒ Object
113 114 115 116 117 118 119 |
# File 'lib/dalli/key_manager.rb', line 113 def prefix_length(digest) return TRUNCATED_KEY_TARGET_SIZE - (TRUNCATED_KEY_SEPARATOR.length + digest.length) if namespace.nil? # For historical reasons, truncated keys with namespaces had a length of 250 rather # than 249 TRUNCATED_KEY_TARGET_SIZE + 1 - (TRUNCATED_KEY_SEPARATOR.length + digest.length) end |
#truncated_key(key) ⇒ Object
Produces a truncated key, if the raw key is longer than the maximum allowed length. The truncated key is produced by generating a hex digest of the key, and appending that to a truncated section of the key.
108 109 110 111 |
# File 'lib/dalli/key_manager.rb', line 108 def truncated_key(key) digest = digest_class.hexdigest(key) "#{key[0, prefix_length(digest)]}#{TRUNCATED_KEY_SEPARATOR}#{digest}" end |
#validate_digest_class_option(opts) ⇒ Object
83 84 85 86 87 |
# File 'lib/dalli/key_manager.rb', line 83 def validate_digest_class_option(opts) return if opts[:digest_class].respond_to?(:hexdigest) raise ArgumentError, 'The digest_class object must respond to the hexdigest method' end |
#validate_key(key) ⇒ Object
Validates the key, and transforms as needed.
If the key is nil or empty, raises ArgumentError. Whitespace characters are allowed for historical reasons, but likely shouldn’t be used. If the key (with namespace) is shorter than the memcached maximum allowed key length, just returns the argument key Otherwise computes a “truncated” key that uses a truncated prefix combined with a 32-byte hex digest of the whole key.
50 51 52 53 54 55 |
# File 'lib/dalli/key_manager.rb', line 50 def validate_key(key) raise ArgumentError, 'key cannot be blank' unless key&.length&.positive? key = key_with_namespace(key) key.length > MAX_KEY_LENGTH ? truncated_key(key) : key end |