timely 0.4.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +6 -0
  3. data/.github/workflows/release.yml +59 -0
  4. data/.github/workflows/ruby.yml +19 -0
  5. data/.rubocop.yml +22 -2
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +23 -0
  8. data/Gemfile +2 -0
  9. data/README.md +13 -2
  10. data/Rakefile +6 -4
  11. data/gemfiles/rails60.gemfile +8 -0
  12. data/gemfiles/rails61.gemfile +8 -0
  13. data/lib/timely.rb +2 -0
  14. data/lib/timely/date.rb +6 -2
  15. data/lib/timely/date_chooser.rb +29 -30
  16. data/lib/timely/date_range.rb +17 -19
  17. data/lib/timely/date_time.rb +3 -1
  18. data/lib/timely/rails.rb +2 -0
  19. data/lib/timely/rails/calendar_tag.rb +3 -3
  20. data/lib/timely/rails/date.rb +3 -1
  21. data/lib/timely/rails/date_group.rb +42 -18
  22. data/lib/timely/rails/date_range_validity_module.rb +8 -6
  23. data/lib/timely/rails/date_time.rb +5 -3
  24. data/lib/timely/rails/extensions.rb +12 -37
  25. data/lib/timely/rails/period.rb +14 -12
  26. data/lib/timely/rails/season.rb +14 -33
  27. data/lib/timely/rails/time.rb +7 -3
  28. data/lib/timely/railtie.rb +2 -0
  29. data/lib/timely/range.rb +4 -2
  30. data/lib/timely/string.rb +4 -2
  31. data/lib/timely/time.rb +7 -3
  32. data/lib/timely/time_since.rb +5 -3
  33. data/lib/timely/trackable_date_set.rb +21 -21
  34. data/lib/timely/version.rb +3 -1
  35. data/lib/timely/week_days.rb +22 -14
  36. data/rails/init.rb +2 -0
  37. data/spec/calendar_tag_spec.rb +11 -10
  38. data/spec/date_chooser_spec.rb +67 -62
  39. data/spec/date_group_spec.rb +103 -5
  40. data/spec/date_range_spec.rb +29 -19
  41. data/spec/date_spec.rb +3 -1
  42. data/spec/extensions_spec.rb +5 -9
  43. data/spec/rails/date_spec.rb +5 -3
  44. data/spec/rails/date_time_spec.rb +9 -7
  45. data/spec/rails/period_spec.rb +2 -0
  46. data/spec/rails/time_spec.rb +6 -4
  47. data/spec/schema.rb +4 -3
  48. data/spec/season_spec.rb +23 -26
  49. data/spec/spec_helper.rb +16 -1
  50. data/spec/support/coverage_loader.rb +3 -1
  51. data/spec/temporal_patterns_spec.rb +5 -5
  52. data/spec/time_since_spec.rb +6 -4
  53. data/spec/time_spec.rb +6 -4
  54. data/spec/trackable_date_set_spec.rb +20 -18
  55. data/spec/week_days_spec.rb +41 -16
  56. data/timely.gemspec +23 -19
  57. metadata +54 -26
  58. data/.travis.yml +0 -22
  59. data/gemfiles/rails5.gemfile +0 -6
  60. data/gemfiles/rails6.gemfile +0 -6
  61. data/spec/string_spec.rb +0 -14
@@ -1,16 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Timely
2
4
  module Time
3
5
  def on_date(year, month = nil, day = nil)
4
6
  if year.is_a?(Date)
5
7
  date = year
6
- year, month, day = date.year, date.month, date.day
8
+ year = date.year
9
+ month = date.month
10
+ day = date.day
7
11
  end
8
12
 
9
- raise ArgumentError, "Year, month, and day needed" unless [year, month, day].all?
13
+ raise ArgumentError, 'Year, month, and day needed' unless [year, month, day].all?
10
14
 
11
15
  ::Time.local(year, month, day, hour, min, sec)
