nanoc-core 4.11.12 → 4.11.17

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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nanoc/core.rb +37 -0
  3. data/lib/nanoc/core/basic_item_rep_collection_view.rb +88 -0
  4. data/lib/nanoc/core/basic_item_rep_view.rb +83 -0
  5. data/lib/nanoc/core/basic_item_view.rb +54 -0
  6. data/lib/nanoc/core/changes_stream.rb +55 -0
  7. data/lib/nanoc/core/checksum_store.rb +1 -1
  8. data/lib/nanoc/core/checksummer.rb +4 -2
  9. data/lib/nanoc/core/compilation_item_rep_collection_view.rb +12 -0
  10. data/lib/nanoc/core/compilation_item_rep_view.rb +57 -0
  11. data/lib/nanoc/core/compilation_item_view.rb +47 -0
  12. data/lib/nanoc/core/compilation_phases/abstract.rb +48 -0
  13. data/lib/nanoc/core/compilation_phases/cache.rb +43 -0
  14. data/lib/nanoc/core/compilation_phases/mark_done.rb +23 -0
  15. data/lib/nanoc/core/compilation_phases/notify.rb +19 -0
  16. data/lib/nanoc/core/compilation_phases/recalculate.rb +49 -0
  17. data/lib/nanoc/core/compilation_phases/resume.rb +52 -0
  18. data/lib/nanoc/core/compilation_phases/write.rb +84 -0
  19. data/lib/nanoc/core/compilation_stages/build_reps.rb +36 -0
  20. data/lib/nanoc/core/compilation_stages/calculate_checksums.rb +42 -0
  21. data/lib/nanoc/core/compilation_stages/cleanup.rb +43 -0
  22. data/lib/nanoc/core/compilation_stages/compile_reps.rb +96 -0
  23. data/lib/nanoc/core/compilation_stages/determine_outdatedness.rb +49 -0
  24. data/lib/nanoc/core/compilation_stages/forget_outdated_dependencies.rb +20 -0
  25. data/lib/nanoc/core/compilation_stages/load_stores.rb +35 -0
  26. data/lib/nanoc/core/compilation_stages/postprocess.rb +21 -0
  27. data/lib/nanoc/core/compilation_stages/preprocess.rb +32 -0
  28. data/lib/nanoc/core/compilation_stages/prune.rb +30 -0
  29. data/lib/nanoc/core/compilation_stages/store_post_compilation_state.rb +20 -0
  30. data/lib/nanoc/core/compilation_stages/store_pre_compilation_state.rb +32 -0
  31. data/lib/nanoc/core/compiled_content_cache.rb +2 -2
  32. data/lib/nanoc/core/compiler.rb +214 -0
  33. data/lib/nanoc/core/compiler_loader.rb +48 -0
  34. data/lib/nanoc/core/config_loader.rb +95 -0
  35. data/lib/nanoc/core/config_view.rb +67 -0
  36. data/lib/nanoc/core/configuration.rb +2 -4
  37. data/lib/nanoc/core/contracts_support.rb +20 -0
  38. data/lib/nanoc/core/dependency_store.rb +3 -3
  39. data/lib/nanoc/core/document_view_mixin.rb +87 -0
  40. data/lib/nanoc/core/errors.rb +108 -0
  41. data/lib/nanoc/core/executor.rb +134 -0
  42. data/lib/nanoc/core/feature.rb +92 -0
  43. data/lib/nanoc/core/filter.rb +269 -0
  44. data/lib/nanoc/core/identifiable_collection_view.rb +111 -0
  45. data/lib/nanoc/core/item_collection_with_reps_view.rb +12 -0
  46. data/lib/nanoc/core/item_collection_without_reps_view.rb +12 -0
  47. data/lib/nanoc/core/item_rep_builder.rb +54 -0
  48. data/lib/nanoc/core/item_rep_selector.rb +67 -0
  49. data/lib/nanoc/core/item_rep_writer.rb +85 -0
  50. data/lib/nanoc/core/layout_collection_view.rb +12 -0
  51. data/lib/nanoc/core/layout_view.rb +9 -0
  52. data/lib/nanoc/core/mutable_config_view.rb +16 -0
  53. data/lib/nanoc/core/mutable_document_view_mixin.rb +60 -0
  54. data/lib/nanoc/core/mutable_identifiable_collection_view.rb +19 -0
  55. data/lib/nanoc/core/mutable_item_collection_view.rb +34 -0
  56. data/lib/nanoc/core/mutable_item_view.rb +9 -0
  57. data/lib/nanoc/core/mutable_layout_collection_view.rb +26 -0
  58. data/lib/nanoc/core/mutable_layout_view.rb +9 -0
  59. data/lib/nanoc/core/outdatedness_checker.rb +222 -0
  60. data/lib/nanoc/core/outdatedness_rules/attributes_modified.rb +41 -0
  61. data/lib/nanoc/core/outdatedness_rules/code_snippets_modified.rb +31 -0
  62. data/lib/nanoc/core/outdatedness_rules/content_modified.rb +21 -0
  63. data/lib/nanoc/core/outdatedness_rules/item_collection_extended.rb +20 -0
  64. data/lib/nanoc/core/outdatedness_rules/layout_collection_extended.rb +20 -0
  65. data/lib/nanoc/core/outdatedness_rules/not_written.rb +17 -0
  66. data/lib/nanoc/core/outdatedness_rules/rules_modified.rb +45 -0
  67. data/lib/nanoc/core/outdatedness_rules/uses_always_outdated_filter.rb +26 -0
  68. data/lib/nanoc/core/post_compile_item_collection_view.rb +12 -0
  69. data/lib/nanoc/core/post_compile_item_rep_collection_view.rb +12 -0
  70. data/lib/nanoc/core/post_compile_item_rep_view.rb +33 -0
  71. data/lib/nanoc/core/post_compile_item_view.rb +20 -0
  72. data/lib/nanoc/core/pruner.rb +123 -0
  73. data/lib/nanoc/core/site_loader.rb +102 -0
  74. data/lib/nanoc/core/trivial_error.rb +10 -0
  75. data/lib/nanoc/core/version.rb +1 -1
  76. data/lib/nanoc/core/view.rb +43 -0
  77. data/lib/nanoc/core/view_context_for_compilation.rb +6 -6
  78. metadata +97 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf201905e79de9d9711910668d228863a48b53e13a78694a50122932960d6189
