yarrow 0.8.0 → 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: 8c362ba73bcbfc325bad91668bf1a1a006dd6355579a36ce96cc60323944804b
4
- data.tar.gz: 51db819b1f52b3b75a9b39287359e22dfb6d52833ce0089636694f4d9feeda15
3
+ metadata.gz: 4ea37c60e3c8bfe51e6ceb9425f0d0c81b93757a681c7987f7852c3335644824
4
+ data.tar.gz: 19cd090d3b3348f633f5d303d8b826fd2b8c054b790136355a41d9b4f0f098c4
5
5
  SHA512:
6
- metadata.gz: c7a41bb6ee0a6bcfd27c83d7780cc70f7b41131daaa4decd02e591346f9270318951b1a68d0f390ac81843593e0bf97a8062da51f3f7f1e2be78b6711af132d6
7
- data.tar.gz: 866d6683eb25f9154d9582266b45016b680d622fca57a71c88b55f8c0ee41dc76076e839684026df8759e72ba73cf2597b96cbe05b83d3c877cc5ebcf6252bcf
6
+ metadata.gz: ebd0dd29f6d8800b20560c2e24fd2988caecf19e9ae5f3e44a3d0b427afc9201971be1b086705e72c874683d30625821b270e6ad944c5c28ca9b6cd9ecd65ea2
7
+ data.tar.gz: 92d36891c8a270ff663a299b2a217ffe3bb6985200e70d84c4c9d29ee87bb00fb7b2e824e0d932d585b5f8b4a22d578748ee58ad3ae022aa8f1b8ab04117ac6f
data/lib/yarrow/config.rb CHANGED
@@ -37,17 +37,32 @@ module Yarrow
37
37
  :port,
38
38
  :host,
39
39
  :handler,
40
- #:docroot,
41
- :middleware,
42
- #:root_dir
40
+ :middleware
43
41
  )
44
42
 
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]
53
+ attribute :generator, :string
54
+ attribute :template_dir, :path
55
+ #attribute :scripts, :array
56
+ end
57
+
45
58
  # Top level root config namespace.
46
59
  class Instance < Yarrow::Schema::Entity
47
60
  attribute :source_dir, :path
48
61
  attribute :output_dir, :path
49
62
  attribute :meta, :any
50
63
  attribute :server, :any
64
+ attribute :content, :__config_content
65
+ #attribute :output, :__config_output
51
66
  end
52
67
  #
53
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,45 +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
- )
4
+ DEFAULT_HOME_NESTING = false
5
+
6
+ DEFAULT_EXPANSION = :tree
10
7
 
11
8
  DEFAULT_EXTENSIONS = [".md", ".yml", ".htm"]
12
9
 
13
10
  DEFAULT_MATCH_PATH = "."
14
11
 
15
- def self.from_name(name)
16
- new(Options.new(container: name.to_sym))
17
- 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
18
58
 
19
- def initialize(properties)
20
- unless properties.respond_to?(:container) || properties.respond_to?(:entity)
21
- 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)
22
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
23
81
 
24
- @properties = properties
82
+ def entity_const
83
+ @entity_const ||= Yarrow::Symbols.to_module_const([module_prefix, entity])
25
84
  end
26
85
 
27
- def container
86
+ def _container
28
87
  return @properties.container if @properties.container
29
88
  Yarrow::Symbols.to_plural(@properties.entity)
30
89
  end
31
90
 
32
- def entity
91
+ def _entity
33
92
  return @properties.entity if @properties.entity
34
93
  Yarrow::Symbols.to_singular(@properties.container)
35
94
  end
36
95
 
37
- def extensions
96
+ def _extensions
38
97
  return @properties.extensions if @properties.extensions
39
98
  DEFAULT_EXTENSIONS
40
99
  end
41
100
 
42
- def match_path
101
+ def _match_path
43
102
  return @properties.match_path if @properties.match_path
44
103
  DEFAULT_MATCH_PATH
45
104
  end
@@ -5,11 +5,14 @@ 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
- target_dir: public
14
+ generator: web
10
15
  template_dir: templates
11
- object_map:
12
- page: Yarrow::Model::Site.pages
13
16
  assets:
14
17
  input_dir: assets
15
18
  output_dir: public/assets
@@ -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
@@ -4,9 +4,16 @@ module Yarrow
4
4
  DEFINED_TYPES = {
5
5
  string: Types::Instance.of(String),
6
6
  integer: Types::Instance.of(Integer),
7
- symbol: Types::Instance.of(Symbol),
7
+ symbol: Types::Instance.of(Symbol).accept(String, :to_sym),
8
8
  path: Types::Instance.of(Pathname).accept(String),
9
- any: Types::Any.new
9
+ any: Types::Any.new,
10
+ array: Types::List.of(Types::Any),
11
+ hash: Types::Instance.of(Hash)
12
+ }
13
+
14
+ TEMPLATE_TYPES = {
15
+ list: Types::List,
16
+ map: Types::Map
10
17
  }
