by_star 3.0.0 → 4.0.1
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/.github/workflows/mysql.yml +92 -0
- data/.github/workflows/postgresql.yml +99 -0
- data/.gitignore +6 -5
- data/.travis.yml +92 -61
- data/CHANGELOG.md +63 -44
- data/Gemfile +18 -18
- data/MIT-LICENSE +20 -20
- data/README.md +616 -577
- data/Rakefile +18 -18
- data/UPGRADING +4 -6
- data/by_star.gemspec +34 -34
- data/cleaner.rb +24 -24
- data/lib/by_star/base.rb +69 -68
- data/lib/by_star/between.rb +185 -156
- data/lib/by_star/directional.rb +35 -37
- data/lib/by_star/kernel/date.rb +41 -50
- data/lib/by_star/kernel/in_time_zone.rb +20 -0
- data/lib/by_star/kernel/time.rb +41 -41
- data/lib/by_star/normalization.rb +156 -127
- data/lib/by_star/orm/active_record/by_star.rb +75 -61
- data/lib/by_star/orm/mongoid/by_star.rb +90 -76
- data/lib/by_star/orm/mongoid/reorder.rb +23 -23
- data/lib/by_star/version.rb +3 -3
- data/lib/by_star.rb +18 -17
- data/spec/database.yml +15 -15
- data/spec/fixtures/active_record/models.rb +12 -12
- data/spec/fixtures/active_record/schema.rb +19 -19
- data/spec/fixtures/mongoid/models.rb +31 -31
- data/spec/fixtures/shared/seeds.rb +36 -26
- data/spec/gemfiles/Gemfile.rails +5 -0
- data/spec/gemfiles/Gemfile.rails32 +7 -0
- data/spec/gemfiles/Gemfile.rails40 +7 -7
- data/spec/gemfiles/Gemfile.rails41 +7 -7
- data/spec/gemfiles/Gemfile.rails42 +7 -7
- data/spec/gemfiles/Gemfile.rails50 +7 -10
- data/spec/gemfiles/Gemfile.rails51 +7 -10
- data/spec/gemfiles/Gemfile.rails52 +7 -0
- data/spec/gemfiles/Gemfile.rails60 +7 -0
- data/spec/gemfiles/Gemfile.rails61 +7 -0
- data/spec/integration/active_record/active_record_spec.rb +41 -38
- data/spec/integration/mongoid/mongoid_spec.rb +39 -37
- data/spec/integration/shared/at_time.rb +53 -0
- data/spec/integration/shared/between_dates.rb +99 -0
- data/spec/integration/shared/between_times.rb +99 -82
- data/spec/integration/shared/by_calendar_month.rb +55 -55
- data/spec/integration/shared/by_cweek.rb +54 -54
- data/spec/integration/shared/by_day.rb +120 -96
- data/spec/integration/shared/by_direction.rb +126 -172
- data/spec/integration/shared/by_fortnight.rb +48 -48
- data/spec/integration/shared/by_month.rb +50 -50
- data/spec/integration/shared/by_quarter.rb +49 -49
- data/spec/integration/shared/by_week.rb +54 -54
- data/spec/integration/shared/by_weekend.rb +49 -49
- data/spec/integration/shared/by_year.rb +48 -48
- data/spec/integration/shared/index_scope_parameter.rb +111 -0
- data/spec/integration/shared/offset_parameter.rb +32 -32
- data/spec/integration/shared/order_parameter.rb +36 -36
- data/spec/integration/shared/relative.rb +174 -174
- data/spec/spec_helper.rb +33 -29
- data/spec/unit/kernel_date_spec.rb +113 -113
- data/spec/unit/kernel_time_spec.rb +57 -57
- data/spec/unit/normalization_spec.rb +384 -305
- data/tmp/.gitignore +1 -1
- metadata +33 -21
- data/spec/gemfiles/Gemfile.master +0 -6
- data/spec/integration/shared/scope_parameter.rb +0 -73
data/lib/by_star/directional.rb
CHANGED
@@ -1,37 +1,35 @@
|
|
1
|
-
module ByStar
|
2
|
-
|
3
|
-
module Directional
|
4
|
-
|
5
|
-
def before(*args)
|
6
|
-
with_by_star_options(*args) do |time, options|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
field
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
37
|
-
end
|
1
|
+
module ByStar
|
2
|
+
|
3
|
+
module Directional
|
4
|
+
|
5
|
+
def before(*args)
|
6
|
+
with_by_star_options(*args) do |time, options|
|
7
|
+
field = by_star_start_field(options)
|
8
|
+
time = ByStar::Normalization.time(time)
|
9
|
+
by_star_before_query(self, field, time)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
alias_method :before_now, :before
|
13
|
+
|
14
|
+
def after(*args)
|
15
|
+
with_by_star_options(*args) do |time, options|
|
16
|
+
field = by_star_start_field(options)
|
17
|
+
time = ByStar::Normalization.time(time)
|
18
|
+
by_star_after_query(self, field, time)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
alias_method :after_now, :after
|
22
|
+
|
23
|
+
def oldest(*args)
|
24
|
+
with_by_star_options(*args) do |time, options|
|
25
|
+
oldest_query(options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def newest(*args)
|
30
|
+
with_by_star_options(*args) do |time, options|
|
31
|
+
newest_query(options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/by_star/kernel/date.rb
CHANGED
@@ -1,50 +1,41 @@
|
|
1
|
-
module ByStar
|
2
|
-
|
3
|
-
module Kernel
|
4
|
-
|
5
|
-
module Date
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def end_of_calendar_month(*args)
|
44
|
-
end_of_month.end_of_week(*args)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
::Date.__send__(:include, ByStar::Kernel::Date)
|
1
|
+
module ByStar
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
|
5
|
+
module Date
|
6
|
+
|
7
|
+
# A "Weekend" is defined as beginning of Saturday to end of Sunday.
|
8
|
+
# The weekend for a given date will be the the next weekend if the day Mon-Thurs,
|
9
|
+
# otherwise the current weekend if the day is Fri-Sun.
|
10
|
+
def beginning_of_weekend
|
11
|
+
beginning_of_week(:monday).advance(days: 5)
|
12
|
+
end
|
13
|
+
|
14
|
+
def end_of_weekend
|
15
|
+
beginning_of_weekend + 1
|
16
|
+
end
|
17
|
+
|
18
|
+
# A "Fortnight" is defined as a two week period, with the first fortnight of the
|
19
|
+
# year beginning on 1st January.
|
20
|
+
def beginning_of_fortnight
|
21
|
+
beginning_of_year + 14 * ((self - beginning_of_year) / 14).to_i
|
22
|
+
end
|
23
|
+
|
24
|
+
def end_of_fortnight
|
25
|
+
beginning_of_fortnight + 13
|
26
|
+
end
|
27
|
+
|
28
|
+
# A "Calendar Month" is defined as a month as it appears on a calendar, including days form
|
29
|
+
# previous/following months which are part of the first/last weeks of the given month.
|
30
|
+
def beginning_of_calendar_month(*args)
|
31
|
+
beginning_of_month.beginning_of_week(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def end_of_calendar_month(*args)
|
35
|
+
end_of_month.end_of_week(*args)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
::Date.__send__(:include, ByStar::Kernel::Date)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ByStar
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
|
5
|
+
module InTimeZone
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
if method_defined?(:to_time_in_current_zone) && !method_defined?(:in_time_zone)
|
10
|
+
alias_method :in_time_zone, :to_time_in_current_zone
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
::Date.__send__(:include, ByStar::Kernel::InTimeZone)
|
18
|
+
::Time.__send__(:include, ByStar::Kernel::InTimeZone)
|
19
|
+
::DateTime.__send__(:include, ByStar::Kernel::InTimeZone)
|
20
|
+
::ActiveSupport::TimeWithZone.__send__(:include, ByStar::Kernel::InTimeZone)
|
data/lib/by_star/kernel/time.rb
CHANGED
@@ -1,41 +1,41 @@
|
|
1
|
-
module ByStar
|
2
|
-
|
3
|
-
module Kernel
|
4
|
-
|
5
|
-
module Time
|
6
|
-
|
7
|
-
# A "Weekend" is defined as beginning of Saturday to end of Sunday.
|
8
|
-
# The weekend for a given date will be the the next weekend if the day Mon-Thurs,
|
9
|
-
# otherwise the current weekend if the day is Fri-Sun.
|
10
|
-
def beginning_of_weekend
|
11
|
-
beginning_of_week(:monday).advance(days: 5)
|
12
|
-
end
|
13
|
-
|
14
|
-
def end_of_weekend
|
15
|
-
(beginning_of_weekend + 47.hours).end_of_hour
|
16
|
-
end
|
17
|
-
|
18
|
-
# A "Fortnight" is defined as a two week period, with the first fortnight of the
|
19
|
-
# year beginning on 1st January.
|
20
|
-
def beginning_of_fortnight
|
21
|
-
(beginning_of_year + 1.fortnight * ((self - beginning_of_year) / 1.fortnight).to_i).beginning_of_day
|
22
|
-
end
|
23
|
-
|
24
|
-
def end_of_fortnight
|
25
|
-
(beginning_of_fortnight + 13.days).end_of_day
|
26
|
-
end
|
27
|
-
|
28
|
-
# A "Calendar Month" is defined as a month as it appears on a calendar, including days form
|
29
|
-
# previous/following months which are part of the first/last weeks of the given month.
|
30
|
-
def beginning_of_calendar_month(*args)
|
31
|
-
beginning_of_month.beginning_of_week(*args)
|
32
|
-
end
|
33
|
-
|
34
|
-
def end_of_calendar_month(*args)
|
35
|
-
end_of_month.end_of_week(*args)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
::Time.__send__(:include, ByStar::Kernel::Time)
|
1
|
+
module ByStar
|
2
|
+
|
3
|
+
module Kernel
|
4
|
+
|
5
|
+
module Time
|
6
|
+
|
7
|
+
# A "Weekend" is defined as beginning of Saturday to end of Sunday.
|
8
|
+
# The weekend for a given date will be the the next weekend if the day Mon-Thurs,
|
9
|
+
# otherwise the current weekend if the day is Fri-Sun.
|
10
|
+
def beginning_of_weekend
|
11
|
+
beginning_of_week(:monday).advance(days: 5)
|
12
|
+
end
|
13
|
+
|
14
|
+
def end_of_weekend
|
15
|
+
(beginning_of_weekend + 47.hours).end_of_hour
|
16
|
+
end
|
17
|
+
|
18
|
+
# A "Fortnight" is defined as a two week period, with the first fortnight of the
|
19
|
+
# year beginning on 1st January.
|
20
|
+
def beginning_of_fortnight
|
21
|
+
(beginning_of_year + 1.fortnight * ((self - beginning_of_year) / 1.fortnight).to_i).beginning_of_day
|
22
|
+
end
|
23
|
+
|
24
|
+
def end_of_fortnight
|
25
|
+
(beginning_of_fortnight + 13.days).end_of_day
|
26
|
+
end
|
27
|
+
|
28
|
+
# A "Calendar Month" is defined as a month as it appears on a calendar, including days form
|
29
|
+
# previous/following months which are part of the first/last weeks of the given month.
|
30
|
+
def beginning_of_calendar_month(*args)
|
31
|
+
beginning_of_month.beginning_of_week(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def end_of_calendar_month(*args)
|
35
|
+
end_of_month.end_of_week(*args)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
::Time.__send__(:include, ByStar::Kernel::Time)
|
@@ -1,127 +1,156 @@
|
|
1
|
-
module ByStar
|
2
|
-
|
3
|
-
class ParseError < StandardError; end
|
4
|
-
|
5
|
-
module Normalization
|
6
|
-
|
7
|
-
class << self
|
8
|
-
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
case value
|
100
|
-
when
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
def
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
1
|
+
module ByStar
|
2
|
+
|
3
|
+
class ParseError < StandardError; end
|
4
|
+
|
5
|
+
module Normalization
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def date(value)
|
10
|
+
value = parse_time(value) if value.is_a?(String)
|
11
|
+
value = value.try(:in_time_zone) unless value.is_a?(Date)
|
12
|
+
value.try(:to_date)
|
13
|
+
end
|
14
|
+
|
15
|
+
def time(value)
|
16
|
+
value = parse_time(value) if value.is_a?(String)
|
17
|
+
value.try(:in_time_zone)
|
18
|
+
end
|
19
|
+
|
20
|
+
def week(value, options={})
|
21
|
+
value = try_string_to_int(value)
|
22
|
+
case value
|
23
|
+
when Integer then week_integer(value, options)
|
24
|
+
else date(value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def week_integer(value, options={})
|
29
|
+
raise ParseError, 'Week number must be between 0 and 52' unless value.in?(0..52)
|
30
|
+
time = Time.zone.local(options[:year] || Time.zone.now.year)
|
31
|
+
time.beginning_of_year + value.to_i.weeks
|
32
|
+
end
|
33
|
+
|
34
|
+
def cweek(value, options={})
|
35
|
+
_value = value
|
36
|
+
if _value.is_a?(Integer)
|
37
|
+
raise ParseError, 'cweek number must be between 1 and 53' unless value.in?(1..53)
|
38
|
+
_value -= 1
|
39
|
+
end
|
40
|
+
week(_value, options)
|
41
|
+
end
|
42
|
+
|
43
|
+
def fortnight(value, options={})
|
44
|
+
value = try_string_to_int(value)
|
45
|
+
case value
|
46
|
+
when Integer then fortnight_integer(value, options)
|
47
|
+
else date(value)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def fortnight_integer(value, options={})
|
52
|
+
raise ParseError, 'Fortnight number must be between 0 and 26' unless value.in?(0..26)
|
53
|
+
time = Time.zone.local(options[:year] || Time.zone.now.year)
|
54
|
+
time + (value * 2).weeks
|
55
|
+
end
|
56
|
+
|
57
|
+
def quarter(value, options={})
|
58
|
+
value = try_string_to_int(value)
|
59
|
+
case value
|
60
|
+
when Integer then quarter_integer(value, options)
|
61
|
+
else date(value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def quarter_integer(value, options={})
|
66
|
+
raise ParseError, 'Quarter number must be between 1 and 4' unless value.in?(1..4)
|
67
|
+
time = Time.zone.local(options[:year] || Time.zone.now.year)
|
68
|
+
time.beginning_of_year + ((value - 1) * 3).months
|
69
|
+
end
|
70
|
+
|
71
|
+
def month(value, options={})
|
72
|
+
value = try_string_to_int(value)
|
73
|
+
case value
|
74
|
+
when Integer, String then month_integer(value, options)
|
75
|
+
else date(value)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def month_integer(value, options={})
|
80
|
+
year = options[:year] || Time.zone.now.year
|
81
|
+
Time.zone.parse "#{year}-#{value}-01"
|
82
|
+
rescue
|
83
|
+
raise ParseError, 'Month must be a number between 1 and 12 or a month name'
|
84
|
+
end
|
85
|
+
|
86
|
+
def year(value, options={})
|
87
|
+
value = try_string_to_int(value)
|
88
|
+
case value
|
89
|
+
when Integer then year_integer(value)
|
90
|
+
else date(value)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def year_integer(value)
|
95
|
+
Time.zone.local(extrapolate_year(value))
|
96
|
+
end
|
97
|
+
|
98
|
+
def extrapolate_year(value)
|
99
|
+
case value.to_i
|
100
|
+
when 0..69
|
101
|
+
2000 + value
|
102
|
+
when 70..99
|
103
|
+
1900 + value
|
104
|
+
else
|
105
|
+
value.to_i
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def try_string_to_int(value)
|
110
|
+
value.is_a?(String) ? Integer(value) : value
|
111
|
+
rescue
|
112
|
+
value
|
113
|
+
end
|
114
|
+
|
115
|
+
def time_in_units(seconds)
|
116
|
+
days = seconds / 1.day
|
117
|
+
time = Time.at(seconds).utc
|
118
|
+
{ days: days, hour: time.hour, min: time.min, sec: time.sec }
|
119
|
+
end
|
120
|
+
|
121
|
+
def apply_offset_start(time, offset)
|
122
|
+
units = time_in_units(offset)
|
123
|
+
time += units.delete(:days).days
|
124
|
+
time.change(units)
|
125
|
+
end
|
126
|
+
|
127
|
+
def apply_offset_end(time, offset)
|
128
|
+
units = time_in_units(offset)
|
129
|
+
time += units.delete(:days).days
|
130
|
+
(time + 1.day).change(units) - 1.second
|
131
|
+
end
|
132
|
+
|
133
|
+
def extract_range(args)
|
134
|
+
case args[0]
|
135
|
+
when Array, Range then [args[0].first, args[0].last]
|
136
|
+
else args[0..1]
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def parse_time(value)
|
143
|
+
defined?(Chronic) ? parse_time_chronic(value) : parse_time_fallback(value)
|
144
|
+
end
|
145
|
+
|
146
|
+
def parse_time_chronic(value)
|
147
|
+
Chronic.time_class = Time.zone
|
148
|
+
Chronic.parse(value) || raise(ByStar::ParseError, "Chronic could not parse String #{value.inspect}")
|
149
|
+
end
|
150
|
+
|
151
|
+
def parse_time_fallback(value)
|
152
|
+
Time.zone.parse(value) || raise(ByStar::ParseError, "Cannot parse String #{value.inspect}")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|