nanoc-core 4.14.6 → 4.14.8

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nanoc/core/action_sequence.rb +1 -1
  3. data/lib/nanoc/core/action_sequence_builder.rb +12 -4
  4. data/lib/nanoc/core/action_sequence_store.rb +8 -5
  5. data/lib/nanoc/core/assertions.rb +12 -2
  6. data/lib/nanoc/core/basic_outdatedness_checker.rb +26 -10
  7. data/lib/nanoc/core/binary_compiled_content_cache.rb +24 -10
  8. data/lib/nanoc/core/checksum_collection.rb +7 -2
  9. data/lib/nanoc/core/checksum_store.rb +26 -9
  10. data/lib/nanoc/core/checksummer.rb +63 -32
  11. data/lib/nanoc/core/code_snippet.rb +1 -1
  12. data/lib/nanoc/core/compilation_stages/build_reps.rb +7 -2
  13. data/lib/nanoc/core/compilation_stages/calculate_checksums.rb +2 -0
  14. data/lib/nanoc/core/compilation_stages/cleanup.rb +8 -2
  15. data/lib/nanoc/core/compilation_stages/compile_reps.rb +78 -36
  16. data/lib/nanoc/core/compilation_stages/determine_outdatedness.rb +2 -0
  17. data/lib/nanoc/core/compilation_stages/forget_outdated_dependencies.rb +5 -1
  18. data/lib/nanoc/core/compilation_stages/load_stores.rb +6 -1
  19. data/lib/nanoc/core/compilation_stages/postprocess.rb +2 -0
  20. data/lib/nanoc/core/compilation_stages/preprocess.rb +12 -3
  21. data/lib/nanoc/core/compilation_stages/prune.rb +6 -1
  22. data/lib/nanoc/core/compilation_stages/store_post_compilation_state.rb +2 -0
  23. data/lib/nanoc/core/compilation_stages/store_pre_compilation_state.rb +6 -1
  24. data/lib/nanoc/core/compiled_content_cache.rb +7 -2
  25. data/lib/nanoc/core/compiled_content_repo.rb +13 -5
  26. data/lib/nanoc/core/compiler.rb +12 -3
  27. data/lib/nanoc/core/compiler_loader.rb +13 -4
  28. data/lib/nanoc/core/config_loader.rb +14 -4
  29. data/lib/nanoc/core/configuration.rb +36 -15
  30. data/lib/nanoc/core/content.rb +5 -1
  31. data/lib/nanoc/core/context.rb +4 -5
  32. data/lib/nanoc/core/contracts_support.rb +26 -8
  33. data/lib/nanoc/core/core_ext/hash.rb +12 -2
  34. data/lib/nanoc/core/data_source.rb +22 -6
  35. data/lib/nanoc/core/dependency.rb +8 -2
  36. data/lib/nanoc/core/dependency_props.rb +27 -8
  37. data/lib/nanoc/core/dependency_store.rb +55 -22
  38. data/lib/nanoc/core/dependency_tracker.rb +20 -4
  39. data/lib/nanoc/core/directed_graph.rb +27 -64
  40. data/lib/nanoc/core/document.rb +4 -1
  41. data/lib/nanoc/core/errors.rb +45 -12
  42. data/lib/nanoc/core/executor.rb +26 -9
  43. data/lib/nanoc/core/feature.rb +2 -1
  44. data/lib/nanoc/core/filter.rb +27 -11
  45. data/lib/nanoc/core/identifiable_collection.rb +2 -1
  46. data/lib/nanoc/core/identifier.rb +23 -8
  47. data/lib/nanoc/core/in_memory_data_source.rb +3 -1
  48. data/lib/nanoc/core/item.rb +1 -1
  49. data/lib/nanoc/core/item_collection.rb +2 -2
  50. data/lib/nanoc/core/item_rep.rb +1 -1
  51. data/lib/nanoc/core/item_rep_builder.rb +14 -5
  52. data/lib/nanoc/core/item_rep_router.rb +27 -13
  53. data/lib/nanoc/core/item_rep_writer.rb +28 -5
  54. data/lib/nanoc/core/layout.rb +1 -1
  55. data/lib/nanoc/core/layout_collection.rb +2 -2
  56. data/lib/nanoc/core/mutable_document_view_mixin.rb +3 -6
  57. data/lib/nanoc/core/outdatedness_checker.rb +170 -95
  58. data/lib/nanoc/core/outdatedness_reasons.rb +45 -16
  59. data/lib/nanoc/core/outdatedness_rules/attributes_modified.rb +24 -10
  60. data/lib/nanoc/core/outdatedness_rules/item_added.rb +9 -4
  61. data/lib/nanoc/core/outdatedness_rules/layout_added.rb +9 -4
  62. data/lib/nanoc/core/outdatedness_rules/not_written.rb +7 -2
  63. data/lib/nanoc/core/outdatedness_rules/rules_modified.rb +14 -6
  64. data/lib/nanoc/core/outdatedness_rules/uses_always_outdated_filter.rb +1 -1
  65. data/lib/nanoc/core/outdatedness_store.rb +7 -1
  66. data/lib/nanoc/core/pattern.rb +4 -1
  67. data/lib/nanoc/core/prefixed_data_source.rb +6 -2
  68. data/lib/nanoc/core/processing_actions/filter.rb +2 -0
  69. data/lib/nanoc/core/processing_actions/layout.rb +2 -0
  70. data/lib/nanoc/core/processing_actions/snapshot.rb +12 -3
  71. data/lib/nanoc/core/pruner.rb +11 -3
  72. data/lib/nanoc/core/regexp_pattern.rb +1 -1
  73. data/lib/nanoc/core/site.rb +10 -4
  74. data/lib/nanoc/core/site_loader.rb +25 -17
  75. data/lib/nanoc/core/store.rb +33 -6
  76. data/lib/nanoc/core/string_pattern.rb +1 -1
  77. data/lib/nanoc/core/textual_compiled_content_cache.rb +60 -5
  78. data/lib/nanoc/core/textual_content.rb +4 -1
  79. data/lib/nanoc/core/version.rb +1 -1
  80. data/lib/nanoc/core/view_context_for_compilation.rb +6 -2
  81. data/lib/nanoc/core/views/basic_item_rep_collection_view.rb +11 -4
  82. data/lib/nanoc/core/views/basic_item_rep_view.rb +9 -2
  83. data/lib/nanoc/core/views/basic_item_view.rb +17 -9
  84. data/lib/nanoc/core/views/compilation_item_rep_view.rb +12 -4
  85. data/lib/nanoc/core/views/compilation_item_view.rb +3 -1
  86. data/lib/nanoc/core/views/identifiable_collection_view.rb +17 -5
  87. data/lib/nanoc/core/views/mutable_item_collection_view.rb +5 -2
  88. data/lib/nanoc/core/views/mutable_layout_collection_view.rb +5 -2
  89. data/lib/nanoc/core/views/post_compile_item_view.rb +3 -1
  90. data/lib/nanoc/core.rb +4 -4
  91. metadata +3 -9
  92. data/lib/nanoc/core/compilation_phases/abstract.rb +0 -48
  93. data/lib/nanoc/core/compilation_phases/cache.rb +0 -28
  94. data/lib/nanoc/core/compilation_phases/mark_done.rb +0 -23
  95. data/lib/nanoc/core/compilation_phases/notify.rb +0 -22
  96. data/lib/nanoc/core/compilation_phases/recalculate.rb +0 -59
  97. data/lib/nanoc/core/compilation_phases/write.rb +0 -31
