duration.rb 0.6.2 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96a11b338ddcec99f2b1b42f0c98b478937688114644edf233bee9b6a894c75d
4
- data.tar.gz: 74717586689952c86539c811efbb6c4666b768b9dd2345759b0f4638a7b9b7a7
3
+ metadata.gz: c8e29deede3e2da3e3291bda645d370df91c119d6b6263c33dfe4c902f927583
4
+ data.tar.gz: 0166b41b22ce52109bdf30a99a141bd766e18094dbaa0ec7ae55b39a8ead08fa
5
5
  SHA512:
6
- metadata.gz: 501a0a8bc4e39897ac84e5c3ec1ad346115a68b0a2c6f99b8bd1b7d3622bebe5821ccc8cf058e961c52285920783ef57ce9c0f8ec7bb085cb69f1db3fc4c37d9
7
- data.tar.gz: eb816a10954321a09980a31c0cce9409574a556ee958b4500d9cccfdb849813c683279f9c94d239b6d212275e1f08fd4157e092f113d6ef2ba813bbe87e88138
6
+ metadata.gz: 5587052c84be1c21d2616745be9eb1cdf009dc5877db0b0e2e66ec8eb4983867c67b6a1449e10e27d5ccac61dd5a06629034611171a412edc458ab45ad3da6f1
7
+ data.tar.gz: 20a868eb602e70efa4dada46349ccbafca1c53e9c9bdc9021a797fb37b286da729c3d4f1a67472a451b06a13b1219bdf3981809e17d15e9f5c7b996f9f27d8a8
data/CHANGELOG CHANGED
@@ -1,5 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 20260822
4
+
5
+ 0.7.0: + Duration::Common#to_s, #inspect.
6
+
7
+ 1. + Duration::Common#to_s: the quantity and the unit, as "45 days". The unit is the class, so naming it says which duration this is without repeating the class. A quantity of one drops the plural.
8
+ 2. + Duration::Common#inspect: the class and the quantity as it is held, as "Duration::Days(45)", after measurand's. Collections call inspect upon their elements, which is where the default ivar-and-address form was most often met. It is the one place an Integer 45 and a Rational 45/1 can be told apart, #to_s rendering both as "45 days".
9
+ 3. ~ README.md: the eleven `# =>` comments which render a duration, being what irb prints and so #inspect, brought to the form it now returns. They had shown an approximation of the default, `#<Nanoseconds @nanoseconds=500>`, which was never quite what was printed either; + a Rendering section for #to_s and #inspect.
10
+ 4. ~ Duration::VERSION: /0.6.2/0.7.0/
11
+
12
+
3
13
  ## 20260819
4
14
 
5
15
  0.6.2: ~ duration.rb.gemspec: spec.files reordered, the globs first.
data/README.md CHANGED
@@ -64,15 +64,15 @@ minutes reads the files for seconds and minutes and leaves the rest unread.
64
64
  ### Basic Duration Creation
65
65
  ```ruby
66
66
  # Create durations using convenience methods
67
- 500.nanoseconds # => #<Nanoseconds @nanoseconds=500>
68
- 500.microseconds # => #<Microseconds @microseconds=500>
69
- 200.milliseconds # => #<Milliseconds @milliseconds=200>
70
- 1.second # => #<Seconds @seconds=1>
71
- 30.minutes # => #<Minutes @minutes=30>
72
- 2.hours # => #<Hours @hours=2>
73
- 7.days # => #<Days @days=7>
74
- 4.weeks # => #<Weeks @weeks=4>
75
- 6.months # => #<Months @months=6>
67
+ 500.nanoseconds # => Duration::Nanoseconds(500)
68
+ 500.microseconds # => Duration::Microseconds(500)
69
+ 200.milliseconds # => Duration::Milliseconds(200)
70
+ 1.second # => Duration::Seconds(1)
71
+ 30.minutes # => Duration::Minutes(30)
72
+ 2.hours # => Duration::Hours(2)
73
+ 7.days # => Duration::Days(7)
74
+ 4.weeks # => Duration::Weeks(4)
75
+ 6.months # => Duration::Months(6)
76
76
  ```
