nanoc 4.4.4 → 4.4.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +9 -8
  4. data/NEWS.md +10 -0
  5. data/lib/nanoc/base.rb +0 -3
  6. data/lib/nanoc/base/contracts_support.rb +55 -2
  7. data/lib/nanoc/base/core_ext/array.rb +0 -2
  8. data/lib/nanoc/base/core_ext/hash.rb +0 -2
  9. data/lib/nanoc/base/entities.rb +1 -0
  10. data/lib/nanoc/base/entities/context.rb +1 -4
  11. data/lib/nanoc/base/entities/directed_graph.rb +0 -10
  12. data/lib/nanoc/base/entities/identifiable_collection.rb +1 -2
  13. data/lib/nanoc/base/entities/identifier.rb +6 -8
  14. data/lib/nanoc/base/entities/item_rep.rb +12 -18
  15. data/lib/nanoc/base/{compilation → entities}/outdatedness_reasons.rb +0 -0
  16. data/lib/nanoc/base/entities/site.rb +3 -19
  17. data/lib/nanoc/base/errors.rb +9 -0
  18. data/lib/nanoc/base/memoization.rb +0 -2
  19. data/lib/nanoc/base/repos/checksum_store.rb +21 -14
  20. data/lib/nanoc/base/repos/compiled_content_cache.rb +11 -15
  21. data/lib/nanoc/base/repos/dependency_store.rb +8 -27
  22. data/lib/nanoc/base/services.rb +3 -0
  23. data/lib/nanoc/base/services/compiler.rb +379 -0
  24. data/lib/nanoc/base/services/compiler_loader.rb +3 -1
  25. data/lib/nanoc/base/services/executor.rb +27 -41
  26. data/lib/nanoc/base/services/item_rep_builder.rb +4 -0
  27. data/lib/nanoc/base/services/item_rep_writer.rb +5 -2
  28. data/lib/nanoc/base/{compilation → services}/outdatedness_checker.rb +1 -1
  29. data/lib/nanoc/base/views/post_compile_item_rep_view.rb +1 -1
  30. data/lib/nanoc/base/views/view_context.rb +3 -3
  31. data/lib/nanoc/checking/check.rb +1 -1
  32. data/lib/nanoc/checking/checks/external_links.rb +1 -1
  33. data/lib/nanoc/cli.rb +0 -4
  34. data/lib/nanoc/cli/commands/compile.rb +2 -2
  35. data/lib/nanoc/cli/commands/shell.rb +1 -1
  36. data/lib/nanoc/data_sources/filesystem.rb +10 -20
  37. data/lib/nanoc/data_sources/filesystem/errors.rb +55 -0
  38. data/lib/nanoc/filters/asciidoc.rb +0 -2
  39. data/lib/nanoc/filters/coffeescript.rb +0 -2
  40. data/lib/nanoc/filters/colorize_syntax.rb +0 -2
  41. data/lib/nanoc/filters/handlebars.rb +0 -2
  42. data/lib/nanoc/filters/mustache.rb +0 -2
  43. data/lib/nanoc/filters/redcarpet.rb +0 -4
  44. data/lib/nanoc/filters/slim.rb +0 -2
  45. data/lib/nanoc/filters/typogruby.rb +0 -2
  46. data/lib/nanoc/filters/xsl.rb +0 -2
  47. data/lib/nanoc/filters/yui_compressor.rb +0 -2
  48. data/lib/nanoc/helpers/capturing.rb +22 -19
  49. data/lib/nanoc/helpers/link_to.rb +3 -7
  50. data/lib/nanoc/helpers/rendering.rb +1 -1
  51. data/lib/nanoc/rule_dsl/action_provider.rb +2 -2
  52. data/lib/nanoc/rule_dsl/compiler_dsl.rb +0 -2
  53. data/lib/nanoc/rule_dsl/recording_executor.rb +6 -6
  54. data/lib/nanoc/rule_dsl/rule.rb +0 -2
  55. data/lib/nanoc/rule_dsl/rule_context.rb +3 -3
  56. data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +5 -5
  57. data/lib/nanoc/spec.rb +1 -1
  58. data/lib/nanoc/version.rb +1 -1
  59. data/test/base/test_compiler.rb +3 -1
  60. data/test/base/test_dependency_tracker.rb +0 -19
  61. data/test/base/test_item_rep.rb +3 -0
  62. data/test/cli/commands/test_create_site.rb +1 -1
  63. data/test/data_sources/test_filesystem.rb +5 -5
  64. data/test/filters/test_coffeescript.rb +2 -0
  65. data/test/filters/test_handlebars.rb +4 -0
  66. data/test/filters/test_uglify_js.rb +4 -0
  67. data/test/filters/test_xsl.rb +1 -1
  68. data/test/helper.rb +6 -0
  69. data/test/helpers/test_capturing.rb +6 -1
  70. data/test/helpers/test_xml_sitemap.rb +1 -1
  71. metadata +6 -6
  72. data/lib/nanoc/base/compilation/compiler.rb +0 -295
  73. data/test/base/test_checksum_store.rb +0 -28