12
16
  end
13
17
 
14
- alias_method :on, :on_date
18
+ alias on on_date
15
19
  end
16
20
  end
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Timely
2
4
  module TimeSince
3
5
  def seconds_since
4
- ::DateTime.now.to_i - self.to_i
6
+ ::DateTime.now.to_i - to_i
5
7
  end
6
8
 
7
9
  def minutes_since
8
- seconds_since/60
10
+ seconds_since / 60
9
11
  end
10
12
 
11
13
  def hours_since
12
- minutes_since/60
14
+ minutes_since / 60
13
15
  end
14
16
  end
15
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  # Track a set of dates (usually a range)
@@ -40,22 +42,20 @@ module Timely
40
42
  @dates_to_do = @dates.dup
41
43
  end
42
44
 
43
- def self.new_for_date(date, opts={})
45
+ def self.new_for_date(date, opts = {})
44
46
  duration = opts[:duration] || 1
45
47
  TrackableDateSet.new(date..(date + duration - 1))
46
48
  end
47
49
 
48
- # Todo: remove
50
+ # TODO: remove
49
51
  # Initialize from a date + duration
50
- def self.from_params(date_string, duration_string=nil)
52
+ def self.from_params(date_string, duration_string = nil)
51
53
  duration = duration_string.to_i
52
- duration = 1 if duration == 0
53
- new_for_date(date_string.to_date, :duration => duration)
54
+ duration = 1 if duration.zero?
55
+ new_for_date(date_string.to_date, duration: duration)
54
56
  end
55
57
 
56
- def dates
57
- @dates
58
- end
58
+ attr_reader :dates
59
59
 
60
60
  # Find the set of dates which are YET to do
61
61
  def find_to_do
@@ -66,18 +66,16 @@ module Timely
66
66
  def dates_done
67
67
  @dates - @dates_to_do
68
68
  end
69
- alias_method :find_done, :dates_done
69
+ alias find_done dates_done
70
70
 
71
71
  # Yield each date to do
72
72
  def each_date_to_do
73
- # Sort method needed as Ruby 1.8 set's aren't ordered
74
- @dates_to_do.sort.each{|date| yield date}
73
+ @dates_to_do.each { |date| yield date }
75
74
  end
76
75
 
77
76
  # Yield each date in the whole set
78
77
  def each_date
79
- # Sort method needed as Ruby 1.8 set's aren't ordered
80
- @dates.sort.each{|date| yield date}
78
+ @dates.each { |date| yield date }
81
79
  end
82
80
 
83
81
  # Set dates as done
@@ -94,9 +92,9 @@ module Timely
94
92
  @dates_to_do.clear
95
93
  end
96
94
 
97
- def has_done?(date_or_date_range)
95
+ def done_dates?(date_or_date_range)
98
96
  if date_or_date_range.is_a?(Enumerable)
99
- @dates_to_do.none?{|date_to_do| date_or_date_range.include?(date_to_do)}
97
+ @dates_to_do.none? { |date_to_do| date_or_date_range.include?(date_to_do) }
100
98
  else
101
99
  !@dates_to_do.include? date_or_date_range
102
100
  end
@@ -112,8 +110,9 @@ module Timely
112
110
  #
113
111
  # action_name => Name to track
114
112
  # {:job_done_when} => Block to call, passed result of yield
115
- def do_once(action_name, opts={})
113
+ def do_once(action_name, opts = {})
116
114
  return if action_applied?(action_name)
115
+
117
116
  result = yield
118
117
 
119
118
  job_done = opts[:job_done_when].blank? || opts[:job_done_when].call(result)
@@ -133,14 +132,15 @@ module Timely
133
132
  def duration
134
133
  @dates.size
135
134
  end
136
- alias_method :number_of_nights, :duration
135
+ alias number_of_nights duration
137
136
 