4
- data.tar.gz: ffae70af266ec5c189b0d09976bfb9ebada587f5ea1eeb73b12dfeaebeb07d36
3
+ metadata.gz: 748b150c5ee93de8c4ce8dcd31ddc4e4dc64897a73d86dd91be9d743b1ff476d
4
+ data.tar.gz: '008722ff9d57b3c5e13fda3e5ac60dd4860a1240076383067a37664ebb7df2ca'
5
5
  SHA512:
6
- metadata.gz: bf812e2fc282b019b2d907ee39a84fe7999b2b2f8565139cc442e3ca38cb75949ea70f27b07058ef4bd52af9a1291c0ca73e6db53790e431976a729f6a4dd3c8
7
- data.tar.gz: ef670404975dfde21013d6878afbf272e7bd41d7dee120e124cb2c61e37e1ad1f5ac64ccc1f4554f57dcde1d1303cac32ef6e088853d569c24f1c070c72abc7c
6
+ metadata.gz: 49b011afe4838c9150bd91ccaf17acd7150f5d143af69b13e623f542ff2af7965205f4b2a595b07e651babada9e902a98e2c879f923070be21c14fd199c5674d
7
+ data.tar.gz: aefeed726b1ac55565446d4fc7ccce5a3d5293029ad7b0e534e33f8f0ff338d0f7d8f9641dfd964125e5a71dbb243aa95e9cf447d071478fea03d1e2a485ea4c
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Ruby stdlib
4
+ require 'fiber'
5
+ require 'find'
4
6
  require 'pstore'