@@ -7,8 +7,10 @@ module Nanoc::Int
7
7
  dependency_store =
8
8
  Nanoc::Int::DependencyStore.new(site.items.to_a + site.layouts.to_a, env_name: site.config.env_name)
9
9
 
10
+ objects = site.items.to_a + site.layouts.to_a + site.code_snippets + [site.config]
11
+
10
12
  checksum_store =
11
- Nanoc::Int::ChecksumStore.new(site: site)
13
+ Nanoc::Int::ChecksumStore.new(site: site, objects: objects)
12
14
 
13
15
  item_rep_repo = Nanoc::Int::ItemRepRepo.new
14
16
 
@@ -7,23 +7,24 @@ module Nanoc
7
7
  end
8
8
  end
9
9
 
10
- def initialize(compiler, dependency_tracker)
11
- @compiler = compiler
10
+ def initialize(rep, compilation_context, dependency_tracker)
11
+ @rep = rep
12
+ @compilation_context = compilation_context
12
13
  @dependency_tracker = dependency_tracker
13
14
  end
14
15
 
15
- def filter(rep, filter_name, filter_args = {})
16
- filter = filter_for_filtering(rep, filter_name)
16
+ def filter(filter_name, filter_args = {})
17
+ filter = filter_for_filtering(@rep, filter_name)
17
18
 
18
19
  begin
19
- Nanoc::Int::NotificationCenter.post(:filtering_started, rep, filter_name)
20
+ Nanoc::Int::NotificationCenter.post(:filtering_started, @rep, filter_name)
20
21
 
21
22
  # Run filter
22
- last = rep.snapshot_contents[:last]
23
- source = rep.binary? ? last.filename : last.string
23
+ last = @rep.snapshot_contents[:last]
24
+ source = @rep.binary? ? last.filename : last.string
24
25
  filter_args.freeze
25
26
  result = filter.setup_and_run(source, filter_args)
26
- rep.snapshot_contents[:last] =
27
+ @rep.snapshot_contents[:last] =
27
28
  if filter.class.to_binary?
28
29
  Nanoc::Int::BinaryContent.new(filter.output_filename).tap(&:freeze)
29
30
  else
@@ -36,15 +37,15 @@ module Nanoc
36
37
  end
37
38
 
38
39
  # Create snapshot
39
- snapshot(rep, rep.snapshot_contents[:post] ? :post : :pre, final: false) unless rep.binary?
40
+ snapshot(@rep.snapshot_contents[:post] ? :post : :pre, final: false) unless @rep.binary?
40
41
  ensure
41
- Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
42
+ Nanoc::Int::NotificationCenter.post(:filtering_ended, @rep, filter_name)
42
43
  end
43
44
  end
44
45
 
45
- def layout(rep, layout_identifier, extra_filter_args = nil)
46
+ def layout(layout_identifier, extra_filter_args = nil)
46
47
  layout = find_layout(layout_identifier)
47
- filter_name, filter_args = *@compiler.filter_name_and_args_for_layout(layout)
48
+ filter_name, filter_args = *@compilation_context.filter_name_and_args_for_layout(layout)
48
49
  if filter_name.nil?
49
50
  raise Nanoc::Int::Errors::Generic, "Cannot find rule for layout matching #{layout_identifier}"
