nanoc 4.9.6 → 4.9.7

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: 8491f07ee37d39dae6c84cb13f3cde0ec967a2fa723d3c6c0ae21283c13d205d
4
- data.tar.gz: 57984873a1fd8f9ecde937539b98e19689d6f08e819e30bc76e328e61807531f
3
+ metadata.gz: 78dad20b688911c787f63c6ff03fd27873eae890508e6c44fdacedecd1eaedc4
4
+ data.tar.gz: 0c8d223657f6655d1833d226e5c597a507a3124cc32ff587ccce4923c441af69
5
5
  SHA512:
6
- metadata.gz: 411feb568085bee7a5d28d8941f1b84dc0d573f8f52684c9067035dc7a50e3844a757df62e7f89b874f0a7ee84d111c46de3c4310695f51ea28733d95400bf0f
7
- data.tar.gz: 1397fbc30d9a1c717c9932174428baa7804b1460efdba033767b5f9efd83b1b6bd048bf9c04719d86c049559451667d6a10ce57a70b4b3d05e2132af43cade74
6
+ metadata.gz: b7e7711db31a5518188be605ef1165515fc41e3d3664c5e2f61cf2687a60ec23f9adc549fec7f119f86360a604d53ba8dcb07d97385174a6bfc7c85dc7aac69b
7
+ data.tar.gz: 3d6557c67ca0999e80f879c89e8784eb849f77a7e6502701a30c4e80829968042cc6e9f40079e8b63457fc252c4aae19e9d6c6e0bbae24652c0e57d0ceab407d
data/NEWS.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Nanoc news
2
2
 
