nanoc 4.9.6 → 4.9.7

Sign up to get free protection for your applications and to get access to all the features.
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
  - - ">="