nanoc-core 4.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/NEWS.md +3 -0
- data/README.md +3 -0
- data/lib/nanoc/core/binary_content.rb +12 -0
- data/lib/nanoc/core/checksummer.rb +287 -0
- data/lib/nanoc/core/code_snippet.rb +57 -0
- data/lib/nanoc/core/configuration-schema.json +122 -0
- data/lib/nanoc/core/configuration.rb +206 -0
- data/lib/nanoc/core/content.rb +46 -0
- data/lib/nanoc/core/context.rb +70 -0
- data/lib/nanoc/core/contracts_support.rb +131 -0
- data/lib/nanoc/core/core_ext/array.rb +54 -0
- data/lib/nanoc/core/core_ext/hash.rb +58 -0
- data/lib/nanoc/core/core_ext/string.rb +20 -0
- data/lib/nanoc/core/data_source.rb +170 -0
- data/lib/nanoc/core/directed_graph.rb +195 -0
- data/lib/nanoc/core/document.rb +124 -0
- data/lib/nanoc/core/error.rb +9 -0
- data/lib/nanoc/core/identifiable_collection.rb +142 -0
- data/lib/nanoc/core/identifier.rb +218 -0
- data/lib/nanoc/core/item.rb +11 -0
- data/lib/nanoc/core/item_collection.rb +15 -0
- data/lib/nanoc/core/item_rep.rb +92 -0
- data/lib/nanoc/core/layout.rb +11 -0
- data/lib/nanoc/core/layout_collection.rb +15 -0
- data/lib/nanoc/core/lazy_value.rb +38 -0
- data/lib/nanoc/core/notification_center.rb +97 -0
- data/lib/nanoc/core/pattern.rb +37 -0
- data/lib/nanoc/core/processing_action.rb +23 -0
- data/lib/nanoc/core/processing_actions/filter.rb +40 -0
- data/lib/nanoc/core/processing_actions/layout.rb +40 -0
- data/lib/nanoc/core/processing_actions/snapshot.rb +50 -0
- data/lib/nanoc/core/processing_actions.rb +12 -0
- data/lib/nanoc/core/regexp_pattern.rb +28 -0
- data/lib/nanoc/core/snapshot_def.rb +22 -0
- data/lib/nanoc/core/string_pattern.rb +29 -0
- data/lib/nanoc/core/temp_filename_factory.rb +53 -0
- data/lib/nanoc/core/textual_content.rb +41 -0
- data/lib/nanoc/core/version.rb +7 -0
- data/lib/nanoc/core.rb +60 -0
- data/lib/nanoc-core.rb +3 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6b14c2953e85fe025ebc7b886e49e7c5479f9a2a5e4ae490b427760ed916646b
|
4
|
+
data.tar.gz: cdc17c42152a6ef9474e1406d1f2078884b298833213707b54cd2825785fe448
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b039e4fdf615feb7cacd556600fa3cf967290335d2034cbe9046b59613ea0e8b736078aa83ca2fc2c921869ee50cf4e62f5fa823341674612ae72801df53dbc
|
7
|
+
data.tar.gz: e1b1374ba0c0bd461de1ccb8ec658dbe65f49c9b0eae2a48efe138757cea4f0f66c0a3b79e0243b9cbc6d6ad312b6a589dbbd3f620bea0948da37b79b82d156d
|
data/NEWS.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
# Creates checksums for given objects.
|
6
|
+
#
|
7
|
+
# A checksum is a string, such as “mL+TaqNsEeiPkWloPgCtAofT1yg=”, that is used
|
8
|
+
# to determine whether a piece of data has changed.
|
9
|
+
class Checksummer
|
10
|
+
class VerboseDigest
|
11
|
+
def initialize
|
12
|
+
@str = +''
|
13
|
+
end
|
14
|
+
|
15
|
+
def update(str)
|
16
|
+
@str << str
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@str
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class CompactDigest
|
25
|
+
def initialize
|
26
|
+
@digest = Digest::SHA1.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def update(str)
|
30
|
+
@digest.update(str)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
@digest.base64digest
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
# @param obj The object to create a checksum for
|
40
|
+
#
|
41
|
+
# @return [String] The digest
|
42
|
+
def calc(obj, digest_class = CompactDigest)
|
43
|
+
digest = digest_class.new
|
44
|
+
update(obj, digest)
|
45
|
+
digest.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def calc_for_content_of(obj)
|
49
|
+
obj.content_checksum_data || obj.checksum_data || Nanoc::Core::Checksummer.calc(obj.content)
|
50
|
+
end
|
51
|
+
|
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)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def define_behavior(klass, behavior)
|
59
|
+
behaviors[klass] = behavior
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def update(obj, digest, visited = Hamster::Set.new)
|
65
|
+
digest.update(obj.class.to_s)
|
66
|
+
|
67
|
+
if visited.include?(obj)
|
68
|
+
digest.update('<recur>')
|
69
|
+
else
|
70
|
+
digest.update('<')
|
71
|
+
behavior_for(obj).update(obj, digest) { |o| update(o, digest, visited.add(obj)) }
|
72
|
+
digest.update('>')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def behaviors
|
77
|
+
return @behaviors if @behaviors
|
78
|
+
|
79
|
+
@behaviors = {}
|
80
|
+
|
81
|
+
# NOTE: Other behaviors are registered elsewhere
|
82
|
+
# (search for `define_behavior`).
|
83
|
+
|
84
|
+
define_behavior(Array, ArrayUpdateBehavior)
|
85
|
+
define_behavior(FalseClass, NoUpdateBehavior)
|
86
|
+
define_behavior(Hash, HashUpdateBehavior)
|
87
|
+
define_behavior(NilClass, NoUpdateBehavior)
|
88
|
+
define_behavior(Numeric, RawUpdateBehavior)
|
89
|
+
define_behavior(Pathname, PathnameUpdateBehavior)
|
90
|
+
define_behavior(String, RawUpdateBehavior)
|
91
|
+
define_behavior(Symbol, RawUpdateBehavior)
|
92
|
+
define_behavior(Time, ToIToSUpdateBehavior)
|
93
|
+
define_behavior(TrueClass, NoUpdateBehavior)
|
94
|
+
|
95
|
+
define_behavior(Nanoc::Core::BinaryContent, BinaryContentUpdateBehavior)
|
96
|
+
define_behavior(Nanoc::Core::Configuration, HashUpdateBehavior)
|
97
|
+
define_behavior(Nanoc::Core::Context, ContextUpdateBehavior)
|
98
|
+
define_behavior(Nanoc::Core::IdentifiableCollection, ArrayUpdateBehavior)
|
99
|
+
define_behavior(Nanoc::Core::Identifier, ToSUpdateBehavior)
|
100
|
+
define_behavior(Nanoc::Core::Item, DocumentUpdateBehavior)
|
101
|
+
define_behavior(Nanoc::Core::ItemRep, ItemRepUpdateBehavior)
|
102
|
+
define_behavior(Nanoc::Core::Layout, DocumentUpdateBehavior)
|
103
|
+
define_behavior(Nanoc::Core::TextualContent, StringUpdateBehavior)
|
104
|
+
|
105
|
+
@behaviors
|
106
|
+
end
|
107
|
+
|
108
|
+
def behavior_for_class(klass)
|
109
|
+
behaviors.fetch(klass) do
|
110
|
+
if Object.equal?(klass.superclass)
|
111
|
+
RescueUpdateBehavior
|
112
|
+
else
|
113
|
+
behavior_for_class(klass.superclass)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def behavior_for(obj)
|
119
|
+
behavior_for_class(obj.class)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class UpdateBehavior
|
124
|
+
def self.update(_obj, _digest)
|
125
|
+
raise NotImpementedError
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class RuleContextUpdateBehavior < UpdateBehavior
|
130
|
+
def self.update(obj, digest)
|
131
|
+
digest.update('item=')
|
132
|
+
yield(obj.item)
|
133
|
+
digest.update(',rep=')
|
134
|
+
yield(obj.rep)
|
135
|
+
digest.update(',items=')
|
136
|
+
yield(obj.items)
|
137
|
+
digest.update(',layouts=')
|
138
|
+
yield(obj.layouts)
|
139
|
+
digest.update(',config=')
|
140
|
+
yield(obj.config)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class ContextUpdateBehavior < UpdateBehavior
|
145
|
+
def self.update(obj, digest)
|
146
|
+
obj.instance_variables.each do |var|
|
147
|
+
digest.update(var.to_s)
|
148
|
+
digest.update('=')
|
149
|
+
yield(obj.instance_variable_get(var))
|
150
|
+
digest.update(',')
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class RawUpdateBehavior < UpdateBehavior
|
156
|
+
def self.update(obj, digest)
|
157
|
+
digest.update(obj.to_s)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class ToSUpdateBehavior < UpdateBehavior
|
162
|
+
def self.update(obj, _digest)
|
163
|
+
yield(obj.to_s)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class ToIToSUpdateBehavior < UpdateBehavior
|
168
|
+
def self.update(obj, digest)
|
169
|
+
digest.update(obj.to_i.to_s)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class StringUpdateBehavior < UpdateBehavior
|
174
|
+
def self.update(obj, _digest)
|
175
|
+
yield(obj.string)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class DataUpdateBehavior < UpdateBehavior
|
180
|
+
def self.update(obj, _digest)
|
181
|
+
yield(obj.data)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class NoUpdateBehavior < UpdateBehavior
|
186
|
+
def self.update(_obj, _digest); end
|
187
|
+
end
|
188
|
+
|
189
|
+
class UnwrapUpdateBehavior < UpdateBehavior
|
190
|
+
def self.update(obj, _digest)
|
191
|
+
yield(obj._unwrap)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class ArrayUpdateBehavior < UpdateBehavior
|
196
|
+
def self.update(obj, digest)
|
197
|
+
obj.each do |el|
|
198
|
+
yield(el)
|
199
|
+
digest.update(',')
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
class HashUpdateBehavior < UpdateBehavior
|
205
|
+
def self.update(obj, digest)
|
206
|
+
obj.each do |key, value|
|
207
|
+
yield(key)
|
208
|
+
digest.update('=')
|
209
|
+
yield(value)
|
210
|
+
digest.update(',')
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
class DocumentUpdateBehavior < UpdateBehavior
|
216
|
+
def self.update(obj, digest)
|
217
|
+
if obj.checksum_data
|
218
|
+
digest.update('checksum_data=' + obj.checksum_data)
|
219
|
+
else
|
220
|
+
if obj.content_checksum_data
|
221
|
+
digest.update('content_checksum_data=' + obj.content_checksum_data)
|
222
|
+
else
|
223
|
+
digest.update('content=')
|
224
|
+
yield(obj.content)
|
225
|
+
end
|
226
|
+
|
227
|
+
if obj.attributes_checksum_data
|
228
|
+
digest.update(',attributes_checksum_data=' + obj.attributes_checksum_data)
|
229
|
+
else
|
230
|
+
digest.update(',attributes=')
|
231
|
+
yield(obj.attributes)
|
232
|
+
end
|
233
|
+
|
234
|
+
digest.update(',identifier=')
|
235
|
+
yield(obj.identifier)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
class ItemRepUpdateBehavior < UpdateBehavior
|
241
|
+
def self.update(obj, digest)
|
242
|
+
digest.update('item=')
|
243
|
+
yield(obj.item)
|
244
|
+
digest.update(',name=')
|
245
|
+
yield(obj.name)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
class PathnameUpdateBehavior < UpdateBehavior
|
250
|
+
def self.update(obj, digest)
|
251
|
+
filename = obj.to_s
|
252
|
+
if File.exist?(filename)
|
253
|
+
stat = File.stat(filename)
|
254
|
+
digest.update(stat.size.to_s + '-' + stat.mtime.to_i.to_s)
|
255
|
+
else
|
256
|
+
digest.update('???')
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
class BinaryContentUpdateBehavior < UpdateBehavior
|
262
|
+
def self.update(obj, _digest)
|
263
|
+
yield(Pathname.new(obj.filename))
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
class RescueUpdateBehavior < UpdateBehavior
|
268
|
+
def self.update(obj, digest)
|
269
|
+
if obj.class.to_s == 'Sass::Importers::Filesystem'
|
270
|
+
digest.update('root=')
|
271
|
+
digest.update(obj.root)
|
272
|
+
return
|
273
|
+
end
|
274
|
+
|
275
|
+
data =
|
276
|
+
begin
|
277
|
+
Marshal.dump(obj)
|
278
|
+
rescue
|
279
|
+
obj.inspect
|
280
|
+
end
|
281
|
+
|
282
|
+
digest.update(data)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
# Nanoc::Core::CodeSnippet represent a piece of custom code of a Nanoc site.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class CodeSnippet
|
9
|
+
include Nanoc::Core::ContractsSupport
|
10
|
+
|
11
|
+
# A string containing the actual code in this code snippet.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :data
|
15
|
+
|
16
|
+
# The filename corresponding to this code snippet.
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
attr_reader :filename
|
20
|
+
|
21
|
+
contract String, String => C::Any
|
22
|
+
# Creates a new code snippet.
|
23
|
+
#
|
24
|
+
# @param [String] data The raw source code which will be executed before
|
25
|
+
# compilation
|
26
|
+
#
|
27
|
+
# @param [String] filename The filename corresponding to this code snippet
|
28
|
+
def initialize(data, filename)
|
29
|
+
@data = data
|
30
|
+
@filename = filename
|
31
|
+
end
|
32
|
+
|
33
|
+
contract C::None => nil
|
34
|
+
# Loads the code by executing it.
|
35
|
+
#
|
36
|
+
# @return [void]
|
37
|
+
def load
|
38
|
+
# rubocop:disable Security/Eval
|
39
|
+
eval('def self.use_helper(mod); Nanoc::Core::Context.instance_eval { include mod }; end', TOPLEVEL_BINDING)
|
40
|
+
eval(@data, TOPLEVEL_BINDING, @filename)
|
41
|
+
# rubocop:enable Security/Eval
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns an object that can be used for uniquely identifying objects.
|
46
|
+
#
|
47
|
+
# @return [Object] An unique reference to this object
|
48
|
+
def reference
|
49
|
+
"code_snippet:#{filename}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def inspect
|
53
|
+
"<#{self.class} filename=\"#{filename}\">"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,122 @@
|
|
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
|
+
}
|
@@ -0,0 +1,206 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
module Core
|
5
|
+
# Represents the site configuration.
|
6
|
+
class Configuration
|
7
|
+
include Nanoc::Core::ContractsSupport
|
8
|
+
|
9
|
+
NONE = Object.new.freeze
|
10
|
+
|
11
|
+
# The default configuration for a data source. A data source's
|
12
|
+
# configuration overrides these options.
|
13
|
+
DEFAULT_DATA_SOURCE_CONFIG = {
|
14
|
+
type: 'filesystem',
|
15
|
+
items_root: '/',
|
16
|
+
layouts_root: '/',
|
17
|
+
config: {},
|
18
|
+
identifier_type: 'full',
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
# The default configuration for a site. A site's configuration overrides
|
22
|
+
# these options: when a {Nanoc::Int::Site} is created with a configuration
|
23
|
+
# that lacks some options, the default value will be taken from
|
24
|
+
# `DEFAULT_CONFIG`.
|
25
|
+
DEFAULT_CONFIG = {
|
26
|
+
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,
|
27
|
+
lib_dirs: %w[lib],
|
28
|
+
commands_dirs: %w[commands],
|
29
|
+
output_dir: 'output',
|
30
|
+
data_sources: [{}],
|
31
|
+
index_filenames: ['index.html'],
|
32
|
+
enable_output_diff: false,
|
33
|
+
prune: { auto_prune: false, exclude: ['.git', '.hg', '.svn', 'CVS'] },
|
34
|
+
string_pattern_type: 'glob',
|
35
|
+
action_provider: 'rule_dsl',
|
36
|
+
}.freeze
|
37
|
+
|
38
|
+
# @return [String, nil] The active environment for the configuration
|
39
|
+
attr_reader :env_name
|
40
|
+
|
41
|
+
contract C::None => C::AbsolutePathString
|
42
|
+
attr_reader :dir
|
43
|
+
|
44
|
+
# Configuration environments property key
|
45
|
+
ENVIRONMENTS_CONFIG_KEY = :environments
|
46
|
+
NANOC_ENV = 'NANOC_ENV'
|
47
|
+
NANOC_ENV_DEFAULT = 'default'
|
48
|
+
|
49
|
+
contract C::KeywordArgs[hash: C::Optional[Hash], env_name: C::Maybe[String], dir: C::AbsolutePathString] => C::Any
|
50
|
+
def initialize(hash: {}, dir:, env_name: nil)
|
51
|
+
@env_name = env_name
|
52
|
+
@wrapped = hash.__nanoc_symbolize_keys_recursively
|
53
|
+
@dir = dir
|
54
|
+
|
55
|
+
validate
|
56
|
+
end
|
57
|
+
|
58
|
+
contract C::None => self
|
59
|
+
def with_defaults
|
60
|
+
new_wrapped = DEFAULT_CONFIG.merge(@wrapped)
|
61
|
+
new_wrapped[:data_sources] = new_wrapped[:data_sources].map do |ds|
|
62
|
+
DEFAULT_DATA_SOURCE_CONFIG.merge(ds)
|
63
|
+
end
|
64
|
+
|
65
|
+
self.class.new(hash: new_wrapped, dir: @dir, env_name: @env_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def with_environment
|
69
|
+
return self unless @wrapped.key?(ENVIRONMENTS_CONFIG_KEY)
|
70
|
+
|
71
|
+
# Set active environment
|
72
|
+
env_name = @env_name || ENV.fetch(NANOC_ENV, NANOC_ENV_DEFAULT)
|
73
|
+
|
74
|
+
# Load given environment configuration
|
75
|
+
env_config = @wrapped[ENVIRONMENTS_CONFIG_KEY].fetch(env_name.to_sym, {})
|
76
|
+
|
77
|
+
self.class.new(hash: @wrapped, dir: @dir, env_name: env_name).merge(env_config)
|
78
|
+
end
|
79
|
+
|
80
|
+
contract C::None => Hash
|
81
|
+
def to_h
|
82
|
+
@wrapped
|
83
|
+
end
|
84
|
+
|
85
|
+
# For compat
|
86
|
+
contract C::None => Hash
|
87
|
+
def attributes
|
88
|
+
to_h
|
89
|
+
end
|
90
|
+
|
91
|
+
contract C::Any => C::Bool
|
92
|
+
def key?(key)
|
93
|
+
@wrapped.key?(key)
|
94
|
+
end
|
95
|
+
|
96
|
+
contract C::Any => C::Any
|
97
|
+
def [](key)
|
98
|
+
@wrapped[key]
|
99
|
+
end
|
100
|
+
|
101
|
+
contract C::Args[C::Any] => C::Any
|
102
|
+
def dig(*keys)
|
103
|
+
@wrapped.dig(*keys)
|
104
|
+
end
|
105
|
+
|
106
|
+
contract C::Any, C::Maybe[C::Any], C::Maybe[C::Func[C::None => C::Any]] => C::Any
|
107
|
+
def fetch(key, fallback = NONE, &_block)
|
108
|
+
@wrapped.fetch(key) do
|
109
|
+
if !fallback.equal?(NONE)
|
110
|
+
fallback
|
111
|
+
elsif block_given?
|
112
|
+
yield(key)
|
113
|
+
else
|
114
|
+
raise KeyError, "key not found: #{key.inspect}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
contract C::Any, C::Any => C::Any
|
120
|
+
def []=(key, value)
|
121
|
+
@wrapped[key] = value
|
122
|
+
end
|
123
|
+
|
124
|
+
contract C::Or[Hash, self] => self
|
125
|
+
def merge(hash)
|
126
|
+
self.class.new(hash: merge_recursively(@wrapped, hash.to_h), dir: @dir, env_name: @env_name)
|
127
|
+
end
|
128
|
+
|
129
|
+
contract C::Any => self
|
130
|
+
def without(key)
|
131
|
+
self.class.new(hash: @wrapped.reject { |k, _v| k == key }, dir: @dir, env_name: @env_name)
|
132
|
+
end
|
133
|
+
|
134
|
+
contract C::Any => self
|
135
|
+
def update(hash)
|
136
|
+
@wrapped.update(hash)
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
contract C::Func[C::Any, C::Any => C::Any] => self
|
141
|
+
def each
|
142
|
+
@wrapped.each { |k, v| yield(k, v) }
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
contract C::None => self
|
147
|
+
def freeze
|
148
|
+
super
|
149
|
+
@wrapped.__nanoc_freeze_recursively
|
150
|
+
self
|
151
|
+
end
|
152
|
+
|
153
|
+
contract C::None => C::AbsolutePathString
|
154
|
+
def output_dir
|
155
|
+
make_absolute(self[:output_dir]).freeze
|
156
|
+
end
|
157
|
+
|
158
|
+
contract C::None => Symbol
|
159
|
+
def action_provider
|
160
|
+
self[:action_provider].to_sym
|
161
|
+
end
|
162
|
+
|
163
|
+
contract C::None => C::IterOf[C::AbsolutePathString]
|
164
|
+
def output_dirs
|
165
|
+
envs = @wrapped.fetch(ENVIRONMENTS_CONFIG_KEY, {})
|
166
|
+
res = [output_dir] + envs.values.map { |v| make_absolute(v[:output_dir]) }
|
167
|
+
res.uniq.compact
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns an object that can be used for uniquely identifying objects.
|
171
|
+
#
|
172
|
+
# @return [Object] An unique reference to this object
|
173
|
+
def reference
|
174
|
+
'configuration'
|
175
|
+
end
|
176
|
+
|
177
|
+
def inspect
|
178
|
+
"<#{self.class}>"
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def make_absolute(path)
|
184
|
+
path && @dir && File.absolute_path(path, @dir).encode('UTF-8')
|
185
|
+
end
|
186
|
+
|
187
|
+
def merge_recursively(config1, config2)
|
188
|
+
config1.merge(config2) do |_, value1, value2|
|
189
|
+
if value1.is_a?(Hash) && value2.is_a?(Hash)
|
190
|
+
merge_recursively(value1, value2)
|
191
|
+
else
|
192
|
+
value2
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def validate
|
198
|
+
dir = File.dirname(__FILE__)
|
199
|
+
schema_data = JSON.parse(File.read(dir + '/configuration-schema.json'))
|
200
|
+
schema = JsonSchema.parse!(schema_data)
|
201
|
+
schema.expand_references!
|
202
|
+
schema.validate!(@wrapped.__nanoc_stringify_keys_recursively)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|