@@ -46,6 +46,8 @@ module Nanoc
46
46
 
47
47
  class Named < AbstractContract
48
48
  def initialize(name)
49
+ super()
50
+
49
51
  @name = name
50
52
  end
51
53
 
@@ -60,11 +62,14 @@ module Nanoc
60
62
 
61
63
  class IterOf < AbstractContract
62
64
  def initialize(contract)
65
+ super()
66
+
63
67
  @contract = contract
64
68
  end
65
69
 
66
70
  def valid?(val)
67
- val.respond_to?(:each) && val.all? { |v| Contract.valid?(v, @contract) }
71
+ val.respond_to?(:each) &&
72
+ val.all? { |v| Contract.valid?(v, @contract) }
68
73
  end
69
74
 
70
75
  def inspect
@@ -97,13 +102,20 @@ module Nanoc
97
102
  false
98
103
  end
99
104
 
100
- @_contracts_support__should_enable = contracts_loadable && !ENV.key?('DISABLE_CONTRACTS')
105
+ @_contracts_support__should_enable =
106
+ contracts_loadable && !ENV.key?('DISABLE_CONTRACTS')
101
107
 
102
108
  if @_contracts_support__should_enable
103
109
  # FIXME: ugly
104
- ::Contracts.const_set('Named', EnabledContracts::Named)
105
- ::Contracts.const_set('IterOf', EnabledContracts::IterOf)
106
- ::Contracts.const_set('AbsolutePathString', EnabledContracts::AbsolutePathString)
110
+ ::Contracts.const_set(
111
+ 'Named', EnabledContracts::Named
112
+ )
113
+ ::Contracts.const_set(
114
+ 'IterOf', EnabledContracts::IterOf
115
+ )
116
+ ::Contracts.const_set(
117
+ 'AbsolutePathString', EnabledContracts::AbsolutePathString
118
+ )
107
119
 