138
- # Can't say whole_period anymore... it's not necessarily sequential dates
139
- # def whole_period
140
- # self.dates
141
- # end
137
+ # Can't say whole_period anymore... it's not necessarily sequential dates
138
+ # def whole_period
139
+ # self.dates
140
+ # end
142
141
 
143
142
  private
143
+
144
144
  def actions_applied
145
145
  @actions_applied ||= Set.new
146
146
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Timely
2
- VERSION = "0.4.2"
4
+ VERSION = '0.9.0'
3
5
  end
@@ -1,6 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Timely
2
4
  class WeekDays
3
- WEEKDAY_KEYS = %i[sun mon tue wed thu fri sat]
5
+ WEEKDAY_KEYS = %i[sun mon tue wed thu fri sat].freeze
6
+
7
+ def self.from_range(date_range)
8
+ dates = Array(date_range)
9
+ return ALL_WEEKDAYS if dates.count >= WEEKDAY_KEYS.count
10
+
11
+ new(dates.each_with_object({}) do |date, result|
12
+ # e.g. {3: true, 5: true}
13
+ result[date.to_date.wday] = true
14
+ end)
15
+ end
4
16
 
5
17
  # Create a new Weekdays object
6
18
  # weekdays can be in three formats
@@ -26,7 +38,7 @@ module Timely
26
38
  when Integer
27
39
  # 4 -> 0000100 (binary) -> "0010000" (reversed string) -> {:tue => true}
28
40
  weekdays.to_s(2).reverse.each_char.with_index do |char, index|
29
- set_day(index, char == "1")
41
+ set_day(index, char == '1')
30
42
  end
31
43
  when Hash
32
44
  weekdays.each_pair do |day, value|
@@ -48,7 +60,7 @@ module Timely
48
60
  }
49
61
  else
50
62
  raise ArgumentError,
51
- "You must initialize with an Integer, Hash or Array"
63
+ 'You must initialize with an Integer, Hash or Array'
52
64
  end
53
65
  end
54
66
 
@@ -63,10 +75,9 @@ module Timely
63
75
 
64
76
  def set_day(day, set)
65
77
  key = day_to_index(day)
66
- unless WEEKDAY_KEYS.include?(key)
67
- raise ArgumentError, "Invalid week day index #{key}"
68
- end
69
- @weekdays[key] = [true, "true", 1, "1"].include?(set)
78
+ raise ArgumentError, "Invalid week day index #{key}" unless WEEKDAY_KEYS.include?(key)
79
+
80
+ @weekdays[key] = [true, 'true', 1, '1'].include?(set)
70
81
  end
71
82
 
72
83
  def applies_for_date?(date)
@@ -95,10 +106,7 @@ module Timely
95
106
  # Returns array of weekday selected
96
107
  # e.g. [:sun, :sat]
97
108
  def weekdays
98
- selected = @weekdays.select { |_day, day_selected| day_selected }
99
- # Ruby 1.8 returns an array for Hash#select and loses order
100
- return selected.keys if selected.is_a?(Hash)
101
- selected.map(&:first).sort_by { |v| WEEKDAY_KEYS.index(v) }
109
+ @weekdays.select { |_day, day_selected| day_selected }.keys
102
110
  end
103
111
 
104
112
  # Returns comma separated and capitalized in Sun-Sat order
@@ -107,7 +115,7 @@ module Timely
107
115
  days = weekdays.map { |day| day.to_s.capitalize }
108
116
  last_day = days.pop
109
117
 
110
- days.empty? ? last_day : days.join(", ") + ", and " + last_day
118
+ days.empty? ? last_day : days.join(', ') + ', and ' + last_day
111
119
  end
112
120
 
113
121
  # 7 bits encoded in decimal number
@@ -116,7 +124,7 @@ module Timely
116
124
  def weekdays_int
117
125
  int = 0
118
126
  WEEKDAY_KEYS.each.with_index do |day, index|