77
77
 
78
78
  ### Conversions
@@ -83,13 +83,46 @@ minutes reads the files for seconds and minutes and leaves the rest unread.
83
83
 
84
84
  # Convert between units. The result is exact (a Rational internally) when the
85
85
  # input is exact; call to_f at the edge for a float.
86
- 90.minutes.to_hours # => #<Hours @hours=(3/2)>
86
+ 90.minutes.to_hours # => Duration::Hours((3/2))
87
87
  90.minutes.to_hours.to_f # => 1.5
88
88
  1.5.hours.to_minutes.to_i # => 90
89
89
  1.day.to_seconds.to_i # => 86400
90
90
  5.minutes.to_hours.to_f # => 0.08333333333333333
91
91
  ```
92
92
 
93
+ ### Rendering
94
+
95
+ `to_s` names the quantity and the unit — the unit being the class, naming it says
96
+ which duration this is without repeating it.
97
+
98
+ ```ruby
99
+ 45.days.to_s # => "45 days"
100
+ 1.day.to_s # => "1 day"
101
+ 1.5.hours.to_s # => "1.5 hours"
102
+ ```
103
+
104
+ The quantity prints as it is held. A Rational which came out whole prints as a whole
105
+ number, and one which did not stays a ratio rather than being expanded into a decimal
106
+ it is not:
107
+
108
+ ```ruby
109
+ 45.days.to_weeks.to_s # => "45/7 weeks"
110
+ 90.minutes.to_hours.to_s # => "3/2 hours"
111
+ ```
112
+
113
+ Call `to_f` where a decimal is wanted, as elsewhere — the rounding happens upon
114
+ request and not before.
115
+
116
+ `inspect` is the other form: the class and the quantity as it is actually held. It is
117
+ the one place an `Integer` 45 and a `Rational` 45/1 can be told apart, `to_s` rendering
118
+ both as `"45 days"`.
119
+
120
+ ```ruby
121
+ 45.days.inspect # => "Duration::Days(45)"
122
+ 45.days.to_weeks.inspect # => "Duration::Weeks((45/7))"
123
+ {held_for: 45.days}.inspect # => "{held_for: Duration::Days(45)}"
124
+ ```
125
+
93
126
  ### Arithmetic and Comparison
94
127
  ```ruby
95
128
  # Durations add and subtract, with the left operand's unit deciding the result:
@@ -101,7 +134,7 @@ minutes reads the files for seconds and minutes and leaves the rest unread.
101
134
  5.minutes == 300.seconds # => true
102
135
  90.seconds > 1.minute # => true
103
136
  [1.hour, 30.seconds, 5.minutes].sort
104
- # => [30.seconds, 5.minutes, 1.hour]
137
+ # => [Duration::Seconds(30), Duration::Minutes(5), Duration::Hours(1)]
105
138
 
106
139
  # Scaled by a number, a duration stays a duration and keeps its unit:
107
140
  5.minutes * 3 # => #<Minutes @minutes=15>
@@ -36,6 +36,24 @@ module Duration
36
36
  quantity <=> other.send(:"to_#{unit}").quantity
37
37
  end
38
38
 
39
+ # The unit is the class, so naming it says which duration this is without
40
+ # repeating the class: 45 days rather than #<Duration::Days:0x000... The
41
+ # quantity is rendered as it is held, an exact Rational staying exact, this
42
+ # library manufacturing no precision it was not given and discarding none
43
+ # it was.
44
+ def to_s
45
+ "#{rendered_quantity} #{quantity == 1 ? unit.to_s.chomp('s') : unit}"
46
+ end
47
+
48
+ # The class and the quantity as it is actually held, after measurand: to_s
49
+ # is what a reader wants and inspect is what the object is. It is the one
50
+ # place the difference between an Integer 45 and a Rational 45/1 shows,
51
+ # which in a library this careful about exactness is worth being able to
52
+ # see.
53
+ def inspect
54
+ "#{self.class}(#{quantity.inspect})"
55
+ end
56
+
39
57
  protected
