nanoc 4.11.0 → 4.11.1

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 (154) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +6 -0
  3. data/lib/nanoc.rb +4 -7
  4. data/lib/nanoc/base.rb +3 -3
  5. data/lib/nanoc/base/assertions.rb +1 -1
  6. data/lib/nanoc/base/entities.rb +2 -20
  7. data/lib/nanoc/base/entities/action_sequence.rb +60 -64
  8. data/lib/nanoc/base/entities/checksum_collection.rb +23 -21
  9. data/lib/nanoc/base/entities/dependency.rb +24 -22
  10. data/lib/nanoc/base/entities/outdatedness_reasons.rb +74 -72
  11. data/lib/nanoc/base/entities/outdatedness_status.rb +19 -17
  12. data/lib/nanoc/base/entities/props.rb +119 -117
  13. data/lib/nanoc/base/entities/site.rb +46 -50
  14. data/lib/nanoc/base/errors.rb +183 -198
  15. data/lib/nanoc/base/repos.rb +4 -2
  16. data/lib/nanoc/base/repos/action_sequence_store.rb +44 -42
  17. data/lib/nanoc/base/repos/aggregate_data_source.rb +24 -22
  18. data/lib/nanoc/base/repos/checksum_store.rb +51 -49
  19. data/lib/nanoc/base/repos/compiled_content_cache.rb +47 -45
  20. data/lib/nanoc/base/repos/compiled_content_store.rb +76 -0
  21. data/lib/nanoc/base/repos/config_loader.rb +74 -72
  22. data/lib/nanoc/base/repos/dependency_store.rb +174 -172
  23. data/lib/nanoc/base/repos/in_mem_data_source.rb +17 -15
  24. data/lib/nanoc/base/repos/item_rep_repo.rb +26 -24
  25. data/lib/nanoc/base/repos/outdatedness_store.rb +50 -48
  26. data/lib/nanoc/base/repos/prefixed_data_source.rb +21 -19
  27. data/lib/nanoc/base/repos/site_loader.rb +75 -73
  28. data/lib/nanoc/base/repos/store.rb +93 -91
  29. data/lib/nanoc/base/services.rb +7 -3
  30. data/lib/nanoc/base/services/action_provider.rb +23 -21
  31. data/lib/nanoc/base/services/action_sequence_builder.rb +42 -34
  32. data/lib/nanoc/base/services/compilation_context.rb +49 -47
  33. data/lib/nanoc/base/services/compiler.rb +177 -170
  34. data/lib/nanoc/base/services/compiler/phases.rb +8 -1
  35. data/lib/nanoc/base/services/compiler/phases/abstract.rb +44 -38
  36. data/lib/nanoc/base/services/compiler/phases/cache.rb +34 -28
  37. data/lib/nanoc/base/services/compiler/phases/mark_done.rb +17 -11
  38. data/lib/nanoc/base/services/compiler/phases/notify.rb +21 -0
  39. data/lib/nanoc/base/services/compiler/phases/recalculate.rb +37 -31
  40. data/lib/nanoc/base/services/compiler/phases/resume.rb +47 -48
  41. data/lib/nanoc/base/services/compiler/phases/write.rb +65 -59
  42. data/lib/nanoc/base/services/compiler/stage.rb +27 -8
  43. data/lib/nanoc/base/services/compiler/stages.rb +7 -1
  44. data/lib/nanoc/base/services/compiler/stages/build_reps.rb +25 -19
  45. data/lib/nanoc/base/services/compiler/stages/calculate_checksums.rb +34 -28
  46. data/lib/nanoc/base/services/compiler/stages/cleanup.rb +33 -27
  47. data/lib/nanoc/base/services/compiler/stages/compile_reps.rb +79 -69
  48. data/lib/nanoc/base/services/compiler/stages/determine_outdatedness.rb +46 -40
  49. data/lib/nanoc/base/services/compiler/stages/forget_outdated_dependencies.rb +15 -9
  50. data/lib/nanoc/base/services/compiler/stages/load_stores.rb +28 -22
  51. data/lib/nanoc/base/services/compiler/stages/postprocess.rb +16 -10
  52. data/lib/nanoc/base/services/compiler/stages/preprocess.rb +25 -19
  53. data/lib/nanoc/base/services/compiler/stages/prune.rb +23 -17
  54. data/lib/nanoc/base/services/compiler/stages/store_post_compilation_state.rb +15 -9
  55. data/lib/nanoc/base/services/compiler/stages/store_pre_compilation_state.rb +26 -20
  56. data/lib/nanoc/base/services/compiler_loader.rb +26 -24
  57. data/lib/nanoc/base/services/dependency_tracker.rb +47 -45
  58. data/lib/nanoc/base/services/executor.rb +16 -15
  59. data/lib/nanoc/base/services/filter.rb +37 -5
  60. data/lib/nanoc/base/services/instrumentor.rb +12 -10
  61. data/lib/nanoc/base/services/item_rep_builder.rb +21 -19
  62. data/lib/nanoc/base/services/item_rep_router.rb +72 -70
  63. data/lib/nanoc/base/services/item_rep_selector.rb +48 -46
  64. data/lib/nanoc/base/services/item_rep_writer.rb +58 -53
  65. data/lib/nanoc/base/services/outdatedness_checker.rb +181 -179
  66. data/lib/nanoc/base/services/outdatedness_rule.rb +23 -21
  67. data/lib/nanoc/base/services/outdatedness_rules.rb +5 -3
  68. data/lib/nanoc/base/services/outdatedness_rules/attributes_modified.rb +28 -24
  69. data/lib/nanoc/base/services/outdatedness_rules/code_snippets_modified.rb +20 -16
  70. data/lib/nanoc/base/services/outdatedness_rules/content_modified.rb +13 -9
  71. data/lib/nanoc/base/services/outdatedness_rules/item_collection_extended.rb +12 -8
  72. data/lib/nanoc/base/services/outdatedness_rules/layout_collection_extended.rb +12 -8
  73. data/lib/nanoc/base/services/outdatedness_rules/not_written.rb +10 -6
  74. data/lib/nanoc/base/services/outdatedness_rules/rules_modified.rb +39 -35
  75. data/lib/nanoc/base/services/outdatedness_rules/uses_always_outdated_filter.rb +19 -15
  76. data/lib/nanoc/base/services/pruner.rb +2 -2
  77. data/lib/nanoc/base/views.rb +7 -0
  78. data/lib/nanoc/base/views/basic_item_view.rb +1 -1
  79. data/lib/nanoc/base/views/compilation_item_rep_view.rb +2 -2
  80. data/lib/nanoc/base/views/identifiable_collection_view.rb +2 -2
  81. data/lib/nanoc/base/views/mixins/document_view_mixin.rb +1 -1
  82. data/lib/nanoc/base/views/mixins/mutable_document_view_mixin.rb +5 -5
  83. data/lib/nanoc/base/views/mutable_item_collection_view.rb +3 -3
  84. data/lib/nanoc/base/views/mutable_layout_collection_view.rb +2 -2
  85. data/lib/nanoc/base/views/view_context_for_compilation.rb +6 -6
  86. data/lib/nanoc/base/views/view_context_for_pre_compilation.rb +2 -2
  87. data/lib/nanoc/base/views/view_context_for_shell.rb +2 -2
  88. data/lib/nanoc/checking/check.rb +1 -1
  89. data/lib/nanoc/cli/commands/compile_listeners/abstract.rb +24 -7
  90. data/lib/nanoc/cli/commands/compile_listeners/debug_printer.rb +79 -15
  91. data/lib/nanoc/cli/commands/compile_listeners/diff_generator.rb +4 -7
  92. data/lib/nanoc/cli/commands/compile_listeners/file_action_printer.rb +15 -24
  93. data/lib/nanoc/cli/commands/compile_listeners/timing_recorder.rb +22 -18
  94. data/lib/nanoc/cli/commands/create-site.rb +2 -7
  95. data/lib/nanoc/cli/commands/shell.rb +1 -1
  96. data/lib/nanoc/cli/commands/show-data.rb +9 -9
  97. data/lib/nanoc/cli/logger.rb +1 -1
  98. data/lib/nanoc/data_sources/filesystem.rb +8 -8
  99. data/lib/nanoc/filters/erb.rb +1 -1
  100. data/lib/nanoc/filters/erubi.rb +1 -1
  101. data/lib/nanoc/filters/erubis.rb +1 -1
  102. data/lib/nanoc/filters/haml.rb +1 -1
  103. data/lib/nanoc/filters/sass.rb +1 -1
  104. data/lib/nanoc/filters/slim.rb +1 -1
  105. data/lib/nanoc/helpers/breadcrumbs.rb +2 -2
  106. data/lib/nanoc/helpers/capturing.rb +9 -8
  107. data/lib/nanoc/helpers/filtering.rb +2 -2
  108. data/lib/nanoc/helpers/rendering.rb +1 -1
  109. data/lib/nanoc/rule_dsl.rb +10 -0
  110. data/lib/nanoc/rule_dsl/action_provider.rb +3 -3
  111. data/lib/nanoc/rule_dsl/action_recorder.rb +3 -3
  112. data/lib/nanoc/rule_dsl/action_sequence_calculator.rb +7 -7
  113. data/lib/nanoc/rule_dsl/compilation_rule.rb +2 -2
  114. data/lib/nanoc/rule_dsl/compilation_rule_context.rb +9 -9
  115. data/lib/nanoc/rule_dsl/compiler_dsl.rb +4 -4
  116. data/lib/nanoc/rule_dsl/routing_rule.rb +3 -3
  117. data/lib/nanoc/rule_dsl/rule.rb +5 -5
  118. data/lib/nanoc/rule_dsl/rule_context.rb +3 -3
  119. data/lib/nanoc/rule_dsl/rules_collection.rb +4 -4
  120. data/lib/nanoc/spec.rb +15 -15
  121. data/lib/nanoc/version.rb +1 -1
  122. metadata +10 -111
  123. data/lib/nanoc/base/contracts_support.rb +0 -130
  124. data/lib/nanoc/base/core_ext.rb +0 -5
  125. data/lib/nanoc/base/core_ext/array.rb +0 -50
  126. data/lib/nanoc/base/core_ext/hash.rb +0 -54
  127. data/lib/nanoc/base/core_ext/string.rb +0 -16
  128. data/lib/nanoc/base/entities/code_snippet.rb +0 -53
  129. data/lib/nanoc/base/entities/configuration-schema.json +0 -122
  130. data/lib/nanoc/base/entities/configuration.rb +0 -206
  131. data/lib/nanoc/base/entities/content.rb +0 -112
  132. data/lib/nanoc/base/entities/context.rb +0 -70
  133. data/lib/nanoc/base/entities/directed_graph.rb +0 -195
  134. data/lib/nanoc/base/entities/document.rb +0 -125
  135. data/lib/nanoc/base/entities/identifiable_collection.rb +0 -141
  136. data/lib/nanoc/base/entities/identifier.rb +0 -222
  137. data/lib/nanoc/base/entities/item.rb +0 -10
  138. data/lib/nanoc/base/entities/item_collection.rb +0 -14
  139. data/lib/nanoc/base/entities/item_rep.rb +0 -91
  140. data/lib/nanoc/base/entities/layout.rb +0 -10
  141. data/lib/nanoc/base/entities/layout_collection.rb +0 -14
  142. data/lib/nanoc/base/entities/lazy_value.rb +0 -43
  143. data/lib/nanoc/base/entities/pattern.rb +0 -85
  144. data/lib/nanoc/base/entities/processing_action.rb +0 -21
  145. data/lib/nanoc/base/entities/processing_actions.rb +0 -5
  146. data/lib/nanoc/base/entities/processing_actions/filter.rb +0 -36
  147. data/lib/nanoc/base/entities/processing_actions/layout.rb +0 -36
  148. data/lib/nanoc/base/entities/processing_actions/snapshot.rb +0 -46
  149. data/lib/nanoc/base/entities/snapshot_def.rb +0 -22
  150. data/lib/nanoc/base/repos/data_source.rb +0 -168
  151. data/lib/nanoc/base/repos/snapshot_repo.rb +0 -67
  152. data/lib/nanoc/base/services/checksummer.rb +0 -274
  153. data/lib/nanoc/base/services/notification_center.rb +0 -87
  154. data/lib/nanoc/base/services/temp_filename_factory.rb +0 -52