119
- int += 2 ** index if @weekdays[day]
127
+ int += 2**index if @weekdays[day]
120
128
  end
121
129
  int
122
130
  end
@@ -133,6 +141,6 @@ module Timely
133
141
  end
134
142
  end
135
143
 
136
- ALL_WEEKDAYS = WeekDays.new(%w[1 1 1 1 1 1 1])
144
+ ALL_WEEKDAYS = WeekDays.new(%w[1 1 1 1 1 1 1]).freeze
137
145
  end
138
146
  end
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'timely/rails'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  class ActionViewTest
@@ -8,22 +10,21 @@ describe Timely::ActionViewHelpers do
8
10
  subject { ActionViewTest.new }
9
11
  let(:string) { double(:string) }
10
12
  let(:date) { Date.new(2000, 12, 25) }
11
- before {
13
+ before do
12
14
  expect(date).to receive(:to_s).with(:calendar).and_return('25-12-2000')
13
15
  expect(Timely).to receive(:current_date).and_return(date)
14
- }
16
+ end
15
17
 
16
18
  it 'should generate calendar tags' do
17
19
  expect(string).to receive(:html_safe)
18
20
  expect(subject).to receive(:tag).with(:input,
19
- :id => 'test',
20
- :class => 'datepicker',
21
- :size => 10,
22
- :maxlength => 10,
23
- :name => 'test',
24
- :type => 'text',
25
- :value => '25-12-2000'
26
- ).and_return(string)
21
+ id: 'test',
22
+ class: 'datepicker',
23
+ size: 10,
24
+ maxlength: 10,
25
+ name: 'test',
26
+ type: 'text',
27
+ value: '25-12-2000').and_return(string)
27
28
  subject.calendar_tag :test
28
29
  end
29
30
  end
@@ -1,110 +1,115 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Timely::DateChooser do
4
6
  before(:all) do
5
- @from = "01-01-2011".to_date
6
- @to = "01-03-2011".to_date
7
+ @from = '01-01-2011'.to_date
8
+ @to = '01-03-2011'.to_date
7
9
  end
8
10
 
9
- #Validation
10
- it "rejects blank FROM dates" do
11
- expect { Timely::DateChooser.new({:from=>""}) }.to raise_error(
12
- Timely::DateChooserException, 'A Start Date is required')
11
+ # Validation
12
+ it 'rejects blank FROM dates' do
13
+ expect { Timely::DateChooser.new(from: '') }.to raise_error(
14
+ Timely::DateChooserException, 'A Start Date is required'
15
+ )
13
16
  end
14
17
 
15
- it "rejects TO dates later than FROM dates" do
16
- expect {Timely::DateChooser.new(
17
- :multiple_dates => true, :from => @from + 10, :to => @from
18
- )}.to raise_error(Timely::DateChooserException, 'Start Date is after End Date')
18
+ it 'rejects TO dates later than FROM dates' do
19
+ expect do
20
+ Timely::DateChooser.new(
21
+ multiple_dates: true, from: @from + 10, to: @from
22
+ )
23
+ end .to raise_error(Timely::DateChooserException, 'Start Date is after End Date')
19
24
  end
20
25
 
21
- #Operation
22
- it "returns today if client only wants single date" do
26
+ # Operation
27
+ it 'returns today if client only wants single date' do
23
28
  expect(Timely::DateChooser.new(
24
- :multiple_dates => false, :from => @from
29
+ multiple_dates: false, from: @from
25
30
  ).choose_dates).to eq [@from]
26
31
  end
27
32
 
28
- #Test specific date of month
29
- it "returns from and to as same (one) day in the case that only from date is given" do
33
+ # Test specific date of month
34
+ it 'returns from and to as same (one) day in the case that only from date is given' do
30
35
  expect(Timely::DateChooser.new(
31
- :multiple_dates => true, :from => @from, :to => ''
36
+ multiple_dates: true, from: @from, to: ''
32
37
  ).choose_dates).to eq [@from]
33
38
  end
34
39
 
35
- it "returns all days between from and to days in the basic case" do
40
+ it 'returns all days between from and to days in the basic case' do
36
41
  expect(Timely::DateChooser.new(
37
- :multiple_dates => true, :from => @from, :to => @to
38
- ).choose_dates).to eq (@from..@to).to_a
42
+ multiple_dates: true, from: @from, to: @to
43
+ ).choose_dates).to eq((@from..@to).to_a)
39
44
  end
40
45
 
41
- it "returns the recurring dates within the range if this option is picked" do
46
+ it 'returns the recurring dates within the range if this option is picked' do
42
47
  expect(Timely::DateChooser.new(
43
- :multiple_dates => true, :select => 'days', :dates => '1,11,3', :from => @from, :to => @to
44
- ).choose_dates).to eq [
45
- "1-01-2011", "3-01-2011", "11-01-2011", "1-02-2011",
46
- "3-02-2011", "11-02-2011", "1-03-2011"
48
+ multiple_dates: true, select: 'days', dates: '1,11,3', from: @from, to: @to
49
+ ).choose_dates).to eq %w[
50
+ 1-01-2011 3-01-2011 11-01-2011 1-02-2011
51
+ 3-02-2011 11-02-2011 1-03-2011
47
52
  ].map(&:to_date)
48
53
  end
49
54
 
50
- it "returns the specific dates, within or outside of the range, if this option is picked" do
55
+ it 'returns the specific dates, within or outside of the range, if this option is picked' do
51
56
  expect(Timely::DateChooser.new(
52
- :multiple_dates => true, :select => 'specific_days', :specific_dates => '11-01-2011, 18-02-2011, 22-06-2011', :from => @from, :to => @to
53
- ).choose_dates).to eq [
54
- "11-01-2011", "18-02-2011", "22-06-2011"
57
+ multiple_dates: true, select: 'specific_days', specific_dates: '11-01-2011, 18-02-2011, 22-06-2011', from: @from, to: @to
58
+ ).choose_dates).to eq %w[
59
+ 11-01-2011 18-02-2011 22-06-2011
55
60
  ].map(&:to_date)
56
61
  end
57
62
 
58
- #Test days of week, every X weeks
59
- it "returns every sunday correctly" do
63
+ # Test days of week, every X weeks
64
+ it 'returns every sunday correctly' do
60
65
  expect(Timely::DateChooser.new(
61
- :multiple_dates => true, :select => 'weekdays', :from => @from, :to => @to,
62
- :interval => {:level => "1", :unit => "week"}, :weekdays => {:sun => true}
63
- ).choose_dates).to eq [
64
- "2-01-2011", "9-01-2011", "16-01-2011", "23-01-2011", "30-01-2011",
65
- "06-02-2011", "13-02-2011", "20-02-2011", "27-02-2011"
66
+ multiple_dates: true, select: 'weekdays', from: @from, to: @to,
67
+ interval: { level: '1', unit: 'week' }, weekdays: { sun: true }
68
+ ).choose_dates).to eq %w[
69
+ 2-01-2011 9-01-2011 16-01-2011 23-01-2011 30-01-2011
70
+ 06-02-2011 13-02-2011 20-02-2011 27-02-2011
66
71
  ].map(&:to_date)
67
72
  end
68
73
 