50
51
  end
@@ -52,64 +53,49 @@ module Nanoc
52
53
  filter_args.freeze
53
54
 
54
55
  # Check whether item can be laid out
55
- raise Nanoc::Int::Errors::CannotLayoutBinaryItem.new(rep) if rep.binary?
56
+ raise Nanoc::Int::Errors::CannotLayoutBinaryItem.new(@rep) if @rep.binary?
56
57
 
57
58
  # Create "pre" snapshot
58
- if rep.snapshot_contents[:post].nil?
59
- snapshot(rep, :pre, final: true)
59
+ if @rep.snapshot_contents[:post].nil?
60
+ snapshot(:pre, final: true)
60
61
  end
61
62
 
62
63
  # Create filter
63
64
  klass = Nanoc::Filter.named(filter_name)
64
65
  raise Nanoc::Int::Errors::UnknownFilter.new(filter_name) if klass.nil?
65
- view_context = @compiler.create_view_context(@dependency_tracker)
66
+ view_context = @compilation_context.create_view_context(@dependency_tracker)
66
67
  layout_view = Nanoc::LayoutView.new(layout, view_context)
67
- filter = klass.new(assigns_for(rep).merge({ layout: layout_view }))
68
+ filter = klass.new(assigns_for(@rep).merge({ layout: layout_view }))
68
69
 
69
70
  # Visit
70
71
  @dependency_tracker.bounce(layout, raw_content: true)
71
72
 
72
73
  begin
73
- Nanoc::Int::NotificationCenter.post(:filtering_started, rep, filter_name)
74
+ Nanoc::Int::NotificationCenter.post(:filtering_started, @rep, filter_name)
74
75
 
75
76
  # Layout
76
77
  content = layout.content
77
78
  arg = content.binary? ? content.filename : content.string
78
79
  res = filter.setup_and_run(arg, filter_args)
79
- rep.snapshot_contents[:last] = Nanoc::Int::TextualContent.new(res).tap(&:freeze)
80
+ @rep.snapshot_contents[:last] = Nanoc::Int::TextualContent.new(res).tap(&:freeze)
80
81
 
81
82
  # Create "post" snapshot
82
- snapshot(rep, :post, final: false)
83
+ snapshot(:post, final: false)
83
84
  ensure
84
- Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
85
+ Nanoc::Int::NotificationCenter.post(:filtering_ended, @rep, filter_name)
85
86
  end
86
87
  end
87
88
 
88
- def snapshot(rep, snapshot_name, final: true, path: nil) # rubocop:disable Lint/UnusedMethodArgument
89
- # NOTE: :path is irrelevant
90
-
91
- unless rep.binary?
92
- rep.snapshot_contents[snapshot_name] = rep.snapshot_contents[:last]
93
- end
94
-
95
- if snapshot_name == :pre && final
96
- rep.snapshot_defs << Nanoc::Int::SnapshotDef.new(:pre, true)
97
- end
98
-
99
- if final
100
- raw_path = rep.raw_path(snapshot: snapshot_name)
101
- if raw_path
102
- ItemRepWriter.new.write(rep, raw_path)
103
- end
104
- end
89
+ def snapshot(snapshot_name, final: true, path: nil) # rubocop:disable Lint/UnusedMethodArgument
90
+ @rep.snapshot_contents[snapshot_name] = @rep.snapshot_contents[:last]
105
91
  end
106
92
 
107
93
  def assigns_for(rep)
108
- @compiler.assigns_for(rep, @dependency_tracker)
94
+ @compilation_context.assigns_for(rep, @dependency_tracker)
109
95
  end
110
96
 
111
97
  def layouts
112
- @compiler.site.layouts
98
+ @compilation_context.site.layouts
113
99
  end
114
100
 
115
101
  def find_layout(arg)
@@ -140,7 +126,7 @@ module Nanoc
140
126
  end
141
127
 
142
128
  def use_globs?
143
- @compiler.site.config[:string_pattern_type] == 'glob'
129
+ @compilation_context.site.config[:string_pattern_type] == 'glob'
144
130
  end
145
131
  end
146
132
  end
