go-duration 0.1.3

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ae1bf552d2be8eba1d80e8f4a1b8fe0f3a3438e6
4
+ data.tar.gz: f2d4b5986aba2578496e8beb0756a0d5db18f651
5
+ SHA512:
6
+ metadata.gz: 957897604363254f46829038ddb0592cf64d3c420bd4bef9509ce518ecfd072ea70d500f3c9974ab6f8d8e9213796860fe34eeb537b8466cfdd13c34e655d6d4
7
+ data.tar.gz: cb45a0f85333bf80c0476cbd57318b28b972e94516cde13ff0d3303922a913cc5508bad5bd62aa8b1d3429bd1674d981ba50798d39304272e708c329e9bfa655
@@ -0,0 +1,3 @@
1
+ require 'go-duration/version'
2
+ require 'go-duration/errors'
3
+ require 'go-duration/duration'
@@ -0,0 +1,131 @@
1
+ module GoDuration
2
+ # The base unit, a single nanosecond.
3
+ NANOSECOND = 1.freeze
4
+
5
+ # One microsecond in nanoseconds.
6
+ MICROSECOND = NANOSECOND << 10.freeze
7
+
8
+ # One millisecond in nanoseconds.
9
+ MILLISECOND = MICROSECOND << 1.freeze
10
+
11
+ # One second in nanoseconds.
12
+ SECOND = MILLISECOND << 1.freeze
13
+
14
+ # One minute in nanoseconds.
15
+ MINUTE = 60 * SECOND.freeze
16
+
17
+ # One hour in nanoseconds.
18
+ HOUR = 60 * MINUTE.freeze
19
+
20
+ # A mapping of Go's unit notations to their nanosecond values. Order is
21
+ # important, it defines how to_s works.
22
+ UNITS = {
23
+ h: HOUR,
24
+ m: MINUTE,
25
+ s: SECOND,
26
+ ms: MILLISECOND,
27
+ µs: MICROSECOND,
28
+ us: MICROSECOND,
29
+ ns: NANOSECOND,
30
+ }.freeze
31
+
32
+ # Duration deals with Golang's time.Duration. This type is commonly used
33
+ # in API's and/or CLI's, and is defined in the language itself (there is no
34
+ # formal specifcation or RFC for it). This class can be used to both parse
35
+ # and format duration strings.
36
+ class Duration
37
+ attr_reader :nanoseconds
38
+
39
+ # Initializes a new duration instance.
40
+ #
41
+ # @param number [Fixnum]
42
+ # @param unit [Symbol, :s]
43
+ #
44
+ # @return [Duration]
45
+ def initialize(number, unit: :s)
46
+ raise InvalidUnitError, unit unless UNITS[unit]
47
+ @nanoseconds = number * UNITS[unit]
48
+ end
49
+
50
+ # Returns the number of microseconds in the duration.
51
+ #
52
+ # @return [Fixnum]
53
+ def microseconds
54
+ nanoseconds / UNITS[:µs]
55
+ end
56
+
57
+ # Returns the number of milliseconds in the duration.
58
+ #
59
+ # @return [Fixnum]
60
+ def milliseconds
61
+ nanoseconds / UNITS[:ms]
62
+ end
63
+
64
+ # Returns the number of seconds in the duration.
65
+ #
66
+ # @return [Fixnum]
67
+ def seconds
68
+ nanoseconds / UNITS[:s]
69
+ end
70
+
71
+ # Returns the number of minutes in the duration.
72
+ #
73
+ # @return [Fixnum]
74
+ def minutes
75
+ nanoseconds / UNITS[:m]
76
+ end
77
+
78
+ # Returns the number of hours in the duration.
79
+ #
80
+ # @return [Fixnum]
81
+ def hours
82
+ nanoseconds / UNITS[:h]
83
+ end
84
+
85
+ # Returns the exact duration in nanoseconds.
86
+ #
87
+ # @return [Fixnum]
88
+ def to_i
89
+ nanoseconds
90
+ end
91
+
92
+ # Formats the duration into a Go duration string.
93
+ #
94
+ # @return [String]
95
+ def to_s
96
+ ns = nanoseconds
97
+ fmt = ""
98
+
99
+ UNITS.each do |unit, value|
100
+ number, ns = ns.divmod(value)
101
+ fmt << "#{number}#{unit}" if number > 0
102
+ end
103
+
104
+ fmt
105
+ end
106
+ end
107
+
108
+ module_function
109
+
110
+ # Parses a Go time.Duration string.
111
+ #
112
+ # @param duration [String] A Go duration string.
113
+ #
114
+ # @return [Duration]
115
+ def parse(duration)
116
+ ns = 0
117
+
118
+ until duration.empty?
119
+ number = duration.slice!(/^[[:digit:]]+/).to_i
120
+ unit = duration.slice!(/^[[:alpha:]]+/).to_sym
121
+
122
+ # Check that the units are recognized.
123
+ raise InvalidUnitError, unit unless UNITS[unit]
124
+
125
+ # Convert to nanoseconds and add to the total.
126
+ ns += (number * UNITS[unit])
127
+ end
128
+
129
+ Duration.new(ns, unit: :ns)
130
+ end
131
+ end
@@ -0,0 +1,11 @@
1
+ module GoDuration
2
+ class GoDurationError < RuntimeError; end
3
+
4
+ class InvalidUnitError < GoDurationError
5
+ def initialize(unit)
6
+ super <<-EOF.gsub(/^\s*/, "")
7
+ Invalid unit `#{unit}'. Must be one of: #{UNITS.keys.join(", ")}
8
+ EOF
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module GoDuration
2
+ VERSION = "0.1.3".freeze
3
+ end
@@ -0,0 +1,69 @@
1
+ require "spec_helper"
2
+
3
+ module GoDuration
4
+ all_duration = "1h1m1s1ms1µs1ns"
5
+ all_nano = HOUR + MINUTE + SECOND + MILLISECOND + MICROSECOND + NANOSECOND
6
+
7
+ describe Duration do
8
+ describe "#new" do
9
+ it "creates from seconds by default" do
10
+ d = Duration.new(13)
11
+ expect(d.nanoseconds).to eq(13 * GoDuration::SECOND)
12
+ end
13
+
14
+ it "creates with the provided unit" do
15
+ d = Duration.new(13, unit: :ms)
16
+ expect(d.nanoseconds).to eq(13 * GoDuration::MILLISECOND)
17
+ end
18
+
19
+ it "raises an error on invalid unit" do
20
+ expect { Duration.new(1, unit: :nope) }
21
+ .to raise_error(GoDuration::InvalidUnitError)
22
+ end
23
+ end
24
+
25
+ describe "#to_s" do
26
+ context "when all units are present" do
27
+ it "renders all of the units" do
28
+ expect(Duration.new(all_nano, unit: :ns).to_s)
29
+ .to eq(all_duration)
30
+ end
31
+ end
32
+
33
+ context "when a unit overflows" do
34
+ it "reduces into a larger unit" do
35
+ expect(Duration.new(63, unit: :s).to_s).to eq("1m3s")
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#parse" do
42
+ it "parses a time.Duration string" do
43
+ d = GoDuration.parse("1h")
44
+ expect(d.nanoseconds).to eq(HOUR)
45
+ end
46
+
47
+ it "recognizes either form of microseconds" do
48
+ a = GoDuration.parse("99us").microseconds
49
+ b = GoDuration.parse("99µs").microseconds
50
+ expect(a).to eq(b)
51
+ end
52
+
53
+ context "when multiple units are present" do
54
+ it "converts and adds them up" do
55
+ d = GoDuration.parse("1h43m")
56
+ expect(d.nanoseconds).to eq(HOUR + (43 * MINUTE))
57
+ end
58
+
59
+ it "recognizes all of the units" do
60
+ d = GoDuration.parse(all_duration)
61
+ expect(d.nanoseconds).to eq(all_nano)
62
+ end
63
+
64
+ it "raises an error if an invalid unit is found" do
65
+ expect { GoDuration.parse("1h2x") }.to raise_error(InvalidUnitError)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1 @@
1
+ require 'go-duration'
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: go-duration
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Uber
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A parser and formatter for Golang's time.Duration
70
+ email:
71
+ - ru@ryanuber.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/go-duration.rb
77
+ - lib/go-duration/duration.rb
78
+ - lib/go-duration/errors.rb
79
+ - lib/go-duration/version.rb
80
+ - spec/go-duration/duration_spec.rb
81
+ - spec/spec_helper.rb
82
+ homepage: https://github.com/ryanuber/go-duration-ruby
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.5.1
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: A parser and formatter for Golang's time.Duration
106
+ test_files:
107
+ - spec/spec_helper.rb
108
+ - spec/go-duration/duration_spec.rb