3
+ ## 4.9.7 (2018-10-05)
4
+
5
+ Enhancements:
6
+
7
+ * Added `title_proc:` option to the blogging helper (#1362, #1363) [Thomas Hochstein]
8
+ * Dropped Ruby 2.3 support, as it is no longer maintained (#1361)
9
+ * Added static configuration file verification (#1360)
10
+
3
11
  ## 4.9.6 (2018-09-19)
4
12
 
5
13
  Fixes:
@@ -6,6 +6,8 @@ require 'ddmemoize'
6
6
  require 'ddmetrics'
7
7
  require 'ddplugin'
8
8
  require 'hamster'
9
+ require 'json'
10
+ require 'json_schema'
9
11
  require 'parallel'
10
12
  require 'ref'
11
13
  require 'slow_enumerator_tools'
@@ -15,6 +15,14 @@ module Nanoc::ArrayExtensions
15
15
  array
16
16
  end
17
17
 
18
+ def __nanoc_stringify_keys_recursively
19
+ array = []
20
+ each do |element|
21
+ array << (element.respond_to?(:__nanoc_stringify_keys_recursively) ? element.__nanoc_stringify_keys_recursively : element)
22
+ end
23
+ array
24
+ end
25
+
18
26
  # Freezes the contents of the array, as well as all array elements. The
19
27
  # array elements will be frozen using {#__nanoc_freeze_recursively} if they respond
20
28
  # to that message, or #freeze if they do not.
@@ -17,6 +17,16 @@ module Nanoc::HashExtensions
17
17
  hash
18
18
  end
19
19
 
20
+ def __nanoc_stringify_keys_recursively
21
+ hash = {}
22
+ each_pair do |key, value|
23
+ new_key = key.is_a?(Symbol) ? key.to_s : key
24
+ new_value = value.respond_to?(:__nanoc_stringify_keys_recursively) ? value.__nanoc_stringify_keys_recursively : value
25
+ hash[new_key] = new_value
26
+ end
27
+ hash
28
+ end
29
+
20
30
  # Freezes the contents of the hash, as well as all hash values. The hash
21
31
  # values will be frozen using {#__nanoc_freeze_recursively} if they respond to
22
32
  # that message, or #freeze if they do not.
@@ -40,8 +40,12 @@ module Nanoc::Int
40
40
  snapshot_actions.map { |a| [a.snapshot_names, a.paths] }
41
41
  end
42
42
 
43
- # TODO: Add contract
44
43
  memoized def serialize
44
+ serialize_uncached
45
+ end
46
+
47
+ contract C::None => Array
48
+ def serialize_uncached
45
49
  to_a.map(&:serialize)
46
50
  end
47
51
 
@@ -52,6 +52,8 @@ module Nanoc::Int
52
52
  @env_name = env_name
53
53
  @wrapped = hash.__nanoc_symbolize_keys_recursively
54
54
  @dir = dir
55
+
56
+ validate
55
57
  end
56
58
 
57
59
  contract C::None => self
@@ -192,5 +194,13 @@ module Nanoc::Int
192
194
  end
193
195
  end
194
196
  end
197
+
198
+ def validate
199
+ dir = File.dirname(__FILE__)
200
+ schema_data = JSON.parse(File.read(dir + '/configuration-schema.json'))
201
+ schema = JsonSchema.parse!(schema_data)
202
+ schema.expand_references!
203
+ schema.validate!(@wrapped.__nanoc_stringify_keys_recursively)
204
+ end
195
205
  end
196
206
  end
@@ -89,12 +89,12 @@ module Nanoc
89
89
  false
90
90
  end
91
91
 
92
- # TODO: Add contract
92
+ contract C::None => Array
93
93
  def marshal_dump
94
94
  [filename, string]
95
95
  end
96
96
 
97
- # TODO: Add contract
97
+ contract Array => C::Any
98
98
  def marshal_load(array)
99
99
  @filename = array[0]
100
100
  @string = Nanoc::Int::LazyValue.new(array[1])
@@ -138,7 +138,7 @@ module Nanoc
138
138
  contract String => self
139
139
  # @return [Nanoc::Identifier]
140
140
  def prefix(string)
141
- if string !~ /\A\//
141
+ unless /\A\//.match?(string)
142
142
  raise InvalidPrefixError.new(string)
143
143
  end
144
144
 
@@ -80,6 +80,10 @@ module Nanoc::Int
80
80
  "item_rep:#{item.identifier}:#{name}"
81
81
  end
82
82
 
83
+ def to_s
84
+ "#{item.identifier} (rep name #{name.inspect})"
85
+ end
86
+
83
87
  def inspect
84
88
  "<#{self.class} name=\"#{name}\" raw_path=\"#{raw_path}\" item.identifier=\"#{item.identifier}\">"
85
89
  end
@@ -20,5 +20,17 @@ module Nanoc::Int::ProcessingActions
20
20
  def to_s
21
21
  "filter #{@filter_name.inspect}, #{@params.inspect}"
22
22
  end
23
+
24
+ def hash
25
+ self.class.hash ^ filter_name.hash ^ params.hash
26
+ end
27
+
28
+ def ==(other)
29
+ self.class == other.class && filter_name == other.filter_name && params == other.params
30
+ end
31
+
32
+ def eql?(other)
33
+ self == other
34
+ end
23
35
  end
24
36
  end
@@ -20,5 +20,17 @@ module Nanoc::Int::ProcessingActions
20
20
  def to_s
21
21
  "layout #{@layout_identifier.inspect}, #{@params.inspect}"
22
22
  end
23
+
24
+ def hash
25
+ self.class.hash ^ layout_identifier.hash ^ params.hash
26
+ end
27
+
28
+ def ==(other)
29
+ self.class == other.class && layout_identifier == other.layout_identifier && params == other.params
30
+ end
31
+
32
+ def eql?(other)
33
+ self == other
34
+ end
23
35
  end
24
36
  end
@@ -30,5 +30,17 @@ module Nanoc::Int::ProcessingActions
30
30
  def to_s
31
31
  "snapshot #{@snapshot_names.inspect}, paths: #{@paths.inspect}"
32
32
  end
33
+
34
+ def hash
35
+ self.class.hash ^ snapshot_names.hash ^ paths.hash
36
+ end
37
+
38
+ def ==(other)
39
+ self.class == other.class && snapshot_names == other.snapshot_names && paths == other.paths
40
+ end
41
+
42
+ def eql?(other)
43
+ self == other
44
+ end
33
45
  end
34
46
  end
@@ -192,7 +192,7 @@ module Nanoc::Int
192
192
  # @param [Symbol] snapshot The name of the snapshot that was attempted to
193
193
  # be made
194
194
  def initialize(rep, snapshot)
195
- super("Attempted to create a snapshot with a duplicate name #{snapshot.inspect} for the item rep “#{rep.inspect}")
195
+ super("Attempted to create a snapshot with a duplicate name #{snapshot.inspect} for the item rep #{rep}")
196
196
  end
197
197
  end
198
198
 
@@ -200,7 +200,7 @@ module Nanoc::Int
200
200
  class CannotGetCompiledContentOfBinaryItem < Generic
201
201
  # @param [Nanoc::Int::ItemRep] rep The binary item representation whose compiled content was attempted to be accessed
202
202
  def initialize(rep)
203
- super("You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is #{rep.inspect}.")
203
+ super("You cannot access the compiled content of a binary item representation (but you can access the path). The offending item rep is #{rep}.")
204
204
  end
205
205
  end
206
206
 
@@ -5,6 +5,8 @@ module Nanoc::Int::Compiler::Phases
5
5
  class Resume < Abstract
6
6
  include Nanoc::Int::ContractsSupport
7
7
 
8
+ DONE = Object.new
9
+
8
10
  def initialize(wrapped:)
9
11
  super(wrapped: wrapped)
10
12
  end
@@ -22,8 +24,12 @@ module Nanoc::Int::Compiler::Phases
22
24
  raise(res)
23
25
  when Proc
24
26
  fiber.resume(res.call)
27
+ when DONE # rubocop:disable Lint/EmptyWhen
28
+ # ignore
25
29
  else
26
- # TODO: raise
30
+ raise Nanoc::Int::Errors::InternalInconsistency.new(
31
+ "Fiber yielded object of unexpected type #{res.class}",
32
+ )
27
33
  end
28
34
  end
29
35
 
@@ -40,6 +46,7 @@ module Nanoc::Int::Compiler::Phases
40
46
  Fiber.new do
41
47
  yield
42
48
  @fibers.delete(rep)
49
+ DONE
43
50
  end
44
51
 
45
52
  @fibers[rep]
@@ -9,13 +9,13 @@ module Nanoc::Int
9
9
 
10
10
  class IdenticalRoutesError < ::Nanoc::Error
11
11
  def initialize(output_path, rep_a, rep_b)
12
- super("The item representations #{rep_a.inspect} and #{rep_b.inspect} are both routed to #{output_path}.")
12
+ super("The item representations #{rep_a} and #{rep_b} are both routed to #{output_path}.")
13
13
  end
14
14
  end
15
15
 
16
16
  class RouteWithoutSlashError < ::Nanoc::Error
17
17
  def initialize(output_path, rep)
18
- super("The item representation #{rep.inspect} is routed to #{output_path}, which does not start with a slash, as required.")
18
+ super("The item representation #{rep} is routed to #{output_path}, which does not start with a slash, as required.")
19
19
  end
20
20
  end
21
21
 
@@ -66,7 +66,8 @@ module Nanoc::Int
66
66
  paths.each do |path|
67
67
  if assigned_paths.include?(path)
68
68
  # TODO: Include snapshot names in error message
69
- raise IdenticalRoutesError.new(path, assigned_paths[path], rep)
69
+ reps = [assigned_paths[path], rep].sort_by { |r| [r.item.identifier, r.name] }
70
+ raise IdenticalRoutesError.new(path, *reps)
70
71
  end
71
72
  end
72
73
  paths.each do |path|
@@ -69,7 +69,7 @@ module ::Nanoc::Checking::Checks
69
69
  next
70
70
  end
71
71
 
72
- if res.code =~ /^3..$/
72
+ if /^3..$/.match?(res.code)
73
73
  if i == 4
74
74
  return Result.new(href, 'too many redirects')
75
75
  end
@@ -101,7 +101,7 @@ module ::Nanoc::Checking::Checks
101
101
  location
102
102
  else
103
103
  base_url = url.dup
104
- base_url.path = (location =~ /^\// ? '' : '/')
104
+ base_url.path = (/^\//.match?(location) ? '' : '/')
105
105
  base_url.query = nil
106
106
  base_url.fragment = nil
107
107
  base_url.to_s + location
@@ -246,7 +246,7 @@ module Nanoc::CLI
246
246
  end
247
247
  end
248
248
  when RuntimeError
249
- if error.message =~ /^can't modify frozen/
249
+ if /^can't modify frozen/.match?(error.message)
250
250
  'You attempted to modify immutable data. Some data cannot ' \
251
251
  'be modified once compilation has started. Such data includes ' \
252
252
  'content and attributes of items and layouts, and filter arguments.'
@@ -286,7 +286,7 @@ module Nanoc::CLI
286
286
 
287
287
  error = unwrap_error(error)
288
288
 
289
- message = "#{error.class}: #{error.message}"
289
+ message = "#{error.class}: #{message_for_error(error)}"
290
290
  unless verbose
291
291
  message = "\e[1m\e[31m" + message + "\e[0m"
292
292
  end
@@ -295,6 +295,15 @@ module Nanoc::CLI
295
295
  stream.puts resolution.to_s if resolution
296
296
  end
297
297
 
298
+ def message_for_error(error)
299
+ case error
300
+ when JsonSchema::AggregateError
301
+ "\n" + error.errors.map { |e| " * #{e.pointer}: #{e.message}" }.join("\n")
302
+ else
303
+ error.message
304
+ end
305
+ end
306
+
298
307
  def write_item_rep(stream, error, verbose: false)
299
308
  return unless error.is_a?(Nanoc::Int::Errors::CompilationError)
300
309
 
@@ -336,7 +336,7 @@ module Nanoc::DataSources
336
336
  end
337
337
 
338
338
  regex =
339
- if filename =~ /(^|\/)index(\.[^\/]+)?$/
339
+ if /(^|\/)index(\.[^\/]+)?$/.match?(filename)
340
340
  allow_periods_in_identifiers? ? /\/?(index)?(\.[^\/\.]+)?$/ : /\/?index(\.[^\/]+)?$/
341
341
  else
342
342
  allow_periods_in_identifiers? ? /\.[^\/\.]+$/ : /\.[^\/]+$/
@@ -42,7 +42,7 @@ class Nanoc::DataSources::Filesystem
42
42
  def parse_with_frontmatter(content_filename)
43
43
  data = Tools.read_file(content_filename, config: @config)
44
44
 
45
- if data !~ /\A#{SEPARATOR}\s*$/
45
+ unless /\A#{SEPARATOR}\s*$/.match?(data)
46
46
  return ParseResult.new(content: data, attributes: {}, attributes_data: '')
47
47
  end
48
48
 
@@ -118,7 +118,7 @@ module Nanoc::Filters
118
118
  parse_fragment(klass, content)
119
119
  end
120
120
  rescue => e
121
- if e.message =~ /can't modify frozen string/
121
+ if /can't modify frozen string/.match?(e.message)
122
122
  parse(content.dup, klass, is_fullpage)
123
123
  else
124
124
  raise e
@@ -32,7 +32,7 @@ module Nanoc::Filters
32
32
  imports.concat(content.scan(/^@import\s+(["'])([^\1]+?)\1;/))
33
33
  imports.concat(content.scan(/^@import\s+url\((["']?)([^)]+?)\1\);/))
34
34
 
35
- imports.map { |i| i[1] =~ /\.(less|css)$/ ? i[1] : i[1] + '.less' }
35
+ imports.map { |i| /\.(less|css)$/.match?(i[1]) ? i[1] : i[1] + '.less' }
36
36
  end
37
37
 
38
38
  def imported_filenames_to_items(imported_filenames)
@@ -134,7 +134,7 @@ module Nanoc::Filters
134
134
 
135
135
  content = apply_gcse_search_workaround(content)
136
136
 
137
- doc = content =~ /<html[\s>]/ ? klass.parse(content) : klass.fragment(content)
137
+ doc = /<html[\s>]/.match?(content) ? klass.parse(content) : klass.fragment(content)
138
138
  selector = selectors.map { |sel| "descendant-or-self::#{sel}" }.join('|')
139
139
  doc.xpath(selector, namespaces).each do |node|
140
140
  if node.name == 'comment'
@@ -36,6 +36,7 @@ module Nanoc::Helpers
36
36
  attr_accessor :preserve_order
37
37
  attr_accessor :content_proc
38
38
  attr_accessor :excerpt_proc
39
+ attr_accessor :title_proc
39
40
  attr_accessor :title
40
41
  attr_accessor :author_name
41
42
  attr_accessor :author_uri
@@ -147,7 +148,7 @@ module Nanoc::Helpers
147
148
  xml.entry do
148
149
  # Add primary attributes
149
150
  xml.id atom_tag_for(article)
150
- xml.title article[:title], type: 'html'
151
+ xml.title title_proc.call(article), type: 'html'
151
152
 
152
153
  # Add dates
153
154
  xml.published attribute_to_time(article[:created_at]).__nanoc_to_iso8601_time
@@ -177,6 +178,7 @@ module Nanoc::Helpers
177
178
  # @option params [Boolean] :preserve_order
178
179
  # @option params [Proc] :content_proc
179
180
  # @option params [Proc] :excerpt_proc
181
+ # @option params [Proc] :title_proc
180
182
  # @option params [String] :alt_link
181
183
  # @option params [String] :id
182
184
  # @option params [String] :title
@@ -200,6 +202,7 @@ module Nanoc::Helpers
200
202
  builder.preserve_order = params.fetch(:preserve_order, false)
201
203
  builder.content_proc = params[:content_proc] || ->(a) { a.compiled_content(snapshot: :pre) }
202
204
  builder.excerpt_proc = params[:excerpt_proc] || ->(a) { a[:excerpt] }
205
+ builder.title_proc = params[:title_proc] || ->(a) { a[:title] }
203
206
  builder.title = params[:title] || @item[:title] || @config[:title]
204
207
  builder.author_name = params[:author_name] || @item[:author_name] || @config[:author_name]
205
208
  builder.author_uri = params[:author_uri] || @item[:author_uri] || @config[:author_uri]
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Nanoc
4
4
  # The current Nanoc version.
5
- VERSION = '4.9.6'
5
+ VERSION = '4.9.7'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nanoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.6
4
+ version: 4.9.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Defreyne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-19 00:00:00.000000000 Z
11
+ date: 2018-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: json_schema
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.19'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.19'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: parallel
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -431,7 +445,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
431
445
  requirements:
432
446
  - - "~>"
433
447
  - !ruby/object:Gem::Version
434
- version: '2.3'
448
+ version: '2.4'
435
449
  required_rubygems_version: !ruby/object:Gem::Requirement
436
450
  requirements:
437
451
  - - ">="