@@ -17,6 +17,10 @@ module Nanoc::Int
17
17
  end
18
18
 
19
19
  Nanoc::Int::ItemRepRouter.new(@reps, @action_provider, @site).run
20
+
21
+ @reps.each do |rep|
22
+ rep.snapshot_defs = @action_provider.snapshots_defs_for(rep)
23
+ end
20
24
  end
21
25
  end
22
26
  end
@@ -3,7 +3,10 @@ module Nanoc::Int
3
3
  class ItemRepWriter
4
4
  TMP_TEXT_ITEMS_DIR = 'text_items'.freeze
5
5
 
6
- def write(item_rep, raw_path)
6
+ def write(item_rep, snapshot_name)
7
+ raw_path = item_rep.raw_path(snapshot: snapshot_name)
8
+ return unless raw_path
9
+
7
10
  # Create parent directory
8
11
  FileUtils.mkdir_p(File.dirname(raw_path))
9
12
 
@@ -15,7 +18,7 @@ module Nanoc::Int
15
18
  :will_write_rep, item_rep, raw_path
16
19
  )
17
20
 
18
- content = item_rep.snapshot_contents[:last]
21
+ content = item_rep.snapshot_contents[snapshot_name]
19
22
  if content.binary?
20
23
  temp_path = content.filename
21
24
  else
@@ -44,7 +44,7 @@ module Nanoc::Int
44
44
  when Nanoc::Int::Layout
45
45
  apply_rules(RULES_FOR_LAYOUT, obj)
46
46
  else
47
- raise "do not know how to check outdatedness of #{obj.inspect}"
47
+ raise Nanoc::Int::Errors::InternalInconsistency, "do not know how to check outdatedness of #{obj.inspect}"
48
48
  end
49
49
  end
50
50
  memoize :outdatedness_status_for
@@ -5,7 +5,7 @@ module Nanoc
5
5
  raise Nanoc::Int::Errors::CannotGetCompiledContentOfBinaryItem.new(unwrap)
6
6
  end
7
7
 
8
- snapshot_contents = @context.compiler.compiled_content_cache[unwrap]
8
+ snapshot_contents = @context.compilation_context.compiled_content_cache[unwrap]
9
9
  snapshot_name = snapshot || (snapshot_contents[:pre] ? :pre : :last)
10
10
 
11
11
  if snapshot_contents[snapshot_name]
@@ -4,13 +4,13 @@ module Nanoc
4
4
  attr_reader :reps
5
5
  attr_reader :items
6
6
  attr_reader :dependency_tracker
7
- attr_reader :compiler
7
+ attr_reader :compilation_context
8
8
 
9
- def initialize(reps:, items:, dependency_tracker:, compiler:)
9
+ def initialize(reps:, items:, dependency_tracker:, compilation_context:)
10
10
  @reps = reps
11
11
  @items = items
12
12
  @dependency_tracker = dependency_tracker
13
- @compiler = compiler
13
+ @compilation_context = compilation_context
14
14
  end
15
15
  end
16
16
  end
@@ -20,7 +20,7 @@ module Nanoc::Checking
20
20
  output_filenames = Dir[output_dir + '/**/*'].select { |f| File.file?(f) }
21
21
 
22
22
  # FIXME: ugly
23
- view_context = site.compiler.create_view_context(Nanoc::Int::DependencyTracker::Null.new)
23
+ view_context = site.compiler.compilation_context.create_view_context(Nanoc::Int::DependencyTracker::Null.new)
24
24
 