69
- it "returns every thursday and sunday correctly" do
74
+ it 'returns every thursday and sunday correctly' do
70
75
  expect(Timely::DateChooser.new(
71
- :multiple_dates => true, :select => 'weekdays',
72
- :interval => {:level => "1", :unit => "week"},
73
- :weekdays => {:sun => true, :thu => true}, :from => @from, :to => @to
74
- ).choose_dates).to eq [
75
- "2-01-2011", "6-01-2011", "9-01-2011", "13-01-2011", "16-01-2011",
76
- "20-01-2011", "23-01-2011", "27-01-2011", "30-01-2011", "3-02-2011",
77
- "06-02-2011", "10-02-2011", "13-02-2011", "17-02-2011", "20-02-2011",
78
- "24-02-2011", "27-02-2011"
76
+ multiple_dates: true, select: 'weekdays',
77
+ interval: { level: '1', unit: 'week' },
78
+ weekdays: { sun: true, thu: true }, from: @from, to: @to
79
+ ).choose_dates).to eq %w[
80
+ 2-01-2011 6-01-2011 9-01-2011 13-01-2011 16-01-2011
81
+ 20-01-2011 23-01-2011 27-01-2011 30-01-2011 3-02-2011
82
+ 06-02-2011 10-02-2011 13-02-2011 17-02-2011 20-02-2011
83
+ 24-02-2011 27-02-2011
79
84
  ].map(&:to_date)
80
85
  end
81
86
 
82
- it "returns every 2nd thursday and sunday correctly" do
87
+ it 'returns every 2nd thursday and sunday correctly' do
83
88
  expect(Timely::DateChooser.new(
84
- :multiple_dates => true, :select => 'weekdays',
85
- :interval => {:level => "2", :unit => "week"},
86
- :weekdays => {:sun => "1", :thu => "1"}, :from => @from, :to => @to
87
- ).choose_dates).to eq [
88
- "2-01-2011", "6-01-2011", "16-01-2011", "20-01-2011", "30-01-2011",
89
- "3-02-2011", "13-02-2011", "17-02-2011", "27-02-2011"
89
+ multiple_dates: true, select: 'weekdays',
90
+ interval: { level: '2', unit: 'week' },
91
+ weekdays: { sun: '1', thu: '1' }, from: @from, to: @to
92
+ ).choose_dates).to eq %w[
93
+ 2-01-2011 6-01-2011 16-01-2011 20-01-2011 30-01-2011
94
+ 3-02-2011 13-02-2011 17-02-2011 27-02-2011
90
95
  ].map(&:to_date)
91
96
  end
92
97
 
93
- #Test correct results for every Nth week of month
94
- it "returns every 1st Tuesday" do
98
+ # Test correct results for every Nth week of month
99
+ it 'returns every 1st Tuesday' do
95
100
  expect(Timely::DateChooser.new(
96
- :multiple_dates => true, :select => 'weekdays', :from => @from, :to => @to,
97
- :interval => {:level => "1", :unit => "week_of_month"}, :weekdays => {:tue => true}
98
- ).choose_dates).to eq ["4-01-2011", "1-02-2011", "1-03-2011"].map(&:to_date)
101
+ multiple_dates: true, select: 'weekdays', from: @from, to: @to,
102
+ interval: { level: '1', unit: 'week_of_month' }, weekdays: { tue: true }
103
+ ).choose_dates).to eq %w[4-01-2011 1-02-2011 1-03-2011].map(&:to_date)
99
104
  end
100
105
 
101
- it "returns every 3st Monday and Friday" do
106
+ it 'returns every 3st Monday and Friday' do
102
107
  expect(Timely::DateChooser.new(
103
- :multiple_dates => true, :select => 'weekdays',
104
- :interval => {:level => "3", :unit => "week_of_month"},
105
- :weekdays => {:mon => true, :fri => true}, :from => @from, :to => @to
106
- ).choose_dates).to eq [
107
- "17-01-2011", "21-01-2011", "18-02-2011", "21-02-2011"
108
+ multiple_dates: true, select: 'weekdays',
109
+ interval: { level: '3', unit: 'week_of_month' },
110
+ weekdays: { mon: true, fri: true }, from: @from, to: @to
111
+ ).choose_dates).to eq %w[
112
+ 17-01-2011 21-01-2011 18-02-2011 21-02-2011
108
113
  ].map(&:to_date)
109
114
  end
110
115
  end