From fa182e618db2c80bd2c112e45c4a6bcc42785c71 Mon Sep 17 00:00:00 2001 From: David Czarnecki Date: Wed, 18 Apr 2012 14:44:36 -0400 Subject: [PATCH] Allow for configurable group separator --- README.md | 7 ++++++- lib/redistat.rb | 6 ++++++ lib/redistat/key.rb | 2 +- lib/redistat/label.rb | 8 ++++---- lib/redistat/summary.rb | 4 ++-- spec/label_spec.rb | 15 +++++++++++++++ spec/summary_spec.rb | 37 +++++++++++++++++++++++++++++++++++++ 7 files changed, 71 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3aaa151..eabfca9 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,12 @@ is the label that you're storing to, or fetching from. Labels support multiple grouping levels by splitting the label string with `/` and storing the same stats for each level. For example, when storing data to a label called `views/product/44`, the data is stored for the label you specify, -and also for `views/product` and `views`. +and also for `views/product` and `views`. You may also configure a different +group separator using the `Redistat.group_separator` option. For example: + +```ruby +Redistat.group_separator = '|' +``` A word of caution: Don't use a crazy number of group levels. As two levels causes twice as many `hincrby` calls to Redis as not using the grouping diff --git a/lib/redistat.rb b/lib/redistat.rb index e41a694..96b0537 100644 --- a/lib/redistat.rb +++ b/lib/redistat.rb @@ -52,6 +52,8 @@ module Redistat class << self + attr_writer :group_separator + def buffer Buffer.instance end @@ -91,6 +93,10 @@ module Redistat connection.flushdb end + def group_separator + @group_separator ||= GROUP_SEPARATOR + end + end end diff --git a/lib/redistat/key.rb b/lib/redistat/key.rb index 598c5f3..180c1fc 100644 --- a/lib/redistat/key.rb +++ b/lib/redistat/key.rb @@ -56,7 +56,7 @@ module Redistat members = db.smembers("#{scope}#{LABEL_INDEX}#{@label}") || [] # older versions of Redis returns nil members.map { |member| child_label = [@label, member].reject { |i| i.nil? } - self.class.new(self.scope, child_label.join(GROUP_SEPARATOR), self.date, @options) + self.class.new(self.scope, child_label.join(Redistat.group_separator), self.date, @options) } end diff --git a/lib/redistat/label.rb b/lib/redistat/label.rb index b4c2101..ed498e8 100644 --- a/lib/redistat/label.rb +++ b/lib/redistat/label.rb @@ -13,7 +13,7 @@ module Redistat def self.join(*args) args = args.map {|i| i.to_s} - self.new(args.reject {|i| i.blank? }.join(GROUP_SEPARATOR)) + self.new(args.reject {|i| i.blank? }.join(Redistat.group_separator)) end def initialize(str, opts = {}) @@ -48,16 +48,16 @@ module Redistat end def me - self.to_s.split(GROUP_SEPARATOR).last + self.to_s.split(Redistat.group_separator).last end def groups return @groups unless @groups.nil? @groups = [] parent = "" - self.to_s.split(GROUP_SEPARATOR).each do |part| + self.to_s.split(Redistat.group_separator).each do |part| if !part.blank? - group = ((parent.blank?) ? "" : "#{parent}#{GROUP_SEPARATOR}") + part + group = ((parent.blank?) ? "" : "#{parent}#{Redistat.group_separator}") + part @groups << Label.new(group) parent = group end diff --git a/lib/redistat/summary.rb b/lib/redistat/summary.rb index b92224a..8b8fbdc 100644 --- a/lib/redistat/summary.rb +++ b/lib/redistat/summary.rb @@ -66,13 +66,13 @@ module Redistat def inject_group_summaries!(stats) summaries = {} stats.each do |key, value| - parts = key.to_s.split(GROUP_SEPARATOR) + parts = key.to_s.split(Redistat.group_separator) parts.pop if parts.size > 0 sum_parts = [] parts.each do |part| sum_parts << part - sum_key = sum_parts.join(GROUP_SEPARATOR) + sum_key = sum_parts.join(Redistat.group_separator) (summaries.has_key?(sum_key)) ? summaries[sum_key] += value : summaries[sum_key] = value end end diff --git a/spec/label_spec.rb b/spec/label_spec.rb index 3d46a7b..511681b 100644 --- a/spec/label_spec.rb +++ b/spec/label_spec.rb @@ -38,6 +38,21 @@ describe Redistat::Label do label.to_s.should == 'email/message/public' end + it "should allow you to use a different group separator" do + include Redistat + Redistat.group_separator = '|' + label = Label.join('email', 'message', 'public') + label.should be_a(Label) + label.to_s.should == 'email|message|public' + label = Label.join(Label.new('email'), Label.new('message'), Label.new('public')) + label.should be_a(Label) + label.to_s.should == 'email|message|public' + label = Label.join('email', '', 'message', nil, 'public') + label.should be_a(Label) + label.to_s.should == 'email|message|public' + Redistat.group_separator = Redistat::GROUP_SEPARATOR + end + describe "Grouping" do before(:each) do @name = "message/public/offensive" diff --git a/spec/summary_spec.rb b/spec/summary_spec.rb index c0e5106..5267702 100644 --- a/spec/summary_spec.rb +++ b/spec/summary_spec.rb @@ -136,4 +136,41 @@ describe Redistat::Summary do summary["visitors/us"].should == "8" end + it "should store label-based grouping enabled stats using a different group separator" do + Redistat.group_separator = '|' + stats = {"views" => 3, "visitors|eu" => 2, "visitors|us" => 4} + label = "views|about_us" + key = Redistat::Key.new(@scope, label, @date) + Redistat::Summary.update_all(key, stats, :hour) + + key.groups[0].label.to_s.should == "views|about_us" + key.groups[1].label.to_s.should == "views" + child1 = key.groups[0] + parent = key.groups[1] + + label = "views|contact" + key = Redistat::Key.new(@scope, label, @date) + Redistat::Summary.update_all(key, stats, :hour) + + key.groups[0].label.to_s.should == "views|contact" + key.groups[1].label.to_s.should == "views" + child2 = key.groups[0] + + summary = db.hgetall(child1.to_s(:hour)) + summary["views"].should == "3" + summary["visitors|eu"].should == "2" + summary["visitors|us"].should == "4" + + summary = db.hgetall(child2.to_s(:hour)) + summary["views"].should == "3" + summary["visitors|eu"].should == "2" + summary["visitors|us"].should == "4" + + summary = db.hgetall(parent.to_s(:hour)) + summary["views"].should == "6" + summary["visitors|eu"].should == "4" + summary["visitors|us"].should == "8" + Redistat.group_separator = Redistat::GROUP_SEPARATOR + end + end