11
18
 
12
19
  def self.register(identifier, type_class)
@@ -18,13 +25,43 @@ module Yarrow
18
25
  end
19
26
 
20
27
  def resolve_type(identifier)
21
- #return identifier unless identifier.is_a?(Symbol)
28
+ # Type is directly resolvable from the definition table
29
+ return DEFINED_TYPES[identifier] if DEFINED_TYPES.key?(identifier)
22
30
 
23
- unless DEFINED_TYPES.key?(identifier)
24
- raise "#{identifier} is not defined"
25
- end
31
+ if identifier.is_a?(Hash)
32
+ # If type identifier is a compound template extract its key and value mapping
33
+ key_id = identifier.keys.first
34
+ value_id = identifier.values.first
35
+
36
+ # Check if the given key is defined as a template type
37
+ unless TEMPLATE_TYPES.key?(key_id)
38
+ raise "compound type #{key_id} is not defined"
39
+ end
26
40
 
27
- return DEFINED_TYPES[identifier]
41
+ # Get reference to the type class we want to resolve
42
+ template_type = TEMPLATE_TYPES[key_id]
43
+
44
+ # Resolve the type to an instance depending on structure of its template args
45
+ resolved_type = if value_id.is_a?(Hash)
46
+ # Map template with two argument constructor
47
+ template_type.new(
48
+ resolve_type(value_id.keys.first),
49
+ resolve_type(value_id.values.first)
50
+ )
51
+ else
52
+ # Use the single arg constructor with the given unit type
53
+ template_type.of(resolve_type(value_id).unit)
54
+ end
55
+
56
+ # Cache the resolved type for later reference
57
+ DEFINED_TYPES[identifier] = resolved_type
58
+
59
+ # Return the resolve type
60
+ resolved_type
61
+ else
62
+ # Not a compound template so we know it’s missing in the lookup table
63
+ raise "type #{identifier} is not defined"
64
+ end
28
65
  end
29
66
  end
30
67
  end
@@ -13,6 +13,19 @@ module Yarrow
13
13
  def dictionary
14
14
  @dictionary ||= Dictionary.new({})
15
15
  end
16
+
17
+ def [](label)
18
+ @label = label
19
+ self
20
+ end
21
+
22
+ def inherited(class_name)
23
+ if @label
24
+ class_type = Yarrow::Schema::Types::Instance.of(class_name)
25
+ Yarrow::Schema::Definitions.register(@label, class_type)
26
+ @label = nil
27
+ end
28
+ end
16
29
  end
17
30
 
18
31
  def initialize(config)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module Yarrow
3
3
  APP_NAME = "Yarrow"
4
- VERSION = "0.8.0"
4
+ VERSION = "0.8.2"
5
5
  end
@@ -4,10 +4,10 @@ module Yarrow
4
4
  # This class is somewhat verbose for simplicity and long-term maintainability
5
5
  # (having a clear and easy to follow construction, rather than doing anything
6
6
  # too clever which has burned this lib in the past).
7
- def initialize(item, parent, url_strategy)
7
+ def initialize(item, parent, is_index)
8
8
  @item = item
9
9
  @parent = parent
10
- @url_strategy = url_strategy
10
+ @is_index = is_index
11
11
  end
12
12
 
13
13
  def name
@@ -23,13 +23,18 @@ module Yarrow
23
23
  end
24
24
 
25
25
  def url
26
- case @url_strategy
27
- when :mirror_source
28
- unless @parent.nil?
29
- "/#{@parent.props[:name]}/#{name}"
30
- else
31
- "/#{name}/"
26
+ if @parent.nil?
27
+ "/"
28
+ else
29
+ segments = [@item.props[:name]]
30
+ current = @parent
31
+
32
+ until current.in(:collection).first.nil? do
33
+ segments << current.props[:name]
34
+ current = current.in(:collection).first
32
35
  end
36
+
37
+ "/" + segments.reverse.join("/")
33
38
  end
34
39
  end
35
40
  end
@@ -6,20 +6,29 @@ module Yarrow
6
6
 
7
7
  graph.n(:collection).each do |collection|
8
8
  # TODO: raise error if both content_only and index_only are set
9
-
10
- # If the collection is tagged :content_only then skip top level listing/index
11
- unless collection.props[:content_only]
12
- manifest.add_document(collection_context(collection))
13
- end
9
+ index = nil
14
10
 
15
11
  # If the collection is tagged :index_only then skip adding individual documents
16
12
  unless collection.props[:index_only]
17
13
  collection.out(:item).each do |item|
18
14
  #if item[:entity].status.to_sym == :published
19
- manifest.add_document(item_context(item))
15
+ if item.props[:name] == "index"
16
+ index = item
17
+ else
18
+ manifest.add_document(item_context(item))
19
+ end
20
20
  #end
21
21
  end