108
120
  warn_about_performance
109
121
  end
@@ -136,13 +148,19 @@ module Nanoc
136
148
 
137
149
  puts '-' * 78
138
150
  puts 'A NOTE ABOUT PERFORMANCE:'
139
- puts 'The `contracts` gem is loaded, which enables extra run-time checks, but can drastically reduce Nanoc’s performance. The `contracts` gem is intended for development purposes, and is not recommended for day-to-day Nanoc usage.'
151
+ puts 'The `contracts` gem is loaded, which enables extra run-time ' \
152
+ 'checks, but can drastically reduce Nanoc’s performance. The ' \
153
+ '`contracts` gem is intended for development purposes, and is ' \
154
+ 'not recommended for day-to-day Nanoc usage.'
140
155
  puts
141
156
 
142
157
  if defined?(Bundler)
143
- puts 'To speed up compilation, remove `contracts` from the Gemfile and run `bundle install`.'
158
+ puts 'To speed up compilation, remove `contracts` from the Gemfile ' \
159
+ 'and run `bundle install`.'
144
160
  else
145
- puts 'To speed up compilation, either uninstall the `contracts` gem, or use Bundler (https://bundler.io/) with a Gemfile that doesn’t include `contracts`.'
161
+ puts 'To speed up compilation, either uninstall the `contracts` ' \
162
+ 'gem, or use Bundler (https://bundler.io/) with a Gemfile ' \
163
+ 'that doesn’t include `contracts`.'
146
164
  end
147
165
 
148
166
  puts '-' * 78
@@ -13,7 +13,12 @@ module Nanoc
13
13
  hash = {}
14
14
  each_pair do |key, value|
15
15
  new_key = key.respond_to?(:to_sym) ? key.to_sym : key
16
- new_value = value.respond_to?(:__nanoc_symbolize_keys_recursively) ? value.__nanoc_symbolize_keys_recursively : value
16
+ new_value =
17
+ if value.respond_to?(:__nanoc_symbolize_keys_recursively)
18
+ value.__nanoc_symbolize_keys_recursively
19
+ else
20
+ value
21
+ end
17
22
  hash[new_key] = new_value
18
23
  end
19
24
  hash
@@ -23,7 +28,12 @@ module Nanoc
23
28
  hash = {}
24
29
  each_pair do |key, value|
25
30
  new_key = key.is_a?(Symbol) ? key.to_s : key
26
- new_value = value.respond_to?(:__nanoc_stringify_keys_recursively) ? value.__nanoc_stringify_keys_recursively : value
31
+ new_value =
32
+ if value.respond_to?(:__nanoc_stringify_keys_recursively)
33
+ value.__nanoc_stringify_keys_recursively
34
+ else
35
+ value
36
+ end
27
37
  hash[new_key] = new_value
28
38
  end
29
39
  hash
@@ -101,13 +101,15 @@ module Nanoc
101
101
 
102
102
  # @api private
103
103
  def item_changes
104
- warn "Caution: Data source #{self.class.identifier.inspect} does not implement #item_changes; live compilation will not pick up changes in this data source."
104
+ warn "Caution: Data source #{self.class.identifier.inspect} does not " \
105
+ 'implement #item_changes; live compilation will not pick up changes in this data source.'
105
106
  Enumerator.new { |_y| sleep }
106
107
  end
107
108
 
108
109
  # @api private
109
110
  def layout_changes
110
- warn "Caution: Data source #{self.class.identifier.inspect} does not implement #layout_changes; live compilation will not pick up changes in this data source."
111
+ warn "Caution: Data source #{self.class.identifier.inspect} does not " \
112
+ 'implement #layout_changes; live compilation will not pick up changes in this data source.'
111
113
  Enumerator.new { |_y| sleep }
