timely 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +22 -2
- data/.travis.yml +0 -6
- data/CHANGELOG.md +6 -0
- data/Gemfile +2 -0
- data/Rakefile +6 -4
- data/gemfiles/rails5.gemfile +4 -2
- data/gemfiles/rails6.gemfile +3 -1
- data/lib/timely/date.rb +6 -2
- data/lib/timely/date_chooser.rb +29 -30
- data/lib/timely/date_range.rb +17 -19
- data/lib/timely/date_time.rb +3 -1
- data/lib/timely/rails/calendar_tag.rb +3 -3
- data/lib/timely/rails/date.rb +3 -1
- data/lib/timely/rails/date_group.rb +24 -24
- data/lib/timely/rails/date_range_validity_module.rb +8 -6
- data/lib/timely/rails/date_time.rb +5 -3
- data/lib/timely/rails/extensions.rb +12 -37
- data/lib/timely/rails/period.rb +14 -12
- data/lib/timely/rails/season.rb +14 -33
- data/lib/timely/rails/time.rb +7 -3
- data/lib/timely/rails.rb +2 -0
- data/lib/timely/railtie.rb +2 -0
- data/lib/timely/range.rb +4 -2
- data/lib/timely/string.rb +4 -2
- data/lib/timely/time.rb +7 -3
- data/lib/timely/time_since.rb +5 -3
- data/lib/timely/trackable_date_set.rb +21 -21
- data/lib/timely/version.rb +3 -1
- data/lib/timely/week_days.rb +14 -16
- data/lib/timely.rb +2 -0
- data/rails/init.rb +2 -0
- data/spec/calendar_tag_spec.rb +11 -10
- data/spec/date_chooser_spec.rb +67 -62
- data/spec/date_group_spec.rb +18 -15
- data/spec/date_range_spec.rb +29 -19
- data/spec/date_spec.rb +3 -1
- data/spec/extensions_spec.rb +5 -9
- data/spec/rails/date_spec.rb +5 -3
- data/spec/rails/date_time_spec.rb +9 -7
- data/spec/rails/period_spec.rb +2 -0
- data/spec/rails/time_spec.rb +6 -4
- data/spec/schema.rb +4 -3
- data/spec/season_spec.rb +23 -26
- data/spec/spec_helper.rb +3 -1
- data/spec/support/coverage_loader.rb +3 -1
- data/spec/temporal_patterns_spec.rb +5 -5
- data/spec/time_since_spec.rb +6 -4
- data/spec/time_spec.rb +6 -4
- data/spec/trackable_date_set_spec.rb +20 -18
- data/spec/week_days_spec.rb +24 -22
- data/timely.gemspec +20 -18
- metadata +32 -20
- data/spec/string_spec.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6fd5bf30099265da88c4957079fd58a4db290fac8cd4ad239ddb395be546d5d3
|
4
|
+
data.tar.gz: d263dca100292aae36f54b22cc2f3b1eebc1c1df0274fc3ef730ce991fc94c4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 784aede0c406afe8e0213f275150ee3bba930969c28acf9ac2e992a96ce42c7f30e042a6e0ae9779dc17f86e6a7744c4b0a07bf72e1d326d6e6176b3ac4b28c4
|
7
|
+
data.tar.gz: a780a85c02adcf074c53376c7995739d609329256b76c370966bedaccf953e0e3cb7607cb0d381873a8a4585b48505c8d2d04f68bebdc94f0b49c947bab84d28
|
data/.rubocop.yml
CHANGED
@@ -1,8 +1,28 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.6
|
3
|
+
Exclude:
|
4
|
+
- lib/timely/temporal_patterns/*.rb
|
5
|
+
|
1
6
|
Metrics/LineLength:
|
2
|
-
Max:
|
7
|
+
Max: 200
|
3
8
|
|
4
9
|
Style/Documentation:
|
5
10
|
Enabled: false
|
6
11
|
|
7
12
|
Style/FrozenStringLiteralComment:
|
8
|
-
Enabled:
|
13
|
+
Enabled: true
|
14
|
+
|
15
|
+
Metrics/BlockLength:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Metrics/MethodLength:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Metrics/AbcSize:
|
22
|
+
Enabled: false
|
23
|
+
|
24
|
+
Metrics/CyclomaticComplexity:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Metrics/PerceivedComplexity:
|
28
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.6.0
|
4
|
+
|
5
|
+
* [TT-6402] Require date group weekdays bit field to be not null/nil
|
6
|
+
IMPORTANT: Rails projects must add a migration to make this field not null!
|
7
|
+
* [TT-6401] Remove Rails 3 support, unused methods
|
8
|
+
|
3
9
|
## 0.5.0
|
4
10
|
|
5
11
|
* [TT-6193] Date group scopes for more efficient searches/restrictions
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
2
4
|
|
3
5
|
desc 'Default: run specs.'
|
4
|
-
task :
|
6
|
+
task default: :spec
|
5
7
|
|
6
8
|
require 'rspec/core/rake_task'
|
7
9
|
|
8
|
-
desc
|
10
|
+
desc 'Run specs'
|
9
11
|
RSpec::Core::RakeTask.new do |t|
|
10
|
-
t.pattern =
|
12
|
+
t.pattern = './spec/**/*_spec.rb' # don't need this, it's default.
|
11
13
|
# Put spec opts in a file named .rspec in root
|
12
14
|
end
|
data/gemfiles/rails5.gemfile
CHANGED
data/gemfiles/rails6.gemfile
CHANGED
data/lib/timely/date.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
module Date
|
3
5
|
def at_time(hour = nil, minute = nil, second = nil)
|
4
6
|
if hour.is_a?(::Time)
|
5
7
|
time = hour
|
6
|
-
hour
|
8
|
+
hour = time.hour
|
9
|
+
minute = time.min
|
10
|
+
second = time.sec
|
7
11
|
end
|
8
12
|
|
9
13
|
::Time.local(year, month, day, hour, minute, second)
|
10
14
|
end
|
11
15
|
|
12
|
-
|
16
|
+
alias at at_time
|
13
17
|
|
14
18
|
# returns true if date between from and to
|
15
19
|
# however if from and/or to are nil, it ignores that query
|
data/lib/timely/date_chooser.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
class DateChooser
|
3
5
|
# Where is this used... so far only in one place, _date_range.html.haml
|
4
6
|
# May be good to refactor this as well, after the class behaviour is refactored.
|
5
7
|
INTERVALS = [
|
6
|
-
{:
|
7
|
-
|
8
|
-
{:code => 'week_of_month', :name => 'week of month', :description =>
|
9
|
-
'Weekdays selected will be chosen in their {{ord}} occurance every month,
|
8
|
+
{ code: 'week', name: 'week(s)', description: 'Weekdays selected will be chosen every {{n}} weeks for the date range' },
|
9
|
+
{ code: 'week_of_month', name: 'week of month', description: 'Weekdays selected will be chosen in their {{ord}} occurance every month,
|
10
10
|
e.g. if wednesday and thursday are selected, the first wednesday and
|
11
11
|
first thursday are selected. Note: this may mean the booking is copied
|
12
|
-
to Thursday 1st and Wednesday 7th'}
|
13
|
-
]
|
12
|
+
to Thursday 1st and Wednesday 7th' }
|
13
|
+
].freeze
|
14
14
|
|
15
|
-
attr_accessor
|
15
|
+
attr_accessor :multiple_dates, :from, :to, :select, :dates, :interval, :weekdays
|
16
16
|
|
17
17
|
def initialize(options)
|
18
18
|
@multiple_dates = options[:multiple_dates] || false
|
@@ -28,8 +28,8 @@ module Timely
|
|
28
28
|
|
29
29
|
def process_date(date)
|
30
30
|
case date
|
31
|
-
when Date
|
32
|
-
when NilClass
|
31
|
+
when Date then date
|
32
|
+
when NilClass then nil
|
33
33
|
when String
|
34
34
|
date !~ /[^[:space:]]/ ? nil : date.to_date
|
35
35
|
end
|
@@ -53,7 +53,7 @@ module Timely
|
|
53
53
|
# so every friday and saturday each fornight
|
54
54
|
def choose_dates
|
55
55
|
# Not multiple dates - just return the From date.
|
56
|
-
return [@from]
|
56
|
+
return [@from] unless @multiple_dates
|
57
57
|
|
58
58
|
# Multiple dates - return the array, adjusted as per input
|
59
59
|
all_days = (@from..@to).to_a
|
@@ -66,21 +66,21 @@ module Timely
|
|
66
66
|
days = @specific_dates.gsub(/\s/, '').split(',')
|
67
67
|
days.map(&:to_date)
|
68
68
|
when 'weekdays'
|
69
|
-
raise DateChooserException,
|
70
|
-
raise DateChooserException,
|
69
|
+
raise DateChooserException, 'No days of the week selected' if @weekdays.weekdays.empty?
|
70
|
+
raise DateChooserException, 'No weekly interval selected' if @interval&.empty?
|
71
71
|
|
72
72
|
all_days.select do |date|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
73
|
+
next unless @weekdays.has_day?(date.wday)
|
74
|
+
|
75
|
+
case @interval[:unit]
|
76
|
+
when 'week'
|
77
|
+
# 0 = first week, 1 = second week, 2 = third week, etc.
|
78
|
+
nth_week = (date - @from).to_i / 7
|
79
|
+
# true every 2nd week (0, 2, 4, 6, etc.)
|
80
|
+
(nth_week % @interval[:level].to_i).zero?
|
81
|
+
when 'week_of_month'
|
82
|
+
week = @interval[:level].to_i
|
83
|
+
(date.mday > (week - 1) * 7 && date.mday <= week * 7)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
else
|
@@ -89,15 +89,14 @@ module Timely
|
|
89
89
|
end
|
90
90
|
|
91
91
|
private
|
92
|
+
|
92
93
|
def validate
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
raise DateChooserException, "Start Date is after End Date" if @from > @to
|
98
|
-
end
|
94
|
+
raise DateChooserException, 'A Start Date is required' unless @from
|
95
|
+
raise DateChooserException, 'Start Date is after End Date' if @multiple_dates && @to && @from > @to
|
96
|
+
|
97
|
+
@to ||= @from if @multiple_dates
|
99
98
|
end
|
100
99
|
end
|
101
100
|
|
102
|
-
class DateChooserException <
|
101
|
+
class DateChooserException < RuntimeError; end
|
103
102
|
end
|
data/lib/timely/date_range.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Timely
|
4
4
|
class DateRange < ::Range
|
@@ -15,14 +15,14 @@ module Timely
|
|
15
15
|
super(args.first.to_date, args.last.to_date)
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
19
|
-
|
18
|
+
alias start_date first
|
19
|
+
alias end_date last
|
20
20
|
|
21
21
|
def self.validate_range(first, last)
|
22
|
-
raise ArgumentError,
|
23
|
-
raise ArgumentError,
|
24
|
-
raise ArgumentError,
|
25
|
-
raise ArgumentError,
|
22
|
+
raise ArgumentError, 'Date range missing start date' if first.nil?
|
23
|
+
raise ArgumentError, 'Date range missing end date' if last.nil?
|
24
|
+
raise ArgumentError, 'Start date is not a date' unless first.is_a? Date
|
25
|
+
raise ArgumentError, 'End date is not a date' unless last.is_a? Date
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.from_params(start_date, duration = nil)
|
@@ -33,19 +33,18 @@ module Timely
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def intersecting_dates(date_range)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
36
|
+
r_start = [start_date, date_range.first].max
|
37
|
+
r_end = [end_date, date_range.last].min
|
38
|
+
|
39
|
+
return [] if r_end < r_start
|
40
|
+
|
41
|
+
r_start..r_end
|
43
42
|
end
|
44
43
|
|
45
44
|
def number_of_nights
|
46
45
|
((last - first) + 1).to_i
|
47
46
|
end
|
48
|
-
|
47
|
+
alias duration number_of_nights
|
49
48
|
|
50
49
|
def to_s(fmt = '%b %Y', date_fmt = '%Y-%m-%d')
|
51
50
|
Timely::DateRange.to_s(first, last, fmt, date_fmt)
|
@@ -65,21 +64,20 @@ module Timely
|
|
65
64
|
"#{first.strftime(month_fmt)} to #{last.strftime(month_fmt)}"
|
66
65
|
end
|
67
66
|
else
|
68
|
-
"#{first.strftime(fmt)} to #{last.strftime(fmt)}#{
|
67
|
+
"#{first.strftime(fmt)} to #{last.strftime(fmt)}#{' (inclusive)' if is_date}"
|
69
68
|
end
|
70
69
|
elsif first
|
71
70
|
"on or after #{first.strftime(fmt)}"
|
72
71
|
elsif last
|
73
72
|
"on or before #{last.strftime(fmt)}"
|
74
73
|
else
|
75
|
-
|
74
|
+
'no date range'
|
76
75
|
end
|
77
76
|
end
|
78
77
|
|
79
|
-
|
80
78
|
private
|
81
79
|
|
82
|
-
def self.default_date_format
|
80
|
+
private_class_method def self.default_date_format
|
83
81
|
# ::Date as we want Ruby's Date not Timely::Date
|
84
82
|
date_format = ::Date::DATE_FORMATS[:short] if ::Date.const_defined?('DATE_FORMATS')
|
85
83
|
date_format || '%Y-%m-%d'
|
data/lib/timely/date_time.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
# Uses Date.current to be more accurate for Rails applications
|
3
5
|
def self.current_date
|
4
6
|
::Date.respond_to?(:current) ? ::Date.current : ::Date.today
|
5
7
|
end
|
6
8
|
|
7
|
-
|
8
9
|
module ActionViewHelpers
|
9
10
|
module FormTagHelper
|
10
11
|
def calendar_tag(name, value = Timely.current_date, *args)
|
@@ -24,11 +25,10 @@ module Timely
|
|
24
25
|
options[:size] ||= 10
|
25
26
|
options[:maxlength] ||= 10
|
26
27
|
|
27
|
-
tag(:input, options.merge(:
|
28
|
+
tag(:input, options.merge(name: name, type: 'text', value: value)).html_safe
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
32
|
module DateHelper
|
33
33
|
def calendar(object_name, method, options = {})
|
34
34
|
value = options[:object] || Timely.current_date
|
data/lib/timely/rails/date.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
class DateGroup < ActiveRecord::Base
|
3
|
-
belongs_to :season, :
|
5
|
+
belongs_to :season, class_name: 'Timely::Season', optional: true, inverse_of: :date_groups
|
4
6
|
|
5
7
|
weekdays_field :weekdays
|
6
8
|
|
9
|
+
validates :weekdays_bit_array, presence: true
|
7
10
|
validates_presence_of :start_date, :end_date
|
8
11
|
validate :validate_date_range!
|
9
12
|
|
@@ -16,16 +19,12 @@ module Timely
|
|
16
19
|
# IMPORTANT: Required for correctness in case of string param.
|
17
20
|
dates = Array(date_range)
|
18
21
|
scope = covering_date(dates.first)
|
19
|
-
if dates.first != dates.last
|
20
|
-
scope = scope.or(covering_date(dates.last))
|
21
|
-
end
|
22
|
+
scope = scope.or(covering_date(dates.last)) if dates.first != dates.last
|
22
23
|
scope
|
23
24
|
}
|
24
25
|
|
25
26
|
scope :for_any_weekdays, lambda { |weekdays_int|
|
26
|
-
|
27
|
-
where((arel_table[:weekdays_bit_array] & weekdays_int).not_eq(0))
|
28
|
-
.or(where(weekdays_bit_array: nil))
|
27
|
+
where((arel_table[:weekdays_bit_array] & weekdays_int.to_i).not_eq(0))
|
29
28
|
}
|
30
29
|
|
31
30
|
scope :applying_for_duration, lambda { |date_range|
|
@@ -43,7 +42,7 @@ module Timely
|
|
43
42
|
elsif weekdays.all_days?
|
44
43
|
true
|
45
44
|
else
|
46
|
-
date_range.intersecting_dates(start_date..end_date).any?{|d| weekdays.applies_for_date?(d)}
|
45
|
+
date_range.intersecting_dates(start_date..end_date).any? { |d| weekdays.applies_for_date?(d) }
|
47
46
|
end
|
48
47
|
end
|
49
48
|
|
@@ -70,30 +69,31 @@ module Timely
|
|
70
69
|
date_groups = []
|
71
70
|
Array.wrap(patterns).each do |pattern|
|
72
71
|
if pattern.frequency.unit == :weeks
|
73
|
-
weekdays = pattern.intervals.map { |i| i.first_datetime.wday }.
|
72
|
+
weekdays = pattern.intervals.map { |i| i.first_datetime.wday }.each_with_object({}) do |wday, hash|
|
74
73
|
hash[wday] = 1
|
75
|
-
hash
|
76
74
|
end
|
77
75
|
date_groups << DateGroup.new(
|
78
|
-
:
|
79
|
-
:
|
80
|
-
:
|
76
|
+
start_date: pattern.first_datetime.to_date,
|
77
|
+
end_date: pattern.last_datetime.to_date,
|
78
|
+
weekdays: weekdays
|
79
|
+
)
|
81
80
|
elsif pattern.frequency.unit == :days && pattern.frequency.duration == 1.day
|
82
81
|
date_groups << DateGroup.new(
|
83
|
-
:
|
84
|
-
:
|
85
|
-
:
|
82
|
+
start_date: pattern.first_datetime.to_date,
|
83
|
+
end_date: pattern.last_datetime.to_date,
|
84
|
+
weekdays: 127
|
85
|
+
)
|
86
86
|
else
|
87
87
|
pattern.datetimes.each do |datetimes|
|
88
88
|
datetimes.group_by(&:week).values.each do |dates|
|
89
|
-
weekdays = dates.map(&:wday).
|
89
|
+
weekdays = dates.map(&:wday).each_with_object({}) do |wday, hash|
|
90
90
|
hash[wday] = 1
|
91
|
-
hash
|
92
91
|
end
|
93
92
|
date_groups << DateGroup.new(
|
94
|
-
:
|
95
|
-
:
|
96
|
-
:
|
93
|
+
start_date: dates.min.to_date.beginning_of_week,
|
94
|
+
end_date: dates.max.to_date.end_of_week,
|
95
|
+
weekdays: weekdays
|
96
|
+
)
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
@@ -104,9 +104,9 @@ module Timely
|
|
104
104
|
private
|
105
105
|
|
106
106
|
def validate_date_range!
|
107
|
-
|
108
|
-
|
109
|
-
|
107
|
+
return unless start_date && end_date && start_date > end_date
|
108
|
+
|
109
|
+
raise ArgumentError, "Incorrect date range #{start_date} is before #{end_date}"
|
110
110
|
end
|
111
111
|
end
|
112
112
|
end
|
@@ -1,25 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
module DateRangeValidityModule
|
3
5
|
def self.included(base)
|
4
6
|
base.class_eval do
|
5
|
-
validates :from, :to, :
|
7
|
+
validates :from, :to, presence: true
|
6
8
|
end
|
7
9
|
end
|
8
10
|
|
9
11
|
def validity_range
|
10
|
-
(from
|
12
|
+
(from..to)
|
11
13
|
end
|
12
14
|
|
13
15
|
def correctness_of_date_range
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
return unless from.present? && to.present? && from > to
|
17
|
+
|
18
|
+
errors.add(:base, 'Invalid Date Range. From date should be less than or equal to To date')
|
17
19
|
end
|
18
20
|
|
19
21
|
def validity_range_to_s
|
20
22
|
"#{from.to_s(:short)} ~ #{to.to_s(:short)}"
|
21
23
|
end
|
22
|
-
|
24
|
+
|
23
25
|
def valid_on?(date)
|
24
26
|
validity_range.include?(date)
|
25
27
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsCoreExtensions
|
2
4
|
module DateTime
|
3
5
|
def advance_considering_calendar(units, num_units)
|
@@ -5,11 +7,11 @@ module RailsCoreExtensions
|
|
5
7
|
when :seconds, :minutes, :hours, :days, :weeks, :months, :years
|
6
8
|
advance(units => num_units)
|
7
9
|
when :calendar_days
|
8
|
-
advance(:
|
10
|
+
advance(days: num_units - 1).end_of_day
|
9
11
|
when :calendar_months
|
10
|
-
advance(:
|
12
|
+
advance(months: num_units - 1).end_of_month
|
11
13
|
when :calendar_years
|
12
|
-
advance(:
|
14
|
+
advance(years: num_units - 1).end_of_year
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
@@ -1,55 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
module Extensions
|
3
5
|
# Add a WeekDays attribute
|
4
6
|
#
|
5
7
|
# By default it will use attribute_bit_array as db field, but this can
|
6
8
|
# be overridden by specifying :db_field => 'somthing_else'
|
7
|
-
def weekdays_field(attribute, options={})
|
9
|
+
def weekdays_field(attribute, options = {})
|
8
10
|
db_field = options[:db_field] || attribute.to_s + '_bit_array'
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
)
|
11
|
+
composed_of(attribute,
|
12
|
+
class_name: '::Timely::WeekDays',
|
13
|
+
mapping: [[db_field, 'weekdays_int']],
|
14
|
+
converter: proc { |field| ::Timely::WeekDays.new(field) })
|
14
15
|
end
|
15
16
|
|
16
17
|
def acts_as_seasonal
|
17
|
-
belongs_to :season, :
|
18
|
+
belongs_to :season, class_name: 'Timely::Season', optional: true
|
18
19
|
accepts_nested_attributes_for :season
|
19
20
|
validates_associated :season
|
20
21
|
|
21
|
-
if ::ActiveRecord::VERSION::MAJOR >= 3
|
22
|
-
scope :season_on, lambda { |*args|
|
23
|
-
date = args.first || ::Date.current # Can't assign in block in Ruby 1.8
|
24
|
-
joins(:season => :date_groups).where("date_groups.start_date <= ? AND date_groups.end_date >= ?", date, date)
|
25
|
-
}
|
26
|
-
|
27
|
-
scope :available_from, lambda { |*args|
|
28
|
-
date = args.first || ::Date.current # Can't assign in block in Ruby 1.8
|
29
|
-
where("boundary_end >= ?", date)
|
30
|
-
}
|
31
|
-
else
|
32
|
-
named_scope :season_on, lambda { |*args|
|
33
|
-
date = args.first || ::Date.current # Can't assign in block in Ruby 1.8
|
34
|
-
{
|
35
|
-
:joins => {:season => :date_groups},
|
36
|
-
:conditions => ["date_groups.start_date <= ? AND date_groups.end_date >= ?", date, date]
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
|
-
named_scope :available_from, lambda { |*args|
|
41
|
-
date = args.first || ::Date.current # Can't assign in block in Ruby 1.8
|
42
|
-
{:conditions => ["boundary_end >= ?", date]}
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
22
|
before_save do |object|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
23
|
+
next unless object.season
|
24
|
+
|
25
|
+
object.boundary_start = object.season.boundary_start
|
26
|
+
object.boundary_end = object.season.boundary_end
|
51
27
|
end
|
52
28
|
end
|
53
29
|
end
|
54
30
|
end
|
55
|
-
|
data/lib/timely/rails/period.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
class Period
|
3
5
|
attr_reader :number, :units
|
4
6
|
|
5
|
-
UNITS = [
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
]
|
7
|
+
UNITS = %i[
|
8
|
+
seconds
|
9
|
+
minutes
|
10
|
+
hours
|
11
|
+
days
|
12
|
+
weeks
|
13
|
+
months
|
14
|
+
years
|
15
|
+
calendar_days
|
16
|
+
calendar_months
|
17
|
+
calendar_years
|
18
|
+
].freeze
|
17
19
|
|
18
20
|
def initialize(number, units)
|
19
21
|
@number = number
|