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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5df770ae3301222917ed286b21cd001dffedfabcbcd957b7645231a85dac6ea9
4
- data.tar.gz: bd565e152c142c751229ff4e3fd8f17f0085f6445722902fb9ba5fe75af4ddf4
3
+ metadata.gz: bd9b91f3f8553c817029a58445250a56093cc07ea8eb856c88798d5afd72d210
4
+ data.tar.gz: e5a67dcedd0eae2113f489f46a472cf1b8b4be45caacc1d8910acc59f70be2a5
5
5
  SHA512:
6
- metadata.gz: eef66c5e59a8054c20647d74cd7beb3749f6683fe359dd7f7effc31c2d659c624a3277b5378039089fd494175515d64cd77eb8a29e8a3ee3917bda65ec708b31
7
- data.tar.gz: 737039391b6228fccabf86725e55e75aa0381044ffbd7d7887d9b480d264ccbaa3b4fcead214efbdbfaa83a24c334818c365cd276140302c2a14f0a11a15de5f
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
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/period`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- TODO: Write usage instructions here
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
- ## Development
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
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
201
+ ### Bug reports
32
202
 
33
- ## Contributing
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
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/period.
205
+ https://github.com/billaul/period/issues
36
206
 
37
207
  ## License
38
208
 
@@ -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 = env_time.now
54
- from -= 1.send(klass) unless method_name.match?(/from_now$/)
55
- from = from.send("beginning_of_#{klass}")
56
- to = count.to_i.send(klass).ago.send("end_of_#{klass}")
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$/)
@@ -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, range.exclude_end?)
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 -(other)
78
- self.class.new((from - other)..(to - other))
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')
@@ -41,12 +41,6 @@ module Period
41
41
  self.class.new(to + duration)
42
42
  end
43
43
 
44
- def ==(other)
45
- raise ArgumentError unless other.class.ancestors.include?(Period::FreePeriod)
46
-
47
- from == other.from && to == other.to
48
- end
49
-
50
44
  def iso_date
51
45
  from
52
46
  end
@@ -1,5 +1,5 @@
1
1
  module Period
2
2
 
3
- VERSION = '1.0.1'.freeze
3
+ VERSION = '1.0.3'.freeze
4
4
 
5
5
  end
@@ -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:
@@ -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
@@ -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["homepage_uri"] = spec.homepage
22
- # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
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.1
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-07 00:00:00.000000000 Z
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
- description: Period.new('01/01/2020'..Time.now)
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: '0'
140
+ version: '2.5'
124
141
  required_rubygems_version: !ruby/object:Gem::Requirement
125
142
  requirements:
126
143
  - - ">="