112
114
  end
113
115
 
@@ -143,9 +145,16 @@ module Nanoc
143
145
  # @param [String, nil] content_checksum_data
144
146
  #
145
147
  # @param [String, nil] attributes_checksum_data
146
- def new_item(content, attributes, identifier, binary: false, checksum_data: nil, content_checksum_data: nil, attributes_checksum_data: nil)
148
+ def new_item(
149
+ content, attributes, identifier,
150
+ binary: false, checksum_data: nil, content_checksum_data: nil,
151
+ attributes_checksum_data: nil
152
+ )
147
153
  content = Nanoc::Core::Content.create(content, binary:)
148
- Nanoc::Core::Item.new(content, attributes, identifier, checksum_data:, content_checksum_data:, attributes_checksum_data:)
154
+ Nanoc::Core::Item.new(
155
+ content, attributes, identifier,
156
+ checksum_data:, content_checksum_data:, attributes_checksum_data:
157
+ )
149
158
  end
150
159
 
151
160
  # Creates a new in-memory layout instance. This is intended for use within
@@ -162,8 +171,15 @@ module Nanoc
162
171
  # @param [String, nil] content_checksum_data
163
172
  #
164
173
  # @param [String, nil] attributes_checksum_data
165
- def new_layout(raw_content, attributes, identifier, checksum_data: nil, content_checksum_data: nil, attributes_checksum_data: nil)
166
- Nanoc::Core::Layout.new(raw_content, attributes, identifier, checksum_data:, content_checksum_data:, attributes_checksum_data:)
174
+ def new_layout(
175
+ raw_content, attributes, identifier,
176
+ checksum_data: nil, content_checksum_data: nil,
177
+ attributes_checksum_data: nil
178
+ )
179
+ Nanoc::Core::Layout.new(
180
+ raw_content, attributes, identifier,
181
+ checksum_data:, content_checksum_data:, attributes_checksum_data:
182
+ )
167
183
  end
168
184
  end
169
185
  end
@@ -7,7 +7,11 @@ module Nanoc
7
7
  class Dependency
8
8
  include Nanoc::Core::ContractsSupport
9
9
 
10
- C_OBJ_FROM = C::Or[Nanoc::Core::Item, Nanoc::Core::Layout, Nanoc::Core::Configuration, Nanoc::Core::IdentifiableCollection]
10
+ C_OBJ_FROM = C::Or[
11
+ Nanoc::Core::Item,
12
+ Nanoc::Core::Layout,
13
+ Nanoc::Core::Configuration,
14
+ Nanoc::Core::IdentifiableCollection]
11
15
  C_OBJ_TO = Nanoc::Core::Item
12
16
 
13
17
  contract C::None => C::Maybe[C_OBJ_FROM]
@@ -19,7 +23,9 @@ module Nanoc
19
23
  contract C::None => Nanoc::Core::DependencyProps
20
24
  attr_reader :props
21
25
 
22
- contract C::Maybe[C_OBJ_FROM], C::Maybe[C_OBJ_TO], Nanoc::Core::DependencyProps => C::Any
26
+ contract C::Maybe[C_OBJ_FROM],
27
+ C::Maybe[C_OBJ_TO],
28
+ Nanoc::Core::DependencyProps => C::Any
23
29
  def initialize(from, to, props)
24
30
  @from = from
25
31
  @to = to
@@ -6,6 +6,11 @@ module Nanoc
6
6
  class DependencyProps
7
7
  include Nanoc::Core::ContractsSupport
8
8
 
9
+ BIT_PATTERN_RAW_CONTENT = 0x01
10
+ BIT_PATTERN_ATTRIBUTES = 0x02
11
+ BIT_PATTERN_COMPILED_CONTENT = 0x04
12
+ BIT_PATTERN_PATH = 0x08
13
+
9
14
  attr_reader :attributes
10
15
  attr_reader :raw_content
11
16
 
@@ -42,8 +47,20 @@ module Nanoc
42
47
  path: C::Optional[C::Bool],
43
48
  ]
44
49
 