22
22
  end
23
+
24
+ # If the collection is tagged :content_only then skip top level listing/index
25
+ unless collection.props[:content_only]
26
+ if index
27
+ manifest.add_document(collection_index_context(collection, index))
28
+ else
29
+ manifest.add_document(collection_context(collection))
30
+ end
31
+ end
23
32
  end
24
33
 
25
34
  manifest
@@ -32,28 +41,6 @@ module Yarrow
32
41
  @assets = []
33
42
  end
34
43
 
35
- def self.collection_context(collection)
36
- # Yarrow::Output::Context.new(
37
- # parent: collection.in(:collection).first,
38
- # name: collection.props[:name],
39
- # #url: collection.props[:url],
40
- # title: collection.props[:title],
41
- # type: collection.props[:type]
42
- # )
43
- Document.new(collection, collection.in(:collection).first, :mirror_source)
44
- end
45
-
46
- def self.item_context(item)
47
- # Yarrow::Output::Context.new(
48
- # parent: item.in(:collection).first,
49
- # name: item.props[:name],
50
- # #url: item.props[:url],
51
- # title: item.props[:title],
52
- # type: item.props[:type]
53
- # )
54
- Document.new(item, item.in(:collection).first, :mirror_source)
55
- end
56
-
57
44
  def add_document(document)
58
45
  @documents << document
59
46
  end
@@ -61,6 +48,18 @@ module Yarrow
61
48
  def add_asset(asset)
62
49
  @assets << asset
63
50
  end
51
+
52
+ def self.collection_context(collection)
53
+ Document.new(collection, collection.in(:collection).first, true)
54
+ end
55
+
56
+ def self.collection_index_context(collection, item)
57
+ Document.new(item, collection.in(:collection).first, false)
58
+ end
59
+
60
+ def self.item_context(item)
61
+ Document.new(item, item.in(:collection).first, false)
62
+ end
64
63
  end
65
64
  end
66
65
  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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yarrow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.2
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-01 00:00:00.000000000 Z
11
+ date: 2022-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -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,92 +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
-
10
- expand_impl(policy)
11
- end
12
-
13
- def expand_impl(policy)
14
- type = policy.container
15
-
16
- # If match path represents entire content dir, then include the entire
17
- # content dir instead of scanning from a subfolder matching the name of
18
- # the collection.
19
- #start_node = if policy.match_path == "."
20
- start_node = if true
21
- graph.n(:root)
22
- else
23
- graph.n(:root).out(name: type.to_s)
24
- end
25
-
26
- # Extract metadata from given start node
27
- collection_metadata = extract_metadata(start_node, type)
28
-
29
- # Collect all nested collections in the subgraph for this content type
30
- subcollections = {}
31
- item_links = []
32
- index = nil
33
-
34
- # Scan and collect all nested files from the root
35
- start_node.depth_first.each do |node|
36
- if node.label == :directory
37
- # Create a collection node representing a collection of documents
38
- index = graph.create_node do |collection_node|
39
- collection_node.label = :collection
40
- collection_node.props[:type] = type
41
- collection_node.props[:name] = node.props[:name]
42
-
43
- # TODO: title needs to be defined from metadata
44
- collection_node.props[:title] = node.props[:name].capitalize
45
- end
46
-
47
- # Add this collection id to the lookup table for edge construction
48
- subcollections[node.props[:path]] = index
49
-
50
- # Join the collection to its parent
51
- unless node.props[:slug] == type.to_s || !subcollections.key?(node.props[:entry].parent.to_s)
52
- graph.create_edge do |edge|
53
- edge.label = :child
54
- edge.from = subcollections[node.props[:entry].parent.to_s].id
55
- edge.to = index.id
56
- end
57
- end
58
- elsif node.label == :file
59
- body, meta = process_content(node.props[:entry])
60
-
61
- # Create an item node representing a file mapped to a unique content object
62
- item = graph.create_node do |item_node|
63
- item_node.label = :item
64
- item_node.props[:type] = policy.record
65
- item_node.props[:name] = node.props[:entry].basename(node.props[:entry].extname).to_s
66
- item_node.props[:body] = body if body
67
- item_node.props[:title] = meta[:title] if meta
68
- # TODO: better handling of metadata on node props
69
- end
70
-
71
- # We may not have an expanded node for the parent collection if this is a
72
- # preorder traversal so save it for later
73
- item_links << {
74
- parent_path: node.props[:entry].parent.to_s,
75
- item_id: item.id
76
- }
77
- end
78
- end
79
-
80
- # Once all files and directories have been expanded, connect all the child
81
- # edges between collections and items
82
- item_links.each do |item_link|
83
- graph.create_edge do |edge|
84
- edge.label = :child
85
- edge.from = subcollections[item_link[:parent_path]].id
86
- edge.to = item_link[:item_id]
87
- end
88
- end
89
- end
90
- end
91
- end
92
- end