From 98a3be098b6a59defa47edeb2babe5f2f910ed04 Mon Sep 17 00:00:00 2001 From: Josch Bockler Date: Thu, 15 Dec 2022 22:01:08 +0100 Subject: [PATCH 1/2] Add support for different configurations Add `Rk.configure` which accepts a name that will create `name_rk`. You can create multiple rk configurations with that if you need the keys in different formats. Remove date from gemspec since it gets automatically added when building the gem Add development dependencies to gemspec for dev setup via: `gem install --development rk` Fix bug that it was not possible to ask rk for configurations options (separator, prefix & suffix) --- .gitignore | 1 + lib/global_call.rb | 27 +++++++++++++++++++++++++ lib/rk.rb | 49 +++++++++++++++++++++++----------------------- rk.gemspec | 5 +++-- test/test_rk.rb | 38 +++++++++++++++++++++++++++++++---- 5 files changed, 89 insertions(+), 31 deletions(-) create mode 100644 lib/global_call.rb diff --git a/.gitignore b/.gitignore index f1d7f5e..b3f02c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.gem .DS_Store +.idea diff --git a/lib/global_call.rb b/lib/global_call.rb new file mode 100644 index 0000000..9eae64f --- /dev/null +++ b/lib/global_call.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Rk + # Anonymous module for including +rk+ to global namespace (class Object). + class GlobalCall < Module + def initialize(name:, rk_instance:) + rk_name = if name.to_s.empty? + "rk" + else + "#{name}_rk" + end + + $_rk ||= {} + $_rk[rk_name] = rk_instance + + super() do + define_method rk_name do |*elements| + if elements.empty? + $_rk[rk_name] + else + $_rk[rk_name].rk(elements) + end + end + end + end + end +end diff --git a/lib/rk.rb b/lib/rk.rb index bf72964..987e32c 100644 --- a/lib/rk.rb +++ b/lib/rk.rb @@ -1,6 +1,19 @@ -# Module for including +rk+ to global namespace (class Object). +# frozen_string_literal: true + +require_relative "../lib/global_call" + module Rk + # Create a rk-configuration + # * name - : optional for creating named configurations + # * block - : optional for setting configurations for details see Rk#initialize + def self.configure(name = nil) + instance = Rk.new + yield(instance) if block_given? + + Object.include(GlobalCall.new(name: name, rk_instance: instance)) + end + # Build Redis keys of several elements. # rk("user", 10) => "user:10" class Rk @@ -12,9 +25,10 @@ class Rk # * suffix - empty # * keys - empty def initialize - @separator = ":" - @prefix = "" - @suffix = "" + self.separator = ":" + self.prefix = "" + self.suffix = "" + # attr_accessor is overwritten to create methods for keys @keys = {} end @@ -28,7 +42,9 @@ def rk(*elements) # rk(rk.user, 10) => "user:10" def method_missing(method, *arg) # Raise an error if a method gets accessed which was not defined before - raise RuntimeError, "'rk.#{method.to_s}' is undefined" unless method.to_s.include?("=") + unless method.to_s.include?("=") + return super + end # Define a method to return a value as set, for example rk.settings = 'set' defines # a method called "settings" which returns the string "set" @@ -58,27 +74,10 @@ def keys=(h) self.send("#{key}=", val) end end - end # class Rk - - # Create and call a global instance of Rk to either build a key or set/get attributes. - def rk(*elements) - $_rk = Rk.new unless $_rk - - # Differ between calling "rk" without/with params - if elements.empty? - # Return instance of Rk for calling methods like "rk.separator" - $_rk - else - # Return key build by Rk.rk - $_rk.rk(elements) - end - end - end # module Rk +# Create a default rk to use it without configuring anything # We could use +extend Rk+ to extend only +main+, but we would have to +include Rk+ in -# any class, hence we include Rk to the global object. -class Object - include Rk -end +#any class, hence we include Rk to the global object +Object.include(Rk::GlobalCall.new(name: nil, rk_instance: Rk::Rk.new)) diff --git a/rk.gemspec b/rk.gemspec index 6e67d63..e2b7cb6 100644 --- a/rk.gemspec +++ b/rk.gemspec @@ -1,12 +1,13 @@ Gem::Specification.new do |g| g.name = "rk" g.version = "1.1.0" - g.date = "2016-12-21" g.summary = "Redis key builder" g.description = "Ruby helper to generate keys for Redis" g.authors = ["Oliver Mensinger"] g.email = "oliver.mensinger@gmail.com" - g.files = ["lib/rk.rb"] + g.files = %w[lib/global_call.rb lib/rk.rb] g.homepage = "https://github.com/omensinger/rk" g.license = "MIT" + + g.add_development_dependency "minitest" end diff --git a/test/test_rk.rb b/test/test_rk.rb index 7a1ed4a..1772b8e 100644 --- a/test/test_rk.rb +++ b/test/test_rk.rb @@ -18,9 +18,11 @@ def key let(:keys) { { user: "user", "statistics" => "stats", "session" => :sess } } def setup - rk.separator = ":" - rk.prefix = "" - rk.suffix = "" + Rk.configure do |config| + config.separator = ":" + config.prefix = "" + config.suffix = "" + end end def test_simple_key @@ -60,7 +62,7 @@ def test_use_defined_key_element end def test_use_undefined_key_element - assert_raises RuntimeError do + assert_raises NoMethodError do rk.something end end @@ -86,4 +88,32 @@ def test_get_keys assert_equal keys_as_strings, rk.keys end + def test_can_access_config_attributes + Rk.configure("test") do |config| + config.separator = ":" + config.prefix = "pre" + config.suffix = "suf" + end + + assert_equal ":", test_rk.separator + assert_equal "pre", test_rk.prefix + assert_equal "suf", test_rk.suffix + end + + def test_allow_second_setting + Rk.configure("foo") do |config| + config.separator = "-" + end + + assert_equal "-", foo_rk.separator + assert_equal ":", rk.separator + end + + def test_named_rk_creates_key + Rk.configure("foo") do |config| + config.prefix = "foo" + config.separator = "-" + end + assert_equal "foo-bar", foo_rk("bar") + end end From 29e7a13f6003eb66ba84a782dfdbf07b142944b6 Mon Sep 17 00:00:00 2001 From: Josch Bockler Date: Thu, 15 Dec 2022 22:42:34 +0100 Subject: [PATCH 2/2] store name of rk configuration inside instance for easier debugging in case of Errors --- lib/global_call.rb | 6 +++--- lib/rk.rb | 9 +++++---- test/test_rk.rb | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/global_call.rb b/lib/global_call.rb index 9eae64f..6621ebf 100644 --- a/lib/global_call.rb +++ b/lib/global_call.rb @@ -3,11 +3,11 @@ module Rk # Anonymous module for including +rk+ to global namespace (class Object). class GlobalCall < Module - def initialize(name:, rk_instance:) - rk_name = if name.to_s.empty? + def initialize(rk_instance) + rk_name = if rk_instance.rk_name.to_s.empty? "rk" else - "#{name}_rk" + "#{rk_instance.rk_name}_rk" end $_rk ||= {} diff --git a/lib/rk.rb b/lib/rk.rb index 987e32c..5f4a5ce 100644 --- a/lib/rk.rb +++ b/lib/rk.rb @@ -9,15 +9,16 @@ module Rk # * block - : optional for setting configurations for details see Rk#initialize def self.configure(name = nil) instance = Rk.new + instance.rk_name = name yield(instance) if block_given? - Object.include(GlobalCall.new(name: name, rk_instance: instance)) + Object.include(GlobalCall.new(instance)) end # Build Redis keys of several elements. # rk("user", 10) => "user:10" class Rk - attr_accessor :separator, :prefix, :suffix, :keys + attr_accessor :separator, :prefix, :suffix, :keys, :rk_name # Set defaults # * separator - : @@ -79,5 +80,5 @@ def keys=(h) # Create a default rk to use it without configuring anything # We could use +extend Rk+ to extend only +main+, but we would have to +include Rk+ in -#any class, hence we include Rk to the global object -Object.include(Rk::GlobalCall.new(name: nil, rk_instance: Rk::Rk.new)) +# any class, hence we include Rk to the global object +Object.include(Rk::GlobalCall.new(Rk::Rk.new)) diff --git a/test/test_rk.rb b/test/test_rk.rb index 1772b8e..5bdfa4f 100644 --- a/test/test_rk.rb +++ b/test/test_rk.rb @@ -98,6 +98,7 @@ def test_can_access_config_attributes assert_equal ":", test_rk.separator assert_equal "pre", test_rk.prefix assert_equal "suf", test_rk.suffix + assert_equal "test", test_rk.rk_name end def test_allow_second_setting