nanoc 4.4.4 → 4.4.5

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