timely 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -12
- data/README.md +5 -0
- data/Rakefile +1 -139
- data/gemfiles/rails3.gemfile +8 -0
- data/gemfiles/rails4.gemfile +9 -0
- data/lib/timely.rb +7 -3
- data/lib/timely/date.rb +20 -0
- data/lib/timely/date_chooser.rb +10 -5
- data/lib/timely/date_range.rb +47 -10
- data/lib/timely/rails.rb +10 -3
- data/lib/timely/rails/calendar_tag.rb +52 -0
- data/lib/timely/rails/date.rb +5 -0
- data/lib/timely/rails/date_group.rb +68 -99
- data/lib/timely/rails/date_range_validity_module.rb +27 -0
- data/lib/timely/rails/date_time.rb +20 -0
- data/lib/timely/rails/extensions.rb +23 -11
- data/lib/timely/rails/period.rb +31 -0
- data/lib/timely/rails/season.rb +65 -75
- data/lib/timely/railtie.rb +7 -0
- data/lib/timely/temporal_patterns/finder.rb +152 -0
- data/lib/timely/temporal_patterns/frequency.rb +108 -0
- data/lib/timely/temporal_patterns/interval.rb +67 -0
- data/lib/timely/temporal_patterns/pattern.rb +160 -0
- data/lib/timely/time_since.rb +17 -0
- data/lib/timely/version.rb +3 -0
- data/spec/calendar_tag_spec.rb +29 -0
- data/spec/date_chooser_spec.rb +36 -27
- data/spec/date_group_spec.rb +9 -9
- data/spec/date_range_spec.rb +58 -20
- data/spec/date_spec.rb +20 -12
- data/spec/extensions_spec.rb +32 -0
- data/spec/rails/date_spec.rb +16 -0
- data/spec/rails/date_time_spec.rb +20 -0
- data/spec/rails/period_spec.rb +17 -0
- data/spec/schema.rb +5 -0
- data/spec/season_spec.rb +21 -24
- data/spec/spec_helper.rb +5 -20
- data/spec/string_spec.rb +4 -3
- data/spec/support/coverage.rb +26 -0
- data/spec/temporal_patterns_spec.rb +28 -0
- data/spec/time_since_spec.rb +24 -0
- data/spec/time_spec.rb +14 -14
- data/spec/trackable_date_set_spec.rb +14 -14
- data/spec/week_days_spec.rb +18 -18
- data/timely.gemspec +34 -98
- metadata +244 -21
- data/lib/timely/temporal_patterns.rb +0 -441
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2cebe03ec2467f4efe23f881f70be2c08fbb7e20
|
4
|
+
data.tar.gz: 355bf2273646023df6e0f7e9218e7a91390dd25a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bec47226548cc65af0aa7e0da099b5dc4f4b80056eb1f47e0f5de53959db654b18ed851245fbab86f9d45a0d80cb3fcc3a0bbcc9cc6188958d120402832b78f1
|
7
|
+
data.tar.gz: c705e73fe8447761b8ea7a79984a77aeb13687bb81bc354e53f5f434d64f9d70f51325da10f81df7811e3c02a18621e02cc5b6dbcf7defcb33aa6f944ea066fe
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2
|
4
|
+
script: bundle exec rake spec
|
5
|
+
gemfile:
|
6
|
+
- gemfiles/rails3.gemfile
|
7
|
+
- gemfiles/rails4.gemfile
|
8
|
+
notifications:
|
9
|
+
email:
|
10
|
+
- support@travellink.com.au
|
11
|
+
flowdock:
|
12
|
+
secure: QC1mV/0NZwA4tU2K1BQSety/seEf7ujL3uUlddXrMm0yHp0NBMlo1tnQ7KKopSKoyoPj9M9KmfhrCdbdZXDOU57WucH+pz7Tn9Zp9VkPUMniN4rYSwkrF17vihM5NpdyDzqo5mzthVPUEV0DtlK+Uu2W4wMUpu1uKaahFzHJH6k=
|
13
|
+
sudo: false
|
14
|
+
cache: bundler
|
data/Gemfile
CHANGED
@@ -1,13 +1,2 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
gemspec
|
3
|
-
|
4
|
-
group :development, :test do
|
5
|
-
gem 'rake', '~> 0.9.2'
|
6
|
-
gem 'rdoc', '~> 3.12'
|
7
|
-
gem 'rspec'
|
8
|
-
gem 'simplecov-rcov'
|
9
|
-
gem 'simplecov'
|
10
|
-
gem 'sqlite3'
|
11
|
-
gem 'activesupport', '~> 2.3.0'
|
12
|
-
gem 'activerecord', '~> 2.3.0'
|
13
|
-
end
|
data/README.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
Timely
|
2
2
|
======
|
3
3
|
|
4
|
+
[![Build Status](https://travis-ci.org/sealink/timely.png?branch=master)](https://travis-ci.org/sealink/timely)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/sealink/timely/badge.png)](https://coveralls.io/r/sealink/timely)
|
6
|
+
[![Dependency Status](https://gemnasium.com/sealink/timely.png?travis)](https://gemnasium.com/sealink/timely)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/sealink/timely.png)](https://codeclimate.com/github/sealink/timely)
|
8
|
+
|
4
9
|
# DESCRIPTION
|
5
10
|
|
6
11
|
Various helpers to work with times, dates and weekdays, etc.
|
data/Rakefile
CHANGED
@@ -1,47 +1,4 @@
|
|
1
|
-
require
|
2
|
-
require 'rake'
|
3
|
-
require 'date'
|
4
|
-
|
5
|
-
#############################################################################
|
6
|
-
#
|
7
|
-
# Helper functions
|
8
|
-
#
|
9
|
-
#############################################################################
|
10
|
-
|
11
|
-
def name
|
12
|
-
@name ||= Dir['*.gemspec'].first.split('.').first
|
13
|
-
end
|
14
|
-
|
15
|
-
def version
|
16
|
-
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
17
|
-
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
18
|
-
end
|
19
|
-
|
20
|
-
def date
|
21
|
-
Date.today.to_s
|
22
|
-
end
|
23
|
-
|
24
|
-
def rubyforge_project
|
25
|
-
name
|
26
|
-
end
|
27
|
-
|
28
|
-
def gemspec_file
|
29
|
-
"#{name}.gemspec"
|
30
|
-
end
|
31
|
-
|
32
|
-
def gem_file
|
33
|
-
"#{name}-#{version}.gem"
|
34
|
-
end
|
35
|
-
|
36
|
-
def replace_header(head, header_name)
|
37
|
-
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
38
|
-
end
|
39
|
-
|
40
|
-
#############################################################################
|
41
|
-
#
|
42
|
-
# Standard tasks
|
43
|
-
#
|
44
|
-
#############################################################################
|
1
|
+
require "bundler/gem_tasks"
|
45
2
|
|
46
3
|
desc 'Default: run specs.'
|
47
4
|
task :default => :spec
|
@@ -53,98 +10,3 @@ RSpec::Core::RakeTask.new do |t|
|
|
53
10
|
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
54
11
|
# Put spec opts in a file named .rspec in root
|
55
12
|
end
|
56
|
-
|
57
|
-
desc "Generate SimpleCov test coverage and open in your browser"
|
58
|
-
task :coverage do
|
59
|
-
ENV['COVERAGE'] = 'true'
|
60
|
-
Rake::Task['spec'].invoke
|
61
|
-
end
|
62
|
-
|
63
|
-
require 'rdoc/task'
|
64
|
-
RDoc::Task.new do |rdoc|
|
65
|
-
rdoc.rdoc_dir = 'rdoc'
|
66
|
-
rdoc.title = "#{name} #{version}"
|
67
|
-
rdoc.rdoc_files.include('README*')
|
68
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
69
|
-
end
|
70
|
-
|
71
|
-
desc "Open an irb session preloaded with this library"
|
72
|
-
task :console do
|
73
|
-
sh "irb -rubygems -r ./lib/#{name}.rb"
|
74
|
-
end
|
75
|
-
|
76
|
-
#############################################################################
|
77
|
-
#
|
78
|
-
# Custom tasks (add your own tasks here)
|
79
|
-
#
|
80
|
-
#############################################################################
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
#############################################################################
|
85
|
-
#
|
86
|
-
# Packaging tasks
|
87
|
-
#
|
88
|
-
#############################################################################
|
89
|
-
|
90
|
-
desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
|
91
|
-
task :release => :build do
|
92
|
-
unless `git branch` =~ /^\* master$/
|
93
|
-
puts "You must be on the master branch to release!"
|
94
|
-
exit!
|
95
|
-
end
|
96
|
-
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
97
|
-
sh "git tag v#{version}"
|
98
|
-
sh "git push origin master"
|
99
|
-
sh "git push origin v#{version}"
|
100
|
-
sh "gem push pkg/#{name}-#{version}.gem"
|
101
|
-
end
|
102
|
-
|
103
|
-
desc "Build #{gem_file} into the pkg directory"
|
104
|
-
task :build => :gemspec do
|
105
|
-
sh "mkdir -p pkg"
|
106
|
-
sh "gem build #{gemspec_file}"
|
107
|
-
sh "mv #{gem_file} pkg"
|
108
|
-
end
|
109
|
-
|
110
|
-
desc "Generate #{gemspec_file}"
|
111
|
-
task :gemspec => :validate do
|
112
|
-
# read spec file and split out manifest section
|
113
|
-
spec = File.read(gemspec_file)
|
114
|
-
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
115
|
-
|
116
|
-
# replace name version and date
|
117
|
-
replace_header(head, :name)
|
118
|
-
replace_header(head, :version)
|
119
|
-
replace_header(head, :date)
|
120
|
-
#comment this out if your rubyforge_project has a different name
|
121
|
-
replace_header(head, :rubyforge_project)
|
122
|
-
|
123
|
-
# determine file list from git ls-files
|
124
|
-
files = `git ls-files`.
|
125
|
-
split("\n").
|
126
|
-
sort.
|
127
|
-
reject { |file| file =~ /^\./ }.
|
128
|
-
reject { |file| file =~ /^(rdoc|pkg)/ }.
|
129
|
-
map { |file| " #{file}" }.
|
130
|
-
join("\n")
|
131
|
-
|
132
|
-
# piece file back together and write
|
133
|
-
manifest = " s.files = %w[\n#{files}\n ]\n"
|
134
|
-
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
|
135
|
-
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
136
|
-
puts "Updated #{gemspec_file}"
|
137
|
-
end
|
138
|
-
|
139
|
-
desc "Validate #{gemspec_file}"
|
140
|
-
task :validate do
|
141
|
-
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
|
142
|
-
unless libfiles.empty?
|
143
|
-
puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
|
144
|
-
exit!
|
145
|
-
end
|
146
|
-
unless Dir['VERSION*'].empty?
|
147
|
-
puts "A `VERSION` file at root level violates Gem best practices."
|
148
|
-
exit!
|
149
|
-
end
|
150
|
-
end
|
data/lib/timely.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
module Timely
|
2
|
-
VERSION = '0.0.2'
|
3
|
-
|
4
2
|
require 'time'
|
5
3
|
require 'date'
|
6
4
|
|
7
5
|
require 'timely/string'
|
8
6
|
require 'timely/date'
|
9
7
|
require 'timely/time'
|
8
|
+
require 'timely/time_since'
|
10
9
|
require 'timely/date_time'
|
11
10
|
require 'timely/range'
|
12
11
|
require 'timely/date_range'
|
13
12
|
require 'timely/date_chooser'
|
14
13
|
require 'timely/week_days'
|
15
|
-
require 'timely/temporal_patterns'
|
14
|
+
require 'timely/temporal_patterns/finder'
|
15
|
+
require 'timely/temporal_patterns/frequency'
|
16
|
+
require 'timely/temporal_patterns/interval'
|
17
|
+
require 'timely/temporal_patterns/pattern'
|
16
18
|
require 'timely/trackable_date_set'
|
19
|
+
|
20
|
+
require 'timely/railtie' if defined?(Rails::Railtie)
|
17
21
|
end
|
data/lib/timely/date.rb
CHANGED
@@ -10,6 +10,26 @@ module Timely
|
|
10
10
|
end
|
11
11
|
|
12
12
|
alias_method :at, :at_time
|
13
|
+
|
14
|
+
# returns true if date between from and to
|
15
|
+
# however if from and/or to are nil, it ignores that query
|
16
|
+
# e.g. date.between?(from, nil) is "date > from",
|
17
|
+
# date.between?(from, nil) is "date < to"
|
18
|
+
# date.between?(nil, nil) is true
|
19
|
+
def between?(from, to)
|
20
|
+
from = from.to_date if from && !from.is_a?(Date)
|
21
|
+
to = to.to_date if to && !to.is_a?(Date)
|
22
|
+
|
23
|
+
if from && to
|
24
|
+
self >= from && self <= to
|
25
|
+
elsif from
|
26
|
+
self >= from
|
27
|
+
elsif to
|
28
|
+
self <= to
|
29
|
+
else
|
30
|
+
true # i.e. no restrictive range return true
|
31
|
+
end
|
32
|
+
end
|
13
33
|
end
|
14
34
|
end
|
15
35
|
|
data/lib/timely/date_chooser.rb
CHANGED
@@ -3,9 +3,9 @@ module Timely
|
|
3
3
|
# Where is this used... so far only in one place, _date_range.html.haml
|
4
4
|
# May be good to refactor this as well, after the class behaviour is refactored.
|
5
5
|
INTERVALS = [
|
6
|
-
{:code => '
|
6
|
+
{:code => 'week', :name => 'week(s)', :description =>
|
7
7
|
'Weekdays selected will be chosen every {{n}} weeks for the date range'},
|
8
|
-
{:code => '
|
8
|
+
{:code => 'week_of_month', :name => 'week of month', :description =>
|
9
9
|
'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
|
@@ -20,6 +20,7 @@ module Timely
|
|
20
20
|
@to = process_date(options[:to])
|
21
21
|
@select = options[:select]
|
22
22
|
@dates = options[:dates]
|
23
|
+
@specific_dates = options[:specific_dates]
|
23
24
|
@interval = options[:interval]
|
24
25
|
@weekdays = WeekDays.new(options[:weekdays]) if @select == 'weekdays'
|
25
26
|
validate
|
@@ -40,7 +41,8 @@ module Timely
|
|
40
41
|
# :to - The end of the date range
|
41
42
|
#
|
42
43
|
# You can either specify specific dates to be chosen each month:
|
43
|
-
# :dates
|
44
|
+
# :dates - A comma separated string of days of the month, e.g. 1,16
|
45
|
+
# :specific_dates - A comma separated string of dates, e.g. 26-10-2012, 03-11-2012, 01-01-2013
|
44
46
|
#
|
45
47
|
# or you can specify how to select the dates
|
46
48
|
# :day - A hash of days, the index being the wday, e.g. 0 = sunday, and the value being 1 if chosen
|
@@ -60,6 +62,9 @@ module Timely
|
|
60
62
|
when 'days'
|
61
63
|
days = @dates.gsub(/\s/, '').split(',')
|
62
64
|
all_days.select { |date| days.include?(date.mday.to_s) }
|
65
|
+
when 'specific_days'
|
66
|
+
days = @specific_dates.gsub(/\s/, '').split(',')
|
67
|
+
days.map(&:to_date)
|
63
68
|
when 'weekdays'
|
64
69
|
raise DateChooserException, "No days of the week selected" if @weekdays.weekdays.empty?
|
65
70
|
raise DateChooserException, "No weekly interval selected" if @interval && @interval.empty?
|
@@ -67,12 +72,12 @@ module Timely
|
|
67
72
|
all_days.select do |date|
|
68
73
|
if @weekdays.has_day?(date.wday)
|
69
74
|
case @interval[:unit]
|
70
|
-
when '
|
75
|
+
when 'week'
|
71
76
|
# 0 = first week, 1 = second week, 2 = third week, etc.
|
72
77
|
nth_week = (date - @from).to_i / 7
|
73
78
|
# true every 2nd week (0, 2, 4, 6, etc.)
|
74
79
|
(nth_week % @interval[:level].to_i).zero?
|
75
|
-
when '
|
80
|
+
when 'week_of_month'
|
76
81
|
week = @interval[:level].to_i
|
77
82
|
(date.mday > (week-1)*7 && date.mday <= week*7)
|
78
83
|
end
|
data/lib/timely/date_range.rb
CHANGED
@@ -1,17 +1,30 @@
|
|
1
|
+
require 'date' # Ensure Date class is loaded for old rubies (1.8)
|
2
|
+
|
1
3
|
module Timely
|
2
4
|
class DateRange < ::Range
|
3
5
|
def initialize(*args)
|
4
6
|
if args.first.is_a?(Range)
|
5
|
-
|
7
|
+
date_range = args.first
|
8
|
+
DateRange.validate_range(date_range.first, date_range.last)
|
9
|
+
super(date_range.first.to_date, date_range.last.to_date)
|
6
10
|
elsif args.size == 1 && args.first.is_a?(Date)
|
7
|
-
|
11
|
+
DateRange.validate_range(args.first, args.last)
|
12
|
+
super(args.first.to_date, args.first.to_date)
|
8
13
|
else
|
9
|
-
|
14
|
+
DateRange.validate_range(args.first, args.last)
|
15
|
+
super(args.first.to_date, args.last.to_date)
|
10
16
|
end
|
11
17
|
end
|
12
18
|
alias_method :start_date, :first
|
13
19
|
alias_method :end_date, :last
|
14
20
|
|
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
|
26
|
+
end
|
27
|
+
|
15
28
|
def self.from_params(start_date, duration = nil)
|
16
29
|
start_date = start_date.to_date
|
17
30
|
duration = [1, duration.to_i].max
|
@@ -34,18 +47,42 @@ module Timely
|
|
34
47
|
end
|
35
48
|
alias_method :duration, :number_of_nights
|
36
49
|
|
37
|
-
def to_s(fmt = '%b %Y')
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
50
|
+
def to_s(fmt = '%b %Y', date_fmt = '%Y-%m-%d')
|
51
|
+
Timely::DateRange.to_s(first, last, fmt, date_fmt)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.to_s(first = nil, last = nil, month_fmt = '%b %Y', date_fmt = default_date_format, time_fmt = nil)
|
55
|
+
time_fmt ||= date_fmt + ' %H:%M'
|
56
|
+
is_date = first.is_a?(Date) || last.is_a?(Date)
|
57
|
+
fmt = is_date ? date_fmt : time_fmt
|
58
|
+
if first && last
|
59
|
+
if first == last
|
42
60
|
first.strftime(fmt)
|
61
|
+
elsif first == first.at_beginning_of_month && last == last.at_end_of_month
|
62
|
+
if first.month == last.month
|
63
|
+
first.strftime(month_fmt)
|
64
|
+
else
|
65
|
+
"#{first.strftime(month_fmt)} to #{last.strftime(month_fmt)}"
|
66
|
+
end
|
43
67
|
else
|
44
|
-
"#{first.strftime(fmt)} to #{last.strftime(fmt)}"
|
68
|
+
"#{first.strftime(fmt)} to #{last.strftime(fmt)}#{" (inclusive)" if is_date}"
|
45
69
|
end
|
70
|
+
elsif first
|
71
|
+
"on or after #{first.strftime(fmt)}"
|
72
|
+
elsif last
|
73
|
+
"on or before #{last.strftime(fmt)}"
|
46
74
|
else
|
47
|
-
"
|
75
|
+
"no date range"
|
48
76
|
end
|
49
77
|
end
|
78
|
+
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def self.default_date_format
|
83
|
+
# ::Date as we want Ruby's Date not Timely::Date
|
84
|
+
date_format = ::Date::DATE_FORMATS[:short] if ::Date.const_defined?('DATE_FORMATS')
|
85
|
+
date_format || '%Y-%m-%d'
|
86
|
+
end
|
50
87
|
end
|
51
88
|
end
|
data/lib/timely/rails.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
require 'timely/rails/extensions'
|
2
|
-
ActiveRecord
|
3
|
-
|
4
|
-
require 'timely/rails/
|
2
|
+
if defined?(ActiveRecord)
|
3
|
+
ActiveRecord::Base.extend Timely::Extensions
|
4
|
+
require 'timely/rails/season'
|
5
|
+
require 'timely/rails/date_group'
|
6
|
+
end
|
7
|
+
require 'timely/rails/date_range_validity_module'
|
8
|
+
require 'timely/rails/calendar_tag'
|
9
|
+
require 'timely/rails/date_time'
|
10
|
+
require 'timely/rails/date'
|
11
|
+
require 'timely/rails/period'
|