yarrow 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/yarrow/config.rb +12 -2
- data/lib/yarrow/configuration.rb +13 -1
- data/lib/yarrow/content/expansion/strategy.rb +53 -0
- data/lib/yarrow/content/expansion/tree.rb +90 -0
- data/lib/yarrow/content/graph.rb +0 -5
- data/lib/yarrow/content/model.rb +11 -34
- data/lib/yarrow/content/policy.rb +75 -18
- data/lib/yarrow/defaults.yml +5 -0
- data/lib/yarrow/generator.rb +2 -2
- data/lib/yarrow/schema/definitions.rb +3 -3
- data/lib/yarrow/version.rb +1 -1
- data/lib/yarrow.rb +7 -9
- metadata +3 -4
- data/lib/yarrow/content/expansion.rb +0 -16
- data/lib/yarrow/content/expansion_strategy.rb +0 -51
- data/lib/yarrow/content/tree_expansion.rb +0 -88
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ea37c60e3c8bfe51e6ceb9425f0d0c81b93757a681c7987f7852c3335644824
|
4
|
+
data.tar.gz: 19cd090d3b3348f633f5d303d8b826fd2b8c054b790136355a41d9b4f0f098c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebd0dd29f6d8800b20560c2e24fd2988caecf19e9ae5f3e44a3d0b427afc9201971be1b086705e72c874683d30625821b270e6ad944c5c28ca9b6cd9ecd65ea2
|
7
|
+
data.tar.gz: 92d36891c8a270ff663a299b2a217ffe3bb6985200e70d84c4c9d29ee87bb00fb7b2e824e0d932d585b5f8b4a22d578748ee58ad3ae022aa8f1b8ab04117ac6f
|
data/lib/yarrow/config.rb
CHANGED
@@ -40,7 +40,16 @@ module Yarrow
|
|
40
40
|
:middleware
|
41
41
|
)
|
42
42
|
|
43
|
-
|
43
|
+
# Yarrow::Schema.define do
|
44
|
+
# type :config_source_map, Yarrow::Schema::Types::Instance.of(Hash).accept(Symbol)
|
45
|
+
# end
|
46
|
+
|
47
|
+
class Content < Yarrow::Schema::Entity[:__config_content]
|
48
|
+
attribute :module, :string
|
49
|
+
attribute :source_map, :hash
|
50
|
+
end
|
51
|
+
|
52
|
+
class Output < Yarrow::Schema::Entity[:__config_output]
|
44
53
|
attribute :generator, :string
|
45
54
|
attribute :template_dir, :path
|
46
55
|
#attribute :scripts, :array
|
@@ -52,7 +61,8 @@ module Yarrow
|
|
52
61
|
attribute :output_dir, :path
|
53
62
|
attribute :meta, :any
|
54
63
|
attribute :server, :any
|
55
|
-
|
64
|
+
attribute :content, :__config_content
|
65
|
+
#attribute :output, :__config_output
|
56
66
|
end
|
57
67
|
#
|
58
68
|
# `content_dir` and `output_dir` are placeholders and should be overriden
|
data/lib/yarrow/configuration.rb
CHANGED
@@ -48,6 +48,17 @@ module Yarrow
|
|
48
48
|
nil
|
49
49
|
end
|
50
50
|
|
51
|
+
content_obj = if config.key?(:content)
|
52
|
+
Yarrow::Config::Content.new(config[:content])
|
53
|
+
else
|
54
|
+
Yarrow::Config::Content.new({
|
55
|
+
module: "",
|
56
|
+
source_map: {
|
57
|
+
pages: :page
|
58
|
+
}
|
59
|
+
})
|
60
|
+
end
|
61
|
+
|
51
62
|
# TODO: messy hack to get rid of Hashie::Mash, this should either be
|
52
63
|
# automated as part of the schema types or a default value should be
|
53
64
|
# generated here (eg: `"#{Dir.pwd}/docs"`)
|
@@ -58,7 +69,8 @@ module Yarrow
|
|
58
69
|
output_dir: Pathname.new(File.expand_path(out_dir_or_string)),
|
59
70
|
source_dir: Pathname.new(File.expand_path(source_dir_or_string)),
|
60
71
|
meta: meta_obj,
|
61
|
-
server: server_obj
|
72
|
+
server: server_obj,
|
73
|
+
content: content_obj
|
62
74
|
)
|
63
75
|
end
|
64
76
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Yarrow
|
2
|
+
module Content
|
3
|
+
module Expansion
|
4
|
+
class Strategy
|
5
|
+
include Yarrow::Tools::FrontMatter
|
6
|
+
|
7
|
+
attr_reader :graph
|
8
|
+
|
9
|
+
def initialize(graph)
|
10
|
+
@graph = graph
|
11
|
+
end
|
12
|
+
|
13
|
+
# Extract collection level configuration/metadata from the root node for
|
14
|
+
# this content type.
|
15
|
+
def extract_metadata(node, type)
|
16
|
+
# TODO: support _index or _slug convention as well
|
17
|
+
meta_file = node.out(slug: type.to_s).first
|
18
|
+
|
19
|
+
if meta_file
|
20
|
+
# Process metadata and add it to the collection node
|
21
|
+
# TODO: pass in content converter object
|
22
|
+
# TODO: index/body content by default if extracted from frontmatter
|
23
|
+
body, data = process_content(meta_file.props[:entry])
|
24
|
+
else
|
25
|
+
# Otherwise, assume default collection behaviour
|
26
|
+
data = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate a default title if not provided in metadata
|
30
|
+
unless data.key?(:title)
|
31
|
+
data[:title] = type.to_s.capitalize
|
32
|
+
end
|
33
|
+
|
34
|
+
data
|
35
|
+
end
|
36
|
+
|
37
|
+
# Workaround for handling meta and content source in multiple files or a single
|
38
|
+
# file with front matter.
|
39
|
+
def process_content(path)
|
40
|
+
case path.extname
|
41
|
+
when '.htm', '.md'
|
42
|
+
read_split_content(path.to_s, symbolize_keys: true)
|
43
|
+
# when '.md'
|
44
|
+
# body, data = read_split_content(path.to_s, symbolize_keys: true)
|
45
|
+
# [Kramdown::Document.new(body).to_html, data]
|
46
|
+
when '.yml'
|
47
|
+
[nil, YAML.load(File.read(path.to_s), symbolize_names: true)]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Yarrow
|
2
|
+
module Content
|
3
|
+
module Expansion
|
4
|
+
class Tree < Strategy
|
5
|
+
def expand(policy)
|
6
|
+
#p graph.n(:root).out(:directory).to_a.count
|
7
|
+
#policy.match()
|
8
|
+
|
9
|
+
#p graph.n(:root).out(:directory).first.props[:name]
|
10
|
+
type = policy.container
|
11
|
+
|
12
|
+
# If match path represents entire content dir, then include the entire
|
13
|
+
# content dir instead of scanning from a subfolder matching the name of
|
14
|
+
# the collection.
|
15
|
+
#start_node = if policy.match_path == "."
|
16
|
+
start_node = if true
|
17
|
+
# TODO: match against source_dir
|
18
|
+
graph.n(:root).out(:directory)
|
19
|
+
else
|
20
|
+
graph.n(:root).out(name: policy.container.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Extract metadata from given start node
|
24
|
+
collection_metadata = extract_metadata(start_node, policy.container)
|
25
|
+
|
26
|
+
# Collect all nested collections in the subgraph for this content type
|
27
|
+
subcollections = {}
|
28
|
+
item_links = []
|
29
|
+
index = nil
|
30
|
+
|
31
|
+
# Scan and collect all nested files from the root
|
32
|
+
start_node.depth_first.each do |node|
|
33
|
+
if node.label == :directory
|
34
|
+
# Create a collection node representing a collection of documents
|
35
|
+
index = graph.create_node do |collection_node|
|
36
|
+
collection_node.label = :collection
|
37
|
+
collection_node.props[:type] = policy.container
|
38
|
+
collection_node.props[:name] = node.props[:name]
|
39
|
+
|
40
|
+
# TODO: title needs to be defined from metadata
|
41
|
+
collection_node.props[:title] = node.props[:name].capitalize
|
42
|
+
end
|
43
|
+
|
44
|
+
# Add this collection id to the lookup table for edge construction
|
45
|
+
subcollections[node.props[:path]] = index
|
46
|
+
|
47
|
+
# Join the collection to its parent
|
48
|
+
unless node.props[:slug] == type.to_s || !subcollections.key?(node.props[:entry].parent.to_s)
|
49
|
+
graph.create_edge do |edge|
|
50
|
+
edge.label = :child
|
51
|
+
edge.from = subcollections[node.props[:entry].parent.to_s].id
|
52
|
+
edge.to = index.id
|
53
|
+
end
|
54
|
+
end
|
55
|
+
elsif node.label == :file
|
56
|
+
body, meta = process_content(node.props[:entry])
|
57
|
+
|
58
|
+
# Create an item node representing a file mapped to a unique content object
|
59
|
+
item = graph.create_node do |item_node|
|
60
|
+
item_node.label = :item
|
61
|
+
item_node.props[:type] = policy.entity
|
62
|
+
item_node.props[:name] = node.props[:entry].basename(node.props[:entry].extname).to_s
|
63
|
+
item_node.props[:body] = body if body
|
64
|
+
item_node.props[:title] = meta[:title] if meta
|
65
|
+
# TODO: better handling of metadata on node props
|
66
|
+
end
|
67
|
+
|
68
|
+
# We may not have an expanded node for the parent collection if this is a
|
69
|
+
# preorder traversal so save it for later
|
70
|
+
item_links << {
|
71
|
+
parent_path: node.props[:entry].parent.to_s,
|
72
|
+
item_id: item.id
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Once all files and directories have been expanded, connect all the child
|
78
|
+
# edges between collections and items
|
79
|
+
item_links.each do |item_link|
|
80
|
+
graph.create_edge do |edge|
|
81
|
+
edge.label = :child
|
82
|
+
edge.from = subcollections[item_link[:parent_path]].id
|
83
|
+
edge.to = item_link[:item_id]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/yarrow/content/graph.rb
CHANGED
data/lib/yarrow/content/model.rb
CHANGED
@@ -1,45 +1,22 @@
|
|
1
1
|
module Yarrow
|
2
2
|
module Content
|
3
|
-
ContentSpec = Yarrow::Schema::Value.new(:namespace, :model) do
|
4
|
-
def to_world
|
5
|
-
"world"
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
ContentPolicy = Yarrow::Schema::Value.new(
|
10
|
-
:dir,
|
11
|
-
:file,
|
12
|
-
:expansion,
|
13
|
-
:container,
|
14
|
-
:record
|
15
|
-
)
|
16
|
-
|
17
3
|
class Model
|
18
|
-
def initialize(
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
@policies = if spec.nil?
|
23
|
-
spec = {
|
24
|
-
root: ContentPolicy.new(
|
25
|
-
expansion: :tree,
|
26
|
-
dir: "*",
|
27
|
-
file: "*.md",
|
28
|
-
:container => :pages,
|
29
|
-
:record => :page
|
30
|
-
)
|
31
|
-
}
|
32
|
-
else
|
33
|
-
spec.model
|
4
|
+
def initialize(content_config)
|
5
|
+
@policies = {}
|
6
|
+
content_config.source_map.each_entry do |policy_label, policy_spec|
|
7
|
+
@policies[policy_label] = Policy.from_spec(policy_label, policy_spec)
|
34
8
|
end
|
35
9
|
end
|
36
10
|
|
37
|
-
def
|
38
|
-
@policies.each_value
|
11
|
+
def expand(graph)
|
12
|
+
@policies.each_value do |policy|
|
13
|
+
strategy = Expansion::Tree.new(graph)
|
14
|
+
strategy.expand(policy)
|
15
|
+
end
|
39
16
|
end
|
40
17
|
|
41
|
-
def policy_for(
|
42
|
-
@policies[
|
18
|
+
def policy_for(policy_label)
|
19
|
+
@policies[policy_label]
|
43
20
|
end
|
44
21
|
end
|
45
22
|
end
|
@@ -1,47 +1,104 @@
|
|
1
1
|
module Yarrow
|
2
2
|
module Content
|
3
3
|
class Policy
|
4
|
-
Options = Yarrow::Schema::Value.new(
|
5
|
-
:container,
|
6
|
-
:entity,
|
7
|
-
:extensions,
|
8
|
-
:match_path
|
9
|
-
)
|
10
|
-
|
11
4
|
DEFAULT_HOME_NESTING = false
|
12
5
|
|
6
|
+
DEFAULT_EXPANSION = :tree
|
7
|
+
|
13
8
|
DEFAULT_EXTENSIONS = [".md", ".yml", ".htm"]
|
14
9
|
|
15
10
|
DEFAULT_MATCH_PATH = "."
|
16
11
|
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
# Construct a content policy from the given source specification.
|
13
|
+
def self.from_spec(policy_label, policy_props, module_prefix="")
|
14
|
+
# TODO: validate length, structure etc
|
15
|
+
|
16
|
+
# If the spec holds a symbol value then treat it as a container => entity mapping
|
17
|
+
if policy_props.is_a?(Symbol)
|
18
|
+
new(policy_label, policy_props, DEFAULT_EXPANSION, DEFAULT_EXTENSIONS, DEFAULT_MATCH_PATH, module_prefix)
|
19
|
+
|
20
|
+
# Otherwise scan through all the props and fill in any gaps
|
21
|
+
else
|
22
|
+
# Use explicit container name if provided
|
23
|
+
container = if policy_props.key?(:container)
|
24
|
+
policy_props[:container]
|
25
|
+
else
|
26
|
+
# If an entity name is provided use its plural for the container name
|
27
|
+
if policy_props.key?(:entity)
|
28
|
+
Yarrow::Symbols.to_plural(policy_props[:entity])
|
29
|
+
else
|
30
|
+
Yarrow::Symbols.to_plural(label)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Use explicit entity name if provided
|
35
|
+
entity = if policy_props.key?(:entity)
|
36
|
+
policy_props[:entity]
|
37
|
+
else
|
38
|
+
if policy_props.key?(:container)
|
39
|
+
Yarrow::Symbols.to_singular(policy_props[:container])
|
40
|
+
else
|
41
|
+
Yarrow::Symbols.to_singular(label)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set expansion strategy
|
46
|
+
expansion = if policy_props.key?(:expansion)
|
47
|
+
policy_props[:expansion]
|
48
|
+
else
|
49
|
+
DEFAULT_EXPANSION
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set list of extensions to turn into documents
|
53
|
+
extensions = if policy_props.key?(:extensions)
|
54
|
+
policy_props[:extensions]
|
55
|
+
else
|
56
|
+
DEFAULT_EXTENSIONS
|
57
|
+
end
|
20
58
|
|
21
|
-
|
22
|
-
|
23
|
-
|
59
|
+
# TODO: handle this in expansion strategies
|
60
|
+
match_path = DEFAULT_MATCH_PATH
|
61
|
+
|
62
|
+
# Construct the new policy
|
63
|
+
new(container, entity, expansion, extensions, match_path, module_prefix)
|
24
64
|
end
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :container, :entity, :expansion, :extensions, :match_path, :module
|
68
|
+
|
69
|
+
def initialize(container, entity, expansion, extensions, match_path, module_prefix)
|
70
|
+
@container = container
|
71
|
+
@entity = entity
|
72
|
+
@expansion = expansion
|
73
|
+
@extensions = extensions
|
74
|
+
@match_path = match_path
|
75
|
+
@module_prefix = module_prefix
|
76
|
+
end
|
77
|
+
|
78
|
+
def container_const
|
79
|
+
@container_const ||= Yarrow::Symbols.to_module_const([module_prefix, container])
|
80
|
+
end
|
25
81
|
|
26
|
-
|
82
|
+
def entity_const
|
83
|
+
@entity_const ||= Yarrow::Symbols.to_module_const([module_prefix, entity])
|
27
84
|
end
|
28
85
|
|
29
|
-
def
|
86
|
+
def _container
|
30
87
|
return @properties.container if @properties.container
|
31
88
|
Yarrow::Symbols.to_plural(@properties.entity)
|
32
89
|
end
|
33
90
|
|
34
|
-
def
|
91
|
+
def _entity
|
35
92
|
return @properties.entity if @properties.entity
|
36
93
|
Yarrow::Symbols.to_singular(@properties.container)
|
37
94
|
end
|
38
95
|
|
39
|
-
def
|
96
|
+
def _extensions
|
40
97
|
return @properties.extensions if @properties.extensions
|
41
98
|
DEFAULT_EXTENSIONS
|
42
99
|
end
|
43
100
|
|
44
|
-
def
|
101
|
+
def _match_path
|
45
102
|
return @properties.match_path if @properties.match_path
|
46
103
|
DEFAULT_MATCH_PATH
|
47
104
|
end
|
data/lib/yarrow/defaults.yml
CHANGED
data/lib/yarrow/generator.rb
CHANGED
@@ -13,8 +13,8 @@ module Yarrow
|
|
13
13
|
provides Content::Graph
|
14
14
|
|
15
15
|
def step(content)
|
16
|
-
|
17
|
-
|
16
|
+
model = Content::Model.new(content.config.content)
|
17
|
+
model.expand(content.graph)
|
18
18
|
content
|
19
19
|
end
|
20
20
|
end
|
@@ -8,7 +8,7 @@ module Yarrow
|
|
8
8
|
path: Types::Instance.of(Pathname).accept(String),
|
9
9
|
any: Types::Any.new,
|
10
10
|
array: Types::List.of(Types::Any),
|
11
|
-
hash: Types::
|
11
|
+
hash: Types::Instance.of(Hash)
|
12
12
|
}
|
13
13
|
|
14
14
|
TEMPLATE_TYPES = {
|
@@ -40,7 +40,7 @@ module Yarrow
|
|
40
40
|
|
41
41
|
# Get reference to the type class we want to resolve
|
42
42
|
template_type = TEMPLATE_TYPES[key_id]
|
43
|
-
|
43
|
+
|
44
44
|
# Resolve the type to an instance depending on structure of its template args
|
45
45
|
resolved_type = if value_id.is_a?(Hash)
|
46
46
|
# Map template with two argument constructor
|
@@ -55,7 +55,7 @@ module Yarrow
|
|
55
55
|
|
56
56
|
# Cache the resolved type for later reference
|
57
57
|
DEFINED_TYPES[identifier] = resolved_type
|
58
|
-
|
58
|
+
|
59
59
|
# Return the resolve type
|
60
60
|
resolved_type
|
61
61
|
else
|
data/lib/yarrow/version.rb
CHANGED
data/lib/yarrow.rb
CHANGED
@@ -14,19 +14,15 @@ require "yarrow/schema/dictionary"
|
|
14
14
|
require "yarrow/schema/entity"
|
15
15
|
require "yarrow/schema/value"
|
16
16
|
require "yarrow/schema/registry"
|
17
|
-
require "yarrow/config"
|
18
|
-
require "yarrow/configuration"
|
19
|
-
require "yarrow/console_runner"
|
20
17
|
require "yarrow/tools/front_matter"
|
21
18
|
require "yarrow/tools/content_utils"
|
22
19
|
require "yarrow/content/graph"
|
20
|
+
require "yarrow/content/policy"
|
21
|
+
require "yarrow/content/model"
|
23
22
|
require "yarrow/content/source"
|
24
|
-
require "yarrow/content/expansion"
|
25
|
-
require "yarrow/content/
|
26
|
-
require "yarrow/content/tree_expansion"
|
23
|
+
require "yarrow/content/expansion/strategy"
|
24
|
+
require "yarrow/content/expansion/tree"
|
27
25
|
require "yarrow/content/resource"
|
28
|
-
require "yarrow/content/model"
|
29
|
-
require "yarrow/content/policy"
|
30
26
|
require "yarrow/web/manifest"
|
31
27
|
require "yarrow/web/document"
|
32
28
|
require "yarrow/web/generator"
|
@@ -36,12 +32,14 @@ require "yarrow/output/web/indexed_file"
|
|
36
32
|
require "yarrow/content_map"
|
37
33
|
require "yarrow/server"
|
38
34
|
require "yarrow/server/livereload"
|
39
|
-
|
40
35
|
require "yarrow/process/workflow"
|
41
36
|
require "yarrow/process/step_processor"
|
42
37
|
require "yarrow/process/expand_content"
|
43
38
|
require "yarrow/process/extract_source"
|
44
39
|
require "yarrow/process/project_manifest"
|
40
|
+
require "yarrow/config"
|
41
|
+
require "yarrow/configuration"
|
42
|
+
require "yarrow/console_runner"
|
45
43
|
|
46
44
|
require "yarrow/generator"
|
47
45
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yarrow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Rickerby
|
@@ -260,14 +260,13 @@ files:
|
|
260
260
|
- lib/yarrow/config.rb
|
261
261
|
- lib/yarrow/configuration.rb
|
262
262
|
- lib/yarrow/console_runner.rb
|
263
|
-
- lib/yarrow/content/expansion.rb
|
264
|
-
- lib/yarrow/content/
|
263
|
+
- lib/yarrow/content/expansion/strategy.rb
|
264
|
+
- lib/yarrow/content/expansion/tree.rb
|
265
265
|
- lib/yarrow/content/graph.rb
|
266
266
|
- lib/yarrow/content/model.rb
|
267
267
|
- lib/yarrow/content/policy.rb
|
268
268
|
- lib/yarrow/content/resource.rb
|
269
269
|
- lib/yarrow/content/source.rb
|
270
|
-
- lib/yarrow/content/tree_expansion.rb
|
271
270
|
- lib/yarrow/content_map.rb
|
272
271
|
- lib/yarrow/defaults.yml
|
273
272
|
- lib/yarrow/generator.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Yarrow
|
2
|
-
module Content
|
3
|
-
class Expansion
|
4
|
-
def initialize(model)
|
5
|
-
@model = model
|
6
|
-
end
|
7
|
-
|
8
|
-
def expand(graph)
|
9
|
-
@model.each_policy do |policy|
|
10
|
-
strategy = TreeExpansion.new(graph)
|
11
|
-
strategy.expand(policy)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module Yarrow
|
2
|
-
module Content
|
3
|
-
class ExpansionStrategy
|
4
|
-
include Yarrow::Tools::FrontMatter
|
5
|
-
|
6
|
-
attr_reader :graph
|
7
|
-
|
8
|
-
def initialize(graph)
|
9
|
-
@graph = graph
|
10
|
-
end
|
11
|
-
|
12
|
-
# Extract collection level configuration/metadata from the root node for
|
13
|
-
# this content type.
|
14
|
-
def extract_metadata(node, type)
|
15
|
-
# TODO: support _index or _slug convention as well
|
16
|
-
meta_file = node.out(slug: type.to_s).first
|
17
|
-
|
18
|
-
if meta_file
|
19
|
-
# Process metadata and add it to the collection node
|
20
|
-
# TODO: pass in content converter object
|
21
|
-
# TODO: index/body content by default if extracted from frontmatter
|
22
|
-
body, data = process_content(meta_file.props[:entry])
|
23
|
-
else
|
24
|
-
# Otherwise, assume default collection behaviour
|
25
|
-
data = {}
|
26
|
-
end
|
27
|
-
|
28
|
-
# Generate a default title if not provided in metadata
|
29
|
-
unless data.key?(:title)
|
30
|
-
data[:title] = type.to_s.capitalize
|
31
|
-
end
|
32
|
-
|
33
|
-
data
|
34
|
-
end
|
35
|
-
|
36
|
-
# Workaround for handling meta and content source in multiple files or a single
|
37
|
-
# file with front matter.
|
38
|
-
def process_content(path)
|
39
|
-
case path.extname
|
40
|
-
when '.htm', '.md'
|
41
|
-
read_split_content(path.to_s, symbolize_keys: true)
|
42
|
-
# when '.md'
|
43
|
-
# body, data = read_split_content(path.to_s, symbolize_keys: true)
|
44
|
-
# [Kramdown::Document.new(body).to_html, data]
|
45
|
-
when '.yml'
|
46
|
-
[nil, YAML.load(File.read(path.to_s), symbolize_names: true)]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
module Yarrow
|
2
|
-
module Content
|
3
|
-
class TreeExpansion < ExpansionStrategy
|
4
|
-
def expand(policy)
|
5
|
-
#p graph.n(:root).out(:directory).to_a.count
|
6
|
-
#policy.match()
|
7
|
-
|
8
|
-
#p graph.n(:root).out(:directory).first.props[:name]
|
9
|
-
type = policy.container
|
10
|
-
|
11
|
-
# If match path represents entire content dir, then include the entire
|
12
|
-
# content dir instead of scanning from a subfolder matching the name of
|
13
|
-
# the collection.
|
14
|
-
#start_node = if policy.match_path == "."
|
15
|
-
start_node = if true
|
16
|
-
# TODO: match against source_dir
|
17
|
-
graph.n(:root).out(:directory)
|
18
|
-
else
|
19
|
-
graph.n(:root).out(name: policy.container.to_s)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Extract metadata from given start node
|
23
|
-
collection_metadata = extract_metadata(start_node, policy.container)
|
24
|
-
|
25
|
-
# Collect all nested collections in the subgraph for this content type
|
26
|
-
subcollections = {}
|
27
|
-
item_links = []
|
28
|
-
index = nil
|
29
|
-
|
30
|
-
# Scan and collect all nested files from the root
|
31
|
-
start_node.depth_first.each do |node|
|
32
|
-
if node.label == :directory
|
33
|
-
# Create a collection node representing a collection of documents
|
34
|
-
index = graph.create_node do |collection_node|
|
35
|
-
collection_node.label = :collection
|
36
|
-
collection_node.props[:type] = policy.container
|
37
|
-
collection_node.props[:name] = node.props[:name]
|
38
|
-
|
39
|
-
# TODO: title needs to be defined from metadata
|
40
|
-
collection_node.props[:title] = node.props[:name].capitalize
|
41
|
-
end
|
42
|
-
|
43
|
-
# Add this collection id to the lookup table for edge construction
|
44
|
-
subcollections[node.props[:path]] = index
|
45
|
-
|
46
|
-
# Join the collection to its parent
|
47
|
-
unless node.props[:slug] == type.to_s || !subcollections.key?(node.props[:entry].parent.to_s)
|
48
|
-
graph.create_edge do |edge|
|
49
|
-
edge.label = :child
|
50
|
-
edge.from = subcollections[node.props[:entry].parent.to_s].id
|
51
|
-
edge.to = index.id
|
52
|
-
end
|
53
|
-
end
|
54
|
-
elsif node.label == :file
|
55
|
-
body, meta = process_content(node.props[:entry])
|
56
|
-
|
57
|
-
# Create an item node representing a file mapped to a unique content object
|
58
|
-
item = graph.create_node do |item_node|
|
59
|
-
item_node.label = :item
|
60
|
-
item_node.props[:type] = policy.record
|
61
|
-
item_node.props[:name] = node.props[:entry].basename(node.props[:entry].extname).to_s
|
62
|
-
item_node.props[:body] = body if body
|
63
|
-
item_node.props[:title] = meta[:title] if meta
|
64
|
-
# TODO: better handling of metadata on node props
|
65
|
-
end
|
66
|
-
|
67
|
-
# We may not have an expanded node for the parent collection if this is a
|
68
|
-
# preorder traversal so save it for later
|
69
|
-
item_links << {
|
70
|
-
parent_path: node.props[:entry].parent.to_s,
|
71
|
-
item_id: item.id
|
72
|
-
}
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# Once all files and directories have been expanded, connect all the child
|
77
|
-
# edges between collections and items
|
78
|
-
item_links.each do |item_link|
|
79
|
-
graph.create_edge do |edge|
|
80
|
-
edge.label = :child
|
81
|
-
edge.from = subcollections[item_link[:parent_path]].id
|
82
|
-
edge.to = item_link[:item_id]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|