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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ad5b5230c51dc3ab72192b82882b333fe9fc72b49fb2e8324881e7a6b7fd269
4
- data.tar.gz: 1de47a9da2ee6f3708c049f85fed2654e7ec4900935056f80dbe42db2842cf7b
3
+ metadata.gz: 5aeec444ee90189672055555263e90807c7f2bad4e366c5e44d74dd4d578cd30
4
+ data.tar.gz: e5bf46db86fee6448233e03aaba2dfe7dc7f66771f6d82c30db2e231e03b48b9
5
5
  SHA512:
6
- metadata.gz: 8d9bde900b4005fdcf26cc826e53858eb47067f6ccd6e01c633861efb305970d37ceddfd7bc1d70b2c68bae1a53abccc178ca1b95f20fc5ae5032cc8ef0e3e11
7
- data.tar.gz: 8d1145ecf55ee9deb075d459e9f2399ec28bf0da6519f60b47cf1fddd679312383c6df4d9e83d8f6222e2aa89c7791b25927efb1705260e880ad54682b4b8037
6
+ metadata.gz: a47c451934a28dda82fae5eb78145791b5d8727e371683f506ade5f3ee4f609167bf5bec209c1dd545ae8399fa82df22ec994903df4c000c36b844b8c42255f3
7
+ data.tar.gz: bc96a85cae09b52d5381a915847c1f76df9613592e632403ca1d69dca74486f7d7bf464b5777d850bb88689cba0ded45101c49503470f2c0e8242d3f09a1f420
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "bundler"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "daily"
@@ -0,0 +1,59 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ name: Build
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v2
15
+ - uses: ruby/setup-ruby@v1
16
+ with:
17
+ bundler-cache: true
18
+ - run: bundle exec rake
19
+
20
+ release:
21
+ needs: build
22
+ name: Release
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v2
27
+
28
+ - name: Generate Changelog
29
+ run: |
30
+ # Get version from github ref (remove 'refs/tags/' and prefix 'v')
31
+ version="${GITHUB_REF#refs/tags/v}"
32
+ npx changelog-parser CHANGELOG.md | jq -cr ".versions | .[] | select(.version == \"$version\") | .body" > ${{ github.workflow }}-CHANGELOG.txt
33
+
34
+ - name: Release
35
+ uses: softprops/action-gh-release@v1
36
+ with:
37
+ body_path: ${{ github.workflow }}-CHANGELOG.txt
38
+ env:
39
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40
+
41
+ publish:
42
+ needs: [build, release]
43
+ name: Publish
44
+ runs-on: ubuntu-latest
45
+
46
+ steps:
47
+ - uses: actions/checkout@v2
48
+ - uses: ruby/setup-ruby@v1
49
+
50
+ - name: Publish to RubyGems
51
+ run: |
52
+ mkdir -p $HOME/.gem
53
+ touch $HOME/.gem/credentials
54
+ chmod 0600 $HOME/.gem/credentials
55
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
56
+ gem build *.gemspec
57
+ gem push *.gem
58
+ env:
59
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
@@ -0,0 +1,19 @@
1
+ name: Build and Test
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ strategy:
6
+ fail-fast: false
7
+ matrix:
8
+ gemfile: [rails60, rails61]
9
+ ruby: ["2.6", "2.7", "3.0"]
10
+ runs-on: ubuntu-latest
11
+ env:
12
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - uses: ruby/setup-ruby@v1
16
+ with:
17
+ ruby-version: ${{ matrix.ruby }}
18
+ bundler-cache: true
19
+ - run: bundle exec rake
@@ -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: 80
7
+ Max: 200
3
8
 
4
9
  Style/Documentation:
5
10
  Enabled: false
6
11
 
7
12
  Style/FrozenStringLiteralComment:
8
- Enabled: false # Using Ruby 2.4 doesn't need it
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
@@ -1 +1 @@
1
- 2.6.3
1
+ 3.0.0
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.0
4
+
5
+ * [TT-8614] Update to build with github actions / ruby 3.0 / rails 6.1
6
+
7
+ ## 0.8.0
8
+
9
+ * [TT-6441] Turns out we don't actually need time difference in QT
10
+ * [TT-6661] Fix issue when detecting intersecting date groups
11
+
12
+ ## 0.7.0
13
+
14
+ * [TT-6441] Due to TimeDifference being unmaintained bring it into the timely library
15
+
16
+ ## 0.6.0
17
+
18
+ * [TT-6402] Require date group weekdays bit field to be not null/nil
19
+ IMPORTANT: Rails projects must add a migration to make this field not null!
20
+ * [TT-6401] Remove Rails 3 support, unused methods
21
+
22
+ ## 0.5.0
23
+
24
+ * [TT-6193] Date group scopes for more efficient searches/restrictions
25
+
3
26
  ## 0.4.2