25
25
  context = {
26
26
  items: Nanoc::ItemCollectionWithRepsView.new(site.items, view_context),
@@ -103,7 +103,7 @@ module ::Nanoc::Checking::Checks
103
103
  if last_err
104
104
  return Result.new(href, last_err.message)
105
105
  else
106
- raise 'should not have gotten here'
106
+ raise Nanoc::Int::Errors::InternalInconsistency, 'last_err cannot be nil'
107
107
  end
108
108
  end
109
109
 
@@ -19,8 +19,6 @@ module Nanoc::CLI
19
19
  autoload 'ErrorHandler', 'nanoc/cli/error_handler'
20
20
 
21
21
  # @return [Boolean] true if debug output is enabled, false if not
22
- #
23
- # @since 3.2.0
24
22
  def self.debug?
25
23
  @debug || false
26
24
  end
@@ -29,8 +27,6 @@ module Nanoc::CLI
29
27
  # false if it should not
30
28
  #
31
29
  # @return [void]
32
- #
33
- # @since 3.2.0
34
30
  def self.debug=(boolean)
35
31
  @debug = boolean
36
32
  end
@@ -420,11 +420,11 @@ module Nanoc::CLI::Commands
420
420
 
421
421
  def default_listener_classes
422
422
  [
423
+ Nanoc::CLI::Commands::Compile::StackProfProfiler,
423
424
  Nanoc::CLI::Commands::Compile::DiffGenerator,
424
425
  Nanoc::CLI::Commands::Compile::DebugPrinter,
425
426
  Nanoc::CLI::Commands::Compile::TimingRecorder,
426
427
  Nanoc::CLI::Commands::Compile::FileActionPrinter,
427
- Nanoc::CLI::Commands::Compile::StackProfProfiler,
428
428
  ]
429
429
  end
430
430
 
@@ -449,7 +449,7 @@ module Nanoc::CLI::Commands
449
449
  end
450
450
 
451
451
  def teardown_listeners
452
- @listeners.each(&:stop_safely)
452
+ @listeners.reverse_each(&:stop_safely)
453
453
  end
454
454
 
455
455
  def reps
@@ -34,7 +34,7 @@ module Nanoc::CLI::Commands
34
34
  reps: reps_for(site),
35
35
  items: site.items,
36
36
  dependency_tracker: Nanoc::Int::DependencyTracker::Null.new,
37
- compiler: nil,
37
+ compilation_context: nil,
38
38
  )
39
39
  end
40
40
 
@@ -117,7 +117,7 @@ module Nanoc::DataSources
117
117
 
118
118
  ProtoDocument.new(is_binary: true, filename: content_filename, attributes: meta)
119
119
  elsif is_binary && klass == Nanoc::Int::Layout
120
- raise "The layout file '#{content_filename}' is a binary file, but layouts can only be textual"
120
+ raise Errors::BinaryLayout.new(content_filename)
121
121
  else
122
122
  parse_result = parse(content_filename, meta_filename)
123
123
 
@@ -239,11 +239,11 @@ module Nanoc::DataSources
239
239
 
240
240
  # Check number of files per type
241
241
  unless [0, 1].include?(meta_filenames.size)
242
- raise "Found #{meta_filenames.size} meta files for #{basename}; expected 0 or 1"
242
+ raise Errors::MultipleMetaFiles.new(meta_filenames, basename)
243
243
  end
244
244
  unless config[:identifier_type] == 'full'
245
245
  unless [0, 1].include?(content_filenames.size)
246
- raise "Found #{content_filenames.size} content files for #{basename}; expected 0 or 1"
246
+ raise Errors::MultipleContentFiles.new(meta_filenames, basename)
247
247
  end
248
248
  end
249
249
 
@@ -352,7 +352,7 @@ module Nanoc::DataSources
352
352
 
353
353
  pieces = data.split(/^(-{5}|-{3})[ \t]*\r?\n?/, 3)
354
354
  if pieces.size < 4
355
- raise "The file '#{content_filename}' appears to start with a metadata section (three or five dashes at the top) but it does not seem to be in the correct format."
355
+ raise Errors::InvalidFormat.new(content_filename)
356
356
  end
357
357
 
358
358
  meta = parse_metadata(pieces[2], content_filename)
@@ -366,7 +366,7 @@ module Nanoc::DataSources
366
366
  begin
367
367
  meta = YAML.load(data) || {}
368
368
  rescue => e
369
- raise "Could not parse YAML for #{filename}: #{e.message}"
369
+ raise Errors::UnparseableMetadata.new(filename, e)
370
370
  end
371
371
 
372
372
  verify_meta(meta, filename)
@@ -386,16 +386,10 @@ module Nanoc::DataSources
386
386
  end
387
387
  end
388
388
 