5
7
  require 'singleton'
6
8
  require 'tmpdir'
9
+ require 'yaml'
7
10
 
8
11
  # External gems
9
12
  require 'json_schema'
@@ -12,10 +15,32 @@ require 'ddmetrics'
12
15
  require 'ddplugin'
13
16
  require 'hamster'
14
17
  require 'slow_enumerator_tools'
18
+ require 'tomlrb'
19
+ require 'tty-platform'
15
20
  require 'zeitwerk'
16
21
 
17
22
  module Nanoc
18
23
  module Core
24
+ # Similar to `nil` except that it can only be compared against using
25
+ # `UNDEFINED.equal?(x)`. Used in places where `nil` already has meaning, and
26
+ # thus cannot be used to mean the presence of nothing.
27
+ UNDEFINED = Object.new
28
+
29
+ # @return [String] A string containing information about this Nanoc version
30
+ # and its environment (Ruby engine and version, Rubygems version if any).
31
+ #
32
+ # @api private
33
+ def self.version_information
34
+ "Nanoc #{Nanoc::VERSION} © 2007–2019 Denis Defreyne.\n" \
35
+ "Running #{RUBY_ENGINE} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) on #{RUBY_PLATFORM} with RubyGems #{Gem::VERSION}.\n"
36
+ end
37
+
38
+ # @return [Boolean] True if the current platform is Windows, false otherwise.
39
+ #
40
+ # @api private
41
+ def self.on_windows?
42
+ @_on_windows ||= TTY::Platform.new.windows?
43
+ end
19
44
  end
20
45
  end
21
46
 
@@ -43,3 +68,15 @@ loader.eager_load
43
68
  require_relative 'core/core_ext/array'
44
69
  require_relative 'core/core_ext/hash'
45
70
  require_relative 'core/core_ext/string'
