nanoc 4.1.6 → 4.2.0b1
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -1
- data/NEWS.md +11 -4
- data/lib/nanoc/base/checksummer.rb +135 -46
- data/lib/nanoc/base/compilation/compiler.rb +18 -28
- data/lib/nanoc/base/compilation/dependency_tracker.rb +22 -32
- data/lib/nanoc/base/compilation/filter.rb +2 -4
- data/lib/nanoc/base/entities.rb +1 -0
- data/lib/nanoc/base/entities/content.rb +14 -3
- data/lib/nanoc/base/entities/document.rb +14 -6
- data/lib/nanoc/base/entities/item.rb +0 -31
- data/lib/nanoc/base/entities/item_rep.rb +1 -1
- data/lib/nanoc/base/entities/lazy_value.rb +36 -0
- data/lib/nanoc/base/entities/pattern.rb +3 -2
- data/lib/nanoc/base/entities/site.rb +2 -0
- data/lib/nanoc/base/memoization.rb +17 -10
- data/lib/nanoc/base/repos/compiled_content_cache.rb +1 -1
- data/lib/nanoc/base/repos/data_source.rb +10 -6
- data/lib/nanoc/base/services/executor.rb +22 -22
- data/lib/nanoc/base/services/item_rep_router.rb +4 -5
- data/lib/nanoc/base/views.rb +0 -1
- data/lib/nanoc/base/views/item_rep_view.rb +3 -9
- data/lib/nanoc/base/views/mixins/document_view_mixin.rb +4 -11
- data/lib/nanoc/base/views/view.rb +1 -0
- data/lib/nanoc/base/views/view_context.rb +5 -1
- data/lib/nanoc/cli/commands/compile.rb +0 -6
- data/lib/nanoc/data_sources.rb +5 -5
- data/lib/nanoc/data_sources/filesystem.rb +219 -90
- data/lib/nanoc/extra/checking/check.rb +1 -2
- data/lib/nanoc/extra/checking/checks.rb +2 -0
- data/lib/nanoc/extra/checking/checks/css.rb +6 -14
- data/lib/nanoc/extra/checking/checks/html.rb +6 -14
- data/lib/nanoc/extra/checking/checks/internal_links.rb +14 -3
- data/lib/nanoc/extra/checking/checks/w3c_validator.rb +28 -0
- data/lib/nanoc/extra/deployers/fog.rb +134 -78
- data/lib/nanoc/extra/link_collector.rb +14 -18
- data/lib/nanoc/filters/sass.rb +3 -3
- data/lib/nanoc/helpers.rb +1 -0
- data/lib/nanoc/helpers/capturing.rb +16 -58
- data/lib/nanoc/helpers/child_parent.rb +51 -0
- data/lib/nanoc/helpers/filtering.rb +0 -1
- data/lib/nanoc/helpers/html_escape.rb +5 -0
- data/lib/nanoc/helpers/link_to.rb +2 -0
- data/lib/nanoc/helpers/rendering.rb +3 -4
- data/lib/nanoc/rule_dsl/action_provider.rb +20 -4
- data/lib/nanoc/rule_dsl/recording_executor.rb +3 -1
- data/lib/nanoc/rule_dsl/rule_context.rb +0 -1
- data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +4 -1
- data/lib/nanoc/spec.rb +217 -0
- data/lib/nanoc/version.rb +1 -1
- data/test/base/test_data_source.rb +4 -2
- data/test/base/test_dependency_tracker.rb +5 -11
- data/test/data_sources/test_filesystem.rb +605 -69
- data/test/extra/checking/checks/test_internal_links.rb +25 -0
- data/test/extra/deployers/test_fog.rb +0 -177
- data/test/filters/test_less.rb +9 -4
- data/test/helpers/test_capturing.rb +38 -212
- data/test/helpers/test_link_to.rb +0 -205
- data/test/helpers/test_xml_sitemap.rb +2 -1
- metadata +7 -12
- data/lib/nanoc/base/views/site_view.rb +0 -14
- data/lib/nanoc/data_sources/filesystem_unified.rb +0 -101
- data/test/data_sources/test_filesystem_unified.rb +0 -559
- data/test/helpers/test_breadcrumbs.rb +0 -60
- data/test/helpers/test_filtering.rb +0 -112
- data/test/helpers/test_html_escape.rb +0 -26
- data/test/helpers/test_rendering.rb +0 -147
- data/test/helpers/test_tagging.rb +0 -92
- data/test/helpers/test_text.rb +0 -18
data/lib/nanoc/base/entities.rb
CHANGED
@@ -27,7 +27,7 @@ module Nanoc
|
|
27
27
|
@filename.freeze
|
28
28
|
end
|
29
29
|
|
30
|
-
# @param [String] content The uncompiled item content (if it is textual
|
30
|
+
# @param [String, Proc] content The uncompiled item content (if it is textual
|
31
31
|
# content) or the path to the filename containing the content (if this
|
32
32
|
# is binary content).
|
33
33
|
#
|
@@ -58,11 +58,13 @@ module Nanoc
|
|
58
58
|
# @api private
|
59
59
|
class TextualContent < Content
|
60
60
|
# @return [String]
|
61
|
-
|
61
|
+
def string
|
62
|
+
@string.value
|
63
|
+
end
|
62
64
|
|
63
65
|
def initialize(string, filename: nil)
|
64
66
|
super(filename)
|
65
|
-
@string = string
|
67
|
+
@string = Nanoc::Int::LazyValue.new(string)
|
66
68
|
end
|
67
69
|
|
68
70
|
def freeze
|
@@ -73,6 +75,15 @@ module Nanoc
|
|
73
75
|
def binary?
|
74
76
|
false
|
75
77
|
end
|
78
|
+
|
79
|
+
def marshal_dump
|
80
|
+
[filename, string]
|
81
|
+
end
|
82
|
+
|
83
|
+
def marshal_load(array)
|
84
|
+
@filename = array[0]
|
85
|
+
@string = Nanoc::Int::LazyValue.new(array[1])
|
86
|
+
end
|
76
87
|
end
|
77
88
|
|
78
89
|
# @api private
|
@@ -6,27 +6,35 @@ module Nanoc
|
|
6
6
|
attr_reader :content
|
7
7
|
|
8
8
|
# @return [Hash]
|
9
|
-
|
9
|
+
def attributes
|
10
|
+
@attributes.value
|
11
|
+
end
|
10
12
|
|
11
13
|
# @return [Nanoc::Identifier]
|
12
14
|
attr_accessor :identifier
|
13
15
|
|
16
|
+
# @return [String, nil]
|
17
|
+
attr_accessor :checksum_data
|
18
|
+
|
14
19
|
# @param [String, Nanoc::Int::Content] content
|
15
20
|
#
|
16
|
-
# @param [Hash] attributes
|
21
|
+
# @param [Hash, Proc] attributes
|
17
22
|
#
|
18
23
|
# @param [String, Nanoc::Identifier] identifier
|
19
|
-
|
24
|
+
#
|
25
|
+
# @param [String, nil] checksum_data Used to determine whether the document has changed
|
26
|
+
def initialize(content, attributes, identifier, checksum_data: nil)
|
20
27
|
@content = Nanoc::Int::Content.create(content)
|
21
|
-
@attributes = attributes.__nanoc_symbolize_keys_recursively
|
28
|
+
@attributes = Nanoc::Int::LazyValue.new(attributes).map(&:__nanoc_symbolize_keys_recursively)
|
22
29
|
@identifier = Nanoc::Identifier.from(identifier)
|
30
|
+
@checksum_data = checksum_data
|
23
31
|
end
|
24
32
|
|
25
33
|
# @return [void]
|
26
34
|
def freeze
|
27
35
|
super
|
28
|
-
|
29
|
-
|
36
|
+
@content.freeze
|
37
|
+
@attributes.freeze
|
30
38
|
end
|
31
39
|
|
32
40
|
# @abstract
|
@@ -1,13 +1,6 @@
|
|
1
1
|
module Nanoc::Int
|
2
2
|
# @api private
|
3
3
|
class Item < ::Nanoc::Int::Document
|
4
|
-
# @see Document#initialize
|
5
|
-
def initialize(content, attributes, identifier)
|
6
|
-
super
|
7
|
-
|
8
|
-
@forced_outdated_status = ForcedOutdatedStatus.new
|
9
|
-
end
|
10
|
-
|
11
4
|
# Returns an object that can be used for uniquely identifying objects.
|
12
5
|
#
|
13
6
|
# @api private
|
@@ -16,29 +9,5 @@ module Nanoc::Int
|
|
16
9
|
def reference
|
17
10
|
[:item, identifier.to_s]
|
18
11
|
end
|
19
|
-
|
20
|
-
# Hack to allow a frozen item to still have modifiable frozen status.
|
21
|
-
#
|
22
|
-
# FIXME: Remove this.
|
23
|
-
class ForcedOutdatedStatus
|
24
|
-
attr_accessor :bool
|
25
|
-
|
26
|
-
def initialize
|
27
|
-
@bool = false
|
28
|
-
end
|
29
|
-
|
30
|
-
def freeze
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# @api private
|
35
|
-
def forced_outdated=(bool)
|
36
|
-
@forced_outdated_status.bool = bool
|
37
|
-
end
|
38
|
-
|
39
|
-
# @api private
|
40
|
-
def forced_outdated?
|
41
|
-
@forced_outdated_status.bool
|
42
|
-
end
|
43
12
|
end
|
44
13
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Nanoc::Int
|
2
|
+
# Holds a value that might be generated lazily.
|
3
|
+
#
|
4
|
+
# @api private
|
5
|
+
class LazyValue
|
6
|
+
# @param [Object, Proc] value_or_proc A value or a proc to generate the value
|
7
|
+
def initialize(value_or_proc)
|
8
|
+
@value = { raw: value_or_proc }
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [Object] The value, generated when needed
|
12
|
+
def value
|
13
|
+
if @value.key?(:raw)
|
14
|
+
value = @value.delete(:raw)
|
15
|
+
@value[:final] = value.respond_to?(:call) ? value.call : value
|
16
|
+
@value.__nanoc_freeze_recursively if frozen?
|
17
|
+
end
|
18
|
+
@value[:final]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns a new lazy value that will apply the given transformation when the value is requested.
|
22
|
+
#
|
23
|
+
# @yield resolved value
|
24
|
+
#
|
25
|
+
# @return [Nanoc::Int::LazyValue]
|
26
|
+
def map
|
27
|
+
Nanoc::Int::LazyValue.new(-> { yield(value) })
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [void]
|
31
|
+
def freeze
|
32
|
+
super
|
33
|
+
@value.__nanoc_freeze_recursively unless @value[:raw]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -29,13 +29,14 @@ module Nanoc::Int
|
|
29
29
|
|
30
30
|
# @api private
|
31
31
|
class StringPattern
|
32
|
+
MATCH_OPTS = File::FNM_PATHNAME | File::FNM_EXTGLOB
|
33
|
+
|
32
34
|
def initialize(string)
|
33
35
|
@string = string
|
34
36
|
end
|
35
37
|
|
36
38
|
def match?(identifier)
|
37
|
-
|
38
|
-
File.fnmatch(@string, identifier.to_s, opts)
|
39
|
+
File.fnmatch(@string, identifier.to_s, MATCH_OPTS)
|
39
40
|
end
|
40
41
|
|
41
42
|
def captures(_identifier)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
|
1
3
|
module Nanoc::Int
|
2
4
|
# Adds support for memoizing functions.
|
3
5
|
#
|
@@ -5,6 +7,14 @@ module Nanoc::Int
|
|
5
7
|
#
|
6
8
|
# @since 3.2.0
|
7
9
|
module Memoization
|
10
|
+
class Wrapper
|
11
|
+
attr_reader :value
|
12
|
+
|
13
|
+
def initialize(value)
|
14
|
+
@value = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
8
18
|
# Memoizes the method with the given name. The modified method will cache
|
9
19
|
# the results of the original method, so that calling a method twice with
|
10
20
|
# the same arguments will short-circuit and return the cached results
|
@@ -39,24 +49,21 @@ module Nanoc::Int
|
|
39
49
|
#
|
40
50
|
# @return [void]
|
41
51
|
def memoize(method_name)
|
42
|
-
# Alias
|
43
52
|
original_method_name = '__nonmemoized_' + method_name.to_s
|
44
53
|
alias_method original_method_name, method_name
|
45
54
|
|
46
|
-
# Redefine
|
47
55
|
define_method(method_name) do |*args|
|
48
|
-
# Get cache
|
49
56
|
@__memoization_cache ||= {}
|
50
57
|
@__memoization_cache[method_name] ||= {}
|
58
|
+
method_cache = @__memoization_cache[method_name]
|
51
59
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
if method_cache.key?(args) && method_cache[args].weakref_alive?
|
61
|
+
method_cache[args].value
|
62
|
+
else
|
63
|
+
send(original_method_name, *args).tap do |r|
|
64
|
+
method_cache[args] = WeakRef.new(Wrapper.new(r))
|
65
|
+
end
|
56
66
|
end
|
57
|
-
|
58
|
-
# Done
|
59
|
-
@__memoization_cache[method_name][args]
|
60
67
|
end
|
61
68
|
end
|
62
69
|
end
|
@@ -130,18 +130,20 @@ module Nanoc
|
|
130
130
|
# Creates a new in-memory item instance. This is intended for use within
|
131
131
|
# the {#items} method.
|
132
132
|
#
|
133
|
-
# @param [String] content The uncompiled item content
|
133
|
+
# @param [String, Proc] content The uncompiled item content
|
134
134
|
# (if it is a textual item) or the path to the filename containing the
|
135
135
|
# content (if it is a binary item).
|
136
136
|
#
|
137
|
-
# @param [Hash] attributes A hash containing this item's attributes.
|
137
|
+
# @param [Hash, Proc] attributes A hash containing this item's attributes.
|
138
138
|
#
|
139
139
|
# @param [String] identifier This item's identifier.
|
140
140
|
#
|
141
141
|
# @param [Boolean] binary Whether or not this item is binary
|
142
|
-
|
142
|
+
#
|
143
|
+
# @param [String, nil] checksum_data Used to determine whether the item has changed
|
144
|
+
def new_item(content, attributes, identifier, binary: false, checksum_data: nil)
|
143
145
|
content = Nanoc::Int::Content.create(content, binary: binary)
|
144
|
-
Nanoc::Int::Item.new(content, attributes, identifier)
|
146
|
+
Nanoc::Int::Item.new(content, attributes, identifier, checksum_data: checksum_data)
|
145
147
|
end
|
146
148
|
|
147
149
|
# Creates a new in-memory layout instance. This is intended for use within
|
@@ -152,8 +154,10 @@ module Nanoc
|
|
152
154
|
# @param [Hash] attributes A hash containing this layout's attributes.
|
153
155
|
#
|
154
156
|
# @param [String] identifier This layout's identifier.
|
155
|
-
|
156
|
-
|
157
|
+
#
|
158
|
+
# @param [String, nil] checksum_data Used to determine whether the layout has changed
|
159
|
+
def new_layout(raw_content, attributes, identifier, checksum_data: nil)
|
160
|
+
Nanoc::Int::Layout.new(raw_content, attributes, identifier, checksum_data: checksum_data)
|
157
161
|
end
|
158
162
|
end
|
159
163
|
end
|
@@ -7,49 +7,36 @@ module Nanoc
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
def initialize(compiler)
|
10
|
+
def initialize(compiler, dependency_tracker)
|
11
11
|
@compiler = compiler
|
12
|
+
@dependency_tracker = dependency_tracker
|
12
13
|
end
|
13
14
|
|
14
15
|
def filter(rep, filter_name, filter_args = {})
|
15
|
-
|
16
|
-
klass = Nanoc::Filter.named(filter_name)
|
17
|
-
raise Nanoc::Int::Errors::UnknownFilter.new(filter_name) if klass.nil?
|
18
|
-
|
19
|
-
# Check whether filter can be applied
|
20
|
-
if klass.from_binary? && !rep.binary?
|
21
|
-
raise Nanoc::Int::Errors::CannotUseBinaryFilter.new(rep, klass)
|
22
|
-
elsif !klass.from_binary? && rep.binary?
|
23
|
-
raise Nanoc::Int::Errors::CannotUseTextualFilter.new(rep, klass)
|
24
|
-
end
|
16
|
+
filter = filter_for_filtering(rep, filter_name)
|
25
17
|
|
26
18
|
begin
|
27
|
-
# Notify start
|
28
19
|
Nanoc::Int::NotificationCenter.post(:filtering_started, rep, filter_name)
|
29
20
|
|
30
|
-
# Create filter
|
31
|
-
filter = klass.new(assigns_for(rep))
|
32
|
-
|
33
21
|
# Run filter
|
34
22
|
last = rep.snapshot_contents[:last]
|
35
23
|
source = rep.binary? ? last.filename : last.string
|
36
24
|
result = filter.setup_and_run(source, filter_args)
|
37
25
|
rep.snapshot_contents[:last] =
|
38
|
-
if
|
26
|
+
if filter.class.to_binary?
|
39
27
|
Nanoc::Int::BinaryContent.new(filter.output_filename).tap(&:freeze)
|
40
28
|
else
|
41
29
|
Nanoc::Int::TextualContent.new(result).tap(&:freeze)
|
42
30
|
end
|
43
31
|
|
44
32
|
# Check whether file was written
|
45
|
-
if
|
33
|
+
if filter.class.to_binary? && !File.file?(filter.output_filename)
|
46
34
|
raise OutputNotWrittenError.new(filter_name, filter.output_filename)
|
47
35
|
end
|
48
36
|
|
49
37
|
# Create snapshot
|
50
38
|
snapshot(rep, rep.snapshot_contents[:post] ? :post : :pre, final: false) unless rep.binary?
|
51
39
|
ensure
|
52
|
-
# Notify end
|
53
40
|
Nanoc::Int::NotificationCenter.post(:filtering_ended, rep, filter_name)
|
54
41
|
end
|
55
42
|
end
|
@@ -73,12 +60,12 @@ module Nanoc
|
|
73
60
|
# Create filter
|
74
61
|
klass = Nanoc::Filter.named(filter_name)
|
75
62
|
raise Nanoc::Int::Errors::UnknownFilter.new(filter_name) if klass.nil?
|
76
|
-
|
63
|
+
view_context = @compiler.create_view_context(@dependency_tracker)
|
64
|
+
layout_view = Nanoc::LayoutView.new(layout, view_context)
|
77
65
|
filter = klass.new(assigns_for(rep).merge({ layout: layout_view }))
|
78
66
|
|
79
67
|
# Visit
|
80
|
-
|
81
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, layout)
|
68
|
+
@dependency_tracker.bounce(layout)
|
82
69
|
|
83
70
|
begin
|
84
71
|
# Notify start
|
@@ -120,7 +107,7 @@ module Nanoc
|
|
120
107
|
end
|
121
108
|
|
122
109
|
def assigns_for(rep)
|
123
|
-
@compiler.assigns_for(rep)
|
110
|
+
@compiler.assigns_for(rep, @dependency_tracker)
|
124
111
|
end
|
125
112
|
|
126
113
|
def layouts
|
@@ -141,6 +128,19 @@ module Nanoc
|
|
141
128
|
raise Nanoc::Int::Errors::UnknownLayout.new(arg)
|
142
129
|
end
|
143
130
|
|
131
|
+
def filter_for_filtering(rep, filter_name)
|
132
|
+
klass = Nanoc::Filter.named(filter_name)
|
133
|
+
raise Nanoc::Int::Errors::UnknownFilter.new(filter_name) if klass.nil?
|
134
|
+
|
135
|
+
if klass.from_binary? && !rep.binary?
|
136
|
+
raise Nanoc::Int::Errors::CannotUseBinaryFilter.new(rep, klass)
|
137
|
+
elsif !klass.from_binary? && rep.binary?
|
138
|
+
raise Nanoc::Int::Errors::CannotUseTextualFilter.new(rep, klass)
|
139
|
+
end
|
140
|
+
|
141
|
+
klass.new(assigns_for(rep))
|
142
|
+
end
|
143
|
+
|
144
144
|
def use_globs?
|
145
145
|
@compiler.site.config[:string_pattern_type] == 'glob'
|
146
146
|
end
|
@@ -28,7 +28,6 @@ module Nanoc::Int
|
|
28
28
|
def route_rep(rep, snapshot_action, paths_to_reps)
|
29
29
|
basic_path = snapshot_action.path
|
30
30
|
return if basic_path.nil?
|
31
|
-
basic_path = basic_path.encode('UTF-8')
|
32
31
|
|
33
32
|
# Check for duplicate paths
|
34
33
|
if paths_to_reps.key?(basic_path)
|
@@ -43,10 +42,10 @@ module Nanoc::Int
|
|
43
42
|
|
44
43
|
def strip_index_filename(basic_path)
|
45
44
|
@site.config[:index_filenames].each do |index_filename|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
rep_path_ending = basic_path[-index_filename.length..-1]
|
46
|
+
next unless rep_path_ending == index_filename
|
47
|
+
|
48
|
+
return basic_path[0..-index_filename.length - 1]
|
50
49
|
end
|
51
50
|
|
52
51
|
basic_path
|
data/lib/nanoc/base/views.rb
CHANGED
@@ -21,7 +21,6 @@ require_relative 'views/mutable_item_view'
|
|
21
21
|
require_relative 'views/mutable_item_collection_view'
|
22
22
|
require_relative 'views/mutable_layout_view'
|
23
23
|
require_relative 'views/mutable_layout_collection_view'
|
24
|
-
require_relative 'views/site_view'
|
25
24
|
|
26
25
|
require_relative 'views/post_compile_item_view'
|
27
26
|
require_relative 'views/post_compile_item_collection_view'
|
@@ -36,9 +36,7 @@ module Nanoc
|
|
36
36
|
#
|
37
37
|
# @return [String] The content at the given snapshot.
|
38
38
|
def compiled_content(snapshot: nil)
|
39
|
-
|
40
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, unwrap.item)
|
41
|
-
|
39
|
+
@context.dependency_tracker.bounce(unwrap.item)
|
42
40
|
@item_rep.compiled_content(snapshot: snapshot)
|
43
41
|
end
|
44
42
|
|
@@ -52,9 +50,7 @@ module Nanoc
|
|
52
50
|
#
|
53
51
|
# @return [String] The item rep’s path.
|
54
52
|
def path(snapshot: :last)
|
55
|
-
|
56
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, unwrap.item)
|
57
|
-
|
53
|
+
@context.dependency_tracker.bounce(unwrap.item)
|
58
54
|
@item_rep.path(snapshot: snapshot)
|
59
55
|
end
|
60
56
|
|
@@ -67,9 +63,7 @@ module Nanoc
|
|
67
63
|
|
68
64
|
# @api private
|
69
65
|
def raw_path(snapshot: :last)
|
70
|
-
|
71
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, unwrap.item)
|
72
|
-
|
66
|
+
@context.dependency_tracker.bounce(unwrap.item)
|
73
67
|
@item_rep.raw_path(snapshot: snapshot)
|
74
68
|
end
|
75
69
|
|