50
+ def self.format_bit_pattern(pat)
51
+ (+'').tap do |s|
52
+ s << (pat.nobits?(BIT_PATTERN_RAW_CONTENT) ? '_' : 'r')
53
+ s << (pat.nobits?(BIT_PATTERN_ATTRIBUTES) ? '_' : 'a')
54
+ s << (pat.nobits?(BIT_PATTERN_COMPILED_CONTENT) ? '_' : 'c')
55
+ s << (pat.nobits?(BIT_PATTERN_PATH) ? '_' : 'p')
56
+ end
57
+ end
58
+
45
59
  contract C_ARGS => C::Any
46
- def initialize(raw_content: false, attributes: false, compiled_content: false, path: false)
60
+ def initialize(
61
+ raw_content: false, attributes: false,
62
+ compiled_content: false, path: false
63
+ )
47
64
  @raw_content = raw_content
48
65
  @attributes = attributes
49
66
  @compiled_content = compiled_content
@@ -155,14 +172,16 @@ module Nanoc
155
172
  end
156
173
  end
157
174
 
158
- contract C::None => Set
175
+ contract C::None => C::Num
159
176
  def active
160
- Set.new.tap do |pr|
161
- pr << :raw_content if raw_content?
162
- pr << :attributes if attributes?
163
- pr << :compiled_content if compiled_content?
164
- pr << :path if path?
165
- end
177
+ res = 0x00
178
+
179
+ res |= BIT_PATTERN_RAW_CONTENT if raw_content?
180
+ res |= BIT_PATTERN_ATTRIBUTES if attributes?
181
+ res |= BIT_PATTERN_COMPILED_CONTENT if compiled_content?
182
+ res |= BIT_PATTERN_PATH if path?
183
+
184
+ res
166
185
  end
167
186
 
168
187
  def attribute_keys
@@ -27,22 +27,28 @@ module Nanoc
27
27
  path: C::Optional[C::Bool],
28
28
  ]
29
29
 
30
- C_OBJ_SRC = Nanoc::Core::Item
31
-
32
- C_OBJ_DST =
30
+ C_OBJ_SRC =
33
31
  C::Or[
32
+ nil,
34
33
  Nanoc::Core::Item,
35
34
  Nanoc::Core::Layout,
36
35
  Nanoc::Core::Configuration,
37
36
  Nanoc::Core::IdentifiableCollection,
38
37
  ]
39
38
 
39
+ C_OBJ_DST = Nanoc::Core::Item
40
+
40
41
  attr_reader :items
41
42
  attr_reader :layouts
42
43
 
43
- contract Nanoc::Core::ItemCollection, Nanoc::Core::LayoutCollection, Nanoc::Core::Configuration => C::Any
44
+ contract Nanoc::Core::ItemCollection,
45
+ Nanoc::Core::LayoutCollection,
46
+ Nanoc::Core::Configuration => C::Any
44
47
  def initialize(items, layouts, config)
45
- super(Nanoc::Core::Store.tmp_path_for(config:, store_name: 'dependencies'), 6)
48
+ super(
49
+ self.class.tmp_path_for(config:, store_name: 'dependencies'),
50
+ 6,
51
+ )
46
52
 
47
53
  @config = config
48
54
  @items = items
@@ -51,7 +57,9 @@ module Nanoc
51
57
  rebuild_refs2objs
52
58
 
53
59
  @new_objects = []
54
- @graph = Nanoc::Core::DirectedGraph.new([nil] + objs2refs(@items) + objs2refs(@layouts))
60
+ @graph = Nanoc::Core::DirectedGraph.new(
61
+ [nil] + objs2refs(@items) + objs2refs(@layouts),
62
+ )
55
63
  end
56
64
 
57
65
  def rebuild_refs2objs
@@ -63,7 +71,7 @@ module Nanoc
63
71
  add_vertex_for(@layouts)
64
72
  end
65
73
 
66
- contract C_OBJ_SRC => C::ArrayOf[Nanoc::Core::Dependency]
74
+ contract C_OBJ_DST => C::ArrayOf[Nanoc::Core::Dependency]
67
75
  def dependencies_causing_outdatedness_of(object)
68
76
  objects_causing_outdatedness_of(object).map do |other_object|
69
77
  props = props_for(other_object, object)
@@ -76,6 +84,19 @@ module Nanoc
76
84
  end
77
85
  end
78
86
 
87
+ contract C_OBJ_SRC => C::ArrayOf[Nanoc::Core::Dependency]
88
+ def dependencies_outdated_because_of(object)
89
+ objects_outdated_because_of(object).map do |other_object|
90
+ props = props_for(object, other_object)
91
+
92
+ Nanoc::Core::Dependency.new(
93
+ object,
94
+ other_object,
95
+ props,
96
+ )
97
+ end
98
+ end
99
+
79
100
  def items=(items)