71
+
72
+ # Tracking issue:
73
+ # https://github.com/nanoc/features/issues/24
74
+ Nanoc::Core::Feature.define('live_cmd', version: '4.11')
75
+
76
+ # Tracking issue:
77
+ # https://github.com/nanoc/features/issues/40
78
+ Nanoc::Core::Feature.define('toml', version: '4.11')
79
+
80
+ # Tracking issue:
81
+ # https://github.com/nanoc/features/issues/20
82
+ Nanoc::Core::Feature.define('binary_compiled_content_cache', version: '4.11')
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class BasicItemRepCollectionView < ::Nanoc::Core::View
6
+ include Enumerable
7
+
8
+ class NoSuchItemRepError < ::Nanoc::Core::Error
9
+ def initialize(rep_name)
10
+ super("No rep named #{rep_name.inspect} was found.")
11
+ end
12
+ end
13
+
14
+ # @api private
15
+ def initialize(item_reps, context)
16
+ super(context)
17
+ @item_reps = item_reps
18
+ end
19
+
20
+ # @api private
21
+ def _unwrap
22
+ @item_reps
23
+ end
24
+
25
+ # @api private
26
+ def view_class
27
+ Nanoc::Core::BasicItemRepView
28
+ end
29
+
30
+ def to_ary
31
+ @item_reps.map { |ir| view_class.new(ir, @context) }
32
+ end
33
+
34
+ # Calls the given block once for each item rep, passing that item rep as a parameter.
35
+ #
36
+ # @yieldparam [Object] item rep view
37
+ #
38
+ # @yieldreturn [void]
39
+ #
40
+ # @return [self]
41
+ def each
42
+ @item_reps.each { |ir| yield view_class.new(ir, @context) }
43
+ self
44
+ end
45
+
46
+ # @return [Integer]
47
+ def size
48
+ @item_reps.size
49
+ end
50
+
51
+ # Return the item rep with the given name, or nil if no item rep exists.
52
+ #
53
+ # @param [Symbol] rep_name
54
+ #
55
+ # @return [nil] if no item rep with the given name was found
56
+ #
57
+ # @return [Nanoc::Core::BasicItemRepView] if an item rep with the given name was found
58
+ def [](rep_name)
59
+ case rep_name
60
+ when Symbol
61
+ res = @item_reps.find { |ir| ir.name == rep_name }
62
+ res && view_class.new(res, @context)
63
+ when Integer
64
+ raise ArgumentError, "expected BasicItemRepCollectionView#[] to be called with a symbol (you likely want `.reps[:default]` rather than `.reps[#{rep_name}]`)"
65
+ else
66
+ raise ArgumentError, 'expected BasicItemRepCollectionView#[] to be called with a symbol'
67
+ end
68
+ end
69
+
70
+ # Return the item rep with the given name, or raises an exception if there
71
+ # is no rep with the given name.
72
+ #
73
+ # @param [Symbol] rep_name
74
+ #
75
+ # @return [Nanoc::Core::BasicItemRepView]
76
+ #
77
+ # @raise if no rep was found
78
+ def fetch(rep_name)
79
+ res = @item_reps.find { |ir| ir.name == rep_name }
80
+ if res
81
+ view_class.new(res, @context)
82
+ else
83
+ raise NoSuchItemRepError.new(rep_name)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class BasicItemRepView < ::Nanoc::Core::View
6
+ # @api private
7
+ def initialize(item_rep, context)
8
+ super(context)
9
+ @item_rep = item_rep
10
+ end
11
+
12
+ # @abstract
13
+ def item_view_class
14
+ Nanoc::Core::BasicItemView
15
+ end
16
+
17
+ # @api private
18
+ def _unwrap
19
+ @item_rep
20
+ end
21
+
22
+ # @see Object#==
23
+ def ==(other)
24
+ other.respond_to?(:item) && other.respond_to?(:name) && item == other.item && name == other.name
25
+ end
26
+
27
+ # @see Object#eql?
28
+ def eql?(other)
29
+ other.is_a?(self.class) &&
30
+ item.eql?(other.item) &&
31
+ name.eql?(other.name)
32
+ end
33
+
34
+ # @see Object#hash
35
+ def hash
36
+ self.class.hash ^ item.identifier.hash ^ name.hash
37
+ end
38
+
39
+ # @return [Symbol]
40
+ def name
41
+ @item_rep.name
42
+ end
43
+
44
+ def snapshot?(name)
45
+ @context.dependency_tracker.bounce(_unwrap.item, compiled_content: true)
46
+ @item_rep.snapshot?(name)
47
+ end
48
+
49
+ # Returns the item rep’s path, as used when being linked to. It starts
50
+ # with a slash and it is relative to the output directory. It does not
51
+ # include the path to the output directory. It will not include the
52
+ # filename if the filename is an index filename.
53
+ #
54
+ # @param [Symbol] snapshot The snapshot for which the path should be
55
+ # returned.
56
+ #
57
+ # @return [String] The item rep’s path.
58
+ def path(snapshot: :last)
59
+ @context.dependency_tracker.bounce(_unwrap.item, path: true)
60
+ @item_rep.path(snapshot: snapshot)
61
+ end
62
+
63
+ # Returns the item that this item rep belongs to.
64
+ #
65
+ # @return [Nanoc::Core::CompilationItemView]
66
+ def item
67
+ item_view_class.new(@item_rep.item, @context)
68
+ end
69
+
70
+ # @api private
71
+ def binary?
72
+ snapshot_def = _unwrap.snapshot_defs.find { |sd| sd.name == :last }
73
+ raise Nanoc::Core::Errors::NoSuchSnapshot.new(_unwrap, :last) if snapshot_def.nil?
74
+
75
+ snapshot_def.binary?
76
+ end
77
+
78
+ def inspect
79
+ "<#{self.class} item.identifier=#{item.identifier} name=#{name}>"
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class BasicItemView < ::Nanoc::Core::View
6
+ include Nanoc::Core::DocumentViewMixin
7
+
8
+ # Returns the children of this item. For items with identifiers that have
9
+ # extensions, returns an empty collection.
10
+ #
11
+ # @return [Enumerable<Nanoc::Core::CompilationItemView>]
12
+ def children
13
+ unless _unwrap.identifier.legacy?
14
+ raise Nanoc::Core::Errors::CannotGetParentOrChildrenOfNonLegacyItem.new(_unwrap.identifier)
15
+ end
16
+
17
+ children_pattern = Nanoc::Core::Pattern.from(_unwrap.identifier.to_s + '*/')
18
+ children = @context.items.select { |i| children_pattern.match?(i.identifier) }
19
+
20
+ children.map { |i| self.class.new(i, @context) }.freeze
21
+ end
22
+
23
+ # Returns the parent of this item, if one exists. For items with identifiers
24
+ # that have extensions, returns nil.
25
+ #
26
+ # @return [Nanoc::Core::CompilationItemView] if the item has a parent
27
+ #
28
+ # @return [nil] if the item has no parent
29
+ def parent
30
+ unless _unwrap.identifier.legacy?
31
+ raise Nanoc::Core::Errors::CannotGetParentOrChildrenOfNonLegacyItem.new(_unwrap.identifier)
32
+ end
33
+
34
+ parent_identifier = '/' + _unwrap.identifier.components[0..-2].join('/') + '/'
35
+ parent_identifier = '/' if parent_identifier == '//'
36
+
37
+ parent = @context.items[parent_identifier]
38
+
39
+ parent && self.class.new(parent, @context)
40
+ end
41
+
42
+ # @return [Boolean] True if the item is binary, false otherwise
43
+ def binary?
44
+ _unwrap.content.binary?
45
+ end
46
+
47
+ # @return [String, nil] The path to the file containing the uncompiled content of this item.
48
+ def raw_filename
49
+ @context.dependency_tracker.bounce(_unwrap, raw_content: true)
50
+ _unwrap.content.filename
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class ChangesStream
6
+ class ChangesListener
7
+ def initialize(y)
8
+ @y = y
9
+ end
10
+
11
+ def unknown
12
+ @y << :unknown
13
+ end
14
+
15
+ def lib
16
+ @y << :lib
17
+ end
18
+
19
+ def to_stop(&block)
20
+ if block_given?
21
+ @to_stop = block
22
+ else
23
+ @to_stop
24
+ end
25
+ end
26
+ end
27
+
28
+ def initialize(enum: nil)
29
+ @enum = enum
30
+ @enum ||=
31
+ Enumerator.new do |y|
32
+ @listener = ChangesListener.new(y)
33
+ yield(@listener)
34
+ end.lazy
35
+ end
36
+
37
+ def stop
38
+ @listener&.to_stop&.call
39
+ end
40
+
41
+ def map
42
+ self.class.new(enum: @enum.map { |e| yield(e) })
43
+ end
44
+
45
+ def to_enum
46
+ @enum
47
+ end
48
+
49
+ def each
50
+ @enum.each { |e| yield(e) }
51
+ nil
52
+ end
53
+ end
54
+ end
55
+ end
@@ -64,7 +64,7 @@ module Nanoc
64
64
 
