humane 0.4.0 → 0.6.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/README.md +25 -7
- data/lib/humane/size_formatter.rb +5 -2
- data/lib/humane/time_formatter.rb +30 -16
- data/lib/humane/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f1d568f746432126417fdd6541c249d81475c663e4e9ae9a772fcbc1dc59e3f
|
|
4
|
+
data.tar.gz: f85e12c6dbd402a4a1d452ba4629e6921418ff8609d6222333b17c1b51ae6a05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fa9e176a20d540c3c325c6f1015c2353b2fbced72397d9bcb645eea021129341781543399ac0a94d1cde5b885e64738e7d723d14c2bfb8548c3b7f7d392664cd
|
|
7
|
+
data.tar.gz: e59a7270df069333babc2d10f6234bbb507853b9b2c1583e437e41f1451a1f0dd6bc82cba1f88ec83989bb31a2957132f8d8c38a4bd96a056fb1a1b293ebd39f
|
data/README.md
CHANGED
|
@@ -22,6 +22,14 @@ time_formatter = Humane::TimeFormatter.new
|
|
|
22
22
|
time_formatter.string(at: Time.now - 180, relative_to: Time.now) # "3 minutes ago"
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
Both methods also accept positional arguments, matching `humane` (Go)'s
|
|
26
|
+
positional-only calling convention:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
Humane::SizeFormatter.new.string(225_935) # "226 KB"
|
|
30
|
+
time_formatter.string(Time.now - 180, Time.now) # "3 minutes ago"
|
|
31
|
+
```
|
|
32
|
+
|
|
25
33
|
Corresponding functions in Swift will have consistent output.
|
|
26
34
|
|
|
27
35
|
```swift
|
|
@@ -33,6 +41,11 @@ let formatter = RelativeDateTimeFormatter(); formatter.unitsStyle = .full
|
|
|
33
41
|
formatter.localizedString(for: time, relativeTo: now) // "3 minutes ago"
|
|
34
42
|
```
|
|
35
43
|
|
|
44
|
+
If you're writing Swift directly rather than calling Foundation by hand,
|
|
45
|
+
[`humane-swift`](https://github.com/woodie/humane-swift) wraps these same two
|
|
46
|
+
formatters with the identical API shape -- including the
|
|
47
|
+
`includeSeconds`/`approximate` options below.
|
|
48
|
+
|
|
36
49
|
## Install
|
|
37
50
|
|
|
38
51
|
```
|
|
@@ -47,16 +60,21 @@ gem "humane"
|
|
|
47
60
|
|
|
48
61
|
## Beyond Foundation's defaults
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
`
|
|
63
|
+
Foundation is the baseline every default matches exactly, in all three
|
|
64
|
+
languages -- these two options on `Humane::TimeFormatter` are how you layer
|
|
65
|
+
ActionView's wording on top of it, not a replacement for it. Both off by
|
|
66
|
+
default, so `Humane::TimeFormatter.new` and calling `RelativeDateTimeFormatter`
|
|
67
|
+
directly always agree:
|
|
52
68
|
|
|
53
|
-
- `include_seconds` (default `false`):
|
|
69
|
+
- `include_seconds` (default `false`): under 30 seconds, collapses to "less than a
|
|
54
70
|
minute ago"/"in less than a minute" instead of an exact second count. Named after
|
|
55
71
|
ActionView's `include_seconds`, which defaults the same way.
|
|
56
|
-
- `approximate` (default `false`): prefixes "about"/"in about" on
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
precision.
|
|
72
|
+
- `approximate` (default `false`): prefixes "about"/"in about" on the hour-scale
|
|
73
|
+
buckets (1 hour, and 2..24 hours), the way ActionView's `distance_of_time_in_words`
|
|
74
|
+
does for those same buckets -- for a render that can't refresh itself and shouldn't
|
|
75
|
+
overstate its own precision. Matches ActionView's own table exactly (down to its
|
|
76
|
+
44:30/89:30 rounding cutoffs), through the "1 day" bucket; week/month/year buckets
|
|
77
|
+
are out of scope. See [issue #1](https://github.com/woodie/humane-ruby/issues/1).
|
|
60
78
|
|
|
61
79
|
```ruby
|
|
62
80
|
Humane::TimeFormatter.new(approximate: true).string(at: t - 15 * 3600, relative_to: t)
|
|
@@ -5,8 +5,11 @@ module Humane
|
|
|
5
5
|
class SizeFormatter
|
|
6
6
|
UNITS = %w[B KB MB GB TB PB EB].freeze
|
|
7
7
|
|
|
8
|
-
# Returns from_byte_count as a Finder-style human-readable string.
|
|
9
|
-
def string(from_byte_count:)
|
|
8
|
+
# Returns from_byte_count as a Finder-style human-readable string; accepts positional or from_byte_count: keyword argument -- see docs/COMMENTS.md.
|
|
9
|
+
def string(positional_from_byte_count = nil, from_byte_count: nil)
|
|
10
|
+
from_byte_count ||= positional_from_byte_count
|
|
11
|
+
raise ArgumentError, "from_byte_count is required" unless from_byte_count
|
|
12
|
+
|
|
10
13
|
return "#{from_byte_count} B" if from_byte_count < 1000
|
|
11
14
|
|
|
12
15
|
exponent = [(Math.log(from_byte_count) / Math.log(1000)).to_i, UNITS.size - 1].min
|
|
@@ -4,40 +4,54 @@ module Humane
|
|
|
4
4
|
# Formats one time relative to another the way Finder-adjacent tools do.
|
|
5
5
|
class TimeFormatter
|
|
6
6
|
# include_seconds shows exact seconds under a minute instead of collapsing to "less than a minute ago/in less than a minute". Defaults to false, matching ActionView's include_seconds.
|
|
7
|
-
# approximate prefixes "about"/"in about" on buckets
|
|
7
|
+
# approximate prefixes "about"/"in about" on the hour-scale buckets (1 hour, and 2..24 hours), matching ActionView's distance_of_time_in_words wording for those buckets. Defaults to false. See docs/COMMENTS.md and humane-ruby issue #1 for the full bucket table this ports.
|
|
8
8
|
def initialize(include_seconds: false, approximate: false)
|
|
9
9
|
@include_seconds = include_seconds
|
|
10
10
|
@approximate = approximate
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
# Returns
|
|
14
|
-
def string(at
|
|
13
|
+
# Returns at relative to relative_to; accepts positional or at:/relative_to: keyword arguments -- see docs/COMMENTS.md.
|
|
14
|
+
def string(positional_at = nil, positional_relative_to = nil, at: nil, relative_to: nil)
|
|
15
|
+
at ||= positional_at
|
|
16
|
+
relative_to ||= positional_relative_to
|
|
17
|
+
raise ArgumentError, "at is required" unless at
|
|
18
|
+
raise ArgumentError, "relative_to is required" unless relative_to
|
|
19
|
+
|
|
15
20
|
seconds = relative_to - at
|
|
16
21
|
future = seconds.negative?
|
|
17
22
|
seconds = seconds.abs
|
|
18
23
|
|
|
19
|
-
if !@include_seconds && seconds <
|
|
24
|
+
if !@include_seconds && seconds < 30
|
|
20
25
|
return future ? "in less than a minute" : "less than a minute ago"
|
|
21
26
|
end
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
elsif seconds < 3600
|
|
27
|
-
pluralize((seconds / 60.0).round, "minute")
|
|
28
|
-
elsif seconds < 86_400
|
|
29
|
-
pluralize((seconds / 3600.0).round, "hour")
|
|
30
|
-
else
|
|
31
|
-
pluralize((seconds / 86_400.0).round, "day")
|
|
32
|
-
end
|
|
28
|
+
if @include_seconds && seconds < 60
|
|
29
|
+
return wrap(pluralize(seconds.to_i, "second"), future: future)
|
|
30
|
+
end
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
# Buckets come from distance_in_minutes, not raw seconds re-divided per unit -- see docs/COMMENTS.md.
|
|
33
|
+
distance_in_minutes = (seconds / 60.0).round
|
|
34
|
+
|
|
35
|
+
text, approximable =
|
|
36
|
+
case distance_in_minutes
|
|
37
|
+
when 1 then ["1 minute", false]
|
|
38
|
+
when 2..44 then [pluralize(distance_in_minutes, "minute"), false]
|
|
39
|
+
when 45..89 then ["1 hour", true]
|
|
40
|
+
when 90..1439 then [pluralize((distance_in_minutes / 60.0).round, "hour"), true]
|
|
41
|
+
when 1440..2519 then ["1 day", false]
|
|
42
|
+
else [pluralize((distance_in_minutes / 1440.0).round, "day"), false]
|
|
43
|
+
end
|
|
35
44
|
|
|
36
|
-
|
|
45
|
+
text = "about #{text}" if @approximate && approximable
|
|
46
|
+
wrap(text, future: future)
|
|
37
47
|
end
|
|
38
48
|
|
|
39
49
|
private
|
|
40
50
|
|
|
51
|
+
def wrap(text, future:)
|
|
52
|
+
future ? "in #{text}" : "#{text} ago"
|
|
53
|
+
end
|
|
54
|
+
|
|
41
55
|
def pluralize(count, unit)
|
|
42
56
|
count == 1 ? "1 #{unit}" : "#{count} #{unit}s"
|
|
43
57
|
end
|
data/lib/humane/version.rb
CHANGED