80
101
  @items = items
81
102
  rebuild_refs2objs
@@ -87,11 +108,11 @@ module Nanoc
87
108
  end
88
109
 
89
110
  def new_items
90
- @new_objects.select { |o| o.is_a?(Nanoc::Core::Item) }
111
+ @new_objects.grep(Nanoc::Core::Item)
91
112
  end
92
113
 
93
114
  def new_layouts
94
- @new_objects.select { |o| o.is_a?(Nanoc::Core::Layout) }
115
+ @new_objects.grep(Nanoc::Core::Layout)
95
116
  end
96
117
 
97
118
  # Returns the direct dependencies for the given object.
@@ -115,19 +136,29 @@ module Nanoc
115
136
  refs2objs(@graph.direct_predecessors_of(obj2ref(object)))
116
137
  end
117
138
 
118
- contract C::Maybe[C_OBJ_SRC], C::Maybe[C_OBJ_DST], C_KEYWORD_PROPS => C::Any
139
+ def objects_outdated_because_of(object)
140
+ refs2objs(@graph.direct_successors_of(obj2ref(object)))
141
+ end
142
+
143
+ contract C::Maybe[C_OBJ_SRC],
144
+ C::Maybe[C_OBJ_DST],
145
+ C_KEYWORD_PROPS => C::Any
119
146
  # Records a dependency from `src` to `dst` in the dependency graph. When
120
- # `dst` is oudated, `src` will also become outdated.
147
+ # `src` is oudated, `dst` will also become outdated.
121
148
  #
122
- # @param [Nanoc::Core::Item, Nanoc::Core::Layout] src The source of the dependency,
123
- # i.e. the object that will become outdated if dst is outdated
149
+ # @param [Nanoc::Core::Item, Nanoc::Core::Layout] src The source of the
150
+ # dependency, i.e. the object that will cause dst to become
151
+ # outdated
124
152
  #
125
- # @param [Nanoc::Core::Item, Nanoc::Core::Layout] dst The destination of the
126
- # dependency, i.e. the object that will cause the source to become
127
- # outdated if the destination is outdated
153
+ # @param [Nanoc::Core::Item, Nanoc::Core::Layout] dst The destination of
154
+ # the dependency, i.e. the object that will become outdated if src is
155
+ # outdated
128
156
  #
129
157
  # @return [void]
130
- def record_dependency(src, dst, raw_content: false, attributes: false, compiled_content: false, path: false)
158
+ def record_dependency(
159
+ src, dst, raw_content: false, attributes: false,
160
+ compiled_content: false, path: false
161
+ )
131
162
  return if src == dst
132
163
 
133
164
  add_vertex_for(src)
@@ -141,11 +172,13 @@ module Nanoc
141
172
  attributes = attributes.to_a
142
173
  end
143
174
 
144
- existing_props = @graph.props_for(dst_ref, src_ref)
145
- new_props = Nanoc::Core::DependencyProps.new(raw_content:, attributes:, compiled_content:, path:)
175
+ existing_props = @graph.props_for(src_ref, dst_ref)
176
+ new_props = Nanoc::Core::DependencyProps.new(
177
+ raw_content:, attributes:, compiled_content:, path:,
178
+ )
146
179
  props = existing_props ? existing_props.merge(new_props) : new_props
147
180
 
148
- @graph.add_edge(dst_ref, src_ref, props:)
181
+ @graph.add_edge(src_ref, dst_ref, props:)
149
182
  end
150
183
 
151
184
  def add_vertex_for(obj)
@@ -157,8 +190,8 @@ module Nanoc
157
190
  # will stick around and new dependencies will appear twice. This function
158
191
  # removes all incoming edges for the given vertex.
159
192
  #
160
- # @param [Nanoc::Core::Item, Nanoc::Core::Layout] object The object for which to
161
- # forget all dependencies
193
+ # @param [Nanoc::Core::Item, Nanoc::Core::Layout] object The object for
194
+ # which to forget all dependencies
162
195
  #
163
196
  # @return [void]
164
197
  def forget_dependencies_for(object)
@@ -44,12 +44,18 @@ module Nanoc
44
44
  end
45
45
 
46
46
  contract C_OBJ, C_ARGS => C::Any
