From a933debf35b5f6a077e5aa29d7b7b6557fdc2e1c Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Thu, 14 May 2015 03:26:47 -0700 Subject: [PATCH] Added dynamic grouping - #80 --- CHANGELOG.md | 5 +++-- README.md | 12 ++++++++++++ lib/groupdate/enumerable.rb | 10 ++++++++++ lib/groupdate/scopes.rb | 10 ++++++++++ test/enumerable_test.rb | 2 +- test/test_helper.rb | 24 +++++++++++++++++++++++- 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0772cd..658a853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ -## 2.4.1 [unreleased] +## 2.5.0 [unreleased] -- raise `ArgumentError` if no block given to enumerable +- Added `group_by_period` method +- Raise `ArgumentError` if no block given to enumerable ## 2.4.0 diff --git a/README.md b/README.md index d2cc95d..b5c9e7d 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,18 @@ User.group_by_hour_of_day(:created_at, format: "%l %P").count.keys.first # 12 am Takes a `String`, which is passed to [strftime](http://strfti.me/), or a `Proc`. You can pass a locale with the `locale` option. +### Dynamic Grouping [master, may change] + +```ruby +User.group_by_period(:day, :created_at).count +``` + +Limit groupings with the `permit` option. + +```ruby +User.group_by_period(params[:period], :created_at, permit: %w[day week]).count +``` + ## Arrays and Hashes ```ruby diff --git a/lib/groupdate/enumerable.rb b/lib/groupdate/enumerable.rb index e18b452..50ce111 100644 --- a/lib/groupdate/enumerable.rb +++ b/lib/groupdate/enumerable.rb @@ -8,4 +8,14 @@ module Enumerable end end end + + def group_by_period(period, options = {}, &block) + # to_sym is unsafe on user input, so convert to strings + permitted_periods = ((options[:permit] || Groupdate::FIELDS).map(&:to_sym) & Groupdate::FIELDS).map(&:to_s) + if permitted_periods.include?(period.to_s) + send("group_by_#{period}", options, &block) + else + raise ArgumentError, "Unpermitted period" + end + end end diff --git a/lib/groupdate/scopes.rb b/lib/groupdate/scopes.rb index 941aea1..cbda9ef 100644 --- a/lib/groupdate/scopes.rb +++ b/lib/groupdate/scopes.rb @@ -10,5 +10,15 @@ module Groupdate Groupdate::Magic.new(field, options).relation(args[0], self) end end + + def group_by_period(period, field, options = {}) + # to_sym is unsafe on user input, so convert to strings + permitted_periods = ((options[:permit] || Groupdate::FIELDS).map(&:to_sym) & Groupdate::FIELDS).map(&:to_s) + if permitted_periods.include?(period.to_s) + send("group_by_#{period}", field, options) + else + raise ArgumentError, "Unpermitted period" + end + end end end diff --git a/test/enumerable_test.rb b/test/enumerable_test.rb index 5f4f090..667f91e 100644 --- a/test/enumerable_test.rb +++ b/test/enumerable_test.rb @@ -19,6 +19,6 @@ class TestEnumerable < Minitest::Test end def call_method(method, field, options) - Hash[User.all.to_a.send(:"group_by_#{method}", options) { |u| u.send(field) }.map { |k, v| [k, v.size] }] + Hash[User.all.to_a.group_by_period(method, options) { |u| u.send(field) }.map { |k, v| [k, v.size] }] end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 7618a4e..2f7278b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -739,6 +739,28 @@ module TestGroupdate assert_equal ({[1, "Sun"] => 1}), User.group(:score).group_by_week(:created_at, format: "%a").count end + # permit + + def test_permit + assert_raises(ArgumentError, "Unpermitted period") { User.group_by_period(:day, :created_at, permit: %w[week]).count } + end + + def test_permit_symbol_symbols + assert_equal ({}), User.group_by_period(:day, :created_at, permit: %i[day]).count + end + + def test_permit_string_symbols + assert_equal ({}), User.group_by_period("day", :created_at, permit: %i[day]).count + end + + def test_permit_symbol_strings + assert_equal ({}), User.group_by_period(:day, :created_at, permit: %w[day]).count + end + + def test_permit_string_strings + assert_equal ({}), User.group_by_period("day", :created_at, permit: %w[day]).count + end + # associations def test_associations @@ -807,7 +829,7 @@ module TestGroupdate end def call_method(method, field, options) - User.send(:"group_by_#{method}", field, options).count + User.group_by_period(method, field, options).count end def create_user(created_at, score = 1) -- libgit2 0.21.0