yarrow 0.8.3 → 0.8.6
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/lib/extensions/mementus.rb +23 -0
- data/lib/yarrow/content/expansion/strategy.rb +17 -0
- data/lib/yarrow/content/expansion/tree.rb +49 -29
- data/lib/yarrow/content/policy.rb +3 -0
- data/lib/yarrow/generator.rb +1 -1
- data/lib/yarrow/schema/definitions.rb +2 -1
- data/lib/yarrow/schema/dictionary.rb +2 -2
- data/lib/yarrow/schema/entity.rb +1 -1
- data/lib/yarrow/schema/types.rb +15 -4
- data/lib/yarrow/version.rb +1 -1
- data/lib/yarrow/web/document.rb +99 -16
- data/lib/yarrow/web/manifest.rb +5 -5
- data/lib/yarrow.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb8358e221f56cb48075609b4ae35e07ef7ea1bef577d6a1f929a8eb26ca4242
|
4
|
+
data.tar.gz: 8730eec22402eb73b1555a7421fd6ea5f22edb049d8dc7083c0b4de1ea777681
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1571c747f38efd25382c758b9974c1e5b644f541aa93f76f9f8d3082c35db13b30cf39da52487e67ad2611feb73fc24ad39acdf7de57393aaa8e16cebe8dc0ea
|
7
|
+
data.tar.gz: aad027b60c53a918b9b96f800e144b8b981f3e083a211524ce329549b8242cbd9100da756b7130adcfac990b7944d557378de963b62042cf2effba12acade81e
|
data/lib/extensions/mementus.rb
CHANGED
@@ -6,6 +6,22 @@ module Mementus
|
|
6
6
|
# Monkeypatch extension to ensure each pipeline step supports enumerable
|
7
7
|
# methods. Mostly used for #map. API needs to be fixed in the gem itself.
|
8
8
|
include Enumerable
|
9
|
+
|
10
|
+
def to
|
11
|
+
Step.new(map { |edge| edge.to }, Pipe.new(graph), graph)
|
12
|
+
end
|
13
|
+
|
14
|
+
def props
|
15
|
+
Step.new(map { |node| node.props }, Pipe.new(graph), graph)
|
16
|
+
end
|
17
|
+
|
18
|
+
# def props
|
19
|
+
# node_props = source.inject([]) do |result, node|
|
20
|
+
# result.concat(node.props)
|
21
|
+
# end
|
22
|
+
|
23
|
+
# Step.new(node_props, Pipe.new(graph), graph)
|
24
|
+
# end
|
9
25
|
end
|
10
26
|
end
|
11
27
|
module Structure
|
@@ -21,4 +37,11 @@ module Mementus
|
|
21
37
|
"nodes_count=#{nodes_count} edges_count=#{edges_count}>"
|
22
38
|
end
|
23
39
|
end
|
40
|
+
|
41
|
+
class Node
|
42
|
+
def merge_props(data)
|
43
|
+
next_props = props.merge(data)
|
44
|
+
@props = next_props.freeze
|
45
|
+
end
|
46
|
+
end
|
24
47
|
end
|
@@ -34,6 +34,23 @@ module Yarrow
|
|
34
34
|
data
|
35
35
|
end
|
36
36
|
|
37
|
+
def populate_collection(node, policy, meta_attrs)
|
38
|
+
node.label = :collection
|
39
|
+
node.props[:type] = policy.collection
|
40
|
+
node.props[:resource] = policy.collection_const.new(meta_attrs)
|
41
|
+
end
|
42
|
+
|
43
|
+
def populate_entity(node, policy, meta_attrs)
|
44
|
+
node.label = :item
|
45
|
+
node.props[:type] = policy.entity
|
46
|
+
node.props[:resource] = policy.entity_const.new(meta_attrs)
|
47
|
+
end
|
48
|
+
|
49
|
+
def merge_collection_index(node, policy, meta_attrs)
|
50
|
+
props = { resource: node.props[:resource].merge(meta_attrs) }
|
51
|
+
node.merge_props(props)
|
52
|
+
end
|
53
|
+
|
37
54
|
# Workaround for handling meta and content source in multiple files or a single
|
38
55
|
# file with front matter.
|
39
56
|
def process_content(path)
|
@@ -21,11 +21,12 @@ module Yarrow
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# Extract metadata from given start node
|
24
|
-
collection_metadata = extract_metadata(start_node, policy.container)
|
24
|
+
#collection_metadata = extract_metadata(start_node, policy.container)
|
25
25
|
|
26
26
|
# Collect all nested collections in the subgraph for this content type
|
27
27
|
subcollections = {}
|
28
|
-
|
28
|
+
entity_links = []
|
29
|
+
index_links = []
|
29
30
|
index = nil
|
30
31
|
|
31
32
|
# Scan and collect all nested files from the root
|
@@ -33,12 +34,14 @@ module Yarrow
|
|
33
34
|
if node.label == :directory
|
34
35
|
# Create a collection node representing a collection of documents
|
35
36
|
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
37
|
|
40
|
-
|
41
|
-
|
38
|
+
collection_attrs = {
|
39
|
+
name: node.props[:name],
|
40
|
+
title: node.props[:name].capitalize,
|
41
|
+
body: ""
|
42
|
+
}
|
43
|
+
|
44
|
+
populate_collection(collection_node, policy, collection_attrs)
|
42
45
|
end
|
43
46
|
|
44
47
|
# Add this collection id to the lookup table for edge construction
|
@@ -54,38 +57,55 @@ module Yarrow
|
|
54
57
|
end
|
55
58
|
elsif node.label == :file
|
56
59
|
body, meta = process_content(node.props[:entry])
|
60
|
+
meta = {} if !meta
|
57
61
|
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
#
|
68
|
-
|
69
|
-
|
62
|
+
# TODO: document mapping convention for index pages and collection metadata
|
63
|
+
# TODO: underscore _index pattern?
|
64
|
+
bare_basename = node.props[:entry].basename(node.props[:entry].extname)
|
65
|
+
if bare_basename.to_s == "index"
|
66
|
+
index_links << {
|
67
|
+
parent_id: subcollections[node.props[:entry].parent.to_s],
|
68
|
+
index_attrs: meta.merge({ body: body})
|
69
|
+
}
|
70
|
+
else
|
71
|
+
# Create an entity node representing a file mapped to a unique content object
|
72
|
+
entity = graph.create_node do |entity_node|
|
73
|
+
|
74
|
+
entity_slug = node.props[:entry].basename(node.props[:entry].extname).to_s
|
70
75
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
76
|
+
entity_attrs = {
|
77
|
+
name: entity_slug,
|
78
|
+
title: entity_slug.gsub("-", " ").capitalize,
|
79
|
+
body: body
|
80
|
+
}
|
81
|
+
|
82
|
+
populate_entity(entity_node, policy, entity_attrs.merge(meta || {}))
|
83
|
+
end
|
84
|
+
|
85
|
+
# We may not have an expanded node for the parent collection if this is a
|
86
|
+
# preorder traversal so save it for later
|
87
|
+
entity_links << {
|
88
|
+
parent_id: subcollections[node.props[:entry].parent.to_s],
|
89
|
+
child_id: entity
|
90
|
+
}
|
91
|
+
end
|
77
92
|
end
|
78
93
|
end
|
79
94
|
|
80
95
|
# Once all files and directories have been expanded, connect all the child
|
81
|
-
# edges between collections and
|
82
|
-
|
96
|
+
# edges between collections and entities
|
97
|
+
entity_links.each do |entity_link|
|
83
98
|
graph.create_edge do |edge|
|
84
99
|
edge.label = :child
|
85
|
-
edge.from =
|
86
|
-
edge.to =
|
100
|
+
edge.from = entity_link[:parent_id].id
|
101
|
+
edge.to = entity_link[:child_id].id
|
87
102
|
end
|
88
103
|
end
|
104
|
+
|
105
|
+
# Merge index page body and metadata with their parent collections
|
106
|
+
index_links.each do |index_link|
|
107
|
+
merge_collection_index(index_link[:parent_id], policy, index_link[:index_attrs])
|
108
|
+
end
|
89
109
|
end
|
90
110
|
end
|
91
111
|
end
|
@@ -81,6 +81,9 @@ module Yarrow
|
|
81
81
|
@container_const ||= Yarrow::Symbols.to_module_const([*module_prefix, container])
|
82
82
|
end
|
83
83
|
|
84
|
+
alias_method :collection, :container
|
85
|
+
alias_method :collection_const, :container_const
|
86
|
+
|
84
87
|
def entity_const
|
85
88
|
@entity_const ||= Yarrow::Symbols.to_module_const([*module_prefix, entity])
|
86
89
|
end
|
data/lib/yarrow/generator.rb
CHANGED
@@ -8,7 +8,8 @@ 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::Instance.of(Hash)
|
11
|
+
hash: Types::Instance.of(Hash),
|
12
|
+
markdown: Types::Instance.of(Kramdown::Document).accept(String)
|
12
13
|
}
|
13
14
|
|
14
15
|
TEMPLATE_TYPES = {
|
@@ -28,13 +28,13 @@ module Yarrow
|
|
28
28
|
|
29
29
|
if missing_attrs.any?
|
30
30
|
missing_attrs.each do |name|
|
31
|
-
raise "wrong number of attributes" unless @attrs_spec[name].is_a?(Types::Any)
|
31
|
+
raise "#{missing_attrs} wrong number of attributes" unless @attrs_spec[name].is_a?(Types::Any)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
mismatching_attrs = input.keys.difference(@attrs_spec.keys)
|
36
36
|
|
37
|
-
raise "attribute does not exist" if mismatching_attrs.any?
|
37
|
+
raise "attribute #{mismatching_attrs} does not exist" if mismatching_attrs.any?
|
38
38
|
|
39
39
|
input.reduce({}) do |converted, (name, value)|
|
40
40
|
converted[name] = @attrs_spec[name].cast(value)
|
data/lib/yarrow/schema/entity.rb
CHANGED
data/lib/yarrow/schema/types.rb
CHANGED
@@ -31,8 +31,13 @@ module Yarrow
|
|
31
31
|
@accepts = {}
|
32
32
|
end
|
33
33
|
|
34
|
-
def accept(type, constructor=:new)
|
35
|
-
accepts[type] =
|
34
|
+
def accept(type, constructor=:new, options=nil)
|
35
|
+
accepts[type] = if options.nil?
|
36
|
+
[constructor]
|
37
|
+
else
|
38
|
+
[constructor, options]
|
39
|
+
end
|
40
|
+
|
36
41
|
self
|
37
42
|
end
|
38
43
|
|
@@ -41,8 +46,14 @@ module Yarrow
|
|
41
46
|
end
|
42
47
|
|
43
48
|
def coerce(input)
|
44
|
-
constructor = accepts[input.class]
|
45
|
-
|
49
|
+
constructor, options = accepts[input.class]
|
50
|
+
|
51
|
+
# TODO: should we clone all input so copy is stored rather than ref?
|
52
|
+
if options.nil?
|
53
|
+
unit.send(constructor, input)
|
54
|
+
else
|
55
|
+
unit.send(constructor, input, options.clone)
|
56
|
+
end
|
46
57
|
end
|
47
58
|
|
48
59
|
def check_instance_of!(input)
|
data/lib/yarrow/version.rb
CHANGED
data/lib/yarrow/web/document.rb
CHANGED
@@ -1,42 +1,125 @@
|
|
1
|
-
module Yarrow
|
1
|
+
module Yarrow
|
2
2
|
module Web
|
3
|
-
class
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@
|
10
|
-
|
3
|
+
class BaseDocument
|
4
|
+
def resource
|
5
|
+
@resource
|
6
|
+
end
|
7
|
+
|
8
|
+
def type
|
9
|
+
@type
|
10
|
+
end
|
11
|
+
|
12
|
+
# TODO: confirm this can be deleted
|
13
|
+
def index
|
14
|
+
_index = @item.out_e(:index)
|
15
|
+
unless _index.first.nil?
|
16
|
+
_index.first.to.props
|
17
|
+
else
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO: confirm this can be deleted
|
23
|
+
def index_body
|
24
|
+
@item.props[:index_body]
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO: manage behaviour with and without current item
|
28
|
+
# TODO: link to manifest
|
29
|
+
#
|
30
|
+
# TODO: replace @item and @collection with @node internally and in class interface
|
31
|
+
def breadcrumbs
|
32
|
+
path = []
|
33
|
+
|
34
|
+
current_parent = @node.in(:collection)
|
35
|
+
|
36
|
+
while !current_parent.first.nil?
|
37
|
+
path << current_parent.first.props[:resource]
|
38
|
+
current_parent = current_parent.in(:collection)
|
39
|
+
end
|
40
|
+
|
41
|
+
path.reverse
|
11
42
|
end
|
12
43
|
|
13
44
|
def name
|
14
|
-
@
|
45
|
+
@resource.name
|
15
46
|
end
|
16
47
|
|
17
48
|
def title
|
18
|
-
@
|
49
|
+
@resource.title
|
19
50
|
end
|
20
51
|
|
21
|
-
def
|
22
|
-
@
|
52
|
+
def body
|
53
|
+
return @resource.body.to_html if @resource.respond_to?(:body)
|
54
|
+
""
|
23
55
|
end
|
24
56
|
|
25
57
|
def url
|
26
58
|
if @parent.nil?
|
27
59
|
"/"
|
28
60
|
else
|
29
|
-
segments = [@
|
61
|
+
segments = [@resource.name]
|
30
62
|
current = @parent
|
31
63
|
|
32
64
|
until current.in(:collection).first.nil? do
|
33
|
-
segments << current.props[:name
|
65
|
+
segments << current.props[:resource].name
|
34
66
|
current = current.in(:collection).first
|
35
67
|
end
|
36
68
|
|
37
|
-
"/"
|
69
|
+
suffix = @is_index ? "/" : ""
|
70
|
+
|
71
|
+
"/" + segments.reverse.join("/") + suffix
|
38
72
|
end
|
39
73
|
end
|
40
74
|
end
|
75
|
+
|
76
|
+
class IndexDocument < BaseDocument
|
77
|
+
# Represents the index document of a collection. This contains
|
78
|
+
# a reference to the individual items in the collection as well as
|
79
|
+
# any document content itself.
|
80
|
+
def initialize(collection, item=nil, is_index=false)
|
81
|
+
@collection = collection
|
82
|
+
@item = item
|
83
|
+
# The parent node of the collection is the first incoming node link
|
84
|
+
@parent = collection.in(:collection).first
|
85
|
+
@is_index = is_index
|
86
|
+
|
87
|
+
template_map = collection.out_e(:child).to.all.inject([]) do |result, node|
|
88
|
+
result << Document.new(node, false)
|
89
|
+
end
|
90
|
+
|
91
|
+
instance_variable_set("@children", template_map)
|
92
|
+
define_singleton_method(:children){ template_map }
|
93
|
+
|
94
|
+
if @item.nil?
|
95
|
+
@resource = collection.props[:resource]
|
96
|
+
@type = collection.props[:type]
|
97
|
+
@node = collection
|
98
|
+
else
|
99
|
+
@resource = item.props[:resource]
|
100
|
+
@type = item.props[:type]
|
101
|
+
@node = item
|
102
|
+
end
|
103
|
+
|
104
|
+
instance_variable_set("@#{@type}", @resource)
|
105
|
+
define_singleton_method(@type){ @resource }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class Document < BaseDocument
|
110
|
+
# This class is somewhat verbose for simplicity and long-term maintainability
|
111
|
+
# (having a clear and easy to follow construction, rather than doing anything
|
112
|
+
# too clever which has burned this lib in the past).
|
113
|
+
def initialize(item, is_index)
|
114
|
+
@item = item
|
115
|
+
@type = item.props[:type]
|
116
|
+
@parent = item.in(:collection).first
|
117
|
+
@node = item
|
118
|
+
@is_index = is_index
|
119
|
+
@resource = item.props[:resource]
|
120
|
+
instance_variable_set("@#{item.props[:type]}", @resource)
|
121
|
+
define_singleton_method(item.props[:type]){ @resource }
|
122
|
+
end
|
123
|
+
end
|
41
124
|
end
|
42
125
|
end
|
data/lib/yarrow/web/manifest.rb
CHANGED
@@ -12,7 +12,7 @@ module Yarrow
|
|
12
12
|
unless collection.props[:index_only]
|
13
13
|
collection.out(:item).each do |item|
|
14
14
|
#if item[:entity].status.to_sym == :published
|
15
|
-
if item.props[:name
|
15
|
+
if item.props[:resource].name == "index"
|
16
16
|
index = item
|
17
17
|
else
|
18
18
|
manifest.add_document(item_context(item))
|
@@ -25,7 +25,7 @@ module Yarrow
|
|
25
25
|
unless collection.props[:content_only]
|
26
26
|
if index
|
27
27
|
manifest.add_document(collection_index_context(collection, index))
|
28
|
-
else
|
28
|
+
else
|
29
29
|
manifest.add_document(collection_context(collection))
|
30
30
|
end
|
31
31
|
end
|
@@ -50,15 +50,15 @@ module Yarrow
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def self.collection_context(collection)
|
53
|
-
|
53
|
+
IndexDocument.new(collection, nil, true)
|
54
54
|
end
|
55
55
|
|
56
56
|
def self.collection_index_context(collection, item)
|
57
|
-
|
57
|
+
IndexDocument.new(collection, item, false)
|
58
58
|
end
|
59
59
|
|
60
60
|
def self.item_context(item)
|
61
|
-
Document.new(item,
|
61
|
+
Document.new(item, false)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
data/lib/yarrow.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Rickerby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|