sitepress-core 1.0.1 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sitepress-core.rb +3 -2
- data/lib/sitepress/asset.rb +1 -13
- data/lib/sitepress/formats.rb +19 -11
- data/lib/sitepress/node.rb +111 -0
- data/lib/sitepress/path.rb +31 -0
- data/lib/sitepress/resource.rb +37 -12
- data/lib/sitepress/resources_pipeline.rb +1 -1
- data/lib/sitepress/site.rb +12 -23
- data/lib/sitepress/source_node_mapper.rb +57 -0
- data/lib/sitepress/version.rb +1 -1
- metadata +12 -11
- data/lib/sitepress/directory_collection.rb +0 -24
- data/lib/sitepress/resources_node.rb +0 -134
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6395983eac0134367f92c65aae2d13cc54fb1cd480bc062c00c24fcdd6575590
|
4
|
+
data.tar.gz: fd7db9816c3b8a6f3f6b9c6bf02e5a06e496209a8c006316f2cd85c9456fcdf2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7430bd142a60bbbd3afbff40dce5e23741975241c9db38e97a258a85241aa191f55dbe89eaa6e08d0b5ee0c20c46fa01fda74fe24044f0f65e871944351ad85d
|
7
|
+
data.tar.gz: 286b316eccf042d8b83c1d231741d06d71a538aaf4cf311b322fe09bf6401e05413d74df1c872d0c6b0f2f64fe9a66e4ad37d041c8b66db249e5b80e4deac278
|
data/lib/sitepress-core.rb
CHANGED
@@ -8,14 +8,15 @@ module Sitepress
|
|
8
8
|
ExistingRequestPathError = Class.new(InvalidRequestPathError)
|
9
9
|
|
10
10
|
autoload :Asset, "sitepress/asset"
|
11
|
-
autoload :DirectoryCollection, "sitepress/directory_collection"
|
12
11
|
autoload :Formats, "sitepress/formats"
|
13
12
|
autoload :Frontmatter, "sitepress/frontmatter"
|
13
|
+
autoload :Node, "sitepress/node"
|
14
|
+
autoload :Path, "sitepress/path"
|
14
15
|
autoload :Resource, "sitepress/resource"
|
15
16
|
autoload :ResourceCollection, "sitepress/resource_collection"
|
16
17
|
autoload :ResourcesPipeline, "sitepress/resources_pipeline"
|
17
|
-
autoload :ResourcesNode, "sitepress/resources_node"
|
18
18
|
autoload :Site, "sitepress/site"
|
19
|
+
autoload :SourceNodeMapper, "sitepress/source_node_mapper"
|
19
20
|
module Middleware
|
20
21
|
autoload :RequestCache, "sitepress/middleware/request_cache"
|
21
22
|
end
|
data/lib/sitepress/asset.rb
CHANGED
@@ -30,10 +30,10 @@ module Sitepress
|
|
30
30
|
path.basename.to_s.split(".").drop(1)
|
31
31
|
end
|
32
32
|
|
33
|
-
# TODO: This is really a "key" or "leafname".
|
34
33
|
def basename
|
35
34
|
path.basename.to_s.split(".").first
|
36
35
|
end
|
36
|
+
alias :node_name :basename
|
37
37
|
|
38
38
|
def format_basename
|
39
39
|
[basename, format_extension].join(".")
|
@@ -67,18 +67,6 @@ module Sitepress
|
|
67
67
|
File.exist? path
|
68
68
|
end
|
69
69
|
|
70
|
-
# Spits out a reasonable default request path. This may be changed
|
71
|
-
# via Resource#request_path.
|
72
|
-
def to_request_path
|
73
|
-
ext = format_extension
|
74
|
-
|
75
|
-
if ext
|
76
|
-
path.dirname.join(basename).sub_ext(".#{ext}").to_s
|
77
|
-
else
|
78
|
-
path.to_s
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
70
|
private
|
83
71
|
def frontmatter
|
84
72
|
Frontmatter.new File.read @path
|
data/lib/sitepress/formats.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module Sitepress
|
2
|
-
# Manages collections of resources that share the same
|
3
|
-
# both of these assets would be stored in the `
|
2
|
+
# Manages collections of resources that share the same Node. Given the files `/a.html` and `/a.gif`,
|
3
|
+
# both of these assets would be stored in the `Node#name = "a"` under `Node#formats` with
|
4
4
|
# the extensions `.gif`, and `.html`.
|
5
5
|
class Formats
|
6
6
|
include Enumerable
|
7
7
|
|
8
8
|
extend Forwardable
|
9
9
|
def_delegators :@formats, :size, :clear
|
10
|
+
def_delegators :@node, :default_format
|
10
11
|
|
11
12
|
def initialize(node: )
|
12
13
|
@node = node
|
@@ -17,12 +18,12 @@ module Sitepress
|
|
17
18
|
@formats.values.each(&block)
|
18
19
|
end
|
19
20
|
|
20
|
-
def remove(
|
21
|
-
@formats.delete(
|
21
|
+
def remove(extension)
|
22
|
+
@formats.delete(symbolize(extension))
|
22
23
|
end
|
23
24
|
|
24
|
-
def
|
25
|
-
@formats[
|
25
|
+
def get(extension)
|
26
|
+
@formats[symbolize(extension || default_format)]
|
26
27
|
end
|
27
28
|
|
28
29
|
def extensions
|
@@ -33,17 +34,24 @@ module Sitepress
|
|
33
34
|
find { |f| f.mime_type == mime_type }
|
34
35
|
end
|
35
36
|
|
36
|
-
def add(asset
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
def add(asset:, format: nil)
|
38
|
+
format = symbolize(format || default_format)
|
39
|
+
|
40
|
+
resource = Resource.new(asset: asset, node: @node, format: format)
|
41
|
+
if @formats.has_key? format
|
42
|
+
raise Sitepress::ExistingRequestPathError, "Resource at #{resource.request_path} already set with format #{format.inspect}"
|
40
43
|
else
|
41
|
-
@formats[
|
44
|
+
@formats[format] = resource
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
45
48
|
def inspect
|
46
49
|
"<#{self.class}: resources=#{map(&:request_path)}>"
|
47
50
|
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def symbolize(format)
|
54
|
+
format&.to_sym
|
55
|
+
end
|
48
56
|
end
|
49
57
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Sitepress
|
2
|
+
# Resource nodes give resources their parent/sibling/child relationships. The relationship are determined
|
3
|
+
# by the `request_path` given to an asset when its added to a node. Given the `request_path` `/foo/bar/biz/buz.html`,
|
4
|
+
# a tree of resource nodes would be built named `foo`, `bar`, `biz`, `buz`. `foo` would be the "root" node and `buz`
|
5
|
+
# a leaf node. The actual `buz.html` asset is then stored on the leaf node as a resource. This tree structure
|
6
|
+
# makes it possible to reason through path relationships from code to build out elements in a website like tree navigation.
|
7
|
+
class Node
|
8
|
+
attr_reader :parent, :name, :default_format, :default_name
|
9
|
+
|
10
|
+
# Default extension
|
11
|
+
DEFAULT_EXTENSION = :html
|
12
|
+
|
13
|
+
DEFAULT_NAME = "index".freeze
|
14
|
+
|
15
|
+
def initialize(parent: nil, name: nil, default_format: DEFAULT_EXTENSION, default_name: DEFAULT_NAME)
|
16
|
+
@parent = parent
|
17
|
+
@name = name.freeze
|
18
|
+
@default_format = default_format
|
19
|
+
@default_name = default_name
|
20
|
+
yield self if block_given?
|
21
|
+
end
|
22
|
+
|
23
|
+
def formats
|
24
|
+
@formats ||= Formats.new(node: self)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the immediate children nodes.
|
28
|
+
def children
|
29
|
+
child_nodes.values
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns sibling nodes and self.
|
33
|
+
def siblings
|
34
|
+
parent ? parent.children : []
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns all parents up to the root node.
|
38
|
+
def parents
|
39
|
+
parents = []
|
40
|
+
node = parent
|
41
|
+
while node do
|
42
|
+
parents << node
|
43
|
+
node = node.parent
|
44
|
+
end
|
45
|
+
parents
|
46
|
+
end
|
47
|
+
|
48
|
+
def root?
|
49
|
+
parent.nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
def leaf?
|
53
|
+
child_nodes.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
def flatten(resources: [])
|
57
|
+
formats.each{ |resource| resources << resource }
|
58
|
+
children.each do |child|
|
59
|
+
child.flatten.each{ |resource| resources << resource }
|
60
|
+
end
|
61
|
+
resources
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove
|
65
|
+
formats.clear
|
66
|
+
parent.remove_child(name) if leaf?
|
67
|
+
end
|
68
|
+
|
69
|
+
def get(path)
|
70
|
+
path = Path.new(path)
|
71
|
+
node = dig(*path.node_names)
|
72
|
+
node.formats.get(path.format) if node
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_child(name)
|
76
|
+
return self if name == default_name
|
77
|
+
child_nodes[name].tap do |node|
|
78
|
+
yield node if block_given?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def inspect
|
83
|
+
"<#{self.class}: name=#{name.inspect} formats=#{formats.map(&:request_path)} children=#{children.map(&:name).inspect}>"
|
84
|
+
end
|
85
|
+
|
86
|
+
def dig(*args)
|
87
|
+
head, *tail = args
|
88
|
+
if (head.nil? or head.empty? or head == default_name) and tail.empty?
|
89
|
+
self
|
90
|
+
elsif child_nodes.has_key?(head)
|
91
|
+
child_nodes[head].dig(*tail)
|
92
|
+
else
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
protected
|
98
|
+
def remove_child(name)
|
99
|
+
child_nodes.delete(name)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def build_child(name)
|
104
|
+
Node.new(parent: self, name: name, default_format: default_format, default_name: default_name)
|
105
|
+
end
|
106
|
+
|
107
|
+
def child_nodes
|
108
|
+
@child_nodes ||= Hash.new { |hash, key| hash[key] = build_child(key) }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sitepress
|
2
|
+
class Path
|
3
|
+
DELIMITER = "/".freeze
|
4
|
+
|
5
|
+
attr_reader :node_names, :ext
|
6
|
+
|
7
|
+
def initialize(path, delimiter: DELIMITER)
|
8
|
+
@path = path
|
9
|
+
@delimiter = delimiter
|
10
|
+
parse_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def format
|
14
|
+
format = @ext.partition(".").last
|
15
|
+
return nil if format.nil? or format.empty?
|
16
|
+
format.to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def strip_leading_slash(path)
|
21
|
+
path.to_s.gsub(/^\//, "")
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_path
|
25
|
+
path, _, file = strip_leading_slash(@path).rpartition(@delimiter)
|
26
|
+
@ext = File.extname(file)
|
27
|
+
@file = File.basename(file, @ext)
|
28
|
+
@node_names = path.split(@delimiter).push(@file)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/sitepress/resource.rb
CHANGED
@@ -9,23 +9,21 @@ module Sitepress
|
|
9
9
|
def_delegators :asset, :mime_type
|
10
10
|
|
11
11
|
attr_writer :body, :data
|
12
|
-
attr_reader :node, :asset, :
|
12
|
+
attr_reader :node, :asset, :format
|
13
13
|
|
14
14
|
# Default scope for querying parent/child/sibling resources.
|
15
15
|
DEFAULT_FILTER_SCOPE = :same
|
16
16
|
|
17
|
-
|
17
|
+
RENDERABLE_MEDIA_TYPE = "text".freeze
|
18
|
+
|
19
|
+
def initialize(asset:, node:, format: nil)
|
18
20
|
@asset = asset
|
19
21
|
@node = node
|
20
|
-
@
|
22
|
+
@format = format
|
21
23
|
end
|
22
24
|
|
23
25
|
def request_path
|
24
|
-
|
25
|
-
# TODO: This `compact` makes me nervous. How can we handle this better?
|
26
|
-
lineage = node.parents.reverse.map(&:name).compact
|
27
|
-
file_name = [node.name, @ext].join
|
28
|
-
File.join("/", *lineage, file_name)
|
26
|
+
File.join("/", *lineage, request_filename)
|
29
27
|
end
|
30
28
|
|
31
29
|
def data
|
@@ -37,7 +35,7 @@ module Sitepress
|
|
37
35
|
end
|
38
36
|
|
39
37
|
def inspect
|
40
|
-
"<#{self.class}:#{object_id} request_path=#{request_path.inspect} asset_path=#{
|
38
|
+
"<#{self.class}:#{object_id} request_path=#{request_path.inspect} asset_path=#{asset.path.to_s.inspect}>"
|
41
39
|
end
|
42
40
|
|
43
41
|
def parent(**args)
|
@@ -60,6 +58,18 @@ module Sitepress
|
|
60
58
|
resource.request_path == request_path
|
61
59
|
end
|
62
60
|
|
61
|
+
# Used internally to construct paths from the current node up to the root node.
|
62
|
+
def lineage
|
63
|
+
@lineage ||= node.parents.reject(&:root?).reverse.map(&:name)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Certain files, like binary file types, aren't something that we should try to
|
67
|
+
# parse. When this returns true in some cases, a reference to the file will be
|
68
|
+
# passed and skip all the overhead of trying to parse and render.
|
69
|
+
def renderable?
|
70
|
+
asset.mime_type.media_type == RENDERABLE_MEDIA_TYPE
|
71
|
+
end
|
72
|
+
|
63
73
|
private
|
64
74
|
# Filters parent/child/sibling resources by a type. The default behavior is to only return
|
65
75
|
# resources of the same type. For example given the pages `/a.html`, `/a.gif`, `/a/b.html`,
|
@@ -79,14 +89,29 @@ module Sitepress
|
|
79
89
|
when :all
|
80
90
|
nodes.map{ |node| node.formats }
|
81
91
|
when :same
|
82
|
-
nodes.map{ |n| n.formats.
|
83
|
-
when String
|
84
|
-
nodes.map{ |n| n.formats.
|
92
|
+
nodes.map{ |n| n.formats.get(format) }.flatten
|
93
|
+
when String, Symbol, NilClass
|
94
|
+
nodes.map{ |n| n.formats.get(type) }.flatten
|
85
95
|
when MIME::Type
|
86
96
|
nodes.map{ |n| n.formats.mime_type(type) }.flatten
|
87
97
|
else
|
88
98
|
raise ArgumentError, "Invalid type argument #{type}. Must be either :same, :all, an extension string, or a Mime::Type"
|
89
99
|
end
|
90
100
|
end
|
101
|
+
|
102
|
+
# Deals with situations, particularly in the root node and other "index" nodes, for the `request_path`
|
103
|
+
def request_filename
|
104
|
+
if node.root? and node.default_format == format
|
105
|
+
""
|
106
|
+
elsif node.root? and format
|
107
|
+
"#{node.default_name}.#{format}"
|
108
|
+
elsif node.root?
|
109
|
+
node.default_name
|
110
|
+
elsif format.nil? or node.default_format == format
|
111
|
+
node.name
|
112
|
+
else
|
113
|
+
"#{node.name}.#{format}"
|
114
|
+
end
|
115
|
+
end
|
91
116
|
end
|
92
117
|
end
|
data/lib/sitepress/site.rb
CHANGED
@@ -33,8 +33,8 @@ module Sitepress
|
|
33
33
|
# A tree representation of the resourecs wthin the site. The root is a node that's
|
34
34
|
# processed by the `resources_pipeline`.
|
35
35
|
def root
|
36
|
-
|
37
|
-
|
36
|
+
Node.new.tap do |node|
|
37
|
+
source_node_mapper.mount node
|
38
38
|
resources_pipeline.process node
|
39
39
|
end
|
40
40
|
end
|
@@ -42,12 +42,12 @@ module Sitepress
|
|
42
42
|
# Returns a list of all the resources within #root.
|
43
43
|
def resources
|
44
44
|
with_resources_cache do
|
45
|
-
ResourceCollection.new(node: root, root_path:
|
45
|
+
ResourceCollection.new(node: root, root_path: pages_path)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def clear_resources_cache
|
50
|
-
@
|
50
|
+
@resources = nil
|
51
51
|
end
|
52
52
|
|
53
53
|
# Root path to website project. Contains helpers, pages, and more.
|
@@ -64,6 +64,10 @@ module Sitepress
|
|
64
64
|
root_path.join("helpers")
|
65
65
|
end
|
66
66
|
|
67
|
+
def assets_path
|
68
|
+
root_path.join("assets")
|
69
|
+
end
|
70
|
+
|
67
71
|
# Quick and dirty way to manipulate resources in the site without
|
68
72
|
# creating classes that implement the #process_resources method.
|
69
73
|
#
|
@@ -98,7 +102,7 @@ module Sitepress
|
|
98
102
|
end
|
99
103
|
|
100
104
|
# An array of procs that manipulate the tree and resources from the
|
101
|
-
#
|
105
|
+
# Node returned by #root.
|
102
106
|
def resources_pipeline
|
103
107
|
@resources_pipeline ||= ResourcesPipeline.new
|
104
108
|
end
|
@@ -106,26 +110,11 @@ module Sitepress
|
|
106
110
|
private
|
107
111
|
def with_resources_cache
|
108
112
|
clear_resources_cache unless cache_resources
|
109
|
-
@
|
113
|
+
@resources ||= yield
|
110
114
|
end
|
111
115
|
|
112
|
-
|
113
|
-
|
114
|
-
# Exclude swap files created by Textmate and vim from being added
|
115
|
-
# to the sitemap.
|
116
|
-
SWAP_FILE_EXTENSIONS = [
|
117
|
-
"~",
|
118
|
-
".swp"
|
119
|
-
]
|
120
|
-
|
121
|
-
# Lazy stream of files that will be rendered by resources.
|
122
|
-
def pages_assets(glob = DEFAULT_GLOB)
|
123
|
-
# TODO: Move this into the DirectoryHandler class so that its not
|
124
|
-
# a concern of site.rb
|
125
|
-
paths = Dir.glob(pages_path.join(glob)).reject do |path|
|
126
|
-
File.directory? path or SWAP_FILE_EXTENSIONS.any? { |ext| path.end_with? ext }
|
127
|
-
end
|
128
|
-
paths.lazy.map { |path| Asset.new(path: path) }
|
116
|
+
def source_node_mapper
|
117
|
+
@source_node_mapper ||= SourceNodeMapper.new(path: pages_path)
|
129
118
|
end
|
130
119
|
end
|
131
120
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Sitepress
|
2
|
+
# Maps a directory of assets into a set of routes that correspond with
|
3
|
+
# the `path` root.
|
4
|
+
class SourceNodeMapper
|
5
|
+
# Exclude swap files created by Textmate and vim from being added
|
6
|
+
# to the sitemap.
|
7
|
+
SWAP_FILE_EXTENSIONS = [
|
8
|
+
"~",
|
9
|
+
".swp",
|
10
|
+
".DS_Store" # TODO: Not a swap file, but something that should be ignored.
|
11
|
+
]
|
12
|
+
|
13
|
+
# Partial rails prefix.
|
14
|
+
PARTIAL_PREFIX = "_".freeze
|
15
|
+
|
16
|
+
attr_reader :assets, :path
|
17
|
+
alias :root :path
|
18
|
+
|
19
|
+
def initialize(path:)
|
20
|
+
@path = path
|
21
|
+
end
|
22
|
+
|
23
|
+
# Mounts the source files from the path to the given node.
|
24
|
+
def mount(node)
|
25
|
+
paths.each do |path, name, format|
|
26
|
+
if path.directory?
|
27
|
+
SourceNodeMapper.new(path: path).mount node.add_child(name)
|
28
|
+
else
|
29
|
+
asset = Asset.new(path: path)
|
30
|
+
node.add_child(name).formats.add(format: format, asset: asset)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
# Returns a list of files, paths, and node names to iterate through to build out nodes
|
37
|
+
def paths
|
38
|
+
Enumerator.new do |y|
|
39
|
+
root.each_child do |path|
|
40
|
+
next if is_swap_file? path
|
41
|
+
next if is_partial_file? path
|
42
|
+
|
43
|
+
node_name, node_format, template_handler = path.basename.to_s.split(".")
|
44
|
+
y << [ path, node_name, node_format&.to_sym ]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_partial_file?(path)
|
50
|
+
path.basename.to_s.start_with? PARTIAL_PREFIX
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_swap_file?(path)
|
54
|
+
SWAP_FILE_EXTENSIONS.any? { |ext| path.to_s.end_with? ext }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/sitepress/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sitepress-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brad Gessler
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '2.99'
|
69
|
-
description:
|
69
|
+
description:
|
70
70
|
email:
|
71
71
|
- bradgessler@gmail.com
|
72
72
|
executables: []
|
@@ -75,23 +75,24 @@ extra_rdoc_files: []
|
|
75
75
|
files:
|
76
76
|
- lib/sitepress-core.rb
|
77
77
|
- lib/sitepress/asset.rb
|
78
|
-
- lib/sitepress/directory_collection.rb
|
79
78
|
- lib/sitepress/extensions/layouts.rb
|
80
79
|
- lib/sitepress/extensions/proc_manipulator.rb
|
81
80
|
- lib/sitepress/formats.rb
|
82
81
|
- lib/sitepress/frontmatter.rb
|
83
82
|
- lib/sitepress/middleware/request_cache.rb
|
83
|
+
- lib/sitepress/node.rb
|
84
|
+
- lib/sitepress/path.rb
|
84
85
|
- lib/sitepress/resource.rb
|
85
86
|
- lib/sitepress/resource_collection.rb
|
86
|
-
- lib/sitepress/resources_node.rb
|
87
87
|
- lib/sitepress/resources_pipeline.rb
|
88
88
|
- lib/sitepress/site.rb
|
89
|
+
- lib/sitepress/source_node_mapper.rb
|
89
90
|
- lib/sitepress/version.rb
|
90
91
|
- sitepress-core.gemspec
|
91
92
|
homepage: https://github.com/sitepress/sitepress
|
92
93
|
licenses: []
|
93
94
|
metadata: {}
|
94
|
-
post_install_message:
|
95
|
+
post_install_message:
|
95
96
|
rdoc_options: []
|
96
97
|
require_paths:
|
97
98
|
- lib
|
@@ -102,12 +103,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
102
103
|
version: '0'
|
103
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
105
|
requirements:
|
105
|
-
- - "
|
106
|
+
- - ">"
|
106
107
|
- !ruby/object:Gem::Version
|
107
|
-
version:
|
108
|
+
version: 1.3.1
|
108
109
|
requirements: []
|
109
|
-
rubygems_version: 3.
|
110
|
-
signing_key:
|
110
|
+
rubygems_version: 3.2.3
|
111
|
+
signing_key:
|
111
112
|
specification_version: 4
|
112
113
|
summary: An embeddable file-backed content management system.
|
113
114
|
test_files: []
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module Sitepress
|
2
|
-
# Maps a directory of assets into a set of routes that correspond with
|
3
|
-
# the `path` root.
|
4
|
-
class DirectoryCollection
|
5
|
-
attr_reader :assets, :path
|
6
|
-
|
7
|
-
def initialize(path: , assets:)
|
8
|
-
@path = path
|
9
|
-
@assets = assets
|
10
|
-
end
|
11
|
-
|
12
|
-
def mount(node)
|
13
|
-
assets.each { |a| node.add path: asset_path_to_request_path(a), asset: a }
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
# Given a @file_path of `/hi`, this method changes `/hi/there/friend.html.erb`
|
18
|
-
# to an absolute `/there/friend` format by removing the file extensions
|
19
|
-
def asset_path_to_request_path(asset)
|
20
|
-
# Relative path of resource to the file_path of this project.
|
21
|
-
asset.path.dirname.join(asset.format_basename).relative_path_from(path).to_s
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
module Sitepress
|
2
|
-
# Resource nodes give resources their parent/sibling/child relationships. The relationship are determined
|
3
|
-
# by the `request_path` given to an asset when its added to a node. Given the `request_path` `/foo/bar/biz/buz.html`,
|
4
|
-
# a tree of resource nodes would be built named `foo`, `bar`, `biz`, `buz`. `foo` would be the "root" node and `buz`
|
5
|
-
# a leaf node. The actual `buz.html` asset is then stored on the leaf node as a resource. This tree structure
|
6
|
-
# makes it possible to reason through path relationships from code to build out elements in a website like tree navigation.
|
7
|
-
class ResourcesNode
|
8
|
-
attr_reader :parent, :name
|
9
|
-
|
10
|
-
DELIMITER = "/".freeze
|
11
|
-
|
12
|
-
def initialize(parent: nil, delimiter: ResourcesNode::DELIMITER, name: nil)
|
13
|
-
@parent = parent
|
14
|
-
@name = name.freeze
|
15
|
-
@delimiter = delimiter.freeze
|
16
|
-
end
|
17
|
-
|
18
|
-
def formats
|
19
|
-
@formats ||= Formats.new(node: self)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Returns the immediate children nodes.
|
23
|
-
def children
|
24
|
-
child_nodes.values
|
25
|
-
end
|
26
|
-
|
27
|
-
# Returns sibling nodes.
|
28
|
-
def siblings
|
29
|
-
parent ? parent.children.reject{ |c| c == self } : []
|
30
|
-
end
|
31
|
-
|
32
|
-
# Returns all parents up to the root node.
|
33
|
-
def parents
|
34
|
-
parents = []
|
35
|
-
node = parent
|
36
|
-
while node do
|
37
|
-
parents << node
|
38
|
-
node = node.parent
|
39
|
-
end
|
40
|
-
parents
|
41
|
-
end
|
42
|
-
|
43
|
-
def root?
|
44
|
-
parent.nil?
|
45
|
-
end
|
46
|
-
|
47
|
-
def leaf?
|
48
|
-
child_nodes.empty?
|
49
|
-
end
|
50
|
-
|
51
|
-
def flatten(resources: [])
|
52
|
-
formats.each{ |resource| resources << resource }
|
53
|
-
children.each do |child|
|
54
|
-
child.flatten.each{ |resource| resources << resource }
|
55
|
-
end
|
56
|
-
resources
|
57
|
-
end
|
58
|
-
|
59
|
-
def remove
|
60
|
-
if leaf?
|
61
|
-
# TODO: Check the parents to see if they also need to be removed if
|
62
|
-
# this call orphans the tree up to a resource.
|
63
|
-
parent.remove_child(name)
|
64
|
-
else
|
65
|
-
formats.clear
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def add(path: , asset: )
|
70
|
-
head, *path = tokenize(path)
|
71
|
-
if path.empty?
|
72
|
-
# When there's no more paths, we're left with the format (e.g. ".html")
|
73
|
-
formats.add(asset: asset, ext: head)
|
74
|
-
else
|
75
|
-
child_nodes[head].add(path: path, asset: asset)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
alias :[]= :add
|
79
|
-
|
80
|
-
def get(path)
|
81
|
-
*path, ext = tokenize(path)
|
82
|
-
node = dig(*path)
|
83
|
-
node.formats.ext(ext) if node
|
84
|
-
end
|
85
|
-
|
86
|
-
def get_node(path)
|
87
|
-
*path, _ = tokenize(path)
|
88
|
-
dig(*path)
|
89
|
-
end
|
90
|
-
alias :[] :get_node
|
91
|
-
|
92
|
-
def inspect
|
93
|
-
"<#{self.class}: formats=#{formats.map(&:request_path)} children=#{children.map(&:name).inspect}>"
|
94
|
-
end
|
95
|
-
|
96
|
-
# TODO: I don't really like how the path is broken up with the "ext" at the end.
|
97
|
-
# It feels inconsistent. Either make an object/struct that encaspulates this or
|
98
|
-
# just pass `index.html` through to the end.
|
99
|
-
def dig(*args)
|
100
|
-
head, *tail = args
|
101
|
-
if head.nil? and tail.empty?
|
102
|
-
self
|
103
|
-
elsif child_nodes.has_key?(head)
|
104
|
-
child_nodes[head].dig(*tail)
|
105
|
-
else
|
106
|
-
nil
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
protected
|
111
|
-
def remove_child(path)
|
112
|
-
*_, segment, _ = tokenize(path)
|
113
|
-
child_nodes.delete(segment)
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
def add_child_node(name)
|
118
|
-
ResourcesNode.new(parent: self, delimiter: @delimiter, name: name)
|
119
|
-
end
|
120
|
-
|
121
|
-
def child_nodes
|
122
|
-
@child_nodes ||= Hash.new { |hash, key| hash[key] = add_child_node(key) }
|
123
|
-
end
|
124
|
-
|
125
|
-
# Returns all of the names for the path along with the format, if set.
|
126
|
-
def tokenize(path)
|
127
|
-
return path if path.respond_to? :to_a
|
128
|
-
path, _, file = path.gsub(/^\//, "").rpartition(@delimiter)
|
129
|
-
ext = File.extname(file)
|
130
|
-
file = File.basename(file, ext)
|
131
|
-
path.split(@delimiter).push(file).push(ext)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|