yarrow 0.8.1 → 0.8.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d26941f2b464c551d825b73999b0365637b9e4feec159ee74de51a1abca3416e
4
- data.tar.gz: 34081172c945cf83e97ab3ee03484436ba380de6c809c2dd87caaa50f1bba315
3
+ metadata.gz: 4ea37c60e3c8bfe51e6ceb9425f0d0c81b93757a681c7987f7852c3335644824
4
+ data.tar.gz: 19cd090d3b3348f633f5d303d8b826fd2b8c054b790136355a41d9b4f0f098c4
5
5
  SHA512:
6
- metadata.gz: 6300e2c0f83c741862cf6c49acc42118636a3832401706057b483d942c07a947ea1124b2c10e056cc5052e25a28a59f896216d0156911026639d16e0faa5ba73
7
- data.tar.gz: 0b897183df8712cbc08d0a479ed1e1d129a90305ad76f9bc802ea262707026ff5ffa57890d0d26d49955f55721ffd0887510671c86430e4780564266758ebaed
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
- class Output < Yarrow::Schema::Entity[:output]
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
- #attribute :output, :output
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
@@ -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
@@ -17,11 +17,6 @@ module Yarrow
17
17
  @config = config
18
18
  end
19
19
 
20
- def expand_pages
21
- expander = Yarrow::Content::Expansion.new(Yarrow::Content::Model.new)
22
- expander.expand(graph)
23
- end
24
-
25
20
  # List of source files.
26
21
  def files
27
22
  graph.nodes(:file)
@@ -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(spec=nil, namespace=nil)
19
- @namespace = []
20
- @namespace << namespace unless namespace.nil?
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 each_policy(&block)
38
- @policies.each_value(&block)
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(policy_key)
42
- @policies[policy_key]
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
- def self.from_name(name)
18
- new(Options.new(container: name.to_sym))
19
- end
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
- def initialize(properties)
22
- unless properties.respond_to?(:container) || properties.respond_to?(:entity)
23
- raise "Must provide a container name or entity name"
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
- @properties = properties
82
+ def entity_const
83
+ @entity_const ||= Yarrow::Symbols.to_module_const([module_prefix, entity])
27
84
  end
28
85
 
29
- def container
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 entity
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 extensions
96
+ def _extensions
40
97
  return @properties.extensions if @properties.extensions
41
98
  DEFAULT_EXTENSIONS
42
99
  end
43
100
 
44
- def match_path
101
+ def _match_path
45
102
  return @properties.match_path if @properties.match_path
46
103
  DEFAULT_MATCH_PATH
47
104
  end
@@ -5,6 +5,11 @@ output_dir: docs
5
5
  meta:
6
6
  title: Default Project
7
7
  author: Default Name
8
+ content:
9
+ module: Yarrow::Content
10
+ source_map:
11
+ pages:
12
+ expansion: tree
8
13
  output:
9
14
  generator: web
10
15
  template_dir: templates
@@ -13,8 +13,8 @@ module Yarrow
13
13
  provides Content::Graph
14
14
 
15
15
  def step(content)
16
- expander = Content::Expansion.new(Yarrow::Content::Model.new)
17
- expander.expand(content.graph)
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::Map.of(Symbol => Types::Any)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Yarrow
3
3
  APP_NAME = "Yarrow"
4
- VERSION = "0.8.1"
4
+ VERSION = "0.8.2"
5
5
  end
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/expansion_strategy"
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.1
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/expansion_strategy.rb
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