time_up 0.0.1 → 0.0.5
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/.standard.yml +1 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile.lock +1 -1
- data/README.md +95 -27
- data/lib/time_up.rb +177 -44
- data/lib/time_up/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6241f3e0e1e66bc75c67a7e7cfc76424ae4e711c5a535b87da3bdf4fa78c153
|
4
|
+
data.tar.gz: 33c77eb409cb4d4d4142207ff93a938a1124b87768047f29be0d51057c4eb5fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df9e90669ceef219dcea0bf8b21548252b97abe40b950b922f6c9ee17987494d145fdd130b5c4735a6e57daffaf5ba2d915057044f424ba68656d9b55b5f7820
|
7
|
+
data.tar.gz: ad014a9ec0471bfbc3f315b673988d7d5b5115ad29d0cc664ad63eaa81547086bff539de50e311078261c99a9616a0e683c75f9e552bf0a254d26e14d0ef702d
|
data/.standard.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby_version: 2.4
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
# 0.0.5
|
2
|
+
|
3
|
+
- Add `median` and `percentile` timer statistics, and added them to
|
4
|
+
`print_detailed_summary`
|
5
|
+
|
6
|
+
# 0.0.4
|
7
|
+
|
8
|
+
- Add `TimeUp.print_detailed_summary`
|
9
|
+
|
10
|
+
# 0.0.3
|
11
|
+
|
12
|
+
- Change the return value of TimeUp.start when passed a block to be the
|
13
|
+
evaluated value of the block (for easier insertion into existing code without
|
14
|
+
adding a bunch of new assignment and returns)
|
15
|
+
- Allow timer instances' `start` method to be called with a block
|
16
|
+
- Add `timings`, `count`, `min`, `max`, and `mean` methods for basic stats
|
17
|
+
tracking
|
18
|
+
- Add `TimeUp.all_stats` to roll up all these
|
19
|
+
|
20
|
+
# 0.0.2
|
21
|
+
|
22
|
+
- Switch from a module method to Thread.current variable
|
23
|
+
|
1
24
|
# 0.0.1
|
2
25
|
|
3
26
|
- Make the gem
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -6,10 +6,13 @@ but don't necessarily want to reach for
|
|
6
6
|
Try `time_up`!
|
7
7
|
|
8
8
|
This gem is especially useful for long-running processes (like test suites) that
|
9
|
-
have several time-intensive operations that are repeated over
|
10
|
-
want to measure
|
11
|
-
test suite spends creating factories, truncating the database, or
|
12
|
-
critical code path.)
|
9
|
+
have several time-intensive operations that are repeated over the life of the
|
10
|
+
process and that you want to measure in aggregate. (For example, to see how
|
11
|
+
much time your test suite spends creating factories, truncating the database, or
|
12
|
+
invoking a critical code path.)
|
13
|
+
|
14
|
+
Here's a [blog post about time_up](https://blog.testdouble.com/posts/2021-07-19-benchmarking-your-ruby-with-time_up/) and
|
15
|
+
a [great example of when it can be useful](https://gist.github.com/searls/feee0b0eac7c329b390fed90c4714afb).
|
13
16
|
|
14
17
|
## Install
|
15
18
|
|
@@ -65,10 +68,10 @@ sleep 5
|
|
65
68
|
puts TimeUp.stop :eggs # => ~5.0
|
66
69
|
```
|
67
70
|
|
68
|
-
`TimeUp.start`
|
69
|
-
`start`, `stop`, `elaped`, and `reset` methods. If you want to
|
70
|
-
instance later, you can also call `TimeUp.timer(:some_name)`. So the
|
71
|
-
example could be rewritten as:
|
71
|
+
When passes without a block, `TimeUp.start` returns an instance of the timer,
|
72
|
+
which has its own `start`, `stop`, `elaped`, and `reset` methods. If you want to
|
73
|
+
find that instance later, you can also call `TimeUp.timer(:some_name)`. So the
|
74
|
+
above example could be rewritten as:
|
72
75
|
|
73
76
|
```ruby
|
74
77
|
egg_timer = TimeUp.start :eggs
|
@@ -107,7 +110,7 @@ TimeUp.print_summary
|
|
107
110
|
Which will output something like:
|
108
111
|
|
109
112
|
```
|
110
|
-
TimeUp
|
113
|
+
TimeUp summary
|
111
114
|
========================
|
112
115
|
:roast 0.07267s
|
113
116
|
:veggies 0.03760s
|
@@ -117,39 +120,87 @@ TimeUp timers summary
|
|
117
120
|
* Denotes that the timer is still active
|
118
121
|
```
|
119
122
|
|
123
|
+
And if you're calling the timers multiple times and want to see some basic
|
124
|
+
statistics in the print-out, you can call `TimeUp.print_detailed_summary`, which
|
125
|
+
will produce this:
|
126
|
+
|
127
|
+
```
|
128
|
+
=============================================================================
|
129
|
+
Name | Elapsed | Count | Min | Max | Mean | Median | 95th %
|
130
|
+
-----------------------------------------------------------------------------
|
131
|
+
:roast | 0.08454 | 3 | 0.00128 | 0.07280 | 0.02818 | 0.01046 | 0.06657
|
132
|
+
:veggies | 0.03779 | 1 | 0.03779 | 0.03779 | 0.03779 | 0.03779 | 0.03779
|
133
|
+
:pasta | 0.01260 | 11 | 0.00000 | 0.01258 | 0.00115 | 0.00000 | 0.00630
|
134
|
+
:souffle* | 0.00024 | 1 | 0.00024 | 0.00025 | 0.00025 | 0.00025 | 0.00026
|
135
|
+
|
136
|
+
* Denotes that the timer is still active
|
137
|
+
```
|
138
|
+
|
120
139
|
## API
|
121
140
|
|
122
141
|
This gem defines a bunch of public methods but they're all pretty short and
|
123
|
-
straightforward, so I'd encourage you to [read the
|
142
|
+
straightforward, so when in doubt, I'd encourage you to [read the
|
143
|
+
code](/lib/time_up.rb).
|
124
144
|
|
125
145
|
### `TimeUp` module
|
126
146
|
|
127
|
-
`TimeUp.
|
147
|
+
`TimeUp.timer(name)` - Returns the `Timer` instance named `name` (creating it,
|
148
|
+
if it doesn't exist)
|
128
149
|
|
129
|
-
`TimeUp.
|
150
|
+
`TimeUp.start(name, [&blk])` - Starts (or restarts) a named
|
151
|
+
[Timer](#timeuptimer-class). If passed a block, will return whatever the block
|
152
|
+
evaluates to. If called without a block, it will return the timer object
|
130
153
|
|
131
|
-
`TimeUp.stop(name)` - Stops the named timer
|
154
|
+
`TimeUp.stop(name)` - Stops the named timer
|
155
|
+
|
156
|
+
`TimeUp.reset(name)` - Resets the named timer's elapsed time to 0, effectively
|
157
|
+
restarting it if it's currently running
|
132
158
|
|
133
159
|
`TimeUp.elapsed(name)` - Returns a `Float` of the total elapsed seconds that the
|
134
|
-
named timer has been running
|
135
|
-
`name`)
|
160
|
+
named timer has been running
|
136
161
|
|
137
|
-
`TimeUp.
|
138
|
-
|
162
|
+
`TimeUp.timings(name)` - Returns an array of each recorded start-to-stop
|
163
|
+
duration (including the current one, if the timer is running) of the named timer
|
164
|
+
|
165
|
+
`TimeUp.count(name)` - The number of times the timer has been started (including
|
166
|
+
the current timing, if the timer is running)
|
167
|
+
|
168
|
+
`TimeUp.min(name)` - The shortest recording by the timer
|
169
|
+
|
170
|
+
`TimeUp.max(name)` - The longest recording by the timer
|
139
171
|
|
140
|
-
`TimeUp.
|
141
|
-
timers you've created
|
172
|
+
`TimeUp.mean(name)` - The arithmetic mean of all recordings by the timer
|
142
173
|
|
143
|
-
`TimeUp.
|
144
|
-
`elapsed` values. Handy for grabbing a snapshot of the state of things at a
|
145
|
-
particular point in time without stopping all your timers
|
174
|
+
`TimeUp.median(name)` - The median of all recordings by the timer
|
146
175
|
|
147
|
-
`TimeUp.
|
148
|
-
|
149
|
-
|
176
|
+
`TimeUp.percentile(name, percent)` - The timing for the given
|
177
|
+
[percentile](https://en.wikipedia.org/wiki/Percentile) of all recordings by the
|
178
|
+
timer
|
150
179
|
|
151
|
-
`TimeUp.
|
152
|
-
timers
|
180
|
+
`TimeUp.total_elapsed` - Returns a `Float` of the sum of `elapsed` across all
|
181
|
+
the timers you've created (note that because you can easily run multiple logical
|
182
|
+
timers simultaneously, this figure may exceed the total time spent by the
|
183
|
+
computer)
|
184
|
+
|
185
|
+
`TimeUp.all_elapsed` - Returns a Hash of timer name keys mapped to their
|
186
|
+
`elapsed` values. Handy for grabbing a reference to a snapshot of the state of
|
187
|
+
things without requiring you to stop your timers
|
188
|
+
|
189
|
+
`TimeUp.all_stats` - Returns a Hash of timer name keys mapped to another
|
190
|
+
hash of their basic statistics (`elapsed`, `count`, `min`, `max`,
|
191
|
+
and `mean`)
|
192
|
+
|
193
|
+
`TimeUp.active_timers` - Returns an Array of all timers that are currently
|
194
|
+
running. Useful for detecting cases where you might be keeping time in multiple
|
195
|
+
places simultaneously
|
196
|
+
|
197
|
+
`TimeUp.print_summary([io])` - Pretty-prints a multi-line summary of all your
|
198
|
+
timers' total elapsed times to standard output (or the provided
|
199
|
+
[IO](https://ruby-doc.org/core-3.0.1/IO.html))
|
200
|
+
|
201
|
+
`TimeUp.print_detailed_summary([io])` - Pretty-prints a multi-line summary of
|
202
|
+
all your timers' elapsed times and basic statistics to standard output (or the
|
203
|
+
provided [IO](https://ruby-doc.org/core-3.0.1/IO.html))
|
153
204
|
|
154
205
|
`TimeUp.stop_all` - Stops all timers
|
155
206
|
|
@@ -166,6 +217,23 @@ reference to them
|
|
166
217
|
|
167
218
|
`elapsed` - A `Float` of the total elapsed seconds the timer has been running
|
168
219
|
|
220
|
+
`timings` - Returns an Array of each recorded start-to-stop duration of the
|
221
|
+
timer (including the current one, if the timer is running)
|
222
|
+
|
223
|
+
`count` - The number of times the timer has been started and stopped
|
224
|
+
|
225
|
+
`min` - The shortest recording of the timer
|
226
|
+
|
227
|
+
`max` - The longest recording of the timer
|
228
|
+
|
229
|
+
`mean` - The arithmetic mean of all recorded durations of the timer
|
230
|
+
|
231
|
+
`median(name)` - The median of all recordings by the timer
|
232
|
+
|
233
|
+
`percentile(name, percent)` - The timing for the given
|
234
|
+
[percentile](https://en.wikipedia.org/wiki/Percentile) of all recordings by the
|
235
|
+
timer
|
236
|
+
|
169
237
|
`active?` - Returns `true` if the timer is running
|
170
238
|
|
171
239
|
`reset(force: false)` - Resets the timer to 0 elapsed seconds. If `force` is
|
data/lib/time_up.rb
CHANGED
@@ -3,132 +3,265 @@ require_relative "time_up/version"
|
|
3
3
|
module TimeUp
|
4
4
|
class Error < StandardError; end
|
5
5
|
|
6
|
-
|
7
|
-
def self.start(name, &blk)
|
8
|
-
raise Error.new("Timer name must be a String or Symbol") unless name.is_a?(Symbol) || name.is_a?(String)
|
9
|
-
timer = @timers[name] ||= Timer.new(name)
|
10
|
-
timer.start
|
11
|
-
if blk
|
12
|
-
blk.call
|
13
|
-
timer.stop
|
14
|
-
end
|
15
|
-
timer
|
16
|
-
end
|
6
|
+
Thread.current[:time_up_timers] = {}
|
17
7
|
|
18
|
-
# Delegate methods
|
19
8
|
def self.timer(name)
|
20
|
-
|
9
|
+
__timers[name] ||= Timer.new(name)
|
21
10
|
end
|
22
11
|
|
23
|
-
|
24
|
-
|
25
|
-
|
12
|
+
# Delegate methods
|
13
|
+
def self.start(name, &blk)
|
14
|
+
timer(name).start(&blk)
|
26
15
|
end
|
27
16
|
|
28
|
-
|
29
|
-
|
30
|
-
|
17
|
+
[
|
18
|
+
:stop,
|
19
|
+
:reset,
|
20
|
+
:elapsed,
|
21
|
+
:timings,
|
22
|
+
:count,
|
23
|
+
:min,
|
24
|
+
:max,
|
25
|
+
:mean,
|
26
|
+
:median
|
27
|
+
].each do |method_name|
|
28
|
+
define_singleton_method method_name do |name|
|
29
|
+
__ensure_timer(name)
|
30
|
+
__timers[name].send(method_name)
|
31
|
+
end
|
31
32
|
end
|
32
33
|
|
33
|
-
def self.
|
34
|
+
def self.percentile(name, percentage)
|
34
35
|
__ensure_timer(name)
|
35
|
-
|
36
|
+
__timers[name].percentile(percentage)
|
36
37
|
end
|
37
38
|
|
38
39
|
# Interrogative methods
|
39
40
|
def self.total_elapsed
|
40
|
-
|
41
|
+
__timers.values.sum(&:elapsed)
|
41
42
|
end
|
42
43
|
|
43
44
|
def self.all_elapsed
|
44
|
-
|
45
|
+
__timers.values.map { |timer|
|
45
46
|
[timer.name, timer.elapsed]
|
46
47
|
}.to_h
|
47
48
|
end
|
48
49
|
|
50
|
+
def self.all_stats
|
51
|
+
__timers.values.map { |timer|
|
52
|
+
[timer.name, {
|
53
|
+
elapsed: timer.elapsed,
|
54
|
+
count: timer.count,
|
55
|
+
min: timer.min,
|
56
|
+
max: timer.max,
|
57
|
+
mean: timer.mean,
|
58
|
+
median: timer.median,
|
59
|
+
"95th": timer.percentile(95)
|
60
|
+
}]
|
61
|
+
}.to_h
|
62
|
+
end
|
63
|
+
|
49
64
|
def self.active_timers
|
50
|
-
|
65
|
+
__timers.values.select(&:active?)
|
51
66
|
end
|
52
67
|
|
53
68
|
def self.print_summary(io = $stdout)
|
54
|
-
longest_name_length =
|
55
|
-
summaries =
|
69
|
+
longest_name_length = __timers.values.map { |t| t.name.inspect.size }.max
|
70
|
+
summaries = __timers.values.map { |timer|
|
56
71
|
name = "#{timer.name.inspect}#{"*" if timer.active?}".ljust(longest_name_length + 1)
|
57
72
|
"#{name}\t#{"%.5f" % timer.elapsed}s"
|
58
73
|
}
|
59
74
|
io.puts <<~SUMMARY
|
60
75
|
|
61
|
-
TimeUp
|
76
|
+
TimeUp summary
|
62
77
|
========================
|
63
78
|
#{summaries.join("\n")}
|
64
79
|
|
65
|
-
#{"* Denotes that the timer is still active\n" if
|
80
|
+
#{"* Denotes that the timer is still active\n" if __timers.values.any?(&:active?)}
|
81
|
+
SUMMARY
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.print_detailed_summary(io = $stdout)
|
85
|
+
cols = {
|
86
|
+
names: ["Name"],
|
87
|
+
elapsed: ["Elapsed"],
|
88
|
+
count: ["Count"],
|
89
|
+
min: ["Min"],
|
90
|
+
max: ["Max"],
|
91
|
+
mean: ["Mean"],
|
92
|
+
median: ["Median"],
|
93
|
+
"95th": ["95th %"]
|
94
|
+
}
|
95
|
+
__timers.values.each { |timer|
|
96
|
+
cols[:names] << "#{timer.name.inspect}#{"*" if timer.active?}"
|
97
|
+
cols[:elapsed] << "%.5f" % timer.elapsed
|
98
|
+
cols[:count] << timer.count.to_s
|
99
|
+
cols[:min] << "%.5f" % timer.min
|
100
|
+
cols[:max] << "%.5f" % timer.max
|
101
|
+
cols[:mean] << "%.5f" % timer.mean
|
102
|
+
cols[:median] << "%.5f" % timer.median
|
103
|
+
cols[:"95th"] << "%.5f" % timer.percentile(95)
|
104
|
+
}
|
105
|
+
|
106
|
+
widths = cols.map { |name, vals|
|
107
|
+
[name, vals.map(&:length).max]
|
108
|
+
}.to_h
|
109
|
+
|
110
|
+
rows = cols[:names].size.times.map { |i|
|
111
|
+
if i == 0
|
112
|
+
cols.keys.map { |name|
|
113
|
+
cols[name][i].center(widths[name])
|
114
|
+
}
|
115
|
+
else
|
116
|
+
cols.keys.map { |name|
|
117
|
+
cols[name][i].ljust(widths[name])
|
118
|
+
}
|
119
|
+
end
|
120
|
+
}
|
121
|
+
|
122
|
+
full_width = widths.values.sum + (rows[0].size - 1) * 3
|
123
|
+
io.puts <<~SUMMARY
|
124
|
+
|
125
|
+
#{"=" * full_width}
|
126
|
+
#{rows[0].join(" | ")}
|
127
|
+
#{"-" * full_width}
|
128
|
+
#{rows[1..-1].map { |row| row.join(" | ") }.join("\n")}
|
129
|
+
|
130
|
+
#{"* Denotes that the timer is still active\n" if __timers.values.any?(&:active?)}
|
66
131
|
SUMMARY
|
67
132
|
end
|
68
133
|
|
69
134
|
# Iterative methods
|
70
135
|
def self.stop_all
|
71
|
-
|
136
|
+
__timers.values.each(&:stop)
|
72
137
|
end
|
73
138
|
|
74
139
|
def self.reset_all
|
75
|
-
|
140
|
+
__timers.values.each(&:reset)
|
76
141
|
end
|
77
142
|
|
78
143
|
def self.delete_all
|
79
|
-
|
80
|
-
|
144
|
+
__timers.values.each { |t| t.reset(force: true) }
|
145
|
+
Thread.current[:time_up_timers] = {}
|
81
146
|
end
|
82
147
|
|
83
148
|
# Internal methods
|
149
|
+
def self.__timers
|
150
|
+
Thread.current[:time_up_timers]
|
151
|
+
end
|
152
|
+
|
84
153
|
def self.__ensure_timer(name)
|
85
|
-
raise Error.new("No timer named #{name.inspect}") unless
|
154
|
+
raise Error.new("No timer named #{name.inspect}") unless __timers[name]
|
86
155
|
end
|
87
156
|
|
88
157
|
class Timer
|
89
158
|
attr_reader :name
|
90
159
|
|
91
160
|
def initialize(name)
|
161
|
+
validate!(name)
|
92
162
|
@name = name
|
93
163
|
@start_time = nil
|
94
|
-
@
|
164
|
+
@total_elapsed = 0.0
|
165
|
+
@past_timings = []
|
95
166
|
end
|
96
167
|
|
97
|
-
def start
|
168
|
+
def start(&blk)
|
98
169
|
@start_time ||= now
|
170
|
+
if blk
|
171
|
+
blk.call.tap do
|
172
|
+
stop
|
173
|
+
end
|
174
|
+
else
|
175
|
+
self
|
176
|
+
end
|
99
177
|
end
|
100
178
|
|
101
179
|
def stop
|
102
180
|
if @start_time
|
103
|
-
|
181
|
+
duration = now - @start_time
|
182
|
+
@past_timings.push(duration)
|
183
|
+
@total_elapsed += duration
|
184
|
+
|
104
185
|
@start_time = nil
|
105
186
|
end
|
106
|
-
@
|
187
|
+
@total_elapsed
|
107
188
|
end
|
108
189
|
|
109
190
|
def elapsed
|
110
191
|
if active?
|
111
|
-
@
|
192
|
+
@total_elapsed + (now - @start_time)
|
112
193
|
else
|
113
|
-
@
|
194
|
+
@total_elapsed
|
114
195
|
end
|
115
196
|
end
|
116
197
|
|
117
|
-
def active?
|
118
|
-
!!@start_time
|
119
|
-
end
|
120
|
-
|
121
198
|
def reset(force: false)
|
122
199
|
if force
|
123
200
|
@start_time = nil
|
124
201
|
elsif !@start_time.nil?
|
125
202
|
@start_time = now
|
126
203
|
end
|
127
|
-
@
|
204
|
+
@total_elapsed = 0.0
|
205
|
+
@past_timings = []
|
206
|
+
end
|
207
|
+
|
208
|
+
def count
|
209
|
+
timings.size
|
210
|
+
end
|
211
|
+
|
212
|
+
def min
|
213
|
+
timings.min
|
214
|
+
end
|
215
|
+
|
216
|
+
def max
|
217
|
+
timings.max
|
218
|
+
end
|
219
|
+
|
220
|
+
def mean
|
221
|
+
times = timings
|
222
|
+
return if times.empty?
|
223
|
+
times.sum / times.size
|
224
|
+
end
|
225
|
+
|
226
|
+
def median
|
227
|
+
times = timings.sort
|
228
|
+
return if times.empty?
|
229
|
+
(times[(times.size - 1) / 2] + times[times.size / 2]) / 2.0
|
230
|
+
end
|
231
|
+
|
232
|
+
def percentile(percent)
|
233
|
+
times = timings.sort
|
234
|
+
return if times.empty?
|
235
|
+
return 0 if percent <= 0
|
236
|
+
return max if percent >= 100
|
237
|
+
return times.first if times.size == 1
|
238
|
+
position = (percent / 100.0) * (times.size - 1)
|
239
|
+
|
240
|
+
partial_ratio = position - position.floor
|
241
|
+
whole, partial = times[position.floor, 2]
|
242
|
+
whole + (partial - whole) * partial_ratio
|
243
|
+
end
|
244
|
+
|
245
|
+
def timings
|
246
|
+
if active?
|
247
|
+
@past_timings + [now - @start_time]
|
248
|
+
else
|
249
|
+
@past_timings
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def active?
|
254
|
+
!!@start_time
|
128
255
|
end
|
129
256
|
|
130
257
|
private
|
131
258
|
|
259
|
+
def validate!(name)
|
260
|
+
unless name.is_a?(Symbol) || name.is_a?(String)
|
261
|
+
raise Error.new("Timer name must be a String or Symbol")
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
132
265
|
def now
|
133
266
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
134
267
|
end
|
data/lib/time_up/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_up
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Searls
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -19,6 +19,7 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- ".github/workflows/main.yml"
|
21
21
|
- ".gitignore"
|
22
|
+
- ".standard.yml"
|
22
23
|
- CHANGELOG.md
|
23
24
|
- Gemfile
|
24
25
|
- Gemfile.lock
|