47
- def bounce(obj, raw_content: false, attributes: false, compiled_content: false, path: false)
47
+ def bounce(
48
+ obj,
49
+ raw_content: false,
50
+ attributes: false,
51
+ compiled_content: false,
52
+ path: false
53
+ )
48
54
  Nanoc::Core::NotificationCenter.post(:dependency_created, @root, obj)
49
55
 
50
56
  @dependency_store.record_dependency(
51
- @root,
52
57
  obj,
58
+ @root,
53
59
  raw_content:,
54
60
  attributes:,
55
61
  compiled_content:,
@@ -60,10 +66,20 @@ module Nanoc
60
66
  class Null < DependencyTracker
61
67
  include Nanoc::Core::ContractsSupport
62
68
 
63
- def initialize; end
69
+ def initialize
70
+ super(nil, root: nil)
71
+ end
64
72
 
65
73
  contract C_OBJ, C_ARGS => C::Any
66
- def bounce(_obj, raw_content: false, attributes: false, compiled_content: false, path: false); end
74
+ def bounce(
75
+ _obj,
76
+ raw_content: false,
77
+ attributes: false,
78
+ compiled_content: false,
79
+ path: false
80
+ )
81
+ # do nothing
82
+ end
67
83
  end
68
84
  end
69
85
  end
@@ -21,8 +21,6 @@ module Nanoc
21
21
  # # Get (direct) predecessors
22
22
  # graph.direct_predecessors_of('b').sort
23
23
  # # => %w( a )
24
- # graph.predecessors_of('e').sort
25
- # # => %w( a b c d )
26
24
  #
27
25
  # # Modify edges
28
26
  # graph.delete_edges_to('c')
@@ -30,8 +28,6 @@ module Nanoc
30
28
  # # Get (direct) predecessors again
31
29
  # graph.direct_predecessors_of('e').sort
32
30
  # # => %w( d )
33
- # graph.predecessors_of('e').sort
34
- # # => %w( c d )
35
31
  class DirectedGraph
36
32
  EMPTY_SET = Set.new.freeze
37
33
 
@@ -39,30 +35,34 @@ module Nanoc
39
35
 
40
36
  # Creates a new directed graph with the given vertices.
41
37
  def initialize(vertices)
42
- @vertices = {}
38
+ @vertex_to_idx_map = {}
39
+ @vertices = []
43
40
  @next_vertex_idx = 0
44
41
  vertices.each do |v|
45
- @vertices[v] = @next_vertex_idx
42
+ @vertices << v
43
+ @vertex_to_idx_map[v] = @next_vertex_idx
46
44
  @next_vertex_idx += 1
47
45
  end
48
46
 
49
47
  @to_graph = {}
48
+ @from_graph = {}
50
49
 
51
50
  @edge_props = {}
52
-
53
- invalidate_caches
54
51
  end
55
52
 
56
53
  def inspect
57
54
  s = []
58
55
 
59
- @vertices.each_pair do |v2, _|
56
+ @vertices.each do |v2|
60
57
  direct_predecessors_of(v2).each do |v1|
61
- s << [v1.inspect + ' -> ' + v2.inspect + ' props=' + @edge_props[[v1, v2]].inspect]
58
+ s << [
59
+ "#{v1.inspect} -> #{v2.inspect} " \
60
+ "props=#{@edge_props[[v1, v2]].inspect}",
61
+ ]
62
62
  end
63
63
  end
64
64
 
65
- self.class.to_s + '(' + s.join(', ') + ')'
65
+ "#{self.class}(#{s.join(', ')})"
66
66
  end
67
67
 
68
68
  # @group Modifying the graph
@@ -81,11 +81,12 @@ module Nanoc
81
81
  @to_graph[to] ||= Set.new
82
82
  @to_graph[to] << from
83
83
 
84
+ @from_graph[from] ||= Set.new
85
+ @from_graph[from] << to
86
+
84
87
  if props
85
88
  @edge_props[[from, to]] = props
86
89
  end
87
-
88
- invalidate_caches
89
90
  end
90
91
 
91
92
  # Adds the given vertex to the graph.
@@ -94,9 +95,10 @@ module Nanoc
94
95
  #
95
96
  # @return [void]
96
97
  def add_vertex(vertex)
97
- return if @vertices.key?(vertex)
98
+ return if @vertex_to_idx_map.key?(vertex)
98
99
 
99
- @vertices[vertex] = @next_vertex_idx
100
+ @vertices << vertex
101
+ @vertex_to_idx_map[vertex] = @next_vertex_idx
100
102
  @next_vertex_idx += 1
101
103
  end
102
104
 
@@ -110,10 +112,9 @@ module Nanoc
110
112
 
111
113
  @to_graph[to].each do |from|
112
114
  @edge_props.delete([from, to])
115
+ @from_graph.delete(from)
113
116
  end
114
117
  @to_graph.delete(to)
115
-
116
- invalidate_caches
117
118
  end
118
119
 
119
120
  # @group Querying the graph
@@ -128,14 +129,8 @@ module Nanoc
128
129
  @to_graph.fetch(to, EMPTY_SET)
129
130
  end
130
131
 
131
- # Returns the predecessors of the given vertex, i.e. the vertices x for
132
- # which there is a path from x to the given vertex y.
133
- #
134
- # @param to The vertex of which the predecessors should be calculated
135
- #
136
- # @return [Array] Predecessors of the given vertex
137
- def predecessors_of(to)
138
- @predecessors[to] ||= recursively_find_vertices(to, :direct_predecessors_of)
132
+ def direct_successors_of(from)
133
+ @from_graph.fetch(from, EMPTY_SET)
139
134
  end
140
135
 
141
136
  def props_for(from, to)
@@ -144,7 +139,7 @@ module Nanoc
144
139
 
145
140
  # @return [Array] The list of all vertices in this graph.
146
141
  def vertices
147
- @vertices.keys.sort_by { |v| @vertices[v] }
142
+ @vertices
148
143
  end
149
144
 
150
145
  # Returns an array of tuples representing the edges. The result of this
@@ -153,47 +148,15 @@ module Nanoc
153
148
  # @return [Array] The list of all edges in this graph.
154
149
  def edges
155
150
  result = []
156
- @vertices.each_pair do |v2, i2|
157
- direct_predecessors_of(v2).map { |v1| [@vertices[v1], v1] }.each do |i1, v1|
158
- result << [i1, i2, @edge_props[[v1, v2]]]
159
- end
151
+ @vertices.each_with_index do |v2, i2|
152
+ direct_predecessors_of(v2)
153
+ .map { |v1| [@vertex_to_idx_map[v1], v1] }
154
+ .each do |i1, v1|
155
+ result << [i1, i2, @edge_props[[v1, v2]]]
156
+ end
160
157
  end
161
158
  result
162
159
  end
163
-
164
- private
165
-
166
- # Invalidates cached data. This method should be called when the internal
167
- # graph representation is changed.
168
- def invalidate_caches
169
- @predecessors = {}
170
- end
171
-
172
- # Recursively finds vertices, starting at the vertex start, using the
173
- # given method, which should be a symbol to a method that takes a vertex
174
- # and returns related vertices (e.g. predecessors, successors).
175
- def recursively_find_vertices(start, method)
176
- all_vertices = Set.new
177
-
178
- processed_vertices = Set.new
179
- unprocessed_vertices = [start]
180
-
181
- until unprocessed_vertices.empty?
182
- # Get next unprocessed vertex
183
- vertex = unprocessed_vertices.pop
184
- next if processed_vertices.include?(vertex)
185
-
186
- processed_vertices << vertex
187
-
188
- # Add predecessors of this vertex
189
- send(method, vertex).each do |v|
190
- all_vertices << v unless all_vertices.include?(v)
191
- unprocessed_vertices << v
192
- end
193
- end
194
-
195
- all_vertices
196
- end
197
160
  end
198
161
  end
199
162
  end
@@ -41,7 +41,10 @@ module Nanoc
41
41
  # @param [String, nil] content_checksum_data
42
42
  #
43
43
  # @param [String, nil] attributes_checksum_data
44
- def initialize(content, attributes, identifier, checksum_data: nil, content_checksum_data: nil, attributes_checksum_data: nil)
44
+ def initialize(
45
+ content, attributes, identifier,
46
+ checksum_data: nil, content_checksum_data: nil, attributes_checksum_data: nil
47
+ )
45
48
  @content = Nanoc::Core::Content.create(content)
46
49
  @attributes = Nanoc::Core::LazyValue.new(attributes).map(&:__nanoc_symbolize_keys_recursively)
47
50
  @identifier = Nanoc::Core::Identifier.from(identifier)