smart-period 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +180 -10
- data/lib/period.rb +7 -6
- data/lib/period/free_period.rb +19 -8
- data/lib/period/standard_period.rb +0 -6
- data/lib/period/version.rb +1 -1
- data/locales/en.yml +1 -0
- data/locales/fr.yml +24 -0
- data/period.gemspec +7 -3
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd9b91f3f8553c817029a58445250a56093cc07ea8eb856c88798d5afd72d210
|
4
|
+
data.tar.gz: e5a67dcedd0eae2113f489f46a472cf1b8b4be45caacc1d8910acc59f70be2a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea9f3a5074c20e26c9e8718c91263b993bdef3a9e6b8f9b28015d60c67947a403fad37d2f51322f4053f87ca0590973084461a290515dd592a7eb677253dd599
|
7
|
+
data.tar.gz: c703f75c931446e9114d06bacb43f0d613e38a5d21b03721d25d2e1e0b0bef1cb74b29cc73f2df1e7170b48fab6a30ddccda40d58a2f23c85e446616e5e3da6f
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
# Period
|
1
|
+
# Smart-Period
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
Smart-Period aims to simplify Time-range manipulation
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -22,17 +20,189 @@ Or install it yourself as:
|
|
22
20
|
|
23
21
|
## Usage
|
24
22
|
|
25
|
-
|
23
|
+
**Smart-Period** was designed to simplify time-range manipulation, specialy with rails and user input
|
24
|
+
|
25
|
+
**Warning** :
|
26
|
+
- A time-range take place between two date and it's different from an abstract duration of time
|
27
|
+
- **Smart-Period** is limited at full day of time and will always round the starting and ending to the beginning and the ending of the day
|
28
|
+
|
29
|
+
|
30
|
+
### Quick view (TL;DR)
|
31
|
+
``` ruby
|
32
|
+
# Get all user created today
|
33
|
+
User.where(created_at: Period.today)
|
34
|
+
# Get how many weeks there is from the beginning of time ?
|
35
|
+
Period.new('01/01/1970'..Time.now).weeks.count
|
36
|
+
# Is Trump still in charge ?
|
37
|
+
Time.now.in? Period.new('20/01/2017'...'20/01/2021')
|
38
|
+
# Get the week of an arbitrary date
|
39
|
+
Period.week('24/04/1990')
|
40
|
+
# Write a date for me (I18n supported)
|
41
|
+
Period.new('20/01/2017'...'20/01/2021').to_s
|
42
|
+
=> "From the 20 January 2017 to the 19 January 2021 included"
|
43
|
+
```
|
44
|
+
|
45
|
+
### Detailed view
|
46
|
+
|
47
|
+
There's two way to create and manipulate a period of time `FreePeriod` and `StandardPeriod`
|
48
|
+
|
49
|
+
### FreePeriod of time
|
50
|
+
|
51
|
+
You can declare **FreePeriod** as simply as :
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
# With Date objects
|
55
|
+
Period.new(3.month.ago..Date.today)
|
56
|
+
# or with Strings
|
57
|
+
Period.new('01/01/2000'...'01/02/2000')
|
58
|
+
# or with a mix
|
59
|
+
Period.new('01/01/2000'..1.week.ago)
|
60
|
+
# or in a rails Controller with params
|
61
|
+
Period.new(params[:start_date]..params[:end_date])
|
62
|
+
```
|
63
|
+
|
64
|
+
**FreePeriod** can be manipulated with `+` and `-`
|
65
|
+
Doing so will move the start **and** the end of the period
|
66
|
+
```ruby
|
67
|
+
Period.new('01/01/2000'..'05/01/2000') + 3.day
|
68
|
+
# is equal to
|
69
|
+
Period.new('04/01/2000'..'08/01/2000')
|
70
|
+
```
|
71
|
+
|
72
|
+
### Standard Period of time
|
73
|
+
|
74
|
+
Using **StandardPeriod** you are limited to strictly bordered periods of time
|
75
|
+
These periods are `day`, `week`, `month`, `quarter` and `year`
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
# To get the week, 42th day ago
|
79
|
+
Period.week(42.day.ago)
|
80
|
+
# To get the first month of 2020
|
81
|
+
Period.month('01/01/2020')
|
82
|
+
# or if you like it verbious
|
83
|
+
Period::Month.new('01/01/2020')
|
84
|
+
# or if you need the current week
|
85
|
+
Period.week(Time.now)
|
86
|
+
```
|
87
|
+
|
88
|
+
**Note** : If you ask for a `month`, `quarter` of `year`, the day part of your param doesn't matter `01/01/2020` give the same result as `14/01/2020` or `29/01/2020`
|
89
|
+
|
90
|
+
**StandardPeriod** can be manipulated with `+` and `-` and will always return a **StandardPeriod** of the same type
|
91
|
+
```ruby
|
92
|
+
# Subtraction are made from the start of the period
|
93
|
+
Period.month('10/02/2000') - 1.day
|
94
|
+
# Return the previous month
|
95
|
+
# Addition are made from the end
|
96
|
+
Period.month('10/02/2000') + 1.day
|
97
|
+
# Return the next month
|
98
|
+
Period.week('10/02/2000') + 67.day
|
99
|
+
# Return a week
|
100
|
+
```
|
101
|
+
**StandardPeriod** also respond to `.next` and `.prev`
|
102
|
+
```ruby
|
103
|
+
Period.month('01/01/2000').next.next.next
|
104
|
+
# Return the month of April 2020
|
105
|
+
```
|
106
|
+
|
107
|
+
You can quickly access close period of time with `.(last|this|next)_(day|week|month|quarter|year)` and `.yesterday` `.today` `.tomorrow`
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
Period.this_week
|
111
|
+
# Same as Period.week(Time.now) but shorter
|
112
|
+
Period.next_month
|
113
|
+
# Return the next month
|
114
|
+
Period.last_year
|
115
|
+
# Return the last year
|
116
|
+
Period.today
|
117
|
+
# No comment
|
118
|
+
```
|
119
|
+
|
120
|
+
### HasMany smaller-periods
|
26
121
|
|
27
|
-
|
122
|
+
**FreePeriod** and some **StandardPeriod** respond to `.days`, `.weeks`, `.months`, `.quarters` and `.years`
|
123
|
+
These methods return an array of **StandardPeriod** who are include inside the current period
|
28
124
|
|
29
|
-
|
125
|
+
| HasMany -> [\<StandardPeriod>] | .days | .weeks | .months | .quarters | .years |
|
126
|
+
|-------------------------------|:----:|:-----:|:------:|:--------:|:-----:|
|
127
|
+
| FreePeriod | X | X | X | X | X |
|
128
|
+
| StandardPeriod::Day | | | | | |
|
129
|
+
| StandardPeriod::Week | X | | | | |
|
130
|
+
| StandardPeriod::Month | X | X | | | |
|
131
|
+
| StandardPeriod::Quarter | X | X | X | | |
|
132
|
+
| StandardPeriod::Year | X | X | X | X | |
|
133
|
+
|
134
|
+
#### Example
|
135
|
+
```ruby
|
136
|
+
# Get how many weeks there is from the beginning of time ?
|
137
|
+
Period.new('01/01/1970'..Time.now).weeks.count
|
138
|
+
# How many day in the current quarter
|
139
|
+
Period.this_quarter.days.count
|
140
|
+
```
|
141
|
+
|
142
|
+
### BelongsTo greater-period
|
143
|
+
|
144
|
+
**StandardPeriod** respond to `.day`, `.week`, `.month`, `.quarter` and `.year`
|
145
|
+
These methods return a **StandardPeriod** who include the current period
|
146
|
+
**FreePeriod** does not respond to these methods
|
147
|
+
|
148
|
+
| BelongTo -> StandardPeriod | .day | .week | .month | .quarter | .year |
|
149
|
+
|----------------------------|:---:|:----:|:-----:|:-------:|:----:|
|
150
|
+
| FreePeriod | | | | | |
|
151
|
+
| StandardPeriod::Day | | X | X | X | X |
|
152
|
+
| StandardPeriod::Week | | | X | X | X |
|
153
|
+
| StandardPeriod::Month | | | | X | X |
|
154
|
+
| StandardPeriod::Quarter | | | | | X |
|
155
|
+
| StandardPeriod::Year | | | | | |
|
156
|
+
|
157
|
+
#### Example with BelongTo and HasMany
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
# Get the first day, of the last week, of the second month, of the current year
|
161
|
+
Period.this_year.months.second.weeks.last.days.first
|
162
|
+
```
|
163
|
+
|
164
|
+
### ActiveRecord
|
165
|
+
|
166
|
+
As **Period** inherite from **Range**, you can natively use them in **ActiveRecord** query
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
# Get all book published this year
|
170
|
+
Book.where(published_at: Period.this_year)
|
171
|
+
```
|
172
|
+
|
173
|
+
### I18n and to_s
|
174
|
+
|
175
|
+
I18n is supported for `en` and `fr`
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
Period.new('01/01/2000'...'01/02/2001').to_s
|
179
|
+
=> "From the 01 January 2000 to the 31 January 2001 included"
|
180
|
+
I18n.locale = :fr
|
181
|
+
Period.new('01/01/2000'...'01/02/2001').to_s
|
182
|
+
=> "Du 01 janvier 2000 au 31 janvier 2001 inclus"
|
183
|
+
```
|
184
|
+
|
185
|
+
See `locales/en.yml` to implement your language support
|
186
|
+
|
187
|
+
If you need to change the format for a single call
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
period.to_s(format: 'Your Format')
|
191
|
+
# or
|
192
|
+
period.strftime('Your Format')
|
193
|
+
```
|
194
|
+
For a FreePeriod or if you need to print the start and the end of your period differently, use `.i18n`
|
195
|
+
```ruby
|
196
|
+
period.i18n do |from, to|
|
197
|
+
"You have from #{from.strftime(...)} until #{to.strftime(...)} to deliver the money !"
|
198
|
+
end
|
199
|
+
```
|
30
200
|
|
31
|
-
|
201
|
+
### Bug reports
|
32
202
|
|
33
|
-
|
203
|
+
If you discover any bugs, feel free to create an issue on GitHub. Please add as much information as possible to help us in fixing the potential bug. We also encourage you to help even more by forking and sending us a pull request.
|
34
204
|
|
35
|
-
|
205
|
+
https://github.com/billaul/period/issues
|
36
206
|
|
37
207
|
## License
|
38
208
|
|
data/lib/period.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative 'period/version.rb'
|
2
2
|
require 'active_support/all'
|
3
3
|
require 'i18n'
|
4
|
+
require_relative 'numeric.rb'
|
4
5
|
|
5
6
|
require_relative 'period/free_period.rb'
|
6
7
|
require_relative 'period/day.rb'
|
@@ -34,8 +35,8 @@ module Period
|
|
34
35
|
Object.const_get("Period::#{period.capitalize}").new(date)
|
35
36
|
end
|
36
37
|
|
37
|
-
define_method period.to_s do
|
38
|
-
Object.const_get("Period::#{period.capitalize}")
|
38
|
+
define_method period.to_s do |range|
|
39
|
+
Object.const_get("Period::#{period.capitalize}").new(range)
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
@@ -50,10 +51,10 @@ module Period
|
|
50
51
|
|
51
52
|
case last_next
|
52
53
|
when 'last'
|
53
|
-
from =
|
54
|
-
|
55
|
-
|
56
|
-
to =
|
54
|
+
from = count.to_i.send(klass).ago.send("beginning_of_#{klass}")
|
55
|
+
to = env_time.now
|
56
|
+
to -= 1.send(klass) unless method_name.match?(/from_now$/)
|
57
|
+
to = to.send("end_of_#{klass}")
|
57
58
|
when 'next'
|
58
59
|
from = env_time.now
|
59
60
|
from += 1.send(klass) unless method_name.match?(/from_now$/)
|
data/lib/period/free_period.rb
CHANGED
@@ -18,15 +18,16 @@ class Period::FreePeriod < Range
|
|
18
18
|
include Period::HasMany::Years
|
19
19
|
|
20
20
|
def initialize(range)
|
21
|
+
raise ::ArgumentError, I18n.t(:param_must_be_a_range, scope: %i[period free_period]) unless range.class.ancestors.include?(Range)
|
21
22
|
from = range.first
|
22
23
|
to = range.last
|
23
24
|
|
24
25
|
from = time_parse(range.first, I18n.t(:start_date_is_invalid, scope: %i[period free_period])).beginning_of_day
|
25
26
|
to = time_parse(range.last, I18n.t(:end_date_is_invalid, scope: %i[period free_period])).end_of_day
|
26
|
-
|
27
|
+
to = to.prev_day if range.exclude_end?
|
27
28
|
raise ::ArgumentError, I18n.t(:start_is_greater_than_end, scope: %i[period free_period]) if from > to
|
28
29
|
|
29
|
-
super(from, to
|
30
|
+
super(from, to)
|
30
31
|
end
|
31
32
|
|
32
33
|
alias from first
|
@@ -44,10 +45,6 @@ class Period::FreePeriod < Range
|
|
44
45
|
raise NotImplementedError
|
45
46
|
end
|
46
47
|
|
47
|
-
def self.from_date(_date)
|
48
|
-
raise NotImplementedError
|
49
|
-
end
|
50
|
-
|
51
48
|
def include?(other)
|
52
49
|
if other.class.in?([DateTime, Time, ActiveSupport::TimeWithZone])
|
53
50
|
from.to_i <= other.to_i && other.to_i <= to.to_i
|
@@ -74,8 +71,22 @@ class Period::FreePeriod < Range
|
|
74
71
|
days.count.days
|
75
72
|
end
|
76
73
|
|
77
|
-
def -(
|
78
|
-
self.class.new((from -
|
74
|
+
def -(duration)
|
75
|
+
self.class.new((from - duration)..(to - duration))
|
76
|
+
end
|
77
|
+
|
78
|
+
def +(duration)
|
79
|
+
self.class.new((from + duration)..(to + duration))
|
80
|
+
end
|
81
|
+
|
82
|
+
def ==(other)
|
83
|
+
raise ArgumentError unless other.class.ancestors.include?(Period::FreePeriod)
|
84
|
+
|
85
|
+
from == other.from && to == other.to
|
86
|
+
end
|
87
|
+
|
88
|
+
def strftime(format)
|
89
|
+
to_s(format: format)
|
79
90
|
end
|
80
91
|
|
81
92
|
def to_s(format: '%d %B %Y')
|
data/lib/period/version.rb
CHANGED
data/locales/en.yml
CHANGED
@@ -6,6 +6,7 @@ en:
|
|
6
6
|
end_date_is_invalid: The end date is invalid
|
7
7
|
start_is_greater_than_end: The start date is greater than the end date
|
8
8
|
incomparable_error: Cannot compare Arguments
|
9
|
+
param_must_be_a_range: The parameter must inherit from the Range class
|
9
10
|
standard_period:
|
10
11
|
date_is_invalid: The date is invalid
|
11
12
|
day:
|
data/locales/fr.yml
CHANGED
@@ -7,6 +7,7 @@ fr:
|
|
7
7
|
start_is_greater_than_end: Date de début supérieur à la date de fin
|
8
8
|
incomparable_error: Les arguments ne sont pas comparables
|
9
9
|
must_implement_to_datetime: L'argument doit repondre a "to_datetime"
|
10
|
+
param_must_be_a_range: Le paramètre doit hériter de la class Range
|
10
11
|
standard_period:
|
11
12
|
day:
|
12
13
|
default_format: '%{wday} %{day} %{month} %{year}'
|
@@ -18,3 +19,26 @@ fr:
|
|
18
19
|
default_format: '%{quarter_nb} semestre %{year}'
|
19
20
|
year:
|
20
21
|
default_format: '%{year}'
|
22
|
+
date:
|
23
|
+
month_names:
|
24
|
+
-
|
25
|
+
- janvier
|
26
|
+
- février
|
27
|
+
- mars
|
28
|
+
- avril
|
29
|
+
- mai
|
30
|
+
- juin
|
31
|
+
- juillet
|
32
|
+
- août
|
33
|
+
- septembre
|
34
|
+
- octobre
|
35
|
+
- novembre
|
36
|
+
- décembre
|
37
|
+
day_names:
|
38
|
+
- dimanche
|
39
|
+
- lundi
|
40
|
+
- mardi
|
41
|
+
- mercredi
|
42
|
+
- jeudi
|
43
|
+
- vendredi
|
44
|
+
- samedi
|
data/period.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.email = ['billau_l@modulotech.fr']
|
10
10
|
|
11
11
|
spec.summary = 'Manage time ranges without brain damage.'
|
12
|
-
spec.description = "Period.new('01/01/2020'..Time.now)"
|
12
|
+
# spec.description = "Period.new('01/01/2020'..Time.now)"
|
13
13
|
spec.homepage = "https://github.com/billaul/period"
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
@@ -18,8 +18,10 @@ Gem::Specification.new do |spec|
|
|
18
18
|
if spec.respond_to?(:metadata)
|
19
19
|
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
20
20
|
|
21
|
-
spec.metadata["
|
22
|
-
|
21
|
+
spec.metadata["bug_tracker_uri"] = spec.homepage + '/issues'
|
22
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
23
|
+
spec.metadata["documentation_uri"] = spec.homepage
|
24
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
23
25
|
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
24
26
|
else
|
25
27
|
raise "RubyGems 2.0 or newer is required to protect against " \
|
@@ -35,8 +37,10 @@ Gem::Specification.new do |spec|
|
|
35
37
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
36
38
|
spec.require_paths = %w[lib locals]
|
37
39
|
|
40
|
+
spec.required_ruby_version = '~> 2.5'
|
38
41
|
spec.add_runtime_dependency 'activesupport', '5.2.3'
|
39
42
|
spec.add_runtime_dependency 'i18n', '1.6.0'
|
40
43
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
41
44
|
spec.add_development_dependency 'rake', '~> 10.0'
|
45
|
+
spec.add_development_dependency 'rails-i18n', '~> 6.0.0'
|
42
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart-period
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- billau_l
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -66,7 +66,21 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '10.0'
|
69
|
-
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rails-i18n
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 6.0.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 6.0.0
|
83
|
+
description:
|
70
84
|
email:
|
71
85
|
- billau_l@modulotech.fr
|
72
86
|
executables: []
|
@@ -110,7 +124,10 @@ homepage: https://github.com/billaul/period
|
|
110
124
|
licenses:
|
111
125
|
- MIT
|
112
126
|
metadata:
|
127
|
+
bug_tracker_uri: https://github.com/billaul/period/issues
|
113
128
|
homepage_uri: https://github.com/billaul/period
|
129
|
+
documentation_uri: https://github.com/billaul/period
|
130
|
+
source_code_uri: https://github.com/billaul/period
|
114
131
|
post_install_message:
|
115
132
|
rdoc_options: []
|
116
133
|
require_paths:
|
@@ -118,9 +135,9 @@ require_paths:
|
|
118
135
|
- locals
|
119
136
|
required_ruby_version: !ruby/object:Gem::Requirement
|
120
137
|
requirements:
|
121
|
-
- - "
|
138
|
+
- - "~>"
|
122
139
|
- !ruby/object:Gem::Version
|
123
|
-
version: '
|
140
|
+
version: '2.5'
|
124
141
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
142
|
requirements:
|
126
143
|
- - ">="
|