nanoc 4.11.0 → 4.11.1

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