dotiw 4.0.1 → 5.0.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 +45 -0
- data/.rspec +2 -0
- data/Appraisals +19 -0
- data/CHANGELOG.md +20 -6
- data/Gemfile +2 -0
- data/MIT-LICENSE +1 -1
- data/README.markdown +131 -62
- data/Rakefile +3 -1
- data/dotiw.gemspec +16 -18
- data/gemfiles/rails_4.gemfile +5 -3
- data/gemfiles/rails_5.0.gemfile +5 -3
- data/gemfiles/rails_5.1.gemfile +5 -3
- data/gemfiles/rails_5.2.gemfile +9 -0
- data/gemfiles/rails_6.0.gemfile +9 -0
- data/lib/dotiw.rb +22 -11
- data/lib/dotiw/action_view/helpers/date_helper.rb +24 -0
- data/lib/dotiw/locale/ar.yml +34 -27
- data/lib/dotiw/locale/pl.yml +7 -0
- data/lib/dotiw/methods.rb +91 -0
- data/lib/dotiw/time_hash.rb +38 -32
- data/lib/dotiw/version.rb +2 -2
- data/spec/lib/dotiw_spec.rb +197 -155
- data/spec/spec_helper.rb +2 -9
- metadata +35 -31
- data/.travis.yml +0 -27
- data/lib/dotiw/action_view_ext/helpers/date_helper.rb +0 -103
data/gemfiles/rails_4.gemfile
CHANGED
data/gemfiles/rails_5.0.gemfile
CHANGED
data/gemfiles/rails_5.1.gemfile
CHANGED
data/lib/dotiw.rb
CHANGED
@@ -1,30 +1,41 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'i18n'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
require 'dotiw/action_view_ext/helpers/date_helper'
|
8
|
-
end
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext'
|
9
7
|
|
10
8
|
module DOTIW
|
9
|
+
extend ActiveSupport::Autoload
|
10
|
+
|
11
|
+
eager_autoload do
|
12
|
+
autoload :VERSION, 'dotiw/version'
|
13
|
+
autoload :TimeHash, 'dotiw/time_hash'
|
14
|
+
autoload :Methods, 'dotiw/methods'
|
15
|
+
end
|
16
|
+
|
11
17
|
extend self
|
12
|
-
|
13
|
-
autoload :VERSION, 'dotiw/version'
|
14
|
-
autoload :TimeHash, 'dotiw/time_hash'
|
15
18
|
|
16
19
|
DEFAULT_I18N_SCOPE = :'datetime.dotiw'
|
17
20
|
|
18
|
-
def init_i18n
|
21
|
+
def init_i18n!
|
19
22
|
I18n.load_path.unshift(*locale_files)
|
20
23
|
I18n.reload!
|
21
24
|
end
|
22
25
|
|
23
|
-
protected
|
26
|
+
protected
|
27
|
+
|
24
28
|
# Returns all locale files shipped with library
|
25
29
|
def locale_files
|
26
30
|
Dir[File.join(File.dirname(__FILE__), 'dotiw', 'locale', '**/*')]
|
27
31
|
end
|
28
32
|
end # DOTIW
|
29
33
|
|
30
|
-
DOTIW.init_i18n
|
34
|
+
DOTIW.init_i18n!
|
35
|
+
|
36
|
+
begin
|
37
|
+
require 'action_view'
|
38
|
+
require_relative 'dotiw/action_view/helpers/date_helper'
|
39
|
+
rescue LoadError
|
40
|
+
# TODO: don't rely on exception
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
module Helpers
|
5
|
+
module DateHelper
|
6
|
+
alias_method :_distance_of_time_in_words, :distance_of_time_in_words
|
7
|
+
alias_method :_time_ago_in_words, :time_ago_in_words
|
8
|
+
|
9
|
+
include DOTIW::Methods
|
10
|
+
|
11
|
+
def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {})
|
12
|
+
return _distance_of_time_in_words(from_time, to_time, options) if options.delete(:vague)
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def distance_of_time_in_percent(from_time, current_time, to_time, options = {})
|
17
|
+
options[:precision] ||= 0
|
18
|
+
distance = to_time - from_time
|
19
|
+
result = ((current_time - from_time) / distance) * 100
|
20
|
+
number_with_precision(result, options).to_s + '%'
|
21
|
+
end
|
22
|
+
end # DateHelper
|
23
|
+
end # Helpers
|
24
|
+
end # ActionView
|
data/lib/dotiw/locale/ar.yml
CHANGED
@@ -2,45 +2,52 @@ ar:
|
|
2
2
|
datetime:
|
3
3
|
dotiw:
|
4
4
|
seconds:
|
5
|
-
|
5
|
+
zero: ثانية
|
6
|
+
one: ثانية واحدة
|
6
7
|
two: ثانيتين
|
7
|
-
few: "%{count}
|
8
|
-
many: "%{count}
|
9
|
-
other: "%{count}
|
8
|
+
few: "%{count} توانٍ"
|
9
|
+
many: "%{count} ثانية"
|
10
|
+
other: "%{count} ثانية"
|
10
11
|
minutes:
|
11
|
-
|
12
|
+
zero: دقيقة
|
13
|
+
one: دقيقة واحدة
|
12
14
|
two: دقيقتين
|
13
15
|
few: "%{count} دقائق"
|
14
|
-
many: "%{count}
|
15
|
-
other: "%{count}
|
16
|
+
many: "%{count} دقيقة"
|
17
|
+
other: "%{count} دقيقة"
|
16
18
|
hours:
|
17
|
-
|
19
|
+
zero: ساعة
|
20
|
+
one: ساعة واحدة
|
18
21
|
two: ساعتين
|
19
22
|
few: "%{count} ساعات"
|
20
|
-
many: "%{count}
|
21
|
-
other: "%{count}
|
23
|
+
many: "%{count} ساعة"
|
24
|
+
other: "%{count} ساعة"
|
22
25
|
days:
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
zero: يوم
|
27
|
+
one: يوم واحد
|
28
|
+
two: يومين
|
29
|
+
few: "%{count} أيام"
|
30
|
+
many: "%{count} يومًا"
|
31
|
+
other: "%{count} يوم"
|
28
32
|
weeks:
|
29
|
-
|
30
|
-
|
33
|
+
zero: أسبوع
|
34
|
+
one: أسبوع واحدة
|
35
|
+
two: أسبوعين
|
31
36
|
few: "%{count} أسابيع"
|
32
37
|
many: "%{count} أسابيع"
|
33
|
-
other: "%{count}
|
38
|
+
other: "%{count} أسيوع"
|
34
39
|
months:
|
35
|
-
|
40
|
+
zero: شهر
|
41
|
+
one: شهر واحد
|
36
42
|
two: شهرين
|
37
43
|
few: "%{count} أشهر"
|
38
|
-
many: "%{count}
|
39
|
-
other: "%{count}
|
44
|
+
many: "%{count} شهراً"
|
45
|
+
other: "%{count} شهر"
|
40
46
|
years:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
+
zero: عام
|
48
|
+
one: عام واحد
|
49
|
+
two: عامين
|
50
|
+
few: "%{count} أعوام"
|
51
|
+
many: "%{count} عاماً"
|
52
|
+
other: "%{count} عام"
|
53
|
+
less_than_x: "%{distance} أقل من"
|
data/lib/dotiw/locale/pl.yml
CHANGED
@@ -4,29 +4,36 @@ pl:
|
|
4
4
|
seconds:
|
5
5
|
one: "1 sekunda"
|
6
6
|
few: "%{count} sekundy"
|
7
|
+
many: "%{count} sekund"
|
7
8
|
other: "%{count} sekund"
|
8
9
|
minutes:
|
9
10
|
one: "1 minuta"
|
10
11
|
few: "%{count} minuty"
|
12
|
+
many: "%{count} minut"
|
11
13
|
other: "%{count} minut"
|
12
14
|
hours:
|
13
15
|
one: "1 godzina"
|
14
16
|
few: "%{count} godziny"
|
17
|
+
many: "%{count} godzin"
|
15
18
|
other: "%{count} godzin"
|
16
19
|
days:
|
17
20
|
one: "1 dzień"
|
18
21
|
few: "%{count} dni"
|
22
|
+
many: "%{count} dni"
|
19
23
|
other: "%{count} dni"
|
20
24
|
weeks:
|
21
25
|
one: "1 tydzień"
|
22
26
|
few: "%{count} tygodnie"
|
27
|
+
many: "%{count} tygodni"
|
23
28
|
other: "%{count} tygodni"
|
24
29
|
months:
|
25
30
|
one: "1 miesiąc"
|
26
31
|
few: "%{count} miesiące"
|
32
|
+
many: "%{count} miesięcy"
|
27
33
|
other: "%{count} miesięcy"
|
28
34
|
years:
|
29
35
|
one: "1 rok"
|
30
36
|
few: "%{count} lata"
|
37
|
+
many: "%{count} lat"
|
31
38
|
other: "%{count} lat"
|
32
39
|
less_than_x: "mniej niż %{distance}"
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DOTIW
|
4
|
+
module Methods
|
5
|
+
def distance_of_time_in_words_hash(from_time, to_time, options = {})
|
6
|
+
from_time = from_time.to_time if !from_time.is_a?(Time) && from_time.respond_to?(:to_time)
|
7
|
+
to_time = to_time.to_time if !to_time.is_a?(Time) && to_time.respond_to?(:to_time)
|
8
|
+
|
9
|
+
DOTIW::TimeHash.new(nil, from_time, to_time, options).to_hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def distance_of_time(seconds, options = {})
|
13
|
+
options[:include_seconds] ||= true
|
14
|
+
_display_time_in_words DOTIW::TimeHash.new(seconds, nil, nil, options).to_hash, options
|
15
|
+
end
|
16
|
+
|
17
|
+
def distance_of_time_in_words(from_time, to_time = 0, include_seconds_or_options = {}, options = {})
|
18
|
+
if include_seconds_or_options.is_a?(Hash)
|
19
|
+
options = include_seconds_or_options
|
20
|
+
else
|
21
|
+
options[:include_seconds] ||= !!include_seconds_or_options
|
22
|
+
end
|
23
|
+
return distance_of_time(from_time, options) if to_time == 0
|
24
|
+
|
25
|
+
hash = distance_of_time_in_words_hash(from_time, to_time, options)
|
26
|
+
_display_time_in_words(hash, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def time_ago_in_words(from_time, include_seconds_or_options = {})
|
30
|
+
distance_of_time_in_words(from_time, Time.current, include_seconds_or_options)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def _display_time_in_words(hash, options = {})
|
36
|
+
options.reverse_merge!(
|
37
|
+
include_seconds: false
|
38
|
+
).symbolize_keys!
|
39
|
+
|
40
|
+
include_seconds = options.delete(:include_seconds)
|
41
|
+
hash.delete(:seconds) if !include_seconds && hash[:minutes]
|
42
|
+
|
43
|
+
options[:except] = Array.wrap(options[:except]).map!(&:to_sym) if options[:except]
|
44
|
+
options[:only] = Array.wrap(options[:only]).map!(&:to_sym) if options[:only]
|
45
|
+
|
46
|
+
# Remove all the values that are nil or excluded. Keep the required ones.
|
47
|
+
hash.delete_if do |key, value|
|
48
|
+
value.nil? || value.zero? ||
|
49
|
+
options[:except]&.include?(key) ||
|
50
|
+
(options[:only] && !options[:only].include?(key))
|
51
|
+
end
|
52
|
+
|
53
|
+
i18n_scope = options.delete(:scope) || DOTIW::DEFAULT_I18N_SCOPE
|
54
|
+
if hash.empty?
|
55
|
+
fractions = DOTIW::TimeHash::TIME_FRACTIONS
|
56
|
+
fractions &= options[:only] if options[:only]
|
57
|
+
fractions -= options[:except] if options[:except]
|
58
|
+
|
59
|
+
I18n.with_options locale: options[:locale], scope: i18n_scope do |locale|
|
60
|
+
# e.g. try to format 'less than 1 days', fallback to '0 days'
|
61
|
+
return locale.translate :less_than_x,
|
62
|
+
distance: locale.translate(fractions.first, count: 1),
|
63
|
+
default: locale.translate(fractions.first, count: 0)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
output = []
|
68
|
+
I18n.with_options locale: options[:locale], scope: i18n_scope do |locale|
|
69
|
+
output = hash.map { |key, value| locale.t(key, count: value) }
|
70
|
+
end
|
71
|
+
|
72
|
+
options.delete(:except)
|
73
|
+
options.delete(:only)
|
74
|
+
highest_measures = options.delete(:highest_measures)
|
75
|
+
highest_measures = 1 if options.delete(:highest_measure_only)
|
76
|
+
output = output[0...highest_measures] if highest_measures
|
77
|
+
|
78
|
+
options[:words_connector] ||= I18n.translate :'datetime.dotiw.words_connector',
|
79
|
+
default: :'support.array.words_connector',
|
80
|
+
locale: options[:locale]
|
81
|
+
options[:two_words_connector] ||= I18n.translate :'datetime.dotiw.two_words_connector',
|
82
|
+
default: :'support.array.two_words_connector',
|
83
|
+
locale: options[:locale]
|
84
|
+
options[:last_word_connector] ||= I18n.translate :'datetime.dotiw.last_word_connector',
|
85
|
+
default: :'support.array.last_word_connector',
|
86
|
+
locale: options[:locale]
|
87
|
+
|
88
|
+
output.to_sentence(options)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end # DOTIW
|
data/lib/dotiw/time_hash.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DOTIW
|
4
4
|
class TimeHash
|
5
|
-
TIME_FRACTIONS = [
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(distance, from_time
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
5
|
+
TIME_FRACTIONS = %i[seconds minutes hours days weeks months years].freeze
|
6
|
+
|
7
|
+
attr_reader :distance, :smallest, :largest, :from_time, :to_time
|
8
|
+
|
9
|
+
def initialize(distance, from_time, to_time = nil, options = {})
|
10
|
+
@output = {}
|
11
|
+
@options = options
|
12
|
+
@distance = distance
|
13
|
+
@from_time = from_time || Time.current
|
14
|
+
@to_time = to_time || (@to_time_not_given = true && @from_time + distance.seconds)
|
15
|
+
@smallest, @largest = [@from_time, @to_time].minmax
|
16
|
+
@to_time += 1.hour if @to_time_not_given && smallest.dst? && !largest.dst?
|
17
|
+
@to_time -= 1.hour if @to_time_not_given && !smallest.dst? && largest.dst?
|
18
|
+
@smallest, @largest = [@from_time, @to_time].minmax
|
19
|
+
@distance ||= begin
|
20
20
|
d = largest - smallest
|
21
|
-
d -= 1.hour if
|
22
|
-
d += 1.hour if !
|
21
|
+
d -= 1.hour if smallest.dst? && !largest.dst?
|
22
|
+
d += 1.hour if !smallest.dst? && largest.dst?
|
23
23
|
d
|
24
24
|
end
|
25
25
|
|
@@ -30,16 +30,16 @@ module DOTIW
|
|
30
30
|
output
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :options, :output
|
35
36
|
|
36
37
|
def build_time_hash
|
37
38
|
if accumulate_on = options.delete(:accumulate_on)
|
38
39
|
accumulate_on = accumulate_on.to_sym
|
39
|
-
if accumulate_on == :years
|
40
|
-
|
41
|
-
|
42
|
-
TIME_FRACTIONS.index(accumulate_on).downto(0) { |i| self.send("build_#{TIME_FRACTIONS[i]}") }
|
40
|
+
return build_time_hash if accumulate_on == :years
|
41
|
+
|
42
|
+
TIME_FRACTIONS.index(accumulate_on).downto(0) { |i| send("build_#{TIME_FRACTIONS[i]}") }
|
43
43
|
else
|
44
44
|
while distance > 0
|
45
45
|
if distance < 1.minute
|
@@ -63,23 +63,23 @@ module DOTIW
|
|
63
63
|
|
64
64
|
def build_seconds
|
65
65
|
output[:seconds] = distance.to_i
|
66
|
-
|
66
|
+
@distance = 0
|
67
67
|
end
|
68
68
|
|
69
69
|
def build_minutes
|
70
|
-
output[:minutes],
|
70
|
+
output[:minutes], @distance = distance.divmod(1.minute.to_i)
|
71
71
|
end
|
72
72
|
|
73
73
|
def build_hours
|
74
|
-
output[:hours],
|
74
|
+
output[:hours], @distance = distance.divmod(1.hour.to_i)
|
75
75
|
end
|
76
76
|
|
77
77
|
def build_days
|
78
|
-
output[:days],
|
78
|
+
output[:days], @distance = distance.divmod(1.day.to_i) unless output[:days]
|
79
79
|
end
|
80
80
|
|
81
81
|
def build_weeks
|
82
|
-
output[:weeks],
|
82
|
+
output[:weeks], @distance = distance.divmod(1.week.to_i) unless output[:weeks]
|
83
83
|
end
|
84
84
|
|
85
85
|
def build_months
|
@@ -110,7 +110,7 @@ module DOTIW
|
|
110
110
|
if weeks < 0
|
111
111
|
# Convert the last month to a week and add to total
|
112
112
|
months -= 1
|
113
|
-
last_month = largest.advance(:
|
113
|
+
last_month = largest.advance(months: -1)
|
114
114
|
days_in_month = Time.days_in_month(last_month.month, last_month.year)
|
115
115
|
weeks += days_in_month / 7
|
116
116
|
days += days_in_month % 7
|
@@ -118,6 +118,12 @@ module DOTIW
|
|
118
118
|
days -= 7
|
119
119
|
weeks += 1
|
120
120
|
end
|
121
|
+
|
122
|
+
if weeks == -1
|
123
|
+
months -= 1
|
124
|
+
weeks = 4
|
125
|
+
days -= 4
|
126
|
+
end
|
121
127
|
end
|
122
128
|
|
123
129
|
if months < 0
|
@@ -131,9 +137,9 @@ module DOTIW
|
|
131
137
|
output[:weeks] = weeks
|
132
138
|
output[:days] = days
|
133
139
|
|
134
|
-
total_days,
|
140
|
+
total_days, @distance = distance.abs.divmod(1.day.to_i)
|
135
141
|
|
136
|
-
[total_days,
|
142
|
+
[total_days, @distance]
|
137
143
|
end
|
138
144
|
end # TimeHash
|
139
145
|
end # DOTIW
|