dotiw 5.3.3 → 5.5.0
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/ruby.yml +17 -16
- data/Appraisals +12 -4
- data/CHANGELOG.md +10 -0
- data/CODEOWNERS +2 -0
- data/README.markdown +20 -0
- data/dotiw.gemspec +3 -0
- data/gemfiles/{rails_4.gemfile → rails_7.0.gemfile} +2 -1
- data/gemfiles/rails_7.1.gemfile +11 -0
- data/gemfiles/rails_7.2.gemfile +11 -0
- data/lib/dotiw/locale/dz.yml +60 -0
- data/lib/dotiw/locale/ru.yml +9 -9
- data/lib/dotiw/methods.rb +101 -15
- data/lib/dotiw/time_hash.rb +5 -3
- data/lib/dotiw/version.rb +1 -1
- data/lib/dotiw.rb +1 -1
- data/spec/lib/dotiw_spec.rb +57 -8
- data/spec/lib/i18n/dz.yml +21 -0
- data/spec/lib/i18n/ru.yml +18 -0
- metadata +52 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 32864f97b3b06dc77f8c793e11a5b17b1d2af506bdfac0c559354f3e4eef7998
|
|
4
|
+
data.tar.gz: 20efed42fb0802a836f078f2791d78e7b863005b73780243ad4867bbf653103e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6bb97a0d7bc860b57432dc81cb3d8a7921c6364c5271db648d30984164f26d6f4003e21de28252f958294960df1b0270cc4fbf83ae7602be23096829404ee2fe
|
|
7
|
+
data.tar.gz: e2d4f70428937b7e5c409666612dd7aefbe63e71d884a3738b240c222fc2f36a8df7a66b83fa4d52fef96cd27e7edd3a9fdecb15e497fa46853e9b3922f83663
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
name: Ruby
|
|
2
2
|
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- master
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- master
|
|
3
|
+
on: [push, pull_request]
|
|
10
4
|
|
|
11
5
|
jobs:
|
|
12
6
|
build:
|
|
@@ -15,19 +9,26 @@ jobs:
|
|
|
15
9
|
fail-fast: false
|
|
16
10
|
matrix:
|
|
17
11
|
include:
|
|
18
|
-
- ruby-version:
|
|
19
|
-
- ruby-version:
|
|
20
|
-
- ruby-version: 2
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- ruby-version: 2.
|
|
12
|
+
- ruby-version: 3.4
|
|
13
|
+
- ruby-version: 3.3
|
|
14
|
+
- ruby-version: 3.2
|
|
15
|
+
- ruby-version: 3.1
|
|
16
|
+
- ruby-version: 3.0
|
|
17
|
+
- ruby-version: 2.7
|
|
18
|
+
- ruby-version: 2.7
|
|
24
19
|
gemfile: gemfiles/rails_5.0.gemfile
|
|
25
|
-
- ruby-version: 2.
|
|
20
|
+
- ruby-version: 2.7
|
|
26
21
|
gemfile: gemfiles/rails_5.1.gemfile
|
|
27
|
-
- ruby-version: 2.
|
|
22
|
+
- ruby-version: 2.7
|
|
28
23
|
gemfile: gemfiles/rails_5.2.gemfile
|
|
29
|
-
- ruby-version:
|
|
24
|
+
- ruby-version: 3.4
|
|
30
25
|
gemfile: gemfiles/rails_6.0.gemfile
|
|
26
|
+
- ruby-version: 3.4
|
|
27
|
+
gemfile: gemfiles/rails_7.0.gemfile
|
|
28
|
+
- ruby-version: 3.4
|
|
29
|
+
gemfile: gemfiles/rails_7.1.gemfile
|
|
30
|
+
- ruby-version: 3.4
|
|
31
|
+
gemfile: gemfiles/rails_7.2.gemfile
|
|
31
32
|
steps:
|
|
32
33
|
- uses: actions/checkout@v2
|
|
33
34
|
- name: Set up Ruby
|
data/Appraisals
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
appraise 'rails_4' do
|
|
2
|
-
gem 'rails', '~> 4.0'
|
|
3
|
-
end
|
|
4
|
-
|
|
5
1
|
appraise 'rails_5.0' do
|
|
6
2
|
gem 'rails', '~> 5.0.0'
|
|
7
3
|
end
|
|
@@ -17,3 +13,15 @@ end
|
|
|
17
13
|
appraise 'rails_6.0' do
|
|
18
14
|
gem 'rails', '~> 6.0.0'
|
|
19
15
|
end
|
|
16
|
+
|
|
17
|
+
appraise 'rails_7.0' do
|
|
18
|
+
gem 'rails', '~> 7.0.0'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
appraise 'rails_7.1' do
|
|
22
|
+
gem 'rails', '~> 7.1.0'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
appraise 'rails_7.2' do
|
|
26
|
+
gem 'rails', '~> 7.2.0'
|
|
27
|
+
end
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 5.4.0 (Next)
|
|
2
|
+
|
|
3
|
+
* [#131](https://github.com/radar/distance_of_time_in_words/pull/131): Deprecates `highest_measure_only`. Adds alternate form of `highest_measures` option to permit rounding up whatever part of the duration was previously silently discarded - [@seansfkelley](https://github.com/seansfkelley).
|
|
4
|
+
* [#133](https://github.com/radar/distance_of_time_in_words/pull/133): Test on Ruby 3.0 and 3.1 - [@dblock](https://github.com/dblock).
|
|
5
|
+
* [#134](https://github.com/radar/distance_of_time_in_words/pull/134): Add support for Dzongkha, the National language of Bhutan - [@KinWang-2013](https://github.com/KinWang-2013).
|
|
6
|
+
* [#135](https://github.com/radar/distance_of_time_in_words/pull/135): Add support for Ruby 2.7 and 3.2, removed support for ruby 2.4, 2.5, 2.6 and Rails 4 - [@KinWang-2013](https://github.com/KinWang-2013).
|
|
7
|
+
* [#136](https://github.com/radar/distance_of_time_in_words/pull/136): Add support for Rails 7 - [@KinWang-2013](https://github.com/KinWang-2013).
|
|
8
|
+
* [#139](https://github.com/radar/distance_of_time_in_words/pull/139): Fix bug with pluralization of Russian translations for numbers ending in 1 - [bitberry-dev](https://github.com/bitberry-dev).
|
|
9
|
+
* Your contribution here.
|
|
10
|
+
|
|
1
11
|
## 5.3.3 (2022/04/25)
|
|
2
12
|
|
|
3
13
|
* [#128](https://github.com/radar/distance_of_time_in_words/pull/128): Adds support for numeric values for both the `from_time` and `to_time` arguments in the `#distance_of_time_in_words` helper - [@bjedrocha](https://github.com/bjedrocha).
|
data/CODEOWNERS
ADDED
data/README.markdown
CHANGED
|
@@ -164,6 +164,8 @@ Culling a whole group of measurements of time:
|
|
|
164
164
|
|
|
165
165
|
#### :highest\_measure\_only
|
|
166
166
|
|
|
167
|
+
> **Deprecated**. Use `highest_measures: 1` instead.
|
|
168
|
+
|
|
167
169
|
For times when Rails `distance_of_time_in_words` is not precise enough and `DOTIW` is too precise. For instance, if you only want to know the highest time part (measure) that elapsed between two dates.
|
|
168
170
|
|
|
169
171
|
```ruby
|
|
@@ -189,6 +191,24 @@ When you want variable precision from `DOTIW`:
|
|
|
189
191
|
=> "1 hour and 1 minute"
|
|
190
192
|
```
|
|
191
193
|
|
|
194
|
+
You can also specify what to do with the extra time with the `remainder` option:
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
>> distance_of_time_in_words(Time.now, Time.now + 1.hour + 1.minute + 1.second, true, highest_measures: { max: 2, remainder: :ceiling })
|
|
198
|
+
=> "1 hour and 2 minutes"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Valid options for `remainder` are `:floor` (default), `:ceiling` and `:round`. Note that `:round` is best-effort and makes some simplifying assumptions:
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
# Only the next-largest unit is examined, which can unexpectedly round down in some situations.
|
|
205
|
+
>> distance_of_time_in_words(Time.now, Time.now + 1.week + 3.days + 23.hours, true, highest_measures: { remainder: :round })
|
|
206
|
+
=> "1 week"
|
|
207
|
+
# The variability of some measures (like months) is ignored and the shortest duration of that measure is used.
|
|
208
|
+
>> distance_of_time_in_words(Time.now, Time.now + 1.month + 14.days, true, highest_measures: { remainder: :round })
|
|
209
|
+
=> "2 months"
|
|
210
|
+
```
|
|
211
|
+
|
|
192
212
|
#### :words_connector
|
|
193
213
|
|
|
194
214
|
This is an option for `to_sentence`, defaults to ', '.
|
data/dotiw.gemspec
CHANGED
|
@@ -27,6 +27,9 @@ Gem::Specification.new do |s|
|
|
|
27
27
|
s.add_development_dependency 'rake'
|
|
28
28
|
s.add_development_dependency 'rspec', '~> 3.0'
|
|
29
29
|
s.add_development_dependency 'tzinfo', '~> 1.2.7'
|
|
30
|
+
s.add_development_dependency 'mutex_m'
|
|
31
|
+
s.add_development_dependency 'base64'
|
|
32
|
+
s.add_development_dependency 'bigdecimal'
|
|
30
33
|
|
|
31
34
|
s.files = `git ls-files`.split("\n")
|
|
32
35
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
dz:
|
|
2
|
+
datetime:
|
|
3
|
+
dotiw:
|
|
4
|
+
seconds:
|
|
5
|
+
one: སྐར་ཆ་ ༡
|
|
6
|
+
other: "སྐར་ཆ་ %{count}"
|
|
7
|
+
minutes:
|
|
8
|
+
one: སྐར་མ་ ༡
|
|
9
|
+
other: "སྐར་མ་ %{count}"
|
|
10
|
+
hours:
|
|
11
|
+
one: ཆུ་ཚོད་ ༡
|
|
12
|
+
other: "ཆུ་ཚོད་ %{count}"
|
|
13
|
+
days:
|
|
14
|
+
one: ཉིནམ་ ༡
|
|
15
|
+
other: "ཉིནམ་ %{count}"
|
|
16
|
+
weeks:
|
|
17
|
+
one: བདུན༌ཕྲག་ ༡
|
|
18
|
+
other: "བདུན༌ཕྲག་ %{count}"
|
|
19
|
+
months:
|
|
20
|
+
one: ཟླཝ་ ༡
|
|
21
|
+
other: "ཟླཝ་ %{count}"
|
|
22
|
+
years:
|
|
23
|
+
one: ལོ་ ༡
|
|
24
|
+
other: "ལོ་ %{count}"
|
|
25
|
+
less_than_x: "%{distance} ་ལས་ཉུངམ་"
|
|
26
|
+
dotiw_compact:
|
|
27
|
+
seconds:
|
|
28
|
+
one: སྐར་ཆ་ ༡
|
|
29
|
+
other: "སྐར་ཆ་ %{count}"
|
|
30
|
+
minutes:
|
|
31
|
+
one: སྐར་མ་ ༡
|
|
32
|
+
other: "སྐར་མ་ %{count}"
|
|
33
|
+
hours:
|
|
34
|
+
one: ཆུ་ཚོད་ ༡
|
|
35
|
+
other: "ཆུ་ཚོད་ %{count}"
|
|
36
|
+
days:
|
|
37
|
+
one: ཉིནམ་ ༡
|
|
38
|
+
other: "ཉིནམ་ %{count}"
|
|
39
|
+
weeks:
|
|
40
|
+
one: བདུན༌ཕྲག་ ༡
|
|
41
|
+
other: "བདུན༌ཕྲག་ %{count}"
|
|
42
|
+
months:
|
|
43
|
+
one: ཟླཝ་ ༡
|
|
44
|
+
other: "ཟླཝ་ %{count}"
|
|
45
|
+
years:
|
|
46
|
+
one: ལོ་ ༡
|
|
47
|
+
other: "ལོ་ %{count}"
|
|
48
|
+
less_than_x: "%{distance} ་ལས་ཉུངམ"
|
|
49
|
+
words_connector: ""
|
|
50
|
+
two_words_connector: " དང་ "
|
|
51
|
+
last_word_connector: " དང་ "
|
|
52
|
+
about_x_years:
|
|
53
|
+
one: ལོ་ ༡ ་དེ་ཅིག
|
|
54
|
+
any: "ལོ་ %{count} ་དེ་ཅིག"
|
|
55
|
+
over_x_years:
|
|
56
|
+
one: "ལོ་ ༡ ་ལས་ལྷགཔ་ཅིག"
|
|
57
|
+
other: "ལོ་ %{count} ་ལས་ལྷགཔ་ཅིག"
|
|
58
|
+
almost_x_years:
|
|
59
|
+
one: ལོ་ ༡ ་མ་ལྷགཔ་ཅིག
|
|
60
|
+
any: "ལོ་ %{count} ་མ་ལྷགཔ་ཅིག"
|
data/lib/dotiw/locale/ru.yml
CHANGED
|
@@ -39,22 +39,22 @@ ru:
|
|
|
39
39
|
less_than_x: "меньше, чем %{distance}"
|
|
40
40
|
dotiw_compact:
|
|
41
41
|
seconds:
|
|
42
|
-
one:
|
|
42
|
+
one: "%{count}с"
|
|
43
43
|
other: "%{count}с"
|
|
44
44
|
minutes:
|
|
45
|
-
one:
|
|
45
|
+
one: "%{count}м"
|
|
46
46
|
other: "%{count}м"
|
|
47
47
|
hours:
|
|
48
|
-
one:
|
|
48
|
+
one: "%{count}ч"
|
|
49
49
|
other: "%{count}ч"
|
|
50
50
|
days:
|
|
51
|
-
one:
|
|
51
|
+
one: "%{count}д"
|
|
52
52
|
other: "%{count}д"
|
|
53
53
|
weeks:
|
|
54
|
-
one:
|
|
54
|
+
one: "%{count}н"
|
|
55
55
|
other: "%{count}н"
|
|
56
56
|
months:
|
|
57
|
-
one:
|
|
57
|
+
one: "%{count}ме"
|
|
58
58
|
other: "%{count}ме"
|
|
59
59
|
years:
|
|
60
60
|
one: "%{count}г"
|
|
@@ -66,11 +66,11 @@ ru:
|
|
|
66
66
|
two_words_connector: ""
|
|
67
67
|
last_word_connector: ""
|
|
68
68
|
about_x_years:
|
|
69
|
-
one:
|
|
69
|
+
one: "~%{count}г"
|
|
70
70
|
any: "~%{count}г"
|
|
71
71
|
over_x_years:
|
|
72
|
-
one: "
|
|
72
|
+
one: ">%{count}г"
|
|
73
73
|
other: ">%{count}г"
|
|
74
74
|
almost_x_years:
|
|
75
|
-
one:
|
|
75
|
+
one: "~%{count}г"
|
|
76
76
|
any: "~%{count}г"
|
data/lib/dotiw/methods.rb
CHANGED
|
@@ -44,6 +44,31 @@ module DOTIW
|
|
|
44
44
|
|
|
45
45
|
private
|
|
46
46
|
|
|
47
|
+
# How many of each measure is necessary to round up to one of the next-largest measure. Note
|
|
48
|
+
# that for simplicity of implementation, we only check one measure when seeing if we should
|
|
49
|
+
# round up. This means that rounding up days to weeks, for instance, cannot draw the line at 3
|
|
50
|
+
# days and 12 hours, but instead either 3 or 4 (whole) days. Let's not even talk about weeks
|
|
51
|
+
# rounding up to months.
|
|
52
|
+
ROUNDING_THRESHOLDS = {
|
|
53
|
+
seconds: 30,
|
|
54
|
+
minutes: 30,
|
|
55
|
+
hours: 12,
|
|
56
|
+
days: 4,
|
|
57
|
+
weeks: 2,
|
|
58
|
+
months: 6,
|
|
59
|
+
years: Float::INFINITY,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ROLLUP_THRESHOLDS = {
|
|
63
|
+
seconds: 60,
|
|
64
|
+
minutes: 60,
|
|
65
|
+
hours: 24,
|
|
66
|
+
days: 7,
|
|
67
|
+
weeks: 4, # !!!
|
|
68
|
+
months: 12,
|
|
69
|
+
years: Float::INFINITY,
|
|
70
|
+
}
|
|
71
|
+
|
|
47
72
|
def normalize_distance_of_time_argument_to_time(value)
|
|
48
73
|
if value.is_a?(Numeric)
|
|
49
74
|
Time.at(value)
|
|
@@ -63,23 +88,29 @@ module DOTIW
|
|
|
63
88
|
end
|
|
64
89
|
|
|
65
90
|
def _display_time_in_words(hash, options = {})
|
|
91
|
+
hash = hash.dup
|
|
92
|
+
|
|
66
93
|
options = options.reverse_merge(
|
|
67
94
|
include_seconds: false
|
|
68
95
|
).symbolize_keys!
|
|
69
96
|
|
|
97
|
+
discarded_hash = {}
|
|
98
|
+
|
|
70
99
|
include_seconds = options.delete(:include_seconds)
|
|
71
|
-
hash.delete(:seconds) if !include_seconds && hash[:minutes]
|
|
100
|
+
discarded_hash[:seconds] = hash.delete(:seconds) if !include_seconds && hash[:minutes]
|
|
72
101
|
|
|
73
102
|
options[:except] = Array.wrap(options[:except]).map!(&:to_sym) if options[:except]
|
|
74
103
|
options[:only] = Array.wrap(options[:only]).map!(&:to_sym) if options[:only]
|
|
75
104
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
(options[:only] && !options[:only].include?(key))
|
|
105
|
+
DOTIW::TimeHash::TIME_FRACTIONS.each do |fraction|
|
|
106
|
+
if options[:except]&.include?(fraction) || (options[:only] && !options[:only].include?(fraction))
|
|
107
|
+
discarded_hash[fraction] = hash.delete fraction
|
|
108
|
+
end
|
|
81
109
|
end
|
|
82
110
|
|
|
111
|
+
hash.delete_if { |key, value| value.nil? || value.zero? }
|
|
112
|
+
discarded_hash.delete_if { |key, value| value.nil? || value.zero? }
|
|
113
|
+
|
|
83
114
|
i18n_scope = options.delete(:scope) || DOTIW::DEFAULT_I18N_SCOPE
|
|
84
115
|
if hash.empty?
|
|
85
116
|
fractions = DOTIW::TimeHash::TIME_FRACTIONS
|
|
@@ -94,16 +125,22 @@ module DOTIW
|
|
|
94
125
|
end
|
|
95
126
|
end
|
|
96
127
|
|
|
97
|
-
output = []
|
|
98
|
-
I18n.with_options locale: options[:locale], scope: i18n_scope do |locale|
|
|
99
|
-
output = hash.map { |key, value| locale.t(key, count: value) }
|
|
100
|
-
end
|
|
101
|
-
|
|
102
128
|
options.delete(:except)
|
|
103
129
|
options.delete(:only)
|
|
104
|
-
|
|
105
|
-
highest_measures =
|
|
106
|
-
|
|
130
|
+
|
|
131
|
+
highest_measures = _compute_highest_measures! options
|
|
132
|
+
if highest_measures
|
|
133
|
+
high_entries, low_entries = hash.to_a.partition.with_index { |_, index| index < highest_measures[:max] }
|
|
134
|
+
hash = high_entries.to_h
|
|
135
|
+
discarded_hash.merge! low_entries.to_h
|
|
136
|
+
|
|
137
|
+
_maybe_round! hash, discarded_hash, highest_measures[:remainder]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
phrases = []
|
|
141
|
+
I18n.with_options locale: options[:locale], scope: i18n_scope do |locale|
|
|
142
|
+
phrases = hash.map { |key, value| locale.t(key, count: value) }
|
|
143
|
+
end
|
|
107
144
|
|
|
108
145
|
options[:words_connector] ||= I18n.translate :"#{i18n_scope}.words_connector",
|
|
109
146
|
default: :'support.array.words_connector',
|
|
@@ -115,7 +152,56 @@ module DOTIW
|
|
|
115
152
|
default: :'support.array.last_word_connector',
|
|
116
153
|
locale: options[:locale]
|
|
117
154
|
|
|
118
|
-
|
|
155
|
+
phrases.to_sentence(options.except(:accumulate_on, :compact))
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def _compute_highest_measures!(options)
|
|
159
|
+
highest_measures = options.delete(:highest_measures)
|
|
160
|
+
highest_measures = 1 if options.delete(:highest_measure_only)
|
|
161
|
+
highest_measures = { max: highest_measures } if highest_measures.is_a?(Integer)
|
|
162
|
+
highest_measures = highest_measures.reverse_merge(max: 1, remainder: :floor) if highest_measures
|
|
163
|
+
|
|
164
|
+
highest_measures
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def _maybe_round!(hash, discarded_hash, remainder)
|
|
168
|
+
smallest_measure_index = DOTIW::TimeHash::TIME_FRACTIONS.index hash.to_a.last[0]
|
|
169
|
+
smallest_measure = DOTIW::TimeHash::TIME_FRACTIONS[smallest_measure_index]
|
|
170
|
+
|
|
171
|
+
case remainder
|
|
172
|
+
when :floor
|
|
173
|
+
# Nothing to do.
|
|
174
|
+
when :ceiling
|
|
175
|
+
# We already filtered out zeroes, so non-empty also means non-zero.
|
|
176
|
+
if !discarded_hash.empty?
|
|
177
|
+
hash[smallest_measure] += 1
|
|
178
|
+
_rollup! hash, smallest_measure_index
|
|
179
|
+
end
|
|
180
|
+
when :round
|
|
181
|
+
# If our smallest measure is already the smallest possible measure, there is no next
|
|
182
|
+
# smallest measure to inspect to see if we need to round up.
|
|
183
|
+
return if smallest_measure_index == 0
|
|
184
|
+
|
|
185
|
+
next_smallest_measure = DOTIW::TimeHash::TIME_FRACTIONS[smallest_measure_index - 1]
|
|
186
|
+
if discarded_hash.fetch(next_smallest_measure, 0) >= ROUNDING_THRESHOLDS[next_smallest_measure]
|
|
187
|
+
hash[smallest_measure] += 1
|
|
188
|
+
_rollup! hash, smallest_measure_index
|
|
189
|
+
end
|
|
190
|
+
else
|
|
191
|
+
raise ArgumentError, "unrecognized remainder value #{remainder.inspect}"
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def _rollup!(hash, smallest_measure_index)
|
|
196
|
+
DOTIW::TimeHash::TIME_FRACTIONS[smallest_measure_index..-1].each_with_index do |fraction, index|
|
|
197
|
+
if hash.fetch(fraction, 0) >= ROLLUP_THRESHOLDS[fraction]
|
|
198
|
+
hash.delete fraction
|
|
199
|
+
next_fraction = DOTIW::TimeHash::TIME_FRACTIONS[smallest_measure_index + index + 1]
|
|
200
|
+
hash[next_fraction] = hash.fetch(next_fraction, 0) + 1
|
|
201
|
+
else
|
|
202
|
+
break
|
|
203
|
+
end
|
|
204
|
+
end
|
|
119
205
|
end
|
|
120
206
|
end
|
|
121
207
|
end
|
data/lib/dotiw/time_hash.rb
CHANGED
|
@@ -43,8 +43,6 @@ module DOTIW
|
|
|
43
43
|
def build_time_hash
|
|
44
44
|
if accumulate_on = options[:accumulate_on]
|
|
45
45
|
accumulate_on = accumulate_on.to_sym
|
|
46
|
-
return build_time_hash if accumulate_on == :years
|
|
47
|
-
|
|
48
46
|
TIME_FRACTIONS.index(accumulate_on).downto(0) { |i| send("build_#{TIME_FRACTIONS[i]}") }
|
|
49
47
|
else
|
|
50
48
|
while distance > 0
|
|
@@ -91,11 +89,15 @@ module DOTIW
|
|
|
91
89
|
def build_months
|
|
92
90
|
build_years_months_weeks_days
|
|
93
91
|
|
|
94
|
-
if (years = output.delete(:years)) > 0
|
|
92
|
+
if options[:accumulate_on]&.to_sym == :months && (years = output.delete(:years)) > 0
|
|
95
93
|
output[:months] += (years * 12)
|
|
96
94
|
end
|
|
97
95
|
end
|
|
98
96
|
|
|
97
|
+
def build_years
|
|
98
|
+
build_years_months_weeks_days
|
|
99
|
+
end
|
|
100
|
+
|
|
99
101
|
def build_years_months_weeks_days
|
|
100
102
|
months = (largest.year - smallest.year) * 12 + (largest.month - smallest.month)
|
|
101
103
|
years, months = months.divmod(12)
|
data/lib/dotiw/version.rb
CHANGED
data/lib/dotiw.rb
CHANGED
data/spec/lib/dotiw_spec.rb
CHANGED
|
@@ -13,10 +13,12 @@ describe 'A better distance_of_time_in_words' do
|
|
|
13
13
|
include DOTIW::Methods
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
START_TIME = '01-08-2009'.to_time
|
|
16
|
+
START_TIME = '01-08-2009'.to_time(:utc)
|
|
17
17
|
|
|
18
18
|
before do
|
|
19
19
|
I18n.locale = :en
|
|
20
|
+
ActiveSupport.to_time_preserves_timezone = :zone
|
|
21
|
+
|
|
20
22
|
allow(Time).to receive(:now).and_return(START_TIME)
|
|
21
23
|
allow(Time.zone).to receive(:now).and_return(START_TIME)
|
|
22
24
|
end
|
|
@@ -113,12 +115,18 @@ describe 'A better distance_of_time_in_words' do
|
|
|
113
115
|
context category do
|
|
114
116
|
fixtures.each_pair do |k, v|
|
|
115
117
|
it v do
|
|
118
|
+
options = {
|
|
119
|
+
locale: lang
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
options[:compact] = true if category.split.include?('compact')
|
|
123
|
+
|
|
116
124
|
expect(
|
|
117
125
|
distance_of_time_in_words(
|
|
118
126
|
START_TIME,
|
|
119
127
|
START_TIME + eval(k),
|
|
120
128
|
true,
|
|
121
|
-
|
|
129
|
+
options
|
|
122
130
|
)
|
|
123
131
|
).to eq(v)
|
|
124
132
|
end
|
|
@@ -165,7 +173,7 @@ describe 'A better distance_of_time_in_words' do
|
|
|
165
173
|
[Time.zone.now, Time.zone.now + 15.days - 1.minute, '14 days, 23 hours, and 59 minutes'],
|
|
166
174
|
[Time.zone.now, Time.zone.now + 29.days - 1.minute, '28 days, 23 hours, and 59 minutes'],
|
|
167
175
|
[Time.zone.now, Time.zone.now + 30.days - 1.minute, '29 days, 23 hours, and 59 minutes'],
|
|
168
|
-
[Time.zone.now, Time.zone.now + 31.
|
|
176
|
+
[Time.zone.now, Time.zone.now + 31.day - 1.minute, '30 days, 23 hours, and 59 minutes'],
|
|
169
177
|
[Time.zone.now, Time.zone.now + 32.days - 1.minute, '31 days, 23 hours, and 59 minutes'],
|
|
170
178
|
[Time.zone.now, Time.zone.now + 33.days - 1.minute, '32 days, 23 hours, and 59 minutes']
|
|
171
179
|
].each do |start, finish, output|
|
|
@@ -211,7 +219,8 @@ describe 'A better distance_of_time_in_words' do
|
|
|
211
219
|
START_TIME + 2.day + 10_000.hour + 10.second,
|
|
212
220
|
:months,
|
|
213
221
|
'13 months, 3 weeks, 1 day, 16 hours, and 10 seconds'],
|
|
214
|
-
['2015-1-15'.to_time, '2016-3-15'.to_time, :months, '14 months']
|
|
222
|
+
['2015-1-15'.to_time, '2016-3-15'.to_time, :months, '14 months'],
|
|
223
|
+
['2015-1-15'.to_time, '2016-3-15'.to_time, :years, '1 year and 2 months']
|
|
215
224
|
].each do |start, finish, accumulator, output|
|
|
216
225
|
it "should be #{output}" do
|
|
217
226
|
expect(distance_of_time_in_words(start, finish, true, accumulate_on: accumulator)).to eq(output)
|
|
@@ -329,7 +338,7 @@ describe 'A better distance_of_time_in_words' do
|
|
|
329
338
|
{ highest_measures: 3 },
|
|
330
339
|
'1 year and 2 weeks'],
|
|
331
340
|
[START_TIME,
|
|
332
|
-
START_TIME + 1.
|
|
341
|
+
START_TIME + 1.day,
|
|
333
342
|
{ only: %i[years months] },
|
|
334
343
|
'less than 1 month'],
|
|
335
344
|
[START_TIME,
|
|
@@ -337,15 +346,55 @@ describe 'A better distance_of_time_in_words' do
|
|
|
337
346
|
{ except: %i[hours minutes seconds] },
|
|
338
347
|
'less than 1 day'],
|
|
339
348
|
[START_TIME,
|
|
340
|
-
START_TIME + 1.
|
|
349
|
+
START_TIME + 1.day,
|
|
341
350
|
{ highest_measures: 1, only: %i[years months] },
|
|
342
|
-
'less than 1 month']
|
|
351
|
+
'less than 1 month'],
|
|
352
|
+
[START_TIME,
|
|
353
|
+
START_TIME + 1.day + 1.hour,
|
|
354
|
+
{ highest_measures: {} },
|
|
355
|
+
'1 day'],
|
|
356
|
+
[START_TIME,
|
|
357
|
+
START_TIME + 1.day + 1.hour,
|
|
358
|
+
{ highest_measures: { remainder: :floor} },
|
|
359
|
+
'1 day'],
|
|
360
|
+
[START_TIME,
|
|
361
|
+
START_TIME + 1.year + 1.minute,
|
|
362
|
+
{ highest_measures: { remainder: :ceiling } },
|
|
363
|
+
'2 years'],
|
|
364
|
+
[START_TIME,
|
|
365
|
+
START_TIME + 1.day + 2.hours + 30.minutes,
|
|
366
|
+
{ highest_measures: { max: 2, remainder: :round } },
|
|
367
|
+
'1 day and 3 hours'],
|
|
368
|
+
[START_TIME,
|
|
369
|
+
START_TIME + 1.day + 23.hours + 59.minutes + 59.seconds,
|
|
370
|
+
{ highest_measures: { max: 3, remainder: :round } },
|
|
371
|
+
'2 days'],
|
|
372
|
+
[START_TIME,
|
|
373
|
+
START_TIME + 1.day,
|
|
374
|
+
{ highest_measures: { remainder: :ceiling }, only: :months },
|
|
375
|
+
'less than 1 month'],
|
|
376
|
+
[START_TIME,
|
|
377
|
+
# Simplistic rounding: one would expect this to round up to a second week.
|
|
378
|
+
START_TIME + 1.week + 3.days + 23.hours,
|
|
379
|
+
{ highest_measures: { remainder: :round } },
|
|
380
|
+
'1 week'],
|
|
381
|
+
[START_TIME,
|
|
382
|
+
# Simplistic rounding: in some months, 15 days is less than half, but we always round it up.
|
|
383
|
+
START_TIME + 1.month + 14.days,
|
|
384
|
+
{ highest_measures: { remainder: :round } },
|
|
385
|
+
'2 months'],
|
|
343
386
|
].each do |start, finish, options, output|
|
|
344
387
|
it "should be #{output}" do
|
|
345
388
|
expect(distance_of_time_in_words(start, finish, true, options)).to eq(output)
|
|
346
389
|
end
|
|
347
390
|
end
|
|
348
391
|
|
|
392
|
+
it "raises ArgumentError when an unrecognized value is passed for highest_measure.remainder" do
|
|
393
|
+
expect do
|
|
394
|
+
distance_of_time_in_words(START_TIME, START_TIME + 1.day, true, { highest_measures: { remainder: :oops }})
|
|
395
|
+
end.to raise_error(ArgumentError)
|
|
396
|
+
end
|
|
397
|
+
|
|
349
398
|
if defined?(ActionView)
|
|
350
399
|
describe 'ActionView without include seconds argument' do
|
|
351
400
|
[
|
|
@@ -397,7 +446,7 @@ describe 'A better distance_of_time_in_words' do
|
|
|
397
446
|
expect(distance_of_time_in_words(start, finish, true, options)).to eq(output)
|
|
398
447
|
end
|
|
399
448
|
end
|
|
400
|
-
|
|
449
|
+
|
|
401
450
|
context 'via ActionController::Base.helpers' do
|
|
402
451
|
it '#distance_of_time_in_words' do
|
|
403
452
|
end_time = START_TIME + 1.year + 2.months + 3.weeks + 4.days + 5.hours + 6.minutes + 7.seconds
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
seconds:
|
|
2
|
+
1.second: སྐར་ཆ་ ༡
|
|
3
|
+
3.seconds: སྐར་ཆ་ 3
|
|
4
|
+
minutes:
|
|
5
|
+
1.minute: སྐར་མ་ ༡
|
|
6
|
+
20.minutes: སྐར་མ་ 20
|
|
7
|
+
hours:
|
|
8
|
+
1.hour: ཆུ་ཚོད་ ༡
|
|
9
|
+
5.hours: ཆུ་ཚོད་ 5
|
|
10
|
+
days:
|
|
11
|
+
1.day: ཉིནམ་ ༡
|
|
12
|
+
6.days: ཉིནམ་ 6
|
|
13
|
+
weeks:
|
|
14
|
+
1.week: བདུན༌ཕྲག་ ༡
|
|
15
|
+
2.weeks: བདུན༌ཕྲག་ 2
|
|
16
|
+
months:
|
|
17
|
+
1.month: ཟླཝ་ ༡
|
|
18
|
+
9.months: ཟླཝ་ 9
|
|
19
|
+
years:
|
|
20
|
+
1.year: ལོ་ ༡
|
|
21
|
+
3.years: ལོ་ 3
|
data/spec/lib/i18n/ru.yml
CHANGED
|
@@ -3,3 +3,21 @@ seconds:
|
|
|
3
3
|
1.second: 1 секунда
|
|
4
4
|
minutes:
|
|
5
5
|
1.minute: 1 минута
|
|
6
|
+
compact seconds:
|
|
7
|
+
1.second: 1с
|
|
8
|
+
11.seconds: 11с
|
|
9
|
+
21.seconds: 21с
|
|
10
|
+
compact minutes:
|
|
11
|
+
1.minute: 1м
|
|
12
|
+
11.minutes: 11м
|
|
13
|
+
21.minutes: 21м
|
|
14
|
+
compact hours:
|
|
15
|
+
1.hour: 1ч
|
|
16
|
+
11.hours: 11ч
|
|
17
|
+
21.hours: 21ч
|
|
18
|
+
compact days:
|
|
19
|
+
1.day: 1д
|
|
20
|
+
compact years:
|
|
21
|
+
1.year: 1г
|
|
22
|
+
11.years: 11г
|
|
23
|
+
21.years: 21г
|
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dotiw
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Bigg
|
|
8
8
|
- Lauran Jansen
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: activesupport
|
|
@@ -123,6 +122,48 @@ dependencies:
|
|
|
123
122
|
- - "~>"
|
|
124
123
|
- !ruby/object:Gem::Version
|
|
125
124
|
version: 1.2.7
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: mutex_m
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: base64
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: bigdecimal
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '0'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - ">="
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '0'
|
|
126
167
|
description: |-
|
|
127
168
|
dotiw is a gem for Rails that overrides the
|
|
128
169
|
default distance_of_time_in_words and provides
|
|
@@ -141,6 +182,7 @@ files:
|
|
|
141
182
|
- ".rspec"
|
|
142
183
|
- Appraisals
|
|
143
184
|
- CHANGELOG.md
|
|
185
|
+
- CODEOWNERS
|
|
144
186
|
- CONTRIBUTING.md
|
|
145
187
|
- Gemfile
|
|
146
188
|
- MIT-LICENSE
|
|
@@ -149,16 +191,19 @@ files:
|
|
|
149
191
|
- benchmarks/time_hash_bench.rb
|
|
150
192
|
- dotiw.gemspec
|
|
151
193
|
- gemfiles/.bundle/config
|
|
152
|
-
- gemfiles/rails_4.gemfile
|
|
153
194
|
- gemfiles/rails_5.0.gemfile
|
|
154
195
|
- gemfiles/rails_5.1.gemfile
|
|
155
196
|
- gemfiles/rails_5.2.gemfile
|
|
156
197
|
- gemfiles/rails_6.0.gemfile
|
|
198
|
+
- gemfiles/rails_7.0.gemfile
|
|
199
|
+
- gemfiles/rails_7.1.gemfile
|
|
200
|
+
- gemfiles/rails_7.2.gemfile
|
|
157
201
|
- lib/dotiw.rb
|
|
158
202
|
- lib/dotiw/action_view/helpers/date_helper.rb
|
|
159
203
|
- lib/dotiw/locale/ar.yml
|
|
160
204
|
- lib/dotiw/locale/da.yml
|
|
161
205
|
- lib/dotiw/locale/de.yml
|
|
206
|
+
- lib/dotiw/locale/dz.yml
|
|
162
207
|
- lib/dotiw/locale/en.yml
|
|
163
208
|
- lib/dotiw/locale/es.yml
|
|
164
209
|
- lib/dotiw/locale/fr.yml
|
|
@@ -182,6 +227,7 @@ files:
|
|
|
182
227
|
- spec/lib/i18n/ar.yml
|
|
183
228
|
- spec/lib/i18n/da.yml
|
|
184
229
|
- spec/lib/i18n/de.yml
|
|
230
|
+
- spec/lib/i18n/dz.yml
|
|
185
231
|
- spec/lib/i18n/en.yml
|
|
186
232
|
- spec/lib/i18n/es.yml
|
|
187
233
|
- spec/lib/i18n/fr.yml
|
|
@@ -203,7 +249,6 @@ homepage: https://github.com/radar/distance_of_time_in_words
|
|
|
203
249
|
licenses:
|
|
204
250
|
- MIT
|
|
205
251
|
metadata: {}
|
|
206
|
-
post_install_message:
|
|
207
252
|
rdoc_options: []
|
|
208
253
|
require_paths:
|
|
209
254
|
- lib
|
|
@@ -218,8 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
218
263
|
- !ruby/object:Gem::Version
|
|
219
264
|
version: '0'
|
|
220
265
|
requirements: []
|
|
221
|
-
rubygems_version: 3.
|
|
222
|
-
signing_key:
|
|
266
|
+
rubygems_version: 3.6.9
|
|
223
267
|
specification_version: 4
|
|
224
268
|
summary: Better distance_of_time_in_words for Rails
|
|
225
269
|
test_files:
|
|
@@ -227,6 +271,7 @@ test_files:
|
|
|
227
271
|
- spec/lib/i18n/ar.yml
|
|
228
272
|
- spec/lib/i18n/da.yml
|
|
229
273
|
- spec/lib/i18n/de.yml
|
|
274
|
+
- spec/lib/i18n/dz.yml
|
|
230
275
|
- spec/lib/i18n/en.yml
|
|
231
276
|
- spec/lib/i18n/es.yml
|
|
232
277
|
- spec/lib/i18n/fr.yml
|