timely 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ad5b5230c51dc3ab72192b82882b333fe9fc72b49fb2e8324881e7a6b7fd269
4
- data.tar.gz: 1de47a9da2ee6f3708c049f85fed2654e7ec4900935056f80dbe42db2842cf7b
3
+ metadata.gz: e311a6b7b3b8f1c2c118f67e3cddc6ef7592091514c64f99c7a8d1f46f617d7a
4
+ data.tar.gz: ae6d6fa3c929fe97a63ed3e907544e97cafb38d2dc768f95d5cea00057d07864
5
5
  SHA512:
6
- metadata.gz: 8d9bde900b4005fdcf26cc826e53858eb47067f6ccd6e01c633861efb305970d37ceddfd7bc1d70b2c68bae1a53abccc178ca1b95f20fc5ae5032cc8ef0e3e11
7
- data.tar.gz: 8d1145ecf55ee9deb075d459e9f2399ec28bf0da6519f60b47cf1fddd679312383c6df4d9e83d8f6222e2aa89c7791b25927efb1705260e880ad54682b4b8037
6
+ metadata.gz: 4f0f48ab52cb955cd0dcc13b89138cc72dc5b444f87589173d346595d822bb12c205a5c93a27c34e5a5ea765807d521931823bd331c4baefa30a48a34e516829
7
+ data.tar.gz: 7013bcafe2fbed12b92caf1fc9da3b07292050fd643cd05a975495674cf5fbd206c815a4d9e65dafbbc25d2af8fb0c646f40a4cf839e4e8a03c08b1b795ec5d6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ * [TT-6193] Date group scopes for more efficient searches/restrictions
6
+
3
7
  ## 0.4.2
4
8
 
5
9
  * [TT-5794] Fix belongs_to associations are not explicitly marked optional
@@ -7,6 +7,32 @@ module Timely
7
7
  validates_presence_of :start_date, :end_date
8
8
  validate :validate_date_range!
9
9
 
10
+ scope :covering_date, lambda { |date|
11
+ # Suitable for use with joins/merge!
12
+ where(arel_table[:start_date].lteq(date)).where(arel_table[:end_date].gteq(date))
13
+ }
14
+
15
+ scope :within_range, lambda { |date_range|
16
+ # IMPORTANT: Required for correctness in case of string param.
17
+ dates = Array(date_range)
18
+ scope = covering_date(dates.first)
19
+ if dates.first != dates.last
20
+ scope = scope.or(covering_date(dates.last))
21
+ end
22
+ scope
23
+ }
24
+
25
+ scope :for_any_weekdays, lambda { |weekdays_int|
26
+ weekdays_int = weekdays_int.to_i
27
+ where((arel_table[:weekdays_bit_array] & weekdays_int).not_eq(0))
28
+ .or(where(weekdays_bit_array: nil))
29
+ }
30
+
31
+ scope :applying_for_duration, lambda { |date_range|
32
+ weekdays_int = Timely::WeekDays.from_range(date_range).weekdays_int
33
+ within_range(date_range).for_any_weekdays(weekdays_int)
34
+ }
35
+
10
36
  def includes_date?(date)
11
37
  date >= start_date && date <= end_date && weekdays.applies_for_date?(date)
12
38
  end
@@ -1,3 +1,3 @@
1
1
  module Timely
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -2,6 +2,16 @@ module Timely
2
2
  class WeekDays
3
3
  WEEKDAY_KEYS = %i[sun mon tue wed thu fri sat]
4
4
 
5
+ def self.from_range(date_range)
6
+ dates = Array(date_range)
7
+ return ALL_WEEKDAYS if dates.count >= WEEKDAY_KEYS.count
8
+
9
+ new(dates.each_with_object({}) { |date, result|
10
+ # e.g. {3: true, 5: true}
11
+ result[date.to_date.wday] = true
12
+ })
13
+ end
14
+
5
15
  # Create a new Weekdays object
6
16
  # weekdays can be in three formats
7
17
  # integer representing binary string
@@ -1,5 +1,7 @@
1
1
  require "spec_helper"
2
- describe Timely::DateGroup do
2
+
3
+
4
+ RSpec.describe Timely::DateGroup do
3
5
  before do
4
6
  @date_group = Timely::DateGroup.new(
5
7
  :start_date => '2000-01-01', :end_date => '2000-01-03', :weekdays => %w(1 1 1 1 1 1 1)
@@ -24,3 +26,58 @@ describe Timely::DateGroup do
24
26
  expect(@date_group.applicable_for_duration?(Timely::DateRange.new('2012-01-01'.to_date, '2012-01-03'.to_date))).to be true
25
27
  end
26
28
  end
29
+
30
+
31
+ RSpec.describe 'Timely::DateGroup.for_any_weekdays' do
32
+ let(:date_range) { ('2019-10-17'.to_date)..('2019-10-18'.to_date) }
33
+ let(:weekdays_int) { Timely::WeekDays.from_range(date_range).weekdays_int }
34
+
35
+ let(:special_group) {
36
+ Timely::DateGroup.create(start_date: date_range.first, end_date: date_range.last).tap { |date_group|
37
+ date_group.update_column(:weekdays_bit_array, nil)
38
+ }.reload
39
+ }
40
+
41
+ let!(:date_groups) { [
42
+ Timely::DateGroup.create(start_date: date_range.first, end_date: date_range.last, weekdays: { thu: true }),
43
+ Timely::DateGroup.create(start_date: date_range.first, end_date: date_range.last, weekdays: { mon: true }),
44
+ special_group,
45
+ ] }
46
+
47
+ RSpec.shared_examples 'finds expected date groups' do
48
+ it 'finds expected date groups' do
49
+ includes_date_groups.each do |date_group|
50
+ expect(date_group.includes_date?(date_range.first)).to eq(true)
51
+ end
52
+ expected_groups.each do |date_group|
53
+ expect(scoped_result).to include(date_group)
54
+ end
55
+ absent_groups.each do |date_group|
56
+ expect(date_group.includes_date?(date_range.first)).to eq(false)
57
+ expect(scoped_result).not_to include(date_group)
58
+ end
59
+ end
60
+ end
61
+
62
+ context '#within_range' do
63
+ let(:scoped_result) { Timely::DateGroup.within_range(date_range).to_a }
64
+ let(:expected_groups) { [ date_groups[0], date_groups[1], date_groups[2] ] }
65
+ let(:absent_groups) { [ ] }
66
+ let(:includes_date_groups) { [] }
67
+ it_behaves_like 'finds expected date groups'
68
+ end
69
+
70
+ let(:includes_date_groups) { expected_groups }
71
+ let(:expected_groups) { [ date_groups[0], date_groups[2] ] }
72
+ let(:absent_groups) { [ date_groups[1] ] }
73
+
74
+ context '#for_any_weekdays' do
75
+ let(:scoped_result) { Timely::DateGroup.for_any_weekdays(weekdays_int).to_a }
76
+ it_behaves_like 'finds expected date groups'
77
+ end
78
+
79
+ context '#applying_for_duration' do
80
+ let(:scoped_result) { Timely::DateGroup.applying_for_duration(date_range).to_a }
81
+ it_behaves_like 'finds expected date groups'
82
+ end
83
+ end
@@ -1,4 +1,4 @@
1
1
  require 'simplecov-rcov'
2
2
  require 'coveralls'
3
3
  require 'coverage/kit'
4
- Coverage::Kit.setup(minimum_coverage: 68.3)
4
+ Coverage::Kit.setup(minimum_coverage: 69.15)
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Timely::WeekDays do
3
+ RSpec.describe Timely::WeekDays do
4
4
  before do
5
5
  @weekdays = Timely::WeekDays.new(:tue => true, :thu => true)
6
6
  end
@@ -49,3 +49,26 @@ describe Timely::WeekDays do
49
49
  expect(Timely::WeekDays.new(%w(1 1 1 1 1 0 1)).all_days?).to be false
50
50
  end
51
51
  end
52
+
53
+ RSpec.describe 'Timely::WeekDays.from_range' do
54
+ {
55
+ 'single date as string': { date_range: '2019-10-17', expected_weekdays: [ :thu ] },
56
+ 'single date as object': { date_range: '2019-10-17'.to_date, expected_weekdays: [ :thu ] },
57
+ 'range with strings': {
58
+ date_range: '2019-10-17'..'2019-10-18',
59
+ expected_weekdays: [ :thu, :fri ],
60
+ },
61
+ 'range with objects': {
62
+ date_range: ('2019-10-17'.to_date)..('2019-10-18'.to_date),
63
+ expected_weekdays: [ :thu, :fri ],
64
+ },
65
+ }.each do |type, data|
66
+ it "#{type} has correct weekdays and applies for dates" do
67
+ weekdays = Timely::WeekDays.from_range(data[:date_range])
68
+ expect(weekdays.weekdays).to eq(data[:expected_weekdays])
69
+ Array(data[:date_range]).each do |date|
70
+ expect(weekdays.applies_for_date?(date.to_date)).to eq(true)
71
+ end
72
+ end
73
+ end
74
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timely
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Noack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-01 00:00:00.000000000 Z
11
+ date: 2019-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler