nanoc-conref-fs 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 35dc702fdbe8ffa00711be829afcf827fe5565fe
4
- data.tar.gz: 83767a5ade9f4945c99f25d3a03122e1ff3467e7
3
+ metadata.gz: fdb225742e914ae1ac3f39c539c290a2c91aabf0
4
+ data.tar.gz: 694937b4c238491409411370271cc9d5d061c0c3
5
5
  SHA512:
6
- metadata.gz: bf4dd287a13d192f38777a6dc31211976ba3e6398ce7b9f53a06769740086dc706217788e05b1a954c35425863b75a41bea4937eaaa801eef7a2c87487b56289
7
- data.tar.gz: 37c643e5e0b2ac33cb40aa87025146d3549aad0d48f7215ce4cbb5f41aa79a65f2580104e4ae78fd7a54343fe5c466b1a6eb70a657e10d83b0c6b98256d69d62
6
+ metadata.gz: 9edf0b62eb28ea4fb128303e7cb442f79b32916b6b562c08f784e09b3d4396e16043a9c96d43837f4b341d4be3a62668168c4a0335c75d42b572318040e34e27
7
+ data.tar.gz: f6cbdd94a675dadc4b3dc2b91704909b415f91c718baf57a85e10e8581d665b32aa93e7f174d5bef783c41b98f4a38649cce52ed3b4a463515f9f69d629c81a2
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # nanoc-conref-fs
2
2
 
3
- This gem adds a new Filesystem type called `ConrefFS` to nanoc.
3
+ This gem adds a new Filesystem type to Nanoc called `ConrefFS`. This filesystem permits you to use reusable content and Liquid variables in your content to generate multiple outputs from a single source. It makes heavy use of item representations (or `rep`s for short).
4
4
 
5
- The idea is that you have a set of YAML files in a data folder which act as your reusables. You can apply thse reusables throughout your content and layout.
5
+ The idea is that you have a set of YAML files in a data folder which act as your reusables. You can apply these reusables throughout your content.
6
6
 