40
58
 
41
59
  def quantity
@@ -44,6 +62,13 @@ module Duration
44
62
 
45
63
  private
46
64
 
65
+ # A Rational which came out whole prints as its numerator, since 45/1 days
66
+ # says nothing 45 days does not. A Rational which did not stays a ratio:
67
+ # 45/7 weeks is what 45 days is, and 6.428571428571429 is not.
68
+ def rendered_quantity
69
+ quantity.is_a?(Rational) && quantity.denominator == 1 ? quantity.numerator.to_s : quantity.to_s
70
+ end
71
+
47
72
  def combine(operator, other)
48
73
  unless other.is_a?(Duration::Common)
49
74
  raise TypeError, "can't combine #{self.class} with #{other.class}"
@@ -1,3 +1,3 @@
1
1
  module Duration
2
- VERSION = '0.6.2'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -98,4 +98,58 @@ describe Duration::Common do
98
98
  _((1.hour - 50.minutes).to_minutes.to_f).must_equal 10.0
99
99
  end
100
100
  end
101
+
102
+ describe "#to_s" do
103
+ it "names the quantity and the unit" do
104
+ _(45.days.to_s).must_equal '45 days'
105
+ _(500.nanoseconds.to_s).must_equal '500 nanoseconds'
106
+ end
107
+
108
+ it "drops the plural at one" do
109
+ _(1.day.to_s).must_equal '1 day'
110
+ _(1.month.to_s).must_equal '1 month'
111
+ end
112
+
113
+ it "keeps a float a float" do
114
+ _(1.5.hours.to_s).must_equal '1.5 hours'
115
+ end
116
+
117
+ it "prints a whole Rational as a whole number" do
118
+ _(Duration::Days.new(45r).to_s).must_equal '45 days'
119
+ end
120
+
121
+ it "keeps an exact ratio a ratio rather than expanding it" do
122
+ # 45 days is exactly 45/7 weeks, and 6.428571428571429 is not.
123
+ _(45.days.to_weeks.to_s).must_equal '45/7 weeks'
124
+ end
125
+
126
+ it "reads the unit from the class rather than repeating it" do
127
+ _(90.minutes.to_hours.to_s).must_equal '3/2 hours'
128
+ end
129
+ end
130
+
131
+ describe "#inspect" do
132
+ it "names the class and the quantity as held" do
133
+ _(45.days.inspect).must_equal 'Duration::Days(45)'
134
+ _(1.5.hours.inspect).must_equal 'Duration::Hours(1.5)'
135
+ end
136
+
137
+ it "carries no address or ivar dump" do
138
+ _(45.days.inspect).wont_match(/0x|@days/)
139
+ end
140
+
141
+ it "shows an exact quantity as the Rational it is, where to_s does not" do
142
+ _(45.days.to_weeks.to_s).must_equal '45/7 weeks'
143
+ _(45.days.to_weeks.inspect).must_equal 'Duration::Weeks((45/7))'
144
+ end
145
+
146
+ it "distinguishes a whole Rational from an Integer, where to_s cannot" do
147
+ _(Duration::Days.new(45r).to_s).must_equal 45.days.to_s
148
+ _(Duration::Days.new(45r).inspect).wont_equal 45.days.inspect
149
+ end
150
+
151
+ it "reaches a duration held inside a collection" do
152
+ _({held_for: 45.days}.inspect).must_equal '{held_for: Duration::Days(45)}'
153
+ end
154
+ end
101
155
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duration.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran