nanoc 4.6.3 → 4.6.4
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/Gemfile.lock +5 -5
- data/NEWS.md +6 -0
- data/lib/nanoc.rb +1 -0
- data/lib/nanoc/cli/commands/compile.rb +28 -61
- data/lib/nanoc/cli/stream_cleaners/utf8.rb +1 -1
- data/lib/nanoc/spec.rb +3 -3
- data/lib/nanoc/telemetry.rb +17 -0
- data/lib/nanoc/telemetry/counter.rb +13 -0
- data/lib/nanoc/telemetry/labelled_counter.rb +27 -0
- data/lib/nanoc/telemetry/labelled_summary.rb +31 -0
- data/lib/nanoc/telemetry/registry.rb +16 -0
- data/lib/nanoc/telemetry/stopwatch.rb +41 -0
- data/lib/nanoc/telemetry/summary.rb +53 -0
- data/lib/nanoc/version.rb +1 -1
- data/spec/nanoc/cli/commands/compile/timing_recorder_spec.rb +35 -4
- data/spec/nanoc/cli/stream_cleaners/utf8_spec.rb +7 -0
- data/spec/nanoc/helpers/blogging_spec.rb +7 -6
- data/spec/nanoc/helpers/capturing_spec.rb +5 -4
- data/spec/nanoc/helpers/child_parent_spec.rb +12 -43
- data/spec/nanoc/helpers/filtering_spec.rb +5 -2
- data/spec/nanoc/helpers/link_to_spec.rb +66 -23
- data/spec/nanoc/helpers/rendering_spec.rb +3 -7
- data/spec/nanoc/spec_spec.rb +68 -0
- data/spec/nanoc/telemetry/counter_spec.rb +18 -0
- data/spec/nanoc/telemetry/labelled_counter_spec.rb +56 -0
- data/spec/nanoc/telemetry/labelled_summary_spec.rb +63 -0
- data/spec/nanoc/telemetry/stopwatch_spec.rb +59 -0
- data/spec/nanoc/telemetry/summary_spec.rb +66 -0
- data/spec/nanoc/telemetry_spec.rb +26 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45e73cb6f9f73af2a760146464d15b5537744e16
|
4
|
+
data.tar.gz: e5c219a107840118bb1fa45ba1396d302dbc5049
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88453d81285519f1ee03821c835f9744096623f07a887f012dc66404bd68342429b211202cc9ec686b430da2d56ffbe2e6c23ec166fded484674512ab1c4c611
|
7
|
+
data.tar.gz: 39bb9372f9c71984af7726da2a1a2290dc85a89af3c7006073265d19620a4fb58f66616badd98ed97651a5006c71be82b0c9a00822727b91c94855cf368e3342
|
data/Gemfile.lock
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
GIT
|
2
2
|
remote: https://github.com/bbatsov/rubocop.git
|
3
|
-
revision:
|
3
|
+
revision: 70f6d9191e2cc1d9726d4a4107f5efc5a797e310
|
4
4
|
specs:
|
5
5
|
rubocop (0.47.1)
|
6
6
|
parser (>= 2.3.3.1, < 3.0)
|
@@ -27,7 +27,7 @@ GIT
|
|
27
27
|
PATH
|
28
28
|
remote: .
|
29
29
|
specs:
|
30
|
-
nanoc (4.6.
|
30
|
+
nanoc (4.6.4)
|
31
31
|
cri (~> 2.3)
|
32
32
|
ddplugin (~> 1.0)
|
33
33
|
hamster (~> 3.0)
|
@@ -246,7 +246,7 @@ GEM
|
|
246
246
|
kramdown (1.13.2)
|
247
247
|
less (2.6.0)
|
248
248
|
commonjs (~> 0.2.7)
|
249
|
-
libv8 (3.16.14.
|
249
|
+
libv8 (3.16.14.19)
|
250
250
|
listen (3.1.5)
|
251
251
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
252
252
|
rb-inotify (~> 0.9, >= 0.9.7)
|
@@ -342,7 +342,7 @@ GEM
|
|
342
342
|
trollop (2.1.2)
|
343
343
|
typogruby (1.0.18)
|
344
344
|
rubypants
|
345
|
-
uglifier (3.1.
|
345
|
+
uglifier (3.1.5)
|
346
346
|
execjs (>= 0.3.0, < 3)
|
347
347
|
unicode-display_width (1.1.3)
|
348
348
|
vcr (3.0.3)
|
@@ -425,4 +425,4 @@ DEPENDENCIES
|
|
425
425
|
yuicompressor
|
426
426
|
|
427
427
|
BUNDLED WITH
|
428
|
-
1.14.
|
428
|
+
1.14.6
|
data/NEWS.md
CHANGED
data/lib/nanoc.rb
CHANGED
@@ -151,55 +151,36 @@ module Nanoc::CLI::Commands
|
|
151
151
|
|
152
152
|
# @param [Enumerable<Nanoc::Int::ItemRep>] reps
|
153
153
|
def initialize(reps:)
|
154
|
-
# rep ->
|
155
|
-
# filter_name ->
|
156
|
-
# accum -> 0.0
|
157
|
-
# last_start -> nil
|
158
|
-
@times_per_rep = {}
|
159
|
-
|
160
154
|
@reps = reps
|
161
155
|
end
|
162
156
|
|
163
157
|
# @see Listener#start
|
164
158
|
def start
|
165
|
-
Nanoc::
|
166
|
-
|
167
|
-
|
159
|
+
@telemetry = Nanoc::Telemetry.new
|
160
|
+
|
161
|
+
stopwatches = {}
|
168
162
|
|
169
|
-
|
170
|
-
|
171
|
-
|
163
|
+
Nanoc::Int::NotificationCenter.on(:filtering_started) do |rep, _filter_name|
|
164
|
+
stopwatch_stack = stopwatches.fetch(rep) { stopwatches[rep] = [] }
|
165
|
+
stopwatch_stack << Nanoc::Telemetry::Stopwatch.new
|
166
|
+
stopwatch_stack.last.start
|
172
167
|
end
|
173
168
|
|
174
169
|
Nanoc::Int::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
|
175
|
-
|
176
|
-
|
170
|
+
stopwatch = stopwatches.fetch(rep).pop
|
171
|
+
stopwatch.stop
|
177
172
|
|
178
|
-
|
179
|
-
@times_per_rep[rep][filter_name].delete(:last_start)
|
173
|
+
@telemetry.summary(:filter_total).observe(stopwatch.duration, filter_name: filter_name)
|
180
174
|
end
|
181
175
|
|
182
176
|
Nanoc::Int::NotificationCenter.on(:compilation_suspended) do |rep, _exception|
|
183
|
-
|
184
|
-
|
185
|
-
times[:accum] << (Time.now - times[:last_start])
|
186
|
-
times.delete(:last_start)
|
187
|
-
times[:suspended] = true
|
188
|
-
|
189
|
-
break
|
190
|
-
end
|
191
|
-
end
|
177
|
+
stopwatch = stopwatches.fetch(rep).last
|
178
|
+
stopwatch.stop if stopwatch && stopwatch.running?
|
192
179
|
end
|
193
180
|
|
194
181
|
Nanoc::Int::NotificationCenter.on(:compilation_started) do |rep|
|
195
|
-
|
196
|
-
|
197
|
-
@times_per_rep[rep][filter_name][:last_start] = Time.now
|
198
|
-
times[:suspended] = false
|
199
|
-
|
200
|
-
break
|
201
|
-
end
|
202
|
-
end
|
182
|
+
stopwatch = stopwatches.fetch(rep, []).last
|
183
|
+
stopwatch.start if stopwatch
|
203
184
|
end
|
204
185
|
end
|
205
186
|
|
@@ -214,25 +195,26 @@ module Nanoc::CLI::Commands
|
|
214
195
|
def profiling_table
|
215
196
|
headers = ['', 'count', 'min', 'avg', 'max', 'tot']
|
216
197
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
tot = samples.reduce(0, &:+)
|
222
|
-
avg = tot / count
|
223
|
-
max = samples.max
|
198
|
+
metric_set = @telemetry.summary(:filter_total)
|
199
|
+
rows = metric_set.labels.map do |label|
|
200
|
+
metric = metric_set.get(label)
|
201
|
+
filter_name = label[:filter_name].to_s
|
224
202
|
|
225
|
-
|
203
|
+
count = metric.count
|
204
|
+
min = metric.min
|
205
|
+
avg = metric.avg
|
206
|
+
tot = metric.sum
|
207
|
+
max = metric.max
|
208
|
+
|
209
|
+
[filter_name, count.to_s] + [min, avg, max, tot].map { |r| "#{format('%4.2f', r)}s" }
|
226
210
|
end
|
227
211
|
|
228
212
|
[headers] + rows
|
229
213
|
end
|
230
214
|
|
231
215
|
def print_profiling_feedback
|
232
|
-
|
233
|
-
return if durations_per_filter.empty?
|
216
|
+
return if @telemetry.summary(:filter_total).labels.empty?
|
234
217
|
|
235
|
-
# Print warning if necessary
|
236
218
|
if @reps.any? { |r| !r.compiled? }
|
237
219
|
$stderr.puts
|
238
220
|
$stderr.puts 'Warning: profiling information may not be accurate because ' \
|
@@ -248,7 +230,7 @@ module Nanoc::CLI::Commands
|
|
248
230
|
|
249
231
|
print_row(table[0], lengths)
|
250
232
|
|
251
|
-
puts "#{'
|
233
|
+
puts "#{'─' * lengths[0]}─┼─#{lengths[1..-1].map { |length| '─' * length }.join('───')}"
|
252
234
|
|
253
235
|
table[1..-1].each { |row| print_row(row, lengths) }
|
254
236
|
end
|
@@ -256,22 +238,7 @@ module Nanoc::CLI::Commands
|
|
256
238
|
def print_row(row, lengths)
|
257
239
|
values = row.zip(lengths).map { |text, length| text.rjust length }
|
258
240
|
|
259
|
-
puts values[0] + '
|
260
|
-
end
|
261
|
-
|
262
|
-
def durations_per_filter
|
263
|
-
@_durations_per_filter ||= begin
|
264
|
-
result = {}
|
265
|
-
|
266
|
-
@times_per_rep.each do |_rep, times_per_filter|
|
267
|
-
times_per_filter.each do |filter_name, data|
|
268
|
-
result[filter_name] ||= []
|
269
|
-
result[filter_name].concat(data[:accum])
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
result
|
274
|
-
end
|
241
|
+
puts values[0] + ' │ ' + values[1..-1].join(' ')
|
275
242
|
end
|
276
243
|
end
|
277
244
|
|
@@ -6,7 +6,7 @@ module Nanoc::CLI::StreamCleaners
|
|
6
6
|
# @see Nanoc::CLI::StreamCleaners::Abstract#clean
|
7
7
|
def clean(s)
|
8
8
|
# FIXME: this decomposition is not generally usable
|
9
|
-
s.
|
9
|
+
s.tr('─┼“”‘’', '-+""\'\'').gsub('…', '...').gsub('©', '(c)')
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
data/lib/nanoc/spec.rb
CHANGED
@@ -32,7 +32,7 @@ module Nanoc
|
|
32
32
|
def create_item(content, attributes, identifier)
|
33
33
|
item = Nanoc::Int::Item.new(content, attributes, identifier)
|
34
34
|
@items = @items.add(item)
|
35
|
-
|
35
|
+
self
|
36
36
|
end
|
37
37
|
|
38
38
|
# Creates a new layout and adds it to the site’s collection of layouts.
|
@@ -47,7 +47,7 @@ module Nanoc
|
|
47
47
|
def create_layout(content, attributes, identifier)
|
48
48
|
layout = Nanoc::Int::Layout.new(content, attributes, identifier)
|
49
49
|
@layouts = @layouts.add(layout)
|
50
|
-
|
50
|
+
self
|
51
51
|
end
|
52
52
|
|
53
53
|
# Creates a new representation for the given item.
|
@@ -60,7 +60,7 @@ module Nanoc
|
|
60
60
|
rep = Nanoc::Int::ItemRep.new(item.unwrap, rep)
|
61
61
|
rep.paths[:last] = [path]
|
62
62
|
@reps << rep
|
63
|
-
|
63
|
+
self
|
64
64
|
end
|
65
65
|
|
66
66
|
# @return [Object] An object that includes the helper functions
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Nanoc
|
2
|
+
# @api private
|
3
|
+
module Telemetry
|
4
|
+
def self.new
|
5
|
+
Registry.new
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require_relative 'telemetry/counter'
|
11
|
+
require_relative 'telemetry/summary'
|
12
|
+
|
13
|
+
require_relative 'telemetry/labelled_counter'
|
14
|
+
require_relative 'telemetry/labelled_summary'
|
15
|
+
|
16
|
+
require_relative 'telemetry/registry'
|
17
|
+
require_relative 'telemetry/stopwatch'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Nanoc::Telemetry
|
2
|
+
class LabelledCounter
|
3
|
+
def initialize
|
4
|
+
@counters = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def increment(labels)
|
8
|
+
get(labels).increment
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(labels)
|
12
|
+
@counters.fetch(labels) { @counters[labels] = Counter.new }
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: add #labels
|
16
|
+
|
17
|
+
def value(labels)
|
18
|
+
get(labels).value
|
19
|
+
end
|
20
|
+
|
21
|
+
def values
|
22
|
+
@counters.each_with_object({}) do |(labels, counter), res|
|
23
|
+
res[labels] = counter.value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Nanoc::Telemetry
|
2
|
+
class LabelledSummary
|
3
|
+
def initialize
|
4
|
+
@summaries = {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def observe(value, labels)
|
8
|
+
get(labels).observe(value)
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(labels)
|
12
|
+
@summaries.fetch(labels) { @summaries[labels] = Summary.new }
|
13
|
+
end
|
14
|
+
|
15
|
+
def labels
|
16
|
+
@summaries.keys
|
17
|
+
end
|
18
|
+
|
19
|
+
def quantile(fraction, labels)
|
20
|
+
get(labels).quantile(fraction)
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: add quantiles(fraction)
|
24
|
+
# TODO: add min(labels)
|
25
|
+
# TODO: add mins
|
26
|
+
# TODO: add max(labels)
|
27
|
+
# TODO: add maxs
|
28
|
+
# TODO: add sum(labels)
|
29
|
+
# TODO: add sums
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Nanoc::Telemetry
|
2
|
+
class Registry
|
3
|
+
def initialize
|
4
|
+
@counters = {}
|
5
|
+
@summaries = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def counter(name)
|
9
|
+
@counters.fetch(name) { @counters[name] = LabelledCounter.new }
|
10
|
+
end
|
11
|
+
|
12
|
+
def summary(name)
|
13
|
+
@summaries.fetch(name) { @summaries[name] = LabelledSummary.new }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Nanoc::Telemetry
|
2
|
+
class Stopwatch
|
3
|
+
attr_reader :duration
|
4
|
+
|
5
|
+
class AlreadyRunningError < StandardError
|
6
|
+
def message
|
7
|
+
'Cannot start, because stopwatch is already running'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class NotRunningError < StandardError
|
12
|
+
def message
|
13
|
+
'Cannot stop, because stopwatch is not running'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@duration = 0.0
|
19
|
+
@last_start = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def start
|
23
|
+
raise AlreadyRunningError if running?
|
24
|
+
@last_start = Time.now
|
25
|
+
end
|
26
|
+
|
27
|
+
def stop
|
28
|
+
raise NotRunningError unless running?
|
29
|
+
@duration += (Time.now - @last_start)
|
30
|
+
@last_start = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def running?
|
34
|
+
!@last_start.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
def stopped?
|
38
|
+
!running?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Nanoc::Telemetry
|
2
|
+
class Summary
|
3
|
+
class EmptySummaryError < StandardError
|
4
|
+
def message
|
5
|
+
'Cannot calculate quantile for empty summary'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@values = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def observe(value)
|
14
|
+
@values << value
|
15
|
+
@sorted_values = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def count
|
19
|
+
@values.size
|
20
|
+
end
|
21
|
+
|
22
|
+
def sum
|
23
|
+
raise EmptySummaryError if @values.empty?
|
24
|
+
@values.reduce(:+)
|
25
|
+
end
|
26
|
+
|
27
|
+
def avg
|
28
|
+
sum / count
|
29
|
+
end
|
30
|
+
|
31
|
+
def min
|
32
|
+
quantile(0.0)
|
33
|
+
end
|
34
|
+
|
35
|
+
def max
|
36
|
+
quantile(1.0)
|
37
|
+
end
|
38
|
+
|
39
|
+
def quantile(fraction)
|
40
|
+
raise EmptySummaryError if @values.empty?
|
41
|
+
|
42
|
+
target = (@values.size - 1) * fraction.to_f
|
43
|
+
interp = target % 1.0
|
44
|
+
sorted_values[target.floor] * (1.0 - interp) + sorted_values[target.ceil] * interp
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def sorted_values
|
50
|
+
@sorted_values ||= @values.sort
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|