65
65
  @checksums = {}
66
66
  new_data.each_pair do |key, checksum|
67
- if references.include?(key) || references.include?(key.first)
67
+ if references.include?(key) || (key.respond_to?(:first) && references.include?(key.first))
68
68
  @checksums[key] = checksum
69
69
  end
70
70
  end
@@ -50,8 +50,8 @@ module Nanoc
50
50
  end
51
51
 
52
52
  def calc_for_each_attribute_of(obj, digest_class = CompactDigest)
53
- obj.attributes.each_with_object({}) do |(key, value), memo|
54
- memo[key] = Nanoc::Core::Checksummer.calc(value, digest_class)
53
+ obj.attributes.transform_values do |value|
54
+ Nanoc::Core::Checksummer.calc(value, digest_class)
55
55
  end
56
56
  end
57
57
 
@@ -95,12 +95,14 @@ module Nanoc
95
95
  define_behavior(Nanoc::Core::BinaryContent, BinaryContentUpdateBehavior)
96
96
  define_behavior(Nanoc::Core::Configuration, HashUpdateBehavior)
97
97
  define_behavior(Nanoc::Core::Context, ContextUpdateBehavior)
98
+ define_behavior(Nanoc::Core::CodeSnippet, DataUpdateBehavior)
98
99
  define_behavior(Nanoc::Core::IdentifiableCollection, ArrayUpdateBehavior)