4
27
 
5
28
  * [TT-5794] Fix belongs_to associations are not explicitly marked optional
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
  gemspec
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # Timely
2
2
 
3
- [![Build Status](https://travis-ci.org/sealink/timely.png?branch=master)](https://travis-ci.org/sealink/timely)
3
+ [![Build Status](https://github.com/sealink/timely/workflows/Build%20and%20Test/badge.svg?branch=master)](https://github.com/sealink/timely/actions)
4
4
  [![Coverage Status](https://coveralls.io/repos/sealink/timely/badge.png)](https://coveralls.io/r/sealink/timely)
5
- [![Dependency Status](https://gemnasium.com/sealink/timely.png?travis)](https://gemnasium.com/sealink/timely)
6
5
  [![Code Climate](https://codeclimate.com/github/sealink/timely.png)](https://codeclimate.com/github/sealink/timely)
7
6
 
8
7
  # DESCRIPTION
@@ -59,3 +58,15 @@ some_date.at_time(some_time) # => Sat May 03 13:40:22 -0500 2008
59
58
  some_time.on(some_date) # => Sat May 03 13:40:22 -0500 2008
60
59
  some_date.at(some_time) # => Sat May 03 13:40:22 -0500 2008
61
60
  ```
61
+
62
+ # Release
63
+
64
+ To publish a new version of this gem the following steps must be taken.
65
+
66
+ * Update the version in the following files
67
+ ```
68
+ CHANGELOG.md
69
+ lib/timely/version.rb
70
+ ````
71
+ * Create a tag using the format v0.1.0
72
+ * Follow build progress in GitHub actions
data/Rakefile CHANGED
@@ -1,12 +1,14 @@
1
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
2
4
 
3
5
  desc 'Default: run specs.'
4
- task :default => :spec
6
+ task default: :spec
5
7
 
6
8
  require 'rspec/core/rake_task'
7
9
 
8
- desc "Run specs"
10
+ desc 'Run specs'
9
11
  RSpec::Core::RakeTask.new do |t|
10
- t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec path: '../'
5
+
6
+ group :development, :test do
7
+ gem 'activerecord', '~> 6.0'
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec path: '../'
5
+
6
+ group :development, :test do
7
+ gem 'activerecord', '~> 6.1'
8
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Timely
2
4
  require 'time'
3
5
  require 'date'
@@ -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, minute, second = time.hour, time.min, time.sec
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
- alias_method :at, :at_time
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
@@ -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
- {:code => 'week', :name => 'week(s)', :description =>
7
- 'Weekdays selected will be chosen every {{n}} weeks for the date range'},
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 :multiple_dates, :from, :to, :select, :dates, :interval, :weekdays
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; date
32
- when NilClass; nil
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] if !@multiple_dates
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, "No days of the week selected" if @weekdays.weekdays.empty?
70
- raise DateChooserException, "No weekly interval selected" if @interval && @interval.empty?
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
- if @weekdays.has_day?(date.wday)
74
- case @interval[:unit]
75
- when 'week'
76
- # 0 = first week, 1 = second week, 2 = third week, etc.
77
- nth_week = (date - @from).to_i / 7
78
- # true every 2nd week (0, 2, 4, 6, etc.)
79
- (nth_week % @interval[:level].to_i).zero?
80
- when 'week_of_month'
81
- week = @interval[:level].to_i
82
- (date.mday > (week-1)*7 && date.mday <= week*7)
83
- end
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
- if !@from
94
- raise DateChooserException, "A Start Date is required"
95
- elsif @multiple_dates
96
- @to ||= @from
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 < Exception; end
101
+ class DateChooserException < RuntimeError; end
103
102
  end
@@ -1,4 +1,4 @@
1
- require 'date' # Ensure Date class is loaded for old rubies (1.8)
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
- alias_method :start_date, :first
19
- alias_method :end_date, :last
18
+ alias start_date first
19
+ alias end_date last
20
20
 
21
21
  def self.validate_range(first, last)
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
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
- start_of_intersection = [self.start_date, date_range.first].max
37
- end_of_intersection = [self.end_date, date_range.last].min
38
- intersection = if end_of_intersection >= start_of_intersection
39
- (start_of_intersection..end_of_intersection)
40
- else
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
- alias_method :duration, :number_of_nights
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)}#{" (inclusive)" if is_date}"
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
- "no date range"
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'
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Timely
2
4
  module DateTime
3
5
  def on_date(date)
4
- self.change(:year => date.year, :month => date.month, :day => date.day)
6
+ change(year: date.year, month: date.month, day: date.day)
5
7
  end
6
8
  end
7
9
  end