Skip to content

Commit

Permalink
Evaluate Proc namespaces every time (not just at initialization) (#923)
Browse files Browse the repository at this point in the history
When creating a dalli client with a Proc for the namespace option, it
would generally mean that the namespace may change from operation to
operation. Saving the result of calling the proc in the KeyManager
instance at initialisation time means that the client will always use
the value of the namespace as it was when the client was created. If
this was the desired behaviour, it would be just as easy to pass that
value as a string instead of a Proc.
  • Loading branch information
nrw505 committed Jun 28, 2022
1 parent 903295c commit f5ec74c
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 6 deletions.
14 changes: 11 additions & 3 deletions lib/dalli/key_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def validate_key(key)
def key_with_namespace(key)
return key if namespace.nil?

"#{namespace}#{NAMESPACE_SEPARATOR}#{key}"
"#{evaluate_namespace}#{NAMESPACE_SEPARATOR}#{key}"
end

def key_without_namespace(key)
Expand All @@ -75,6 +75,8 @@ def digest_class
end

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

Expand All @@ -87,9 +89,15 @@ def validate_digest_class_option(opts)
def namespace_from_options
raw_namespace = @key_options[:namespace]
return nil unless raw_namespace
return raw_namespace.call.to_s if raw_namespace.is_a?(Proc)
return raw_namespace.to_s unless raw_namespace.is_a?(Proc)

raw_namespace
end

def evaluate_namespace
return namespace.call.to_s if namespace.is_a?(Proc)

raw_namespace.to_s
namespace
end

##
Expand Down
27 changes: 24 additions & 3 deletions test/test_key_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,34 @@
end

describe 'when there is a Proc provided as a namespace parameter' do
let(:options) { { namespace: namespace_as_symbol } }
let(:options) { { namespace: namespace_as_proc } }
let(:namespace_as_proc) { proc { namespace_as_symbol } }
let(:namespace_as_symbol) { namespace_as_s.to_sym }
let(:namespace_as_s) { SecureRandom.hex(5) }

it 'the namespace is the stringified symbol' do
assert_equal namespace_as_s, key_manager.namespace
it 'the namespace is the proc' do
assert_equal namespace_as_proc, key_manager.namespace
end

it 'the evaluated namespace is the stringified symbol' do
assert_equal namespace_as_s, key_manager.evaluate_namespace
end
end

describe 'when the namespace Proc returns dynamic results' do
count = 0

let(:options) { { namespace: namespace_as_proc } }
let(:namespace_as_proc) do
proc { count += 1 }
end

it 'evaluates the namespace proc every time we need it' do
assert_equal 0, count
assert_equal '1', key_manager.evaluate_namespace
assert_equal(/\A2:/, key_manager.namespace_regexp)
assert_equal '3', key_manager.evaluate_namespace
assert_equal '4:test', key_manager.key_with_namespace('test')
end
end
end
Expand Down

0 comments on commit f5ec74c

Please sign in to comment.