sitepress-core 4.1.1 → 5.0.0.beta
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.
Potentially problematic release.
This version of sitepress-core might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/sitepress/data.rb +16 -13
- data/lib/sitepress/directory.rb +54 -0
- data/lib/sitepress/image.rb +84 -0
- data/lib/sitepress/node.rb +6 -0
- data/lib/sitepress/{asset.rb → page.rb} +47 -7
- data/lib/sitepress/parsers/base.rb +6 -0
- data/lib/sitepress/parsers/frontmatter.rb +9 -13
- data/lib/sitepress/parsers/notion.rb +8 -0
- data/lib/sitepress/path.rb +0 -8
- data/lib/sitepress/resource.rb +35 -10
- data/lib/sitepress/resource_indexer.rb +5 -2
- data/lib/sitepress/resources_pipeline.rb +0 -2
- data/lib/sitepress/site.rb +4 -4
- data/lib/sitepress/static.rb +47 -0
- data/lib/sitepress/version.rb +1 -1
- data/lib/sitepress-core.rb +9 -2
- data/sitepress-core.gemspec +1 -0
- metadata +20 -4
- data/lib/sitepress/asset_node_mapper.rb +0 -45
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef3344c3cfd0d28305f9f3684d9193008812425f5a0651889e180f7bd1e71738
|
|
4
|
+
data.tar.gz: a61c4ee48c2dc69971d0fef76763bea2bafb215a37c9a1f32e720417149f9316
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8fece92fa30224dc287d4689441f6db3f9a196ea6d517399b509dcd3cb8bad9232778fd281a3105cb6219966699499e40b3ec4a8fa254125041576bcaee64205
|
|
7
|
+
data.tar.gz: 0c7f1972a0982c708281c29c21ad066ed5f8b7cbef2beced7219439472ac698a439dee672ab41e3c22f77f4f89992dbd81985932fb1594550b90c225d3270a9b
|
data/lib/sitepress/data.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "forwardable"
|
|
2
|
+
|
|
1
3
|
module Sitepress
|
|
2
4
|
module Data
|
|
3
5
|
def self.manage(value)
|
|
@@ -70,22 +72,23 @@ module Sitepress
|
|
|
70
72
|
end
|
|
71
73
|
|
|
72
74
|
def method_missing(name, *args, **kwargs, &block)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
self.fetch(key, *args, &block)
|
|
83
|
-
when "?"
|
|
84
|
-
!!self[key]
|
|
85
|
-
end
|
|
75
|
+
key, modifier, _ = name.to_s.partition(/[!?]/)
|
|
76
|
+
|
|
77
|
+
case modifier
|
|
78
|
+
when ""
|
|
79
|
+
self[key]
|
|
80
|
+
when "!"
|
|
81
|
+
self.fetch(key, *args, &block)
|
|
82
|
+
when "?"
|
|
83
|
+
!!self[key]
|
|
86
84
|
end
|
|
87
85
|
end
|
|
88
86
|
|
|
87
|
+
def respond_to_missing?(name, include_private = false)
|
|
88
|
+
key, _, _ = name.to_s.partition(/[!?]/)
|
|
89
|
+
@hash.key?(key) || @hash.key?(key.to_sym) || super
|
|
90
|
+
end
|
|
91
|
+
|
|
89
92
|
def dig(*args, **kwargs, &block)
|
|
90
93
|
Data.manage @hash.dig(*args, **kwargs, &block)
|
|
91
94
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require "mime/types"
|
|
2
|
+
|
|
3
|
+
module Sitepress
|
|
4
|
+
# Maps a directory of files into a tree of nodes that form the navigational
|
|
5
|
+
# structure of a website. You can subclass this to handle different file
|
|
6
|
+
# types or directory structures.
|
|
7
|
+
class Directory
|
|
8
|
+
attr_reader :asset_paths
|
|
9
|
+
|
|
10
|
+
def initialize(path)
|
|
11
|
+
@asset_paths = AssetPaths.new(path: path)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Mounts the source files from the path into the given node.
|
|
15
|
+
def mount(node)
|
|
16
|
+
asset_paths.each do |path|
|
|
17
|
+
if path.directory?
|
|
18
|
+
process_directory path, node
|
|
19
|
+
else
|
|
20
|
+
process_asset path, node
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
|
|
27
|
+
def process_directory(path, node)
|
|
28
|
+
node_name = File.basename path
|
|
29
|
+
self.class.new(path).mount(node.child(node_name))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def process_asset(path, node)
|
|
33
|
+
asset = source_for(path)
|
|
34
|
+
node.child(asset.node_name).resources.add_asset(asset, format: asset.format)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def source_for(path)
|
|
38
|
+
mime = MIME::Types.type_for(path.to_s).first&.content_type
|
|
39
|
+
|
|
40
|
+
case mime
|
|
41
|
+
when *Image.mime_types
|
|
42
|
+
Image.new(path: path)
|
|
43
|
+
when *Page.mime_types, nil
|
|
44
|
+
# nil handles template files like .erb that have no MIME type
|
|
45
|
+
Page.new(path: path)
|
|
46
|
+
else
|
|
47
|
+
Static.new(path: path)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Backwards compatibility
|
|
53
|
+
AssetNodeMapper = Directory
|
|
54
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require "mime/types"
|
|
2
|
+
require "fastimage"
|
|
3
|
+
|
|
4
|
+
module Sitepress
|
|
5
|
+
# A source for image files. Extracts dimensions via fastimage.
|
|
6
|
+
#
|
|
7
|
+
# Example:
|
|
8
|
+
# image = Image.new(path: "photos/sunset.jpg")
|
|
9
|
+
# image.width # => 1920
|
|
10
|
+
# image.height # => 1080
|
|
11
|
+
# image.data["width"] # => 1920
|
|
12
|
+
#
|
|
13
|
+
class Image
|
|
14
|
+
MIME_TYPES = %w[image/png image/jpeg image/gif image/webp].freeze
|
|
15
|
+
|
|
16
|
+
def self.mime_types
|
|
17
|
+
MIME_TYPES
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_reader :path
|
|
21
|
+
|
|
22
|
+
def initialize(path:)
|
|
23
|
+
@path = Pathname.new(path)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def filename
|
|
27
|
+
path.basename.to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def node_name
|
|
31
|
+
path.basename(".*").to_s.split(".").first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def format
|
|
35
|
+
path.extname.delete(".").to_sym
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def mime_type
|
|
39
|
+
MIME::Types.type_for(path.to_s).first
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def size
|
|
43
|
+
exists? ? File.size(path) : nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def width
|
|
47
|
+
dimensions[0]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def height
|
|
51
|
+
dimensions[1]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def data
|
|
55
|
+
@data ||= Data.manage({
|
|
56
|
+
"width" => width,
|
|
57
|
+
"height" => height
|
|
58
|
+
}.compact)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def body
|
|
62
|
+
File.binread(path)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def exists?
|
|
66
|
+
path.exist?
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def inspect
|
|
70
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} path=#{path.to_s.inspect}>"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def dimensions
|
|
76
|
+
@dimensions ||= begin
|
|
77
|
+
return [nil, nil] unless exists?
|
|
78
|
+
FastImage.size(path.to_s) || [nil, nil]
|
|
79
|
+
rescue
|
|
80
|
+
[nil, nil]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/sitepress/node.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "forwardable"
|
|
2
|
+
|
|
1
3
|
module Sitepress
|
|
2
4
|
# Resource nodes give resources their parent/sibling/child relationships. The relationship are determined
|
|
3
5
|
# by the `request_path` given to an asset when its added to a node. Given the `request_path` `/foo/bar/biz/buz.html`,
|
|
@@ -96,6 +98,10 @@ module Sitepress
|
|
|
96
98
|
"<#{self.class}: name=#{name.inspect}, formats=#{formats.inspect}, children=#{children.map(&:name).inspect}, resource_request_paths=#{resources.map(&:request_path)}>"
|
|
97
99
|
end
|
|
98
100
|
|
|
101
|
+
def <<(mountable)
|
|
102
|
+
mountable.mount(self)
|
|
103
|
+
end
|
|
104
|
+
|
|
99
105
|
def dig(*args)
|
|
100
106
|
head, *tail = args
|
|
101
107
|
if (head.nil? or head.empty? or head == default_name) and tail.empty?
|
|
@@ -3,16 +3,35 @@ require "forwardable"
|
|
|
3
3
|
require "fileutils"
|
|
4
4
|
|
|
5
5
|
module Sitepress
|
|
6
|
-
# Represents a
|
|
6
|
+
# Represents a page on a website - a file that may be parsed to extract
|
|
7
7
|
# metadata or be renderable via a template. Multiple resources
|
|
8
|
-
# may point to the same
|
|
8
|
+
# may point to the same page. Properties of a page should be mutable.
|
|
9
9
|
# The Resource object is immutable and may be modified by the Resources proxy.
|
|
10
|
-
class
|
|
10
|
+
class Page
|
|
11
11
|
# If we can't resolve a mime type for the resource, we'll fall
|
|
12
12
|
# back to this binary octet-stream type so the client can download
|
|
13
13
|
# the resource and figure out what to do with it.
|
|
14
14
|
DEFAULT_MIME_TYPE = MIME::Types["application/octet-stream"].first
|
|
15
15
|
|
|
16
|
+
# MIME types that Page can handle - text-based content that may have frontmatter
|
|
17
|
+
MIME_TYPES = %w[
|
|
18
|
+
text/html
|
|
19
|
+
text/plain
|
|
20
|
+
text/markdown
|
|
21
|
+
text/x-web-markdown
|
|
22
|
+
text/css
|
|
23
|
+
text/javascript
|
|
24
|
+
application/json
|
|
25
|
+
application/xml
|
|
26
|
+
text/xml
|
|
27
|
+
image/svg+xml
|
|
28
|
+
text/x-haml
|
|
29
|
+
].freeze
|
|
30
|
+
|
|
31
|
+
def self.mime_types
|
|
32
|
+
MIME_TYPES
|
|
33
|
+
end
|
|
34
|
+
|
|
16
35
|
# Parsers can be swapped out to deal with different types of resources, like Notion
|
|
17
36
|
# documents, JSON, exif data on images, etc.
|
|
18
37
|
DEFAULT_PARSER = Parsers::Frontmatter
|
|
@@ -44,9 +63,19 @@ module Sitepress
|
|
|
44
63
|
@body ||= exists? ? parse_error { parser.body } : nil
|
|
45
64
|
end
|
|
46
65
|
|
|
66
|
+
# Returns the line number where the body starts in the original file.
|
|
67
|
+
# Used to adjust error line numbers when frontmatter is present.
|
|
68
|
+
def body_line_offset
|
|
69
|
+
exists? ? parser.body_line_offset : 1
|
|
70
|
+
end
|
|
71
|
+
|
|
47
72
|
# Treat resources with the same request path as equal.
|
|
48
|
-
def ==(
|
|
49
|
-
path ==
|
|
73
|
+
def ==(other)
|
|
74
|
+
path == other.path
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def inspect
|
|
78
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} path=#{path.to_s.inspect}>"
|
|
50
79
|
end
|
|
51
80
|
|
|
52
81
|
def mime_type
|
|
@@ -60,9 +89,11 @@ module Sitepress
|
|
|
60
89
|
!!handler
|
|
61
90
|
end
|
|
62
91
|
|
|
63
|
-
#
|
|
92
|
+
# When changing the parser, clear all cached parsed data.
|
|
64
93
|
def parser=(parser_klass)
|
|
65
94
|
@parser = nil
|
|
95
|
+
@data = nil
|
|
96
|
+
@body = nil
|
|
66
97
|
@parser_klass = parser_klass
|
|
67
98
|
end
|
|
68
99
|
|
|
@@ -86,11 +117,17 @@ module Sitepress
|
|
|
86
117
|
@parser_klass::Renderer.new(data: data, body: body)
|
|
87
118
|
end
|
|
88
119
|
|
|
120
|
+
# Renders the page in a view context. This is part of the Renderable protocol
|
|
121
|
+
# that allows any object to be used as a resource source.
|
|
122
|
+
def render_in(view_context)
|
|
123
|
+
view_context.render inline: body, type: handler
|
|
124
|
+
end
|
|
125
|
+
|
|
89
126
|
private
|
|
90
127
|
def parse_error(&parse)
|
|
91
128
|
parse.call
|
|
92
129
|
rescue StandardError => e
|
|
93
|
-
raise ParseError
|
|
130
|
+
raise ParseError, "Error parsing #{path.expand_path}: #{e.class} - #{e.message}"
|
|
94
131
|
end
|
|
95
132
|
|
|
96
133
|
def parser
|
|
@@ -104,4 +141,7 @@ module Sitepress
|
|
|
104
141
|
MIME::Types.type_for(format_extension).first if format_extension
|
|
105
142
|
end
|
|
106
143
|
end
|
|
144
|
+
|
|
145
|
+
# Backwards compatibility
|
|
146
|
+
Asset = Page
|
|
107
147
|
end
|
|
@@ -10,6 +10,12 @@ module Sitepress
|
|
|
10
10
|
@body = source
|
|
11
11
|
@data = {}
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
# Returns the line number where the body starts in the original file.
|
|
15
|
+
# Subclasses should override this if they strip content from the beginning.
|
|
16
|
+
def body_line_offset
|
|
17
|
+
1
|
|
18
|
+
end
|
|
13
19
|
end
|
|
14
20
|
end
|
|
15
21
|
end
|
|
@@ -14,12 +14,7 @@ module Sitepress
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def dump_yaml(data)
|
|
17
|
-
|
|
18
|
-
YAML.safe_dump data, permitted_classes: Frontmatter.permitted_classes
|
|
19
|
-
else
|
|
20
|
-
# Live dangerously, lol
|
|
21
|
-
YAML.dump data
|
|
22
|
-
end
|
|
17
|
+
YAML.safe_dump data, permitted_classes: Frontmatter.permitted_classes
|
|
23
18
|
end
|
|
24
19
|
|
|
25
20
|
def render
|
|
@@ -46,7 +41,13 @@ module Sitepress
|
|
|
46
41
|
PATTERN = /\A(#{DELIMITER}#{NEWLINE}(.+?)#{NEWLINE}#{DELIMITER}#{NEWLINE}*)?(.+)\Z/m
|
|
47
42
|
|
|
48
43
|
def initialize(content)
|
|
49
|
-
|
|
44
|
+
@frontmatter_block, @data, @body = content.match(PATTERN).captures
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns the line number where the body starts in the original file.
|
|
48
|
+
def body_line_offset
|
|
49
|
+
return 1 unless @frontmatter_block
|
|
50
|
+
@frontmatter_block.count("\n") + 1
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
def data
|
|
@@ -54,12 +55,7 @@ module Sitepress
|
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
def load_yaml(data)
|
|
57
|
-
|
|
58
|
-
YAML.safe_load data, permitted_classes: self.class.permitted_classes
|
|
59
|
-
else
|
|
60
|
-
# Live dangerously, lol
|
|
61
|
-
YAML.load data
|
|
62
|
-
end
|
|
58
|
+
YAML.safe_load data, permitted_classes: self.class.permitted_classes
|
|
63
59
|
end
|
|
64
60
|
|
|
65
61
|
class << self
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "yaml"
|
|
2
|
+
require "strscan"
|
|
2
3
|
|
|
3
4
|
module Sitepress
|
|
4
5
|
module Parsers
|
|
@@ -19,10 +20,17 @@ module Sitepress
|
|
|
19
20
|
@raw_data.append scanner.captures
|
|
20
21
|
end
|
|
21
22
|
scanner.scan(/\n/)
|
|
23
|
+
# Track where body starts for line number offset
|
|
24
|
+
@header_content = content[0, scanner.pos]
|
|
22
25
|
# Parse body
|
|
23
26
|
@body = scanner.rest
|
|
24
27
|
end
|
|
25
28
|
|
|
29
|
+
# Returns the line number where the body starts in the original file.
|
|
30
|
+
def body_line_offset
|
|
31
|
+
@header_content.count("\n") + 1
|
|
32
|
+
end
|
|
33
|
+
|
|
26
34
|
def data
|
|
27
35
|
Hash[@raw_data.prepend([TITLE_KEY, @title])]
|
|
28
36
|
end
|
data/lib/sitepress/path.rb
CHANGED
|
@@ -23,14 +23,6 @@ module Sitepress
|
|
|
23
23
|
action_view_template_handlers_extensions || HANDLER_EXTENSIONS
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
# I tried to hook this into Rails engines in the `config.after_initialize` block,
|
|
27
|
-
# but the way template handlers register their extensions is across the board.
|
|
28
|
-
#
|
|
29
|
-
# config.after_initialize do
|
|
30
|
-
# Sitepress::Path.handler_extensions = ActionView::Template::Handlers.method(:extensions)
|
|
31
|
-
# ends
|
|
32
|
-
#
|
|
33
|
-
# I couldn't get that working, instead I do this check to find the handlers.
|
|
34
26
|
def action_view_template_handlers_extensions
|
|
35
27
|
ActionView::Template::Handlers.extensions if defined?(ActionView::Template::Handlers)
|
|
36
28
|
end
|
data/lib/sitepress/resource.rb
CHANGED
|
@@ -4,23 +4,44 @@ module Sitepress
|
|
|
4
4
|
# Represents the request path of an asset. There may be multiple
|
|
5
5
|
# resources that point to the same asset. Resources are immutable
|
|
6
6
|
# and may be altered by the resource proxy.
|
|
7
|
+
#
|
|
8
|
+
# The source can be any object that implements the Renderable protocol:
|
|
9
|
+
# - #data - returns a Hash of metadata
|
|
10
|
+
# - #render_in(view_context) - renders the content
|
|
7
11
|
class Resource
|
|
8
12
|
extend Forwardable
|
|
9
|
-
def_delegators :
|
|
13
|
+
def_delegators :source, :body
|
|
10
14
|
|
|
11
|
-
attr_reader :node, :
|
|
15
|
+
attr_reader :node, :source
|
|
16
|
+
alias :asset :source # Backwards compatibility
|
|
17
|
+
|
|
18
|
+
# Check if the source implements the data protocol.
|
|
19
|
+
def has_data?
|
|
20
|
+
source.respond_to?(:data)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Check if the source implements the render_in protocol.
|
|
24
|
+
def renderable?
|
|
25
|
+
source.respond_to?(:render_in)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns metadata from the source, or an empty hash if not available.
|
|
29
|
+
def data
|
|
30
|
+
has_data? ? source.data : {}
|
|
31
|
+
end
|
|
12
32
|
|
|
13
33
|
attr_accessor :format, :mime_type, :handler
|
|
14
34
|
|
|
15
35
|
# Default scope for querying parent/child/sibling resources.
|
|
16
36
|
DEFAULT_FILTER_SCOPE = :same
|
|
17
37
|
|
|
18
|
-
def initialize(asset
|
|
19
|
-
@
|
|
38
|
+
def initialize(asset: nil, source: nil, node:, format: nil, mime_type: nil, handler: nil)
|
|
39
|
+
@source = source || asset
|
|
40
|
+
raise ArgumentError, "Either asset: or source: must be provided" unless @source
|
|
20
41
|
@node = node
|
|
21
|
-
@format = format ||
|
|
22
|
-
@mime_type = mime_type ||
|
|
23
|
-
@handler = handler ||
|
|
42
|
+
@format = format || @source.format
|
|
43
|
+
@mime_type = mime_type || @source.mime_type
|
|
44
|
+
@handler = handler || source_handler
|
|
24
45
|
end
|
|
25
46
|
|
|
26
47
|
def request_path
|
|
@@ -71,7 +92,7 @@ module Sitepress
|
|
|
71
92
|
# Clones should be initialized with a nil node. Initializing with a node would mean that multiple resources
|
|
72
93
|
# are pointing to the same node, which shouldn't be possible.
|
|
73
94
|
def clone
|
|
74
|
-
self.class.new(
|
|
95
|
+
self.class.new(source: @source, node: nil, format: @format, mime_type: @mime_type, handler: @handler)
|
|
75
96
|
end
|
|
76
97
|
|
|
77
98
|
# Removes the resource from the node's resources list.
|
|
@@ -80,7 +101,7 @@ module Sitepress
|
|
|
80
101
|
end
|
|
81
102
|
|
|
82
103
|
def inspect
|
|
83
|
-
"
|
|
104
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} request_path=#{request_path.inspect} source=#{source.inspect}>"
|
|
84
105
|
end
|
|
85
106
|
|
|
86
107
|
def parent(**args)
|
|
@@ -109,7 +130,7 @@ module Sitepress
|
|
|
109
130
|
end
|
|
110
131
|
|
|
111
132
|
def render_in(view_context)
|
|
112
|
-
|
|
133
|
+
renderable? ? source.render_in(view_context) : nil
|
|
113
134
|
end
|
|
114
135
|
|
|
115
136
|
private
|
|
@@ -135,6 +156,10 @@ module Sitepress
|
|
|
135
156
|
end
|
|
136
157
|
end
|
|
137
158
|
|
|
159
|
+
def source_handler
|
|
160
|
+
@source.handler if @source.respond_to?(:handler)
|
|
161
|
+
end
|
|
162
|
+
|
|
138
163
|
# Deals with situations, particularly in the root node and other "index" nodes, for the `request_path`
|
|
139
164
|
def request_filename
|
|
140
165
|
if node.root? and node.default_format == format
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
require "forwardable"
|
|
2
|
+
require "set"
|
|
3
|
+
|
|
1
4
|
module Sitepress
|
|
2
5
|
# Flattens a tree of Sitepress::Node and Sitepress:Resource classes into a collection of
|
|
3
6
|
# resources that can be quickly globbed, queried, or accessed.
|
|
@@ -17,8 +20,8 @@ module Sitepress
|
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def glob(pattern)
|
|
20
|
-
paths = Dir.glob
|
|
21
|
-
resources.select { |r| paths.include?
|
|
23
|
+
paths = Dir.glob(root_path.join(pattern)).to_set
|
|
24
|
+
resources.select { |r| paths.include?(r.asset.path.to_s) }
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
def get(request_path)
|
data/lib/sitepress/site.rb
CHANGED
|
@@ -19,18 +19,18 @@ module Sitepress
|
|
|
19
19
|
self.root_path = root_path
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
# A tree representation of the
|
|
22
|
+
# A tree representation of the resources within the site. The root is a node that's
|
|
23
23
|
# processed by the `resources_pipeline`.
|
|
24
24
|
def root
|
|
25
25
|
@root ||= Node.new.tap do |root|
|
|
26
|
-
asset_node_mapper
|
|
26
|
+
root << asset_node_mapper
|
|
27
27
|
resources_pipeline.process root
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
# Maps a path of directories and files into the root node.
|
|
32
|
-
def asset_node_mapper
|
|
33
|
-
|
|
32
|
+
def asset_node_mapper
|
|
33
|
+
Directory.new(pages_path)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# Returns a list of all the resources within #root.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require "mime/types"
|
|
2
|
+
|
|
3
|
+
module Sitepress
|
|
4
|
+
# A source for static files that are served as-is without processing.
|
|
5
|
+
# Used as a fallback for files that don't match Image or Page MIME types.
|
|
6
|
+
#
|
|
7
|
+
# Example:
|
|
8
|
+
# static = Static.new(path: "fonts/roboto.woff2")
|
|
9
|
+
# static.mime_type # => #<MIME::Type font/woff2>
|
|
10
|
+
# static.body # => binary content
|
|
11
|
+
#
|
|
12
|
+
class Static
|
|
13
|
+
attr_reader :path
|
|
14
|
+
|
|
15
|
+
def initialize(path:)
|
|
16
|
+
@path = Pathname.new(path)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def node_name
|
|
20
|
+
path.basename(".*").to_s.split(".").first
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def format
|
|
24
|
+
path.extname.delete(".").to_sym
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def mime_type
|
|
28
|
+
MIME::Types.type_for(path.to_s).first
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def body
|
|
32
|
+
File.binread(path)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def data
|
|
36
|
+
@data ||= Data.manage({})
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def exists?
|
|
40
|
+
path.exist?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def inspect
|
|
44
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} path=#{path.to_s.inspect}>"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/sitepress/version.rb
CHANGED
data/lib/sitepress-core.rb
CHANGED
|
@@ -4,17 +4,23 @@ module Sitepress
|
|
|
4
4
|
# Errors raised by Sitepress
|
|
5
5
|
Error = Class.new(StandardError)
|
|
6
6
|
|
|
7
|
+
# Raised when an asset fails to parse (e.g., invalid YAML frontmatter)
|
|
8
|
+
ParseError = Class.new(Error)
|
|
9
|
+
|
|
7
10
|
# Raised by Resources if a path is added that's not a valid path.
|
|
8
11
|
InvalidRequestPathError = Class.new(RuntimeError)
|
|
9
12
|
|
|
10
13
|
# Raised by Resources if a path is already in its index
|
|
11
14
|
ExistingRequestPathError = Class.new(InvalidRequestPathError)
|
|
12
15
|
|
|
13
|
-
autoload :Asset, "sitepress/
|
|
14
|
-
autoload :AssetNodeMapper, "sitepress/
|
|
16
|
+
autoload :Asset, "sitepress/page" # Backwards compatibility
|
|
17
|
+
autoload :AssetNodeMapper, "sitepress/directory" # Backwards compatibility
|
|
15
18
|
autoload :AssetPaths, "sitepress/asset_paths"
|
|
19
|
+
autoload :Directory, "sitepress/directory"
|
|
16
20
|
autoload :Data, "sitepress/data"
|
|
21
|
+
autoload :Image, "sitepress/image"
|
|
17
22
|
autoload :Node, "sitepress/node"
|
|
23
|
+
autoload :Page, "sitepress/page"
|
|
18
24
|
autoload :Path, "sitepress/path"
|
|
19
25
|
autoload :Parsers, "sitepress/parsers"
|
|
20
26
|
autoload :Resource, "sitepress/resource"
|
|
@@ -22,4 +28,5 @@ module Sitepress
|
|
|
22
28
|
autoload :ResourceIndexer, "sitepress/resource_indexer"
|
|
23
29
|
autoload :ResourcesPipeline, "sitepress/resources_pipeline"
|
|
24
30
|
autoload :Site, "sitepress/site"
|
|
31
|
+
autoload :Static, "sitepress/static"
|
|
25
32
|
end
|
data/sitepress-core.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sitepress-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 5.0.0.beta
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brad Gessler
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-02-20 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: bundler
|
|
@@ -65,6 +65,20 @@ dependencies:
|
|
|
65
65
|
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '2.99'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: fastimage
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '2.0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '2.0'
|
|
68
82
|
email:
|
|
69
83
|
- bradgessler@gmail.com
|
|
70
84
|
executables: []
|
|
@@ -72,13 +86,14 @@ extensions: []
|
|
|
72
86
|
extra_rdoc_files: []
|
|
73
87
|
files:
|
|
74
88
|
- lib/sitepress-core.rb
|
|
75
|
-
- lib/sitepress/asset.rb
|
|
76
|
-
- lib/sitepress/asset_node_mapper.rb
|
|
77
89
|
- lib/sitepress/asset_paths.rb
|
|
78
90
|
- lib/sitepress/data.rb
|
|
91
|
+
- lib/sitepress/directory.rb
|
|
79
92
|
- lib/sitepress/extensions/layouts.rb
|
|
80
93
|
- lib/sitepress/extensions/proc_manipulator.rb
|
|
94
|
+
- lib/sitepress/image.rb
|
|
81
95
|
- lib/sitepress/node.rb
|
|
96
|
+
- lib/sitepress/page.rb
|
|
82
97
|
- lib/sitepress/parsers.rb
|
|
83
98
|
- lib/sitepress/parsers/base.rb
|
|
84
99
|
- lib/sitepress/parsers/frontmatter.rb
|
|
@@ -89,6 +104,7 @@ files:
|
|
|
89
104
|
- lib/sitepress/resources.rb
|
|
90
105
|
- lib/sitepress/resources_pipeline.rb
|
|
91
106
|
- lib/sitepress/site.rb
|
|
107
|
+
- lib/sitepress/static.rb
|
|
92
108
|
- lib/sitepress/version.rb
|
|
93
109
|
- sitepress-core.gemspec
|
|
94
110
|
homepage: https://sitepress.cc/
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
module Sitepress
|
|
2
|
-
# Maps a tree of Directory and Asset objects in a a tree of nodes that
|
|
3
|
-
# format the navigational structure of a website. You can override this
|
|
4
|
-
# this in a site to deal with different file systems. For example, Notion
|
|
5
|
-
# has a completely different file structure for its content than Rails, so
|
|
6
|
-
# we could extend this class to properly map those differences into a tree
|
|
7
|
-
# of nodes.
|
|
8
|
-
class AssetNodeMapper
|
|
9
|
-
attr_reader :node, :asset_paths
|
|
10
|
-
|
|
11
|
-
def initialize(path:, node:)
|
|
12
|
-
@asset_paths = AssetPaths.new(path: path)
|
|
13
|
-
@node = node
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Mounts the source files from the path to the given node.
|
|
17
|
-
def map
|
|
18
|
-
asset_paths.each do |path|
|
|
19
|
-
if path.directory?
|
|
20
|
-
process_directory path
|
|
21
|
-
else
|
|
22
|
-
process_asset path
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
protected
|
|
28
|
-
|
|
29
|
-
def process_directory(path)
|
|
30
|
-
node_name = File.basename path
|
|
31
|
-
node_mapper path: path, node: node.child(node_name)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def process_asset(path)
|
|
35
|
-
asset = Asset.new(path: path)
|
|
36
|
-
node.child(asset.node_name).resources.add_asset(asset, format: asset.format)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
private
|
|
40
|
-
|
|
41
|
-
def node_mapper(*args, **kwargs)
|
|
42
|
-
self.class.new(*args, **kwargs).map
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|