99
100
  define_behavior(Nanoc::Core::Identifier, ToSUpdateBehavior)
100
101
  define_behavior(Nanoc::Core::Item, DocumentUpdateBehavior)
101
102
  define_behavior(Nanoc::Core::ItemRep, ItemRepUpdateBehavior)
102
103
  define_behavior(Nanoc::Core::Layout, DocumentUpdateBehavior)
103
104
  define_behavior(Nanoc::Core::TextualContent, StringUpdateBehavior)
105
+ define_behavior(Nanoc::Core::View, UnwrapUpdateBehavior)
104
106
 
105
107
  @behaviors
106
108
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class CompilationItemRepCollectionView < ::Nanoc::Core::BasicItemRepCollectionView
6
+ # @api private
7
+ def view_class
8
+ Nanoc::Core::CompilationItemRepView
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nanoc
4
+ module Core
5
+ class CompilationItemRepView < ::Nanoc::Core::BasicItemRepView
6
+ # How long to wait before the requested file appears.
7
+ #
8
+ # This is a bit of a hack -- ideally, Nanoc would know that the file is
9
+ # being generated, and wait the appropriate amount of time.
10
+ FILE_APPEAR_TIMEOUT = 10.0
11
+
12
+ # @abstract
13
+ def item_view_class
14
+ Nanoc::Core::CompilationItemView
15
+ end
16
+
17
+ # Returns the item rep’s raw path. It includes the path to the output
18
+ # directory and the full filename.
19
+ #
20
+ # @param [Symbol] snapshot The snapshot for which the path should be
21
+ # returned.
22
+ #
23
+ # @return [String] The item rep’s raw path.
24
+ def raw_path(snapshot: :last)
25
+ @context.dependency_tracker.bounce(_unwrap.item, compiled_content: true)
26
+
27
+ res = @item_rep.raw_path(snapshot: snapshot)
28
+
29
+ unless @item_rep.compiled?
30
+ Fiber.yield(Nanoc::Core::Errors::UnmetDependency.new(@item_rep, snapshot))
31
+ end
32
+
33
+ # Wait for file to exist
34
+ if res
35
+ start = Time.now
36
+ sleep 0.05 until File.file?(res) || Time.now - start > FILE_APPEAR_TIMEOUT
37
+ raise Nanoc::Core::Errors::InternalInconsistency, "File did not apear in time: #{res}" unless File.file?(res)
38
+ end
39
+
40
+ res
41
+ end
42
+
43
+ # Returns the compiled content.
44
+ #
45
+ # @param [String] snapshot The name of the snapshot from which to
46
+ # fetch the compiled content. By default, the returned compiled content
47
+ # will be the content compiled right before the first layout call (if
48
+ # any).
49
+ #
50
+ # @return [String] The content at the given snapshot.
51
+ def compiled_content(snapshot: nil)
52
+ @context.dependency_tracker.bounce(_unwrap.item, compiled_content: true)
53
+ @context.compiled_content_store.compiled_content(rep: _unwrap, snapshot: snapshot)
54
+ end
55
+ end
56
+ end
57
+ end