@@ -1,130 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc::Int
4
- # @api private
5
- module ContractsSupport
6
- class Ignorer
7
- include Singleton
8
-
9
- def method_missing(*_args) # rubocop:disable Style/MethodMissingSuper
10
- self
11
- end
12
-
13
- def respond_to_missing?(*_args)
14
- true
15
- end
16
- end
17
-
18
- module DisabledContracts
19
- Any = Ignorer.instance
20
- Bool = Ignorer.instance
21
- Num = Ignorer.instance
22
- KeywordArgs = Ignorer.instance
23
- Args = Ignorer.instance
24
- Optional = Ignorer.instance
25
- Maybe = Ignorer.instance
26
- None = Ignorer.instance
27
- ArrayOf = Ignorer.instance
28
- Or = Ignorer.instance
29
- Func = Ignorer.instance
30
- RespondTo = Ignorer.instance
31
- Named = Ignorer.instance
32
- IterOf = Ignorer.instance
33
- HashOf = Ignorer.instance
34
- AbsolutePathString = Ignorer.instance
35
-
36
- def contract(*args); end
37
- end
38
-
39
- module EnabledContracts
40
- class AbstractContract
41
- def self.[](*vals)
42
- new(*vals)
43
- end
44
- end
45
-
46
- class Named < AbstractContract
47
- def initialize(name)
48
- @name = name
49
- end
50
-
51
- def valid?(val)
52
- val.is_a?(Kernel.const_get(@name))
53
- end
54
-
55
- def inspect
56
- "#{self.class}(#{@name})"
57
- end
58
- end
59
-
60
- class IterOf < AbstractContract
61
- def initialize(contract)
62
- @contract = contract
63
- end
64
-
65
- def valid?(val)
66
- val.respond_to?(:each) && val.all? { |v| Contract.valid?(v, @contract) }
67
- end
68
-
69
- def inspect
70
- "#{self.class}(#{@contract})"
71
- end
72
- end
73
-
74
- class AbsolutePathString < AbstractContract
75
- def self.valid?(val)
76
- val.is_a?(String) && Pathname.new(val).absolute?
77
- end
78
- end
79
-
80
- def contract(*args)
81
- Contract(*args)
82
- end
83
- end
84
-
85
- def self.setup_once
86
- @_contracts_support__setup ||= false
87
- return @_contracts_support__should_enable if @_contracts_support__setup
88
-
89
- @_contracts_support__setup = true
90
-
91
- contracts_loadable =
92
- begin
93
- require 'contracts'
94
- true
95
- rescue LoadError
96
- false
97
- end
98
-
99
- @_contracts_support__should_enable = contracts_loadable && !ENV.key?('DISABLE_CONTRACTS')
100
-
101
- if @_contracts_support__should_enable
102
- # FIXME: ugly
103
- ::Contracts.const_set('Named', EnabledContracts::Named)
104
- ::Contracts.const_set('IterOf', EnabledContracts::IterOf)
105
- ::Contracts.const_set('AbsolutePathString', EnabledContracts::AbsolutePathString)
106
- end
107
-
108
- @_contracts_support__should_enable
109
- end
110
-
111
- def self.enabled?
112
- setup_once
113
- end
114
-
115
- def self.included(base)
116
- should_enable = setup_once
117
-
118
- if should_enable
119
- unless base.include?(::Contracts::Core)
120
- base.include(::Contracts::Core)
121
- base.extend(EnabledContracts)
122
- base.const_set('C', ::Contracts)
123
- end
124
- else
125
- base.extend(DisabledContracts)
126
- base.const_set('C', DisabledContracts)
127
- end
128
- end
129
- end
130
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'nanoc/base/core_ext/array'
4
- require 'nanoc/base/core_ext/hash'
5
- require 'nanoc/base/core_ext/string'
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- module Nanoc::ArrayExtensions
5
- # Returns a new array where all items' keys are recursively converted to
6
- # symbols by calling {Nanoc::ArrayExtensions#__nanoc_symbolize_keys_recursively} or
7
- # {Nanoc::HashExtensions#__nanoc_symbolize_keys_recursively}.
8
- #
9
- # @return [Array] The converted array
10
- def __nanoc_symbolize_keys_recursively
11
- array = []
12
- each do |element|
13
- array << (element.respond_to?(:__nanoc_symbolize_keys_recursively) ? element.__nanoc_symbolize_keys_recursively : element)
14
- end
15
- array
16
- end
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
-
26
- # Freezes the contents of the array, as well as all array elements. The
27
- # array elements will be frozen using {#__nanoc_freeze_recursively} if they respond
28
- # to that message, or #freeze if they do not.
29
- #
30
- # @see Hash#__nanoc_freeze_recursively
31
- #
32
- # @return [void]
33
- def __nanoc_freeze_recursively
34
- return if frozen?
35
-
36
- freeze
37
- each do |value|
38
- if value.respond_to?(:__nanoc_freeze_recursively)
39
- value.__nanoc_freeze_recursively
40
- else
41
- value.freeze
42
- end
43
- end
44
- end
45
- end
46
-
47
- # @api private
48
- class Array
49
- include Nanoc::ArrayExtensions
50
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- module Nanoc::HashExtensions
5
- # Returns a new hash where all keys are recursively converted to symbols by
6
- # calling {Nanoc::ArrayExtensions#__nanoc_symbolize_keys_recursively} or
7
- # {Nanoc::HashExtensions#__nanoc_symbolize_keys_recursively}.
8
- #
9
- # @return [Hash] The converted hash
10
- def __nanoc_symbolize_keys_recursively
11
- hash = {}
12
- each_pair do |key, value|
13
- new_key = key.respond_to?(:to_sym) ? key.to_sym : key
14
- new_value = value.respond_to?(:__nanoc_symbolize_keys_recursively) ? value.__nanoc_symbolize_keys_recursively : value
15
- hash[new_key] = new_value
16
- end
17
- hash
18
- end
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
-
30
- # Freezes the contents of the hash, as well as all hash values. The hash
31
- # values will be frozen using {#__nanoc_freeze_recursively} if they respond to
32
- # that message, or #freeze if they do not.
33
- #
34
- # @see Array#__nanoc_freeze_recursively
35
- #
36
- # @return [void]
37
- def __nanoc_freeze_recursively
38
- return if frozen?
39
-
40
- freeze
41
- each_pair do |_key, value|
42
- if value.respond_to?(:__nanoc_freeze_recursively)
43
- value.__nanoc_freeze_recursively
44
- else
45
- value.freeze
46
- end
47
- end
48
- end
49
- end
50
-
51
- # @api private
52
- class Hash
53
- include Nanoc::HashExtensions
54
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- module Nanoc::StringExtensions
5
- # Transforms string into an actual identifier
6
- #
7
- # @return [String] The identifier generated from the receiver
8
- def __nanoc_cleaned_identifier
9
- "/#{self}/".gsub(/^\/+|\/+$/, '/')
10
- end
11
- end
12
-
13
- # @api private
14
- class String
15
- include Nanoc::StringExtensions
16
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc::Int
4
- # Nanoc::Int::CodeSnippet represent a piece of custom code of a Nanoc site.
5
- #
6
- # @api private
7
- class CodeSnippet
8
- include Nanoc::Int::ContractsSupport
9
-
10
- # A string containing the actual code in this code snippet.
11
- #
12
- # @return [String]
13
- attr_reader :data
14
-
15
- # The filename corresponding to this code snippet.
16
- #
17
- # @return [String]
18
- attr_reader :filename
19
-
20
- contract String, String => C::Any
21
- # Creates a new code snippet.
22
- #
23
- # @param [String] data The raw source code which will be executed before
24
- # compilation
25
- #
26
- # @param [String] filename The filename corresponding to this code snippet
27
- def initialize(data, filename)
28
- @data = data
29
- @filename = filename
30
- end
31
-
32
- contract C::None => nil
33
- # Loads the code by executing it.
34
- #
35
- # @return [void]
36
- def load
37
- eval('def self.use_helper(mod); Nanoc::Int::Context.instance_eval { include mod }; end', TOPLEVEL_BINDING)
38
- eval(@data, TOPLEVEL_BINDING, @filename)
39
- nil
40
- end
41
-
42
- # Returns an object that can be used for uniquely identifying objects.
43
- #
44
- # @return [Object] An unique reference to this object
45
- def reference
46
- "code_snippet:#{filename}"
47
- end
48
-
49
- def inspect
50
- "<#{self.class} filename=\"#{filename}\">"
51
- end
52
- end
53
- end
@@ -1,122 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-04/schema#",
3
- "title": "Nanoc configuration schema",
4
- "type": "object",
5
- "properties": {
6
- "text_extensions": {
7
- "type": "array",
8
- "items": {
9
- "type": "string"
10
- }
11
- },
12
- "output_dir": {
13
- "type": "string"
14
- },
15
- "index_filenames": {
16
- "type": "array",
17
- "items": {
18
- "type": "string"
19
- }
20
- },
21
- "enable_output_diff": {
22
- "type": "boolean"
23
- },
24
- "prune": {
25
- "type": "object",
26
- "additionalProperties": false,
27
- "properties": {
28
- "auto_prune": {
29
- "type": "boolean"
30
- },
31
- "exclude": {
32
- "type": "array",
33
- "items": {
34
- "type": "string"
35
- }
36
- }
37
- }
38
- },
39
- "commands_dirs": {
40
- "type": "array",
41
- "items": {
42
- "type": "string"
43
- }
44
- },
45
- "lib_dirs": {
46
- "type": "array",
47
- "items": {
48
- "type": "string"
49
- }
50
- },
51
- "data_sources": {
52
- "type": "array",
53
- "items": {
54
- "type": "object",
55
- "properties": {
56
- "type": {
57
- "type": "string"
58
- },
59
- "items_root": {
60
- "anyOf": [
61
- { "type": "string" },
62
- { "type": "null" }
63
- ]
64
- },
65
- "layouts_root": {
66
- "anyOf": [
67
- { "type": "string" },
68
- { "type": "null" }
69
- ]
70
- }
71
- }
72
- }
73
- },
74
- "string_pattern_type": {
75
- "type": "string",
76
- "enum": ["glob", "legacy"]
77
- },
78
- "checks": {
79
- "type": "object",
80
- "properties": {
81
- "internal_links": {
82
- "type": "object",
83
- "additionalProperties": false,
84
- "properties": {
85
- "exclude": {
86
- "type": "array",
87
- "items": {
88
- "type": "string"
89
- }
90
- }
91
- }
92
- },
93
- "external_links": {
94
- "type": "object",
95
- "additionalProperties": false,
96
- "properties": {
97
- "exclude": {
98
- "type": "array",
99
- "items": {
100
- "type": "string"
101
- }
102
- },
103
- "exclude_files": {
104
- "type": "array",
105
- "items": {
106
- "type": "string"
107
- }
108
- }
109
- }
110
- }
111
- }
112
- },
113
- "environments": {
114
- "type": "object",
115
- "patternProperties": {
116
- "^.*$": {
117
- "type": "object"
118
- }
119
- }
120
- }
121
- }
122
- }
@@ -1,206 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nanoc::Int
4
- # Represents the site configuration.
5
- #
6
- # @api private
7
- class Configuration
8
- include Nanoc::Int::ContractsSupport
9
-
10
- NONE = Object.new.freeze
11
-
12
- # The default configuration for a data source. A data source's
13
- # configuration overrides these options.
14
- DEFAULT_DATA_SOURCE_CONFIG = {
15
- type: 'filesystem',
16
- items_root: '/',
17
- layouts_root: '/',
18
- config: {},
19
- identifier_type: 'full',
20
- }.freeze
21
-
22
- # The default configuration for a site. A site's configuration overrides
23
- # these options: when a {Nanoc::Int::Site} is created with a configuration
24
- # that lacks some options, the default value will be taken from
25
- # `DEFAULT_CONFIG`.
26
- DEFAULT_CONFIG = {
27
- text_extensions: %w[adoc asciidoc atom css erb haml htm html js less markdown md php rb sass scss tex txt xhtml xml coffee hb handlebars mustache ms slim rdoc].sort,
28
- lib_dirs: %w[lib],
29
- commands_dirs: %w[commands],
30
- output_dir: 'output',
31
- data_sources: [{}],
32
- index_filenames: ['index.html'],
33
- enable_output_diff: false,
34
- prune: { auto_prune: false, exclude: ['.git', '.hg', '.svn', 'CVS'] },
35
- string_pattern_type: 'glob',
36
- action_provider: 'rule_dsl',
37
- }.freeze
38
-
39
- # @return [String, nil] The active environment for the configuration
40
- attr_reader :env_name
41
-
42
- contract C::None => C::AbsolutePathString
43
- attr_reader :dir
44
-
45
- # Configuration environments property key
46
- ENVIRONMENTS_CONFIG_KEY = :environments
47
- NANOC_ENV = 'NANOC_ENV'
48
- NANOC_ENV_DEFAULT = 'default'
49
-
50
- contract C::KeywordArgs[hash: C::Optional[Hash], env_name: C::Maybe[String], dir: C::AbsolutePathString] => C::Any
51
- def initialize(hash: {}, dir:, env_name: nil)
52
- @env_name = env_name
53
- @wrapped = hash.__nanoc_symbolize_keys_recursively
54
- @dir = dir
55
-
56
- validate
57
- end
58
-
59
- contract C::None => self
60
- def with_defaults
61
- new_wrapped = DEFAULT_CONFIG.merge(@wrapped)
62
- new_wrapped[:data_sources] = new_wrapped[:data_sources].map do |ds|
63
- DEFAULT_DATA_SOURCE_CONFIG.merge(ds)
64
- end
65
-
66
- self.class.new(hash: new_wrapped, dir: @dir, env_name: @env_name)
67
- end
68
-
69
- def with_environment
70
- return self unless @wrapped.key?(ENVIRONMENTS_CONFIG_KEY)
71
-
72
- # Set active environment
73
- env_name = @env_name || ENV.fetch(NANOC_ENV, NANOC_ENV_DEFAULT)
74
-
75
- # Load given environment configuration
76
- env_config = @wrapped[ENVIRONMENTS_CONFIG_KEY].fetch(env_name.to_sym, {})
77
-
78
- self.class.new(hash: @wrapped, dir: @dir, env_name: env_name).merge(env_config)
79
- end
80
-
81
- contract C::None => Hash
82
- def to_h
83
- @wrapped
84
- end
85
-
86
- # For compat
87
- contract C::None => Hash
88
- def attributes
89
- to_h
90
- end
91
-
92
- contract C::Any => C::Bool
93
- def key?(key)
94
- @wrapped.key?(key)
95
- end
96
-
97
- contract C::Any => C::Any
98
- def [](key)
99
- @wrapped[key]
100
- end
101
-
102
- contract C::Args[C::Any] => C::Any
103
- def dig(*keys)
104
- @wrapped.dig(*keys)
105
- end
106
-
107
- contract C::Any, C::Maybe[C::Any], C::Maybe[C::Func[C::None => C::Any]] => C::Any
108
- def fetch(key, fallback = NONE, &_block)
109
- @wrapped.fetch(key) do
110
- if !fallback.equal?(NONE)
111
- fallback
112
- elsif block_given?
113
- yield(key)
114
- else
115
- raise KeyError, "key not found: #{key.inspect}"
116
- end
117
- end
118
- end
119
-
120
- contract C::Any, C::Any => C::Any
121
- def []=(key, value)
122
- @wrapped[key] = value
123
- end
124
-
125
- contract C::Or[Hash, self] => self
126
- def merge(hash)
127
- self.class.new(hash: merge_recursively(@wrapped, hash.to_h), dir: @dir, env_name: @env_name)
128
- end
129
-
130
- contract C::Any => self
131
- def without(key)
132
- self.class.new(hash: @wrapped.reject { |k, _v| k == key }, dir: @dir, env_name: @env_name)
133
- end
134
-
135
- contract C::Any => self
136
- def update(hash)
137
- @wrapped.update(hash)
138
- self
139
- end
140
-
141
- contract C::Func[C::Any, C::Any => C::Any] => self
142
- def each
143
- @wrapped.each { |k, v| yield(k, v) }
144
- self
145
- end
146
-
147
- contract C::None => self
148
- def freeze
149
- super
150
- @wrapped.__nanoc_freeze_recursively
151
- self
152
- end
153
-
154
- contract C::None => C::AbsolutePathString
155
- def output_dir
156
- make_absolute(self[:output_dir]).freeze
157
- end
158
-
159
- contract C::None => Symbol
160
- def action_provider
161
- self[:action_provider].to_sym
162
- end
163
-
164
- contract C::None => C::IterOf[C::AbsolutePathString]
165
- def output_dirs
166
- envs = @wrapped.fetch(ENVIRONMENTS_CONFIG_KEY, {})
167
- res = [output_dir] + envs.values.map { |v| make_absolute(v[:output_dir]) }
168
- res.uniq.compact
169
- end
170
-
171
- # Returns an object that can be used for uniquely identifying objects.
172
- #
173
- # @return [Object] An unique reference to this object
174
- def reference
175
- 'configuration'
176
- end
177
-
178
- def inspect
179
- "<#{self.class}>"
180
- end
181
-
182
- private
183
-
184
- def make_absolute(path)
185
- path && @dir && File.absolute_path(path, @dir).encode('UTF-8')
186
- end
187
-
188
- def merge_recursively(config1, config2)
189
- config1.merge(config2) do |_, value1, value2|
190
- if value1.is_a?(Hash) && value2.is_a?(Hash)
191
- merge_recursively(value1, value2)
192
- else
193
- value2
194
- end
195
- end
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
205
- end
206
- end