Commit a933debf35b5f6a077e5aa29d7b7b6557fdc2e1c

Authored by Andrew Kane
1 parent f509b2a3

Added dynamic grouping - #80

CHANGELOG.md
1   -## 2.4.1 [unreleased]
  1 +## 2.5.0 [unreleased]
2 2  
3   -- raise `ArgumentError` if no block given to enumerable
  3 +- Added `group_by_period` method
  4 +- Raise `ArgumentError` if no block given to enumerable
4 5  
5 6 ## 2.4.0
6 7  
... ...
README.md
... ... @@ -139,6 +139,18 @@ User.group_by_hour_of_day(:created_at, format: "%l %P").count.keys.first # 12 am
139 139  
140 140 Takes a `String`, which is passed to [strftime](http://strfti.me/), or a `Proc`. You can pass a locale with the `locale` option.
141 141  
  142 +### Dynamic Grouping [master, may change]
  143 +
  144 +```ruby
  145 +User.group_by_period(:day, :created_at).count
  146 +```
  147 +
  148 +Limit groupings with the `permit` option.
  149 +
  150 +```ruby
  151 +User.group_by_period(params[:period], :created_at, permit: %w[day week]).count
  152 +```
  153 +
142 154 ## Arrays and Hashes
143 155  
144 156 ```ruby
... ...
lib/groupdate/enumerable.rb
... ... @@ -8,4 +8,14 @@ module Enumerable
8 8 end
9 9 end
10 10 end
  11 +
  12 + def group_by_period(period, options = {}, &block)
  13 + # to_sym is unsafe on user input, so convert to strings
  14 + permitted_periods = ((options[:permit] || Groupdate::FIELDS).map(&:to_sym) & Groupdate::FIELDS).map(&:to_s)
  15 + if permitted_periods.include?(period.to_s)
  16 + send("group_by_#{period}", options, &block)
  17 + else
  18 + raise ArgumentError, "Unpermitted period"
  19 + end
  20 + end
11 21 end
... ...
lib/groupdate/scopes.rb
... ... @@ -10,5 +10,15 @@ module Groupdate
10 10 Groupdate::Magic.new(field, options).relation(args[0], self)
11 11 end
12 12 end
  13 +
  14 + def group_by_period(period, field, options = {})
  15 + # to_sym is unsafe on user input, so convert to strings
  16 + permitted_periods = ((options[:permit] || Groupdate::FIELDS).map(&:to_sym) & Groupdate::FIELDS).map(&:to_s)
  17 + if permitted_periods.include?(period.to_s)
  18 + send("group_by_#{period}", field, options)
  19 + else
  20 + raise ArgumentError, "Unpermitted period"
  21 + end
  22 + end
13 23 end
14 24 end
... ...
test/enumerable_test.rb
... ... @@ -19,6 +19,6 @@ class TestEnumerable < Minitest::Test
19 19 end
20 20  
21 21 def call_method(method, field, options)
22   - Hash[User.all.to_a.send(:"group_by_#{method}", options) { |u| u.send(field) }.map { |k, v| [k, v.size] }]
  22 + Hash[User.all.to_a.group_by_period(method, options) { |u| u.send(field) }.map { |k, v| [k, v.size] }]
23 23 end
24 24 end
... ...
test/test_helper.rb
... ... @@ -739,6 +739,28 @@ module TestGroupdate
739 739 assert_equal ({[1, "Sun"] => 1}), User.group(:score).group_by_week(:created_at, format: "%a").count
740 740 end
741 741  
  742 + # permit
  743 +
  744 + def test_permit
  745 + assert_raises(ArgumentError, "Unpermitted period") { User.group_by_period(:day, :created_at, permit: %w[week]).count }
  746 + end
  747 +
  748 + def test_permit_symbol_symbols
  749 + assert_equal ({}), User.group_by_period(:day, :created_at, permit: %i[day]).count
  750 + end
  751 +
  752 + def test_permit_string_symbols
  753 + assert_equal ({}), User.group_by_period("day", :created_at, permit: %i[day]).count
  754 + end
  755 +
  756 + def test_permit_symbol_strings
  757 + assert_equal ({}), User.group_by_period(:day, :created_at, permit: %w[day]).count
  758 + end
  759 +
  760 + def test_permit_string_strings
  761 + assert_equal ({}), User.group_by_period("day", :created_at, permit: %w[day]).count
  762 + end
  763 +
742 764 # associations
743 765  
744 766 def test_associations
... ... @@ -807,7 +829,7 @@ module TestGroupdate
807 829 end
808 830  
809 831 def call_method(method, field, options)
810   - User.send(:"group_by_#{method}", field, options).count
  832 + User.group_by_period(method, field, options).count
811 833 end
812 834  
813 835 def create_user(created_at, score = 1)
... ...