Skip to content

Commit 2a9876c

Browse files
Merge pull request #323 from jekyll/file-path-helpers
Create `PathHelper` and `FileHelper` mixins to abstract path and file logic
2 parents 35f519f + 0d95f93 commit 2a9876c

19 files changed

+505
-199
lines changed

lib/jekyll-admin.rb

+18-22
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,18 @@
1616
require "sinatra/reloader"
1717
require "sinatra/namespace"
1818

19-
# Jekyll-Admin stuffs
20-
require "jekyll-admin/version"
21-
require "jekyll-admin/server"
22-
require "jekyll-admin/static_server"
23-
require "jekyll-admin/server/collection.rb"
24-
require "jekyll-admin/server/configuration.rb"
25-
require "jekyll-admin/server/data.rb"
26-
require "jekyll-admin/server/page.rb"
27-
require "jekyll-admin/server/static_file.rb"
28-
require "jekyll-admin/apiable.rb"
29-
require "jekyll-admin/urlable.rb"
30-
require "jekyll-admin/data_file.rb"
31-
require "jekyll-admin/directory.rb"
32-
require "jekyll-admin/page_without_a_file.rb"
33-
34-
# Monkey Patches
35-
require_relative "./jekyll/commands/serve"
36-
[Jekyll::Page, Jekyll::Document, Jekyll::StaticFile, Jekyll::Collection].each do |klass|
37-
klass.include JekyllAdmin::APIable
38-
klass.include JekyllAdmin::URLable
39-
end
40-
4119
module JekyllAdmin
20+
autoload :APIable, "jekyll-admin/apiable"
21+
autoload :DataFile, "jekyll-admin/data_file"
22+
autoload :Directory, "jekyll-admin/directory"
23+
autoload :FileHelper, "jekyll-admin/file_helper"
24+
autoload :PageWithoutAFile, "jekyll-admin/page_without_a_file"
25+
autoload :PathHelper, "jekyll-admin/path_helper"
26+
autoload :Server, "jekyll-admin/server"
27+
autoload :StaticServer, "jekyll-admin/static_server"
28+
autoload :URLable, "jekyll-admin/urlable"
29+
autoload :Version, "jekyll-admin/version"
30+
4231
def self.site
4332
@site ||= begin
4433
site = Jekyll.sites.first
@@ -47,3 +36,10 @@ def self.site
4736
end
4837
end
4938
end
39+
40+
# Monkey Patches
41+
require_relative "./jekyll/commands/serve"
42+
[Jekyll::Page, Jekyll::Document, Jekyll::StaticFile, Jekyll::Collection].each do |klass|
43+
klass.include JekyllAdmin::APIable
44+
klass.include JekyllAdmin::URLable
45+
end

lib/jekyll-admin/apiable.rb

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def to_api(include_content: false)
4040
# array with each rendered document, which we don't want.
4141
if is_a?(Jekyll::Collection)
4242
output.delete("docs")
43+
output["entries_url"] = entries_url
4344
end
4445

4546
if is_a?(Jekyll::Document)

lib/jekyll-admin/data_file.rb

+11-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ class DataFile
55

66
include APIable
77
include URLable
8+
include PathHelper
9+
extend PathHelper
10+
11+
alias_method :path, :relative_path
812

913
# Initialize a new DataFile object
1014
#
@@ -17,17 +21,6 @@ def exists?
1721
@exists ||= File.exist?(absolute_path)
1822
end
1923

20-
def absolute_path
21-
@absolute_path ||= Jekyll.sanitized_path(JekyllAdmin.site.source, relative_path)
22-
end
23-
alias_method :file_path, :absolute_path
24-
25-
# Returns the relative path relative to site source
26-
def relative_path
27-
@relative_path = File.join(DataFile.data_dir, basename_with_extension)
28-
end
29-
alias_method :path, :relative_path
30-
3124
# Returns unparsed content as it exists on disk
3225
def raw_content
3326
@raw_content ||= File.open(absolute_path, "r:UTF-8", &:read)
@@ -65,10 +58,9 @@ def to_liquid
6558
end
6659

6760
def self.all
68-
data_dir = Jekyll.sanitized_path(JekyllAdmin.site.source, DataFile.data_dir)
69-
data_dir = Pathname.new(data_dir)
61+
data_dir = sanitized_path DataFile.data_dir
7062
Dir["#{data_dir}/*.{#{EXTENSIONS.join(",")}}"].map do |path|
71-
new(Pathname.new(path).relative_path_from(data_dir).to_s)
63+
new path_without_site_source(path)
7264
end
7365
end
7466

@@ -90,5 +82,10 @@ def basename
9082
def basename_with_extension
9183
[basename, extension].join
9284
end
85+
alias_method :filename, :basename_with_extension
86+
87+
def namespace
88+
"data"
89+
end
9390
end
9491
end