389
- class InvalidMetadataError < Nanoc::Error
390
- def initialize(filename, klass)
391
- super("The file #{filename} has invalid metadata (expected key-value pairs, found #{klass} instead)")
392
- end
393
- end
394
-
395
389
  def verify_meta(meta, filename)
396
390
  return if meta.is_a?(Hash)
397
391
 
398
- raise InvalidMetadataError.new(filename, meta.class)
392
+ raise Errors::InvalidMetadata.new(filename, meta.class)
399
393
  end
400
394
 
401
395
  # Reads the content of the file with the given name and returns a string
@@ -407,7 +401,7 @@ module Nanoc::DataSources
407
401
  begin
408
402
  data = File.read(filename)
409
403
  rescue => e
410
- raise "Could not read #{filename}: #{e.inspect}"
404
+ raise Errors::FileUnreadable.new(filename, e)
411
405
  end
412
406
 
413
407
  # Fix
@@ -422,11 +416,11 @@ module Nanoc::DataSources
422
416
  begin
423
417
  data.encode!('UTF-8')
424
418
  rescue
425
- raise_encoding_error(filename, original_encoding)
419
+ raise Errors::InvalidEncoding.new(filename, original_encoding)
426
420
  end
427
421
 
428
422
  unless data.valid_encoding?
429
- raise_encoding_error(filename, original_encoding)
423
+ raise Errors::InvalidEncoding.new(filename, original_encoding)
430
424
  end
431
425
  end
432
426
 
@@ -435,12 +429,8 @@ module Nanoc::DataSources
435
429
 
436
430
  data
437
431
  end
438
-
439
- # Raises an invalid encoding error for the given filename and encoding.
440
- def raise_encoding_error(filename, encoding)
441
- raise "Could not read #{filename} because the file is not valid #{encoding}."
442
- end
443
432
  end
444
433
  end
445
434
 
446
435
  require_relative 'filesystem/tools'
436
+ require_relative 'filesystem/errors'
@@ -0,0 +1,55 @@
1
+ class Nanoc::DataSources::Filesystem < Nanoc::DataSource
2
+ # @api private
3
+ module Errors
4
+ class Generic < ::Nanoc::Error
5
+ end
6
+
7
+ class BinaryLayout < Generic
8
+ def initialize(content_filename)
9
+ super("The layout file '#{content_filename}' is a binary file, but layouts can only be textual")
10
+ end
11
+ end
12
+
13
+ class MultipleMetaFiles < Generic
14
+ def initialize(meta_filenames, basename)
15
+ super("Found #{meta_filenames.size} meta files for #{basename}; expected 0 or 1")
16
+ end
17
+ end
18
+
19
+ class MultipleContentFiles < Generic
20
+ def initialize(content_filenames, basename)
21
+ super("Found #{content_filenames.size} content files for #{basename}; expected 0 or 1")
22
+ end
23
+ end
24
+
25
+ class InvalidFormat < Generic
26
+ def initialize(content_filename)
27
+ super("The file '#{content_filename}' appears to start with a metadata section (three or five dashes at the top) but it does not seem to be in the correct format.")
28
+ end
29
+ end
30
+
31
+ class UnparseableMetadata < Generic
32
+ def initialize(filename, error)
33
+ super("Could not parse metadata for #{filename}: #{error.message}")
34
+ end
35
+ end
36
+
37
+ class InvalidMetadata < Generic
38
+ def initialize(filename, klass)
39
+ super("The file #{filename} has invalid metadata (expected key-value pairs, found #{klass} instead)")
40
+ end
41
+ end
42
+
43
+ class InvalidEncoding < Generic
44
+ def initialize(filename, encoding)
45
+ super("Could not read #{filename} because the file is not valid #{encoding}.")
46
+ end
47
+ end
48
+
49
+ class FileUnreadable < Generic
50
+ def initialize(filename, error)
51
+ super("Could not read #{filename}: #{error.inspect}")
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,6 +1,4 @@
1
1
  module Nanoc::Filters
2
- # @since 3.2.0
3
- #
4
2
  # @api private
5
3
  class AsciiDoc < Nanoc::Filter
6
4
  # Runs the content through [AsciiDoc](http://www.methods.co.nz/asciidoc/).