7
7
  [![Build Status](https://travis-ci.org/gjtorikian/nanoc-conref-fs.svg)](https://travis-ci.org/gjtorikian/nanoc-conref-fs)
8
8
 
9
- Set the data source in your *nanoc.yaml* file:
9
+ To get started, set the data source in your *nanoc.yaml* file:
10
10
 
11
11
  ``` yml
12
12
  data_sources:
@@ -14,7 +14,18 @@ data_sources:
14
14
  type: conref-fs
15
15
  ```
16
16
 
17
- **NOTE:** If you use this library with nanoc's ERB filter, and want to use `render`, you'll need to monkey-patch an alias to avoid conflicts:
17
+ You'll probably also want to provide a list of `rep`s which define all the item reps available to your site. For example:
18
+
19
+ ``` yml
20
+ data_sources:
21
+ -
22
+ type: conref-fs
23
+ reps:
24
+ - :default
25
+ - :X
26
+ ```
27
+
28
+ **NOTE:** If you use this library with Nanoc's ERB filter, and want to use `render`, you'll need to monkey-patch an alias to avoid conflicts with Liquid:
18
29
 
19
30
  ``` ruby
20
31
  require 'nanoc-conref-fs'
@@ -27,64 +38,100 @@ Nanoc::Helpers::Rendering.module_eval do
27
38
  end
28
39
  ```
29
40
 
30
- Then, use `renderp` instead of `render`.
41
+ Then, you can use `renderp` just as you would with `render`.
31
42
 
32
43
  ## Usage
33
44
 
34
- Nearly all the usage of this gem relies on a *data* folder, sibling to your *content* and *layouts* folders. See [the test fixture](test/fixtures/data) for an example.
35
-
36
- You'll also need some relevant keys added to your *nanoc.yaml* file:
37
-
38
- * The `data_variables` key applies additional/dynamic values to your data files, based on their path. For example, the following `data_variables` configuration adds a `version` attribute to every data file, whose value is `dotcom`:
39
-
40
- ``` yaml
41
- data_variables:
42
- -
43
- scope:
44
- path: ""
45
- values:
46
- version: "dotcom"
47
- ```
48
-
49
- You could add to this key to indicate that any data file called *changed* instead has a version of `something_different`:
50
-
51
- ``` yaml
52
- data_variables:
53
- -
54
- scope:
55
- path: ""
56
- values:
57
- version: "dotcom"
58
- -
59
- scope:
60
- path: "changed"
61
- values:
62
- version: "2.0"
63
- ```
64
-
65
- * Similarly, the `page_variables` also use `scope`s and `value`s to determine variables:
66
-
67
- ``` yaml
68
- page_variables:
69
- -
70
- scope:
71
- path: ""
72
- values:
73
- version: "dotcom"
74
- -
75
- scope:
76
- path: "different"
77
- values:
78
- version: "2.0"
79
- ```
80
-
81
- In this case, every file path will get a `version` of `dotcom`, but any file matching `different` will get a version of 2.0.
45
+ Nearly all the usage of this gem relies on a *data* folder, sibling to your *content* and *layouts* folders. See [the test fixture](test/fixtures/data) for an example. You can change this with the `data_dir` config option:
46
+
47
+ ``` yml
48
+ data_sources:
49
+ -
50
+ type: conref-fs
51
+ data_dir: 'somewhere_else'
52
+ reps:
53
+ - :default
54
+ - :X
55
+ ```
56
+
57
+ Then, you can [construct a data folder filled with YAML files](https://github.com/gjtorikian/nanoc-conref-fs/tree/master/test/fixtures/data). These act as the source of your reusable content.
58
+
59
+ Finally, you'll need some relevant keys added to your *nanoc.yaml* file.
60
+
61
+ ### Data folder variables
62
+
63
+ The `data_variables` key applies additional/dynamic values to your data files, based on their path. For example, the following `data_variables` configuration adds a `version` attribute to every data file, whose value is `dotcom`:
64
+
65
+ ``` yaml
66
+ data_variables:
67
+ -
68
+ scope:
69
+ path: ""
70
+ values:
71
+ version: "dotcom"
72
+ ```
73
+
74
+ You could add to this key to indicate that any data file called *changed* instead has a version of `something_different`:
75
+
76
+ ``` yaml
77
+ data_variables:
78
+ -
79
+ scope:
80
+ path: ""
81
+ values:
82
+ version: "dotcom"
83
+ -
84
+ scope:
85
+ path: "changed"
86
+ values:
87
+ version: "2.0"
88
+ ```
89
+
90
+ In addition to `path`, you can provide an array of `reps` to define which `reps` should receive which version:
91
+
92
+ ``` yaml
93
+ data_variables:
94
+ -
95
+ scope:
96
+ path: "feature"
97
+ values:
98
+ version: "dotcom"
99
+ -
100
+ scope:
101
+ path: "feature"
102
+ reps:
103
+ - :X
104
+ values:
105
+ version: "something_else"
106
+ ```
107
+
108
+ In this example, any data folder with a path containing "feature" will have `page.version` equal to `dotcom`. However, if you're constructing for the `:X` item representation, `page.version` becomes `something_else`.
109
+
110
+ ### Page variables
111
+
112
+ Similarly, the `page_variables` also use `scope`s, `rep`s, and `value`s to determine variables:
113
+
114
+ ``` yaml
115
+ page_variables:
116
+ -
117
+ scope:
118
+ path: ""
119
+ values:
120
+ version: "dotcom"
121
+ -
122
+ scope:
123
+ path: "different"
124
+ values:
125
+ version: "2.0"
126
+ ```
127
+
128
+ In this case, every file path will get a `version` of `dotcom`, but any file matching `different` will get a version of 2.0.
82
129
 
83
130
  See the tests for further usage of these conditionals. In both cases, `path` is converted into a Ruby regular expression before being matched against a filename.
84
131
 
85
132
  ### Associating files with data
86
133
 
87
- If you have a special `data_association` value, additional metadata to items will be applied:
134
+ If you have a special `data_association` value in your `scope`, additional metadata to items will be applied:
88
135
 
89
136
  * An attribute called `:parents`, which adds the parent "map topic" to an item.
90
137
  * An attribute called `:children`, which adds any children of a "map topic."
@@ -96,3 +143,25 @@ You can retrieve the stored data at any time (for example, in a layout) by calli
96
143
  ### Retrieving data files
97
144
 
98
145
  You can fetch anything in the *data* folder by passing in a string, demarcated with `.`s, to `VariableMixin.fetch_data_file`. For example, `VariableMixin.fetch_data_file('reusables.intro')` will fetch the file in *data/reusables/intro.yml*.
146
+
147
+ ### Ignoring content
148
+
149
+ You can use the `create_ignore_rules` method to construct ignore rules for your content. For example, say you have a category file that looks like this:
150
+
151
+ ``` yaml
152
+ Something:
153
+ - Blah1
154
+ {% if page.version == 'dotcom' %}
155
+ - Blah2
156
+ {% endif %}
157
+ ```
158
+
159
+ By default, Nanoc will try to compile and layout a page for `Blah2` for every item rep, even though it probably shouldn't.
160
+
161
+ You can use `create_ignore_rules`, passing in an item rep and a category file to generate ignore rules. For example:
162
+
163
+ ``` ruby
164
+ ConrefFS.create_ignore_rules(:X, 'categories.category').each do |f|
165
+ ignore f, rep: :X
166
+ end
167
+ ```
@@ -0,0 +1,98 @@
1
+ module NanocConrefFS
2
+ module Ancestry
3
+ def create_parents(toc, meta)
4
+ if toc.is_a?(Array)
5
+ find_array_parents(toc, meta[:title])
6
+ elsif toc.is_a?(Hash)
7
+ find_hash_parents(toc, meta[:title])
8
+ end
9
+ end
10
+ module_function :create_parents
11
+
12
+ def create_children(toc, meta)
13
+ if toc.is_a?(Array)
14
+ find_array_children(toc, meta[:title])
15
+ elsif toc.is_a?(Hash)
16
+ find_hash_children(toc, meta[:title])
17
+ end
18
+ end
19
+ module_function :create_children
20
+
21
+ # Given a category file that's an array, this method finds
22
+ # the parent of an item
23
+ def find_array_parents(toc, title)
24
+ parents = ''
25
+ toc.each do |item|
26
+ if item.is_a?(Hash)
27
+ parents = find_hash_parents(item, title)
28
+ break unless parents.empty?
29
+ end
30
+ end
31
+ parents
32
+ end
33
+ module_function :find_array_parents
34
+
35
+ # Given a category file that's a hash, this method finds
36
+ # the parent of an item
37
+ def find_hash_parents(toc, title)
38
+ parents = ''
39
+ toc.each_key do |key|
40
+ toc[key].each do |item|
41
+ if item.is_a?(Hash)
42
+ if item.keys.include?(title)
43
+ parents = key
44
+ break
45
+ else
46
+ if item[item.keys.first].include?(title)
47
+ parents = key
48
+ break
49
+ end
50
+ end
51
+ elsif title == item
52
+ parents = key
53
+ break
54
+ end
55
+ end
56
+ break unless parents.empty?
57
+ end
58
+ parents
59
+ end
60
+ module_function :find_hash_parents
61
+
62
+ # Given a category file that's an array, this method finds
63
+ # the children of an item, probably a map topic
64
+ def find_array_children(toc, title)
65
+ children = ''
66
+ toc.each do |item|
67
+ next unless item.is_a?(Hash)
68
+ item.each_pair do |key, values|
69
+ if key == title
70
+ children = values.flatten
71
+ break
72
+ end
73
+ end
74
+ break unless children.empty?
75
+ end
76
+ children
77
+ end
78
+ module_function :find_array_children
79
+
80
+ # Given a category file that's a hash, this method finds
81
+ # the children of an item, probably a map topic
82
+ def find_hash_children(toc, title)
83
+ children = ''
84
+ toc.each_key do |key|
85
+ toc[key].each do |item|
86
+ next unless item.is_a?(Hash)
87
+ unless item[title].nil?
88
+ children = item.values.flatten
89
+ break
90
+ end
91
+ end
92
+ break unless children.empty?
93
+ end
94
+ children
95
+ end
96
+ module_function :find_hash_children
97
+ end
98
+ end
@@ -0,0 +1,27 @@
1
+ module Nanoc
2
+ class ItemView
3
+ # allows apply_attributes to create new item attributes
4
+ def []=(key, value)
5
+ unwrap.attributes[key] = value
6
+ end
7
+ end
8
+ end
9
+
10
+ module Nanoc::HashExtensions
11
+ alias_method :original_freeze, :__nanoc_freeze_recursively
12
+
13
+ # prevents the item's frozen attributes from remaining frozen
14
+ def __nanoc_freeze_recursively
15
+ return if caller.first =~ %r{base/entities/document.rb}
16
+ original_freeze
17
+ end
18
+ end
19
+
20
+ class ConrefFSFilter < Nanoc::Filter
21
+ identifier :'conref-fs-filter'
22
+
23
+ def run(content, _)
24
+ ConrefFS.apply_attributes(@config, item, @rep.name)
25
+ NanocConrefFS::Conrefifier.liquify(@config, path: @item[:filename], content: content, rep: @rep.name)
26
+ end
27
+ end
@@ -1,202 +1,145 @@
1
1
  require_relative 'conrefifier'
2
-
3
- # Unsure why attr_accessor does not work here
4
- module VariableMixin
5
- def self.variables
6
- @variables
7
- end
8
-
9
- def self.variables=(variables)
10
- @variables = variables
11
- end
12
-
13
- def self.fetch_data_file(association)
14
- reference = association.split('.')
15
- variables = VariableMixin.variables
16
- data = variables['site']['data']
17
- while key = reference.shift
18
- data = data[key]
19
- end
20
- data
21
- end
22
- end
2
+ require 'active_support/core_ext/string'
23
3
 
24
4
  class ConrefFS < Nanoc::DataSource
25
5
  include Nanoc::DataSources::Filesystem
26
- include VariableMixin
6
+ include NanocConrefFS::Variables
7
+ include NanocConrefFS::Ancestry
27
8
 
28
9
  identifier :'conref-fs'
29
10
 
30
11
  # Before iterating over the file objects, this method loads the data folder
31
12
  # and applies it to an ivar for later usage.
32
- def load_objects(dir_name, kind, klass)
33
- if klass == Nanoc::Int::Item && @variables.nil?
34
- data = Datafiles.process(@site_config)
35
- config = @site_config.to_h
36
- @variables = { 'site' => { 'config' => config, 'data' => data } }
37
- VariableMixin.variables = @variables
38
- end
39
- super
13
+ def up
14
+ data_files = NanocConrefFS::Datafiles.collect_data(data_dir_name)
15
+ NanocConrefFS::Variables.data_files = data_files
16
+ NanocConrefFS::Variables.variables = {}
17
+ reps = @config[:reps] || [:default]
18
+ reps.each { |rep| ConrefFS.load_data_folder(@site_config, rep) }
40
19
  end
41
20
 
42
- # This function calls the parent super, then adds additional metadata to the item.
43
- def parse(content_filename, meta_filename, _kind)
44
- meta, content = super
45
- page_vars = Conrefifier.file_variables(@site_config[:page_variables], content_filename)
21
+ def data_dir_name
22
+ config.fetch(:data_dir) { |_| 'data' }
23
+ end
24
+
25
+ def self.load_data_folder(config, rep)
26
+ return unless NanocConrefFS::Variables.variables[rep].nil?
27
+ data_files = NanocConrefFS::Variables.data_files
28
+ data = NanocConrefFS::Datafiles.process(data_files, config, rep)
29
+ NanocConrefFS::Variables.variables[rep] = { 'site' => { 'config' => config, 'data' => data } }
30
+ end
31
+
32
+ def self.apply_attributes(config, item, rep)
33
+ page_vars = NanocConrefFS::Conrefifier.file_variables(config[:page_variables], item[:filename], rep)
34
+
35
+ frontmatter_vars = { :page => page_vars }.merge(NanocConrefFS::Variables.variables[rep])
36
+
46
37
  unless page_vars[:data_association].nil?
47
38
  association = page_vars[:data_association]
48
- toc = VariableMixin.fetch_data_file(association)
49
- meta[:parents] = if toc.is_a?(Array)
50
- find_array_parents(toc, meta['title'])
51
- elsif toc.is_a?(Hash)
52
- find_hash_parents(toc, meta['title'])
53
- end
54
-
55
- meta[:children] = if toc.is_a?(Array)
56
- find_array_children(toc, meta['title'])
57
- elsif toc.is_a?(Hash)
58
- find_hash_children(toc, meta['title'])
59
- end
60
- end
61
- page_vars.each_pair do |name, value|
62
- meta[name.to_s] = value
39
+ toc = NanocConrefFS::Variables.fetch_data_file(association, rep)
40
+ item[:parents] = NanocConrefFS::Ancestry::create_parents(toc, item.attributes)
41
+ item[:children] = NanocConrefFS::Ancestry::create_children(toc, item.attributes)
63
42
  end
64
- [meta, content]
65
- end
66
43
 
67
- # Given a category file that's an array, this method finds
68
- # the parent of an item
69
- def find_array_parents(toc, title)
70
- parents = ''
71
- toc.each do |item|
72
- if item.is_a?(Hash)
73
- parents = find_hash_parents(item, title)
74
- break unless parents.empty?
75
- end
44
+ page_vars.each_pair do |key, value|
45
+ item[key] = value
76
46
  end
77
- parents
78
- end
79
47
 
80
- # Given a category file that's a hash, this method finds
81
- # the parent of an item
82
- def find_hash_parents(toc, title)
83
- parents = ''
84
- toc.keys.each do |key|
85
- toc[key].each do |item|
86
- if item.is_a?(Hash)
87
- if item.keys.include?(title)
88
- parents = key
89
- break
90
- else
91
- if item[item.keys.first].include?(title)
92
- parents = key
93
- break
94
- end
95
- end
96
- elsif title == item
97
- parents = key
98
- break
48
+ item.attributes.each_pair do |key, value|
49
+ if value.is_a?(Array)
50
+ item[key] = value.map do |arr_v|
51
+ return arr_v unless arr_v =~ NanocConrefFS::Conrefifier::SINGLE_SUB
52
+ NanocConrefFS::Conrefifier.apply_liquid(arr_v, frontmatter_vars)
53
+ end
54
+ else
55
+ if value =~ NanocConrefFS::Conrefifier::SINGLE_SUB
56
+ value = NanocConrefFS::Conrefifier.apply_liquid(value, frontmatter_vars)
57
+ item[key] = value
99
58
  end
100
59
  end
101
- break unless parents.empty?
102
60
  end
103
- parents
104
61
  end
105
62
 
106
- # Given a category file that's an array, this method finds
107
- # the children of an item, probably a map topic
108
- def find_array_children(toc, title)
109
- children = ''
110
- toc.each do |item|
111
- next unless item.is_a?(Hash)
112
- item.each_pair do |key, values|
113
- if key == title
114
- children = values.flatten
115
- break
116
- end
117
- end
118
- break unless children.empty?
119
- end
120
- children
63
+ # There are a lot of problems when trying to parse liquid
64
+ # out of the frontmatter—all of them dealing with collision between
65
+ # the { character in Liquid and its signfigance in YAML. We'll overload
66
+ # the parse method here to resolve those issues ahead of time.
67
+ def parse(content_filename, meta_filename, _kind)
68
+ # Read data
69
+ data = read(content_filename)
70
+
71
+ # Check presence of metadata section
72
+ return [{}, data] if data !~ /\A-{3,5}\s*$/
73
+
74
+ # Split data
75
+ pieces = data.split(/^(-{5}|-{3})[ \t]*\r?\n?/, 3)
76
+ if pieces.size < 4
77
+ raise RuntimeError.new(
78
+ "The file '#{content_filename}' appears to start with a metadata section (three or five dashes at the top) but it does not seem to be in the correct format.",
79
+ )
121
80
  end
122
81
 
123
- # Given a category file that's a hash, this method finds
124
- # the children of an item, probably a map topic
125
- def find_hash_children(toc, title)
126
- children = ''
127
- toc.keys.each do |key|
128
- toc[key].each do |item|
129
- next unless item.is_a?(Hash)
130
- unless item[title].nil?
131
- children = item.values.flatten
132
- break
133
- end
134
- end
135
- break unless children.empty?
136
- end
137
- children
138
- end
82
+ # N.B. the only change to the original function
83
+ pieces[2].gsub!(/^([^:]+): (\{\{.+)/, '\1: \'\2\'')
139
84
 
140
- # This file reads each piece of content as it comes in. It also applies the conref variables
141
- # (demarcated by Liquid's {{ }} tags) using both the data/ folder and any variables defined
142
- # within the nanoc.yaml config file
143
- def read(filename)
144
- content = ''
85
+ # Parse
145
86
  begin
146
- page_vars = Conrefifier.file_variables(@site_config[:page_variables], filename)
147
- page_vars = { :page => page_vars }.merge(@variables)
148
-
149
- content = File.read(filename)
150
- return content unless filename.start_with?('content', 'layouts')
151
-
152
- # we must obfuscate essential ExtendedMarkdownFilter content
153
- content = content.gsub(/\{\{\s*#(\S+)\s*\}\}/, '[[#\1]]')
154
- content = content.gsub(/\{\{\s*\/(\S+)\s*\}\}/, '[[/\1]]')
155
- content = content.gsub(/\{\{\s*(octicon-\S+\s*[^\}]+)\s*\}\}/, '[[\1]]')
156
- rescue => e
157
- raise "Could not read #{filename}: #{e.inspect}"
87
+ meta = YAML.load(pieces[2]) || {}
88
+ rescue Exception => e
89
+ raise "Could not parse YAML for #{content_filename}: #{e.message}"
158
90
  end
91
+ verify_meta(meta, content_filename)
92
+ content = pieces[4]
159
93
 
160
- begin
161
- result = content
94
+ # Done
95
+ [meta, content]
96
+ end
162
97
 
163
- # This pass replaces any matched conditionals
164
- if result =~ Conrefifier::BLOCK_SUB || result =~ Conrefifier::SINGLE_SUB
165
- result = Conrefifier.apply_liquid(result, page_vars)
166
- end
98
+ def self.create_ignore_rules(rep, file)
99
+ current_articles = NanocConrefFS::Variables.fetch_data_file(file, rep)
100
+ current_articles = flatten_list(current_articles).flatten
101
+ current_articles = fix_nested_content(current_articles)
167
102
 
168
- # This second pass renders any previously inserted
169
- # data conditionals within the body. If a Liquid parse
170
- # returns a blank string, we'll return the original
171
- if result =~ Conrefifier::SINGLE_SUB
172
- result = result.gsub(Conrefifier::SINGLE_SUB) do |match|
173
- liquified = Conrefifier.apply_liquid(match, page_vars)
174
- liquified.empty? ? match : liquified
175
- end
176
- end
103
+ basic_yaml = NanocConrefFS::Variables.data_files["data/#{file.tr!('.', '/')}.yml"]
104
+ basic_yaml.gsub!(/\{%.+/, '')
105
+ full_file = YAML.load(basic_yaml)
106
+
107
+ full_user_articles = flatten_list(full_file).flatten
108
+ full_user_articles = fix_nested_content(full_user_articles)
109
+
110
+ blacklisted_articles = full_user_articles - current_articles
111
+ blacklisted_articles.map do |article|
112
+ "#{article.parameterize}.md"
113
+ end
114
+ end
177
115
 
178
- # This converts ": *" frontmatter strings into HTML equivalents;
179
- # otherwise, ": *" messes the YAML parsing
180
- result = result.gsub(/\A---\s*\n(.*?\n?)^---\s*$\n?/m) do |frontmatter|
181
- frontmatter.gsub(/:\s*(\*.+)/) do |_|
182
- asterisk_match = Regexp.last_match[1]
183
- if asterisk_match[1] != '*'
184
- asterisk_match = asterisk_match.sub(/\*(.+?)\*/, ': <em>\1</em>')
185
- else
186
- asterisk_match = asterisk_match.sub(/\*{2}(.+?)\*{2}/, ': <strong>\1</strong>')
187
- end
188
- asterisk_match
116
+ def self.flatten_list(arr)
117
+ result = []
118
+ return result unless arr
119
+ arr.each do |item|
120
+ if item.is_a?(Hash)
121
+ item.each_pair do |key, value|
122
+ result << key
123
+ result.concat(value)
189
124
  end
125
+ else
126
+ result << item
190
127
  end
128
+ end
191
129
 
192
- result
193
- rescue Liquid::SyntaxError => e
194
- # unrecognized Liquid, so just return the content
195
- STDERR.puts "Could not convert #{filename}: #{e.message}"
196
- result
197
- rescue => e
198
- raise "#{e.message}: #{e.inspect}"
130
+ result
131
+ end
132
+
133
+ def self.fix_nested_content(articles)
134
+ articles.delete_if do |i|
135
+ if i.is_a? Hash
136
+ articles.concat(i.keys.concat(i.values).flatten)
137
+ true
138
+ else
139
+ false
140
+ end
199
141
  end
142
+ articles
200
143
  end
201
144
 
202
145
  # This method is extracted from the Nanoc default FS