lib/jekyll-admin/file_helper.rb

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
module JekyllAdmin
2+
module FileHelper
3+
4+
# The file the user requested in the URL
5+
def requested_file
6+
find_by_path(path)
7+
end
8+
9+
# The file ultimately written to disk
10+
# This may be the requested file, or in the case of a rename will be read
11+
# from the new path that was actually written to disk
12+
def written_file
13+
find_by_path(write_path)
14+
end
15+
16+
# Write a file to disk with the given content
17+
def write_file(path, content)
18+
Jekyll.logger.debug "WRITING:", path
19+
path = sanitized_path(path)
20+
FileUtils.mkdir_p File.dirname(path)
21+
File.write(path, content)
22+
site.process
23+
end
24+
25+
# Delete the file at the given path
26+
def delete_file(path)
27+
Jekyll.logger.debug "DELETING:", path
28+
FileUtils.rm_f sanitized_path(path)
29+
site.process
30+
end
31+
32+
private
33+
34+
def ensure_requested_file
35+
ensure_file(requested_file)
36+
end
37+
38+
def ensure_written_file
39+
ensure_file(written_file)
40+
end
41+
42+
def find_by_path(path)
43+
files = case namespace
44+
when "collections"
45+
collection.docs
46+
when "data"
47+
DataFile.all
48+
when "pages", "static_files"
49+
site.public_send(namespace.to_sym)
50+
else
51+
[]
52+
end
53+
files.find { |f| sanitized_path(f.path) == path }
54+
end
55+
56+
def ensure_file(file)
57+
render_404 if file.nil?
58+
end
59+
60+
def ensure_directory
61+
render_404 unless Dir.exist?(directory_path)
62+
end
63+
end
64+
end

lib/jekyll-admin/path_helper.rb

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
module JekyllAdmin
2+
module PathHelper
3+
def sanitized_path(path)
4+
path = path_without_site_source(path)
5+
Jekyll.sanitized_path JekyllAdmin.site.source, path
6+
end
7+
8+
# Returns the basename + extension for the requested file
9+
def filename
10+
params["ext"] ||= "yml" if namespace == "data"
11+
"#{params["path"]}.#{params["ext"]}"
12+
end
13+
14+
# Returns the sanitized path relative to the site source
15+
def sanitized_relative_path(path)
16+
path_without_site_source sanitized_path(path)
17+
end
18+
19+
# Returns the sanitized absolute path to the requested object
20+
def absolute_path
21+
sanitized_path File.join(directory_path, filename)
22+
end
23+
alias_method :path, :absolute_path
24+
25+
# Returns the sanitized relative path to the requested object
26+
def relative_path
27+
sanitized_relative_path absolute_path
28+
end
29+
30+
# Returns the sanitized absolute path to write the requested object
31+
def write_path
32+
if renamed?
33+
sanitized_path request_payload["path"]
34+
else
35+
path
36+
end
37+
end
38+
alias_method :request_path, :write_path
39+
40+
# Returns the sanitized relative path to write the requested object
41+
def relative_write_path
42+
sanitized_relative_path write_path
43+
end
44+
45+
# Is this request renaming a file?
46+
def renamed?
47+
return false unless request_payload["path"]
48+
ensure_leading_slash(request_payload["path"]) != relative_path
49+
end
50+
51+
private
52+
53+
# Returns the path to the requested file's containing directory
54+
def directory_path
55+
case namespace
56+
when "collections"
57+
sanitized_path File.join(collection.relative_directory, params["splat"].first)
58+
when "data"
59+
sanitized_path File.join(DataFile.data_dir)
60+
else
61+
sanitized_path params["splat"].first
62+
end
63+
end
64+
65+
def ensure_leading_slash(input)
66+
return input if input.nil? || input.empty? || input.start_with?("/")
67+
"/#{input}"
68+
end
69+
70+
def path_without_site_source(path)
71+
path.to_s.gsub(%r!\A#{Regexp.escape(JekyllAdmin.site.source)}!, "")
72+
end
73+
end
74+
end

lib/jekyll-admin/server.rb

+22-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module JekyllAdmin
22
class Server < Sinatra::Base
33
ROUTES = %w(collections configuration data pages static_files).freeze
4+
include JekyllAdmin::PathHelper
5+
include JekyllAdmin::FileHelper
46

57
register Sinatra::Namespace
68

@@ -40,20 +42,17 @@ def render_404
4042
end
4143

4244
def request_payload
43-
@request_payload ||= begin
44-
request.body.rewind
45-
JSON.parse request.body.read
46-
end
45+
@request_payload ||= if request_body.to_s.empty?
46+
{}
47+
else
48+
JSON.parse(request_body)
49+
end
4750
end
4851

4952
def base_url
5053
"#{request.scheme}://#{request.host_with_port}"
5154
end
5255

53-
def sanitized_path(questionable_path)
54-
Jekyll.sanitized_path JekyllAdmin.site.source, questionable_path
55-
end
56-
5756
def front_matter
5857
request_payload["front_matter"]
5958
end
@@ -69,18 +68,24 @@ def document_body
6968
end
7069
alias page_body document_body
7170

72-
def write_file(path, content)
73-
path = sanitized_path(path)
74-
FileUtils.mkdir_p File.dirname(path)
75-
File.open(path, "wb") do |file|
76-
file.write(content)
71+
private
72+
73+
def request_body
74+
@request_body ||= begin
75+
request.body.rewind
76+
request.body.read
7777
end
78-
site.process
7978
end
8079

81-
def delete_file(path)
82-
File.delete sanitized_path(path)
83-
site.process
80+
def namespace
81+
namespace = request.path_info.split("/")[1].to_s.downcase
82+
namespace if ROUTES.include?(namespace)
8483
end
8584
end
8685
end
86+
87+
require "jekyll-admin/server/collection"
88+
require "jekyll-admin/server/configuration"
89+
require "jekyll-admin/server/data"
90+
require "jekyll-admin/server/page"
91+
require "jekyll-admin/server/static_file"

0 commit comments

Comments
 (0)