active_date_range 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +34 -0
- data/Gemfile.lock +41 -38
- data/README.md +22 -0
- data/active_date_range.gemspec +1 -0
- data/bin/console +1 -0
- data/lib/active_date_range.rb +2 -0
- data/lib/active_date_range/active_model_type.rb +13 -0
- data/lib/active_date_range/date_range.rb +57 -21
- data/lib/active_date_range/humanizer.rb +9 -2
- data/lib/active_date_range/version.rb +1 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8f934208add7b15537a13d906fa465a3ae83626551f7b1a7c485c0383e32a10
|
4
|
+
data.tar.gz: 7e1c52e9c9b1da73c8c1212892761ad314d6a7490dbd8f1e516fae3f5d6ab368
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 854500cb33e2a2bf026f29433eadca6619802db32086d33656262487d7da42735c63f7eddf22849587eae15948792362c6be18ab28bead739d508f8210ed60f7
|
7
|
+
data.tar.gz: e806e16dd17491eb7a45518e428b5a64b42e3fefa774b10659528c9aa8afa4b0ab0c2f5b8d5416bfb140d448c8d4f52061d3db6b276611a468d498a897ac8e5f
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
## 0.3.0
|
2
|
+
|
3
|
+
* `include?` now behaves like `cover?` for better performance
|
4
|
+
|
5
|
+
*Edwin Vlieg*
|
6
|
+
|
7
|
+
* Add intersection support:
|
8
|
+
|
9
|
+
```
|
10
|
+
date_range.intersection(other_date_range) # => DateRange
|
11
|
+
```
|
12
|
+
|
13
|
+
*Edwin Vlieg*
|
14
|
+
|
15
|
+
|
16
|
+
* Add support for boundless ranges:
|
17
|
+
|
18
|
+
```
|
19
|
+
date_range = DateRange.parse('202101..')
|
20
|
+
date_range.boundless? # => true
|
21
|
+
date_range.in_groups_of(:month) # => Enumerator::Lazy
|
22
|
+
Model.where(date: date_range) # => SQL "WHERE date >= 2021-01-01"
|
23
|
+
```
|
24
|
+
|
25
|
+
*Edwin Vlieg*
|
26
|
+
|
27
|
+
* Add ActiveModel type for date range:
|
28
|
+
|
29
|
+
```
|
30
|
+
attribute :period, :date_range
|
31
|
+
```
|
32
|
+
|
33
|
+
*Edwin Vlieg*
|
34
|
+
|
1
35
|
## 0.2.0
|
2
36
|
|
3
37
|
* Add support for weeks:
|
data/Gemfile.lock
CHANGED
@@ -1,41 +1,43 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
active_date_range (0.
|
4
|
+
active_date_range (0.3.0)
|
5
5
|
activesupport (~> 6.1)
|
6
6
|
i18n
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
actionpack (6.1.2
|
12
|
-
actionview (= 6.1.2
|
13
|
-
activesupport (= 6.1.2
|
11
|
+
actionpack (6.1.3.2)
|
12
|
+
actionview (= 6.1.3.2)
|
13
|
+
activesupport (= 6.1.3.2)
|
14
14
|
rack (~> 2.0, >= 2.0.9)
|
15
15
|
rack-test (>= 0.6.3)
|
16
16
|
rails-dom-testing (~> 2.0)
|
17
17
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
18
|
-
actionview (6.1.2
|
19
|
-
activesupport (= 6.1.2
|
18
|
+
actionview (6.1.3.2)
|
19
|
+
activesupport (= 6.1.3.2)
|
20
20
|
builder (~> 3.1)
|
21
21
|
erubi (~> 1.4)
|
22
22
|
rails-dom-testing (~> 2.0)
|
23
23
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
24
|
-
|
24
|
+
activemodel (6.1.3.2)
|
25
|
+
activesupport (= 6.1.3.2)
|
26
|
+
activesupport (6.1.3.2)
|
25
27
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
26
28
|
i18n (>= 1.6, < 2)
|
27
29
|
minitest (>= 5.1)
|
28
30
|
tzinfo (~> 2.0)
|
29
31
|
zeitwerk (~> 2.3)
|
30
|
-
ast (2.4.
|
32
|
+
ast (2.4.2)
|
31
33
|
builder (3.2.4)
|
32
34
|
coderay (1.1.3)
|
33
35
|
concurrent-ruby (1.1.8)
|
34
36
|
crass (1.0.6)
|
35
37
|
erubi (1.10.0)
|
36
|
-
ffi (1.
|
38
|
+
ffi (1.15.1)
|
37
39
|
formatador (0.2.5)
|
38
|
-
guard (2.
|
40
|
+
guard (2.17.0)
|
39
41
|
formatador (>= 0.2.4)
|
40
42
|
listen (>= 2.7, < 4.0)
|
41
43
|
lumberjack (>= 1.0.12, < 2.0)
|
@@ -48,29 +50,29 @@ GEM
|
|
48
50
|
guard-minitest (2.4.6)
|
49
51
|
guard-compat (~> 1.2)
|
50
52
|
minitest (>= 3.0)
|
51
|
-
i18n (1.8.
|
53
|
+
i18n (1.8.10)
|
52
54
|
concurrent-ruby (~> 1.0)
|
53
|
-
listen (3.
|
55
|
+
listen (3.5.1)
|
54
56
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
55
57
|
rb-inotify (~> 0.9, >= 0.9.10)
|
56
|
-
loofah (2.9.
|
58
|
+
loofah (2.9.1)
|
57
59
|
crass (~> 1.0.2)
|
58
60
|
nokogiri (>= 1.5.9)
|
59
61
|
lumberjack (1.2.8)
|
60
62
|
method_source (1.0.0)
|
61
|
-
mini_portile2 (2.5.
|
62
|
-
minitest (5.14.
|
63
|
+
mini_portile2 (2.5.1)
|
64
|
+
minitest (5.14.4)
|
63
65
|
nenv (0.3.0)
|
64
|
-
nokogiri (1.11.
|
66
|
+
nokogiri (1.11.5)
|
65
67
|
mini_portile2 (~> 2.5.0)
|
66
68
|
racc (~> 1.4)
|
67
69
|
notiffany (0.1.3)
|
68
70
|
nenv (~> 0.1)
|
69
71
|
shellany (~> 0.0)
|
70
|
-
parallel (1.
|
71
|
-
parser (
|
72
|
+
parallel (1.20.1)
|
73
|
+
parser (3.0.1.1)
|
72
74
|
ast (~> 2.4.1)
|
73
|
-
pry (0.14.
|
75
|
+
pry (0.14.1)
|
74
76
|
coderay (~> 1.1)
|
75
77
|
method_source (~> 1.0)
|
76
78
|
racc (1.5.2)
|
@@ -82,45 +84,45 @@ GEM
|
|
82
84
|
nokogiri (>= 1.6)
|
83
85
|
rails-html-sanitizer (1.3.0)
|
84
86
|
loofah (~> 2.3)
|
85
|
-
railties (6.1.2
|
86
|
-
actionpack (= 6.1.2
|
87
|
-
activesupport (= 6.1.2
|
87
|
+
railties (6.1.3.2)
|
88
|
+
actionpack (= 6.1.3.2)
|
89
|
+
activesupport (= 6.1.3.2)
|
88
90
|
method_source
|
89
91
|
rake (>= 0.8.7)
|
90
92
|
thor (~> 1.0)
|
91
93
|
rainbow (3.0.0)
|
92
94
|
rake (12.3.3)
|
93
|
-
rb-fsevent (0.
|
95
|
+
rb-fsevent (0.11.0)
|
94
96
|
rb-inotify (0.10.1)
|
95
97
|
ffi (~> 1.0)
|
96
|
-
regexp_parser (1.
|
97
|
-
rexml (3.2.
|
98
|
-
rubocop (
|
98
|
+
regexp_parser (2.1.1)
|
99
|
+
rexml (3.2.5)
|
100
|
+
rubocop (1.15.0)
|
99
101
|
parallel (~> 1.10)
|
100
|
-
parser (>=
|
102
|
+
parser (>= 3.0.0.0)
|
101
103
|
rainbow (>= 2.2.2, < 4.0)
|
102
|
-
regexp_parser (>= 1.
|
104
|
+
regexp_parser (>= 1.8, < 3.0)
|
103
105
|
rexml
|
104
|
-
rubocop-ast (>=
|
106
|
+
rubocop-ast (>= 1.5.0, < 2.0)
|
105
107
|
ruby-progressbar (~> 1.7)
|
106
|
-
unicode-display_width (>= 1.4.0, <
|
107
|
-
rubocop-ast (
|
108
|
-
parser (>=
|
108
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
109
|
+
rubocop-ast (1.5.0)
|
110
|
+
parser (>= 3.0.1.1)
|
109
111
|
rubocop-packaging (0.5.1)
|
110
112
|
rubocop (>= 0.89, < 2.0)
|
111
|
-
rubocop-performance (1.
|
112
|
-
rubocop (>=
|
113
|
+
rubocop-performance (1.11.3)
|
114
|
+
rubocop (>= 1.7.0, < 2.0)
|
113
115
|
rubocop-ast (>= 0.4.0)
|
114
|
-
rubocop-rails (2.
|
116
|
+
rubocop-rails (2.10.1)
|
115
117
|
activesupport (>= 4.2.0)
|
116
118
|
rack (>= 1.1)
|
117
|
-
rubocop (>=
|
118
|
-
ruby-progressbar (1.
|
119
|
+
rubocop (>= 1.7.0, < 2.0)
|
120
|
+
ruby-progressbar (1.11.0)
|
119
121
|
shellany (0.0.1)
|
120
122
|
thor (1.1.0)
|
121
123
|
tzinfo (2.0.4)
|
122
124
|
concurrent-ruby (~> 1.0)
|
123
|
-
unicode-display_width (
|
125
|
+
unicode-display_width (2.0.0)
|
124
126
|
zeitwerk (2.4.2)
|
125
127
|
|
126
128
|
PLATFORMS
|
@@ -128,6 +130,7 @@ PLATFORMS
|
|
128
130
|
|
129
131
|
DEPENDENCIES
|
130
132
|
active_date_range!
|
133
|
+
activemodel
|
131
134
|
guard
|
132
135
|
guard-minitest
|
133
136
|
minitest (~> 5.0)
|
data/README.md
CHANGED
@@ -93,6 +93,16 @@ date_range.previous(2) # => DateRange.parse('201901..20
|
|
93
93
|
date_range.next # => DateRange.parse('202201..202212')
|
94
94
|
date_range + DateRange.parse('202201..202202') # => DateRange.parse('202101..202202')
|
95
95
|
date_range.in_groups_of(:month) # => [DateRange.parse('202101..202101'), ..., DateRange.parse('202112..202112')]
|
96
|
+
date_range.intersection(DateRange.parse('202101..202102')) # => DateRange.parse('202101..202102')
|
97
|
+
```
|
98
|
+
|
99
|
+
Support for boundless ranges is also available:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
date_range = DateRange.parse('202101..')
|
103
|
+
date_range.boundless? # => true
|
104
|
+
date_range.in_groups_of(:month) # => Enumerator::Lazy
|
105
|
+
Model.where(date: date_range) # => SQL "WHERE date >= 2021-01-01"
|
96
106
|
```
|
97
107
|
|
98
108
|
And lastly you can call `.humanize` to get a localizable human representation of the range for in the user interface:
|
@@ -104,6 +114,18 @@ date_range.humanize(format: :explicit) # => 'January 1st, 2021 - December 31st
|
|
104
114
|
|
105
115
|
See [active_date_range/locale/en.yml](https://github.com/moneybird/active-date-range/blob/main/lib/active_date_range/locale/en.yml) for all the I18n keys you need to translate for your application.
|
106
116
|
|
117
|
+
### ActiveModel type
|
118
|
+
|
119
|
+
Date ranges are also available as an ActiveModel type. So you can use a date range attribute and the value will automatically be converted:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
class Report
|
123
|
+
include ActiveModel::Attributes
|
124
|
+
|
125
|
+
attribute :period, :date_range
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
107
129
|
### Usage example
|
108
130
|
|
109
131
|
Use the shorthands to link to a specific period:
|
data/active_date_range.gemspec
CHANGED
data/bin/console
CHANGED
data/lib/active_date_range.rb
CHANGED
@@ -11,6 +11,7 @@ require "active_date_range/core_ext/date"
|
|
11
11
|
require "active_date_range/version"
|
12
12
|
require "active_date_range/date_range"
|
13
13
|
require "active_date_range/humanizer"
|
14
|
+
require "active_date_range/active_model_type"
|
14
15
|
|
15
16
|
module ActiveDateRange
|
16
17
|
class Error < StandardError; end
|
@@ -18,4 +19,5 @@ module ActiveDateRange
|
|
18
19
|
class InvalidAddition < Error; end
|
19
20
|
class InvalidDateRangeFormat < Error; end
|
20
21
|
class UnknownGranularity < Error; end
|
22
|
+
class BoundlessRangeError < Error; end
|
21
23
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveDateRange
|
4
|
+
class DateRangeType < ActiveModel::Type::String
|
5
|
+
def cast(value)
|
6
|
+
ActiveDateRange::DateRange.parse(value)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
if defined?(ActiveModel)
|
12
|
+
ActiveModel::Type.register(:date_range, ActiveDateRange::DateRangeType)
|
13
|
+
end
|
@@ -35,12 +35,14 @@ module ActiveDateRange
|
|
35
35
|
return SHORTHANDS[input.to_sym].call if SHORTHANDS.key?(input.to_sym)
|
36
36
|
|
37
37
|
begin_date, end_date = input.split("..")
|
38
|
-
raise InvalidDateRangeFormat, "#{input} doesn't have a begin..end format"
|
38
|
+
raise InvalidDateRangeFormat, "#{input} doesn't have a begin..end format" if begin_date.blank? && end_date.blank?
|
39
39
|
|
40
40
|
DateRange.new(parse_date(begin_date), parse_date(end_date, last: true))
|
41
41
|
end
|
42
42
|
|
43
43
|
def self.parse_date(input, last: false)
|
44
|
+
return if input.blank?
|
45
|
+
|
44
46
|
match_data = input.match(RANGE_PART_REGEXP)
|
45
47
|
raise InvalidDateRangeFormat, "#{input} isn't a valid date format YYYYMMDD or YYYYMM" unless match_data
|
46
48
|
|
@@ -62,12 +64,13 @@ module ActiveDateRange
|
|
62
64
|
# Make sures the begin date is before the end date.
|
63
65
|
def initialize(begin_date, end_date = nil)
|
64
66
|
begin_date, end_date = begin_date.begin, begin_date.end if begin_date.kind_of?(Range)
|
67
|
+
begin_date, end_date = begin_date.first, begin_date.last if begin_date.kind_of?(Array)
|
65
68
|
begin_date = begin_date.to_date if begin_date.kind_of?(Time)
|
66
69
|
end_date = end_date.to_date if end_date.kind_of?(Time)
|
67
70
|
|
68
|
-
raise InvalidDateRange, "Date range invalid, begin should be a date"
|
69
|
-
raise InvalidDateRange, "Date range invalid, end should be a date"
|
70
|
-
raise InvalidDateRange, "Date range invalid, begin #{begin_date} is after end #{end_date}" if begin_date > end_date
|
71
|
+
raise InvalidDateRange, "Date range invalid, begin should be a date" if begin_date && !begin_date.kind_of?(Date)
|
72
|
+
raise InvalidDateRange, "Date range invalid, end should be a date" if end_date && !end_date.kind_of?(Date)
|
73
|
+
raise InvalidDateRange, "Date range invalid, begin #{begin_date} is after end #{end_date}" if begin_date && end_date && begin_date > end_date
|
71
74
|
|
72
75
|
super(begin_date, end_date)
|
73
76
|
end
|
@@ -84,8 +87,14 @@ module ActiveDateRange
|
|
84
87
|
self.begin <=> other.begin
|
85
88
|
end
|
86
89
|
|
90
|
+
def boundless?
|
91
|
+
self.begin.nil? || self.end.nil?
|
92
|
+
end
|
93
|
+
|
87
94
|
# Returns the number of days in the range
|
88
95
|
def days
|
96
|
+
return if boundless?
|
97
|
+
|
89
98
|
@days ||= (self.end - self.begin).to_i + 1
|
90
99
|
end
|
91
100
|
|
@@ -119,22 +128,22 @@ module ActiveDateRange
|
|
119
128
|
|
120
129
|
# Returns true when begin of the range is at the beginning of the month
|
121
130
|
def begin_at_beginning_of_month?
|
122
|
-
self.begin.day == 1
|
131
|
+
self.begin.present? && self.begin.day == 1
|
123
132
|
end
|
124
133
|
|
125
134
|
# Returns true when begin of the range is at the beginning of the quarter
|
126
135
|
def begin_at_beginning_of_quarter?
|
127
|
-
begin_at_beginning_of_month? && [1, 4, 7, 10].include?(self.begin.month)
|
136
|
+
self.begin.present? && begin_at_beginning_of_month? && [1, 4, 7, 10].include?(self.begin.month)
|
128
137
|
end
|
129
138
|
|
130
139
|
# Returns true when begin of the range is at the beginning of the year
|
131
140
|
def begin_at_beginning_of_year?
|
132
|
-
begin_at_beginning_of_month? && self.begin.month == 1
|
141
|
+
self.begin.present? && begin_at_beginning_of_month? && self.begin.month == 1
|
133
142
|
end
|
134
143
|
|
135
144
|
# Returns true when begin of the range is at the beginning of the week
|
136
145
|
def begin_at_beginning_of_week?
|
137
|
-
self.begin == self.begin.at_beginning_of_week
|
146
|
+
self.begin.present? && self.begin == self.begin.at_beginning_of_week
|
138
147
|
end
|
139
148
|
|
140
149
|
# Returns true when the range is exactly one month long
|
@@ -166,49 +175,49 @@ module ActiveDateRange
|
|
166
175
|
|
167
176
|
# Returns true when the range is exactly one or more months long
|
168
177
|
def full_month?
|
169
|
-
begin_at_beginning_of_month? && self.end == self.end.at_end_of_month
|
178
|
+
begin_at_beginning_of_month? && self.end.present? && self.end == self.end.at_end_of_month
|
170
179
|
end
|
171
180
|
|
172
181
|
alias :full_months? :full_month?
|
173
182
|
|
174
183
|
# Returns true when the range is exactly one or more quarters long
|
175
184
|
def full_quarter?
|
176
|
-
begin_at_beginning_of_quarter? && self.end == self.end.at_end_of_quarter
|
185
|
+
begin_at_beginning_of_quarter? && self.end.present? && self.end == self.end.at_end_of_quarter
|
177
186
|
end
|
178
187
|
|
179
188
|
alias :full_quarters? :full_quarter?
|
180
189
|
|
181
190
|
# Returns true when the range is exactly one or more years long
|
182
191
|
def full_year?
|
183
|
-
begin_at_beginning_of_year? && self.end == self.end.at_end_of_year
|
192
|
+
begin_at_beginning_of_year? && self.end.present? && self.end == self.end.at_end_of_year
|
184
193
|
end
|
185
194
|
|
186
195
|
alias :full_years? :full_year?
|
187
196
|
|
188
197
|
# Returns true when the range is exactly one or more weeks long
|
189
198
|
def full_week?
|
190
|
-
begin_at_beginning_of_week? && self.end == self.end.at_end_of_week
|
199
|
+
begin_at_beginning_of_week? && self.end.present? && self.end == self.end.at_end_of_week
|
191
200
|
end
|
192
201
|
|
193
202
|
alias :full_weeks? :full_week?
|
194
203
|
|
195
204
|
# Returns true when begin and end are in the same year
|
196
205
|
def same_year?
|
197
|
-
self.begin.year == self.end.year
|
206
|
+
!boundless? && self.begin.year == self.end.year
|
198
207
|
end
|
199
208
|
|
200
209
|
# Returns true when the date range is before the given date. Accepts both a <tt>Date</tt>
|
201
210
|
# and <tt>DateRange</tt> as input.
|
202
211
|
def before?(date)
|
203
212
|
date = date.begin if date.kind_of?(DateRange)
|
204
|
-
self.end.before?(date)
|
213
|
+
self.end.present? && self.end.before?(date)
|
205
214
|
end
|
206
215
|
|
207
216
|
# Returns true when the date range is after the given date. Accepts both a <tt>Date</tt>
|
208
217
|
# and <tt>DateRange</tt> as input.
|
209
218
|
def after?(date)
|
210
219
|
date = date.end if date.kind_of?(DateRange)
|
211
|
-
self.begin.after?(date)
|
220
|
+
self.begin.present? && self.begin.after?(date)
|
212
221
|
end
|
213
222
|
|
214
223
|
# Returns the granularity of the range. Returns either <tt>:year</tt>, <tt>:quarter</tt> or
|
@@ -255,7 +264,7 @@ module ActiveDateRange
|
|
255
264
|
relative_param
|
256
265
|
else
|
257
266
|
format = full_month? ? "%Y%m" : "%Y%m%d"
|
258
|
-
"#{self.begin
|
267
|
+
"#{self.begin&.strftime(format)}..#{self.end&.strftime(format)}"
|
259
268
|
end
|
260
269
|
end
|
261
270
|
|
@@ -274,6 +283,8 @@ module ActiveDateRange
|
|
274
283
|
# DateRange.this_month.previous # => DateRange.prev_month
|
275
284
|
# DateRange.this_month.previous(2) # => DateRange.prev_month.previous + DateRange.prev_month
|
276
285
|
def previous(periods = 1)
|
286
|
+
raise BoundlessRangeError, "Can't calculate previous for boundless range" if boundless?
|
287
|
+
|
277
288
|
begin_date = if granularity
|
278
289
|
self.begin - periods.send(granularity)
|
279
290
|
elsif full_month?
|
@@ -293,6 +304,8 @@ module ActiveDateRange
|
|
293
304
|
# DateRange.this_month.next # => DateRange.next_month
|
294
305
|
# DateRange.this_month.next(2) # => DateRange.next_month + DateRange.next_month.next
|
295
306
|
def next(periods = 1)
|
307
|
+
raise BoundlessRangeError, "Can't calculate next for boundless range" if boundless?
|
308
|
+
|
296
309
|
end_date = self.end + (granularity ? periods.send(granularity) : days.days)
|
297
310
|
end_date = end_date.at_end_of_month if full_month?
|
298
311
|
|
@@ -310,17 +323,40 @@ module ActiveDateRange
|
|
310
323
|
# DateRange.parse("202101..202103").in_groups_of(:month) # => [DateRange.parse("202001..202001"), DateRange.parse("202002..202002"), DateRange.parse("202003..202003")]
|
311
324
|
# DateRange.parse("202101..202106").in_groups_of(:month, amount: 2) # => [DateRange.parse("202001..202002"), DateRange.parse("202003..202004"), DateRange.parse("202005..202006")]
|
312
325
|
def in_groups_of(granularity, amount: 1)
|
313
|
-
raise
|
326
|
+
raise BoundlessRangeError, "Can't group date range without a begin." if self.begin.nil?
|
314
327
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
328
|
+
if boundless?
|
329
|
+
grouped_collection(granularity, amount: amount)
|
330
|
+
else
|
331
|
+
grouped_collection(granularity, amount: amount).to_a
|
332
|
+
end
|
319
333
|
end
|
320
334
|
|
321
335
|
# Returns a human readable format for the date range. See DateRange::Humanizer for options.
|
322
336
|
def humanize(format: :short)
|
323
337
|
Humanizer.new(self, format: format).humanize
|
324
338
|
end
|
339
|
+
|
340
|
+
# Returns the intersection of the current and the other date range
|
341
|
+
def intersection(other)
|
342
|
+
intersection = self.to_a.intersection(other.to_a).sort
|
343
|
+
DateRange.new(intersection) if intersection.any?
|
344
|
+
end
|
345
|
+
|
346
|
+
def include?(other)
|
347
|
+
cover?(other)
|
348
|
+
end
|
349
|
+
|
350
|
+
private
|
351
|
+
def grouped_collection(granularity, amount: 1)
|
352
|
+
raise UnknownGranularity, "Unknown granularity #{granularity}. Valid are: month, quarter and year" unless %w[month quarter year].include?(granularity.to_s)
|
353
|
+
|
354
|
+
lazy
|
355
|
+
.chunk { |d| [d.year, d.send(granularity)] }
|
356
|
+
.map { |_, group| DateRange.new(group.first..group.last) }
|
357
|
+
.with_index
|
358
|
+
.slice_before { |_, index| index % amount == 0 }
|
359
|
+
.map { |group| group.map(&:first).inject(:+) }
|
360
|
+
end
|
325
361
|
end
|
326
362
|
end
|
@@ -108,12 +108,19 @@ module ActiveDateRange
|
|
108
108
|
month_format = date_range.full_month? ? "month" : "day_month"
|
109
109
|
abbr = "abbr_" if date_range.same_year?
|
110
110
|
|
111
|
+
begin_formatted = I18n.localize(date_range.begin, format: :"#{abbr}#{format}_#{month_format}") if date_range.begin
|
112
|
+
end_formatted = I18n.localize(date_range.end, format: :"#{format}_#{month_format}") if date_range.end
|
113
|
+
|
111
114
|
range(
|
112
|
-
|
113
|
-
|
115
|
+
begin_formatted || infinite,
|
116
|
+
end_formatted || infinite
|
114
117
|
)
|
115
118
|
end
|
116
119
|
|
120
|
+
def infinite
|
121
|
+
"∞"
|
122
|
+
end
|
123
|
+
|
117
124
|
def range(range_begin, range_end)
|
118
125
|
I18n.translate(:range, scope: :date, begin: range_begin, end: range_end)
|
119
126
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_date_range
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edwin Vlieg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activemodel
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: ActiveDateRange provides a range of dates with a powerful API to manipulate
|
98
112
|
and use date ranges in your software.
|
99
113
|
email:
|
@@ -117,6 +131,7 @@ files:
|
|
117
131
|
- bin/console
|
118
132
|
- bin/setup
|
119
133
|
- lib/active_date_range.rb
|
134
|
+
- lib/active_date_range/active_model_type.rb
|
120
135
|
- lib/active_date_range/core_ext/date.rb
|
121
136
|
- lib/active_date_range/core_ext/integer.rb
|
122
137
|
- lib/active_date_range/date_range.rb
|
@@ -145,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
160
|
- !ruby/object:Gem::Version
|
146
161
|
version: '0'
|
147
162
|
requirements: []
|
148
|
-
rubygems_version: 3.
|
163
|
+
rubygems_version: 3.1.4
|
149
164
|
signing_key:
|
150
165
|
specification_version: 4
|
151
166
|
summary: DateRange for ActiveSupport
|