impression 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +5 -3
- data/README.md +44 -2
- data/impression.gemspec +2 -1
- data/lib/impression/file_tree.rb +59 -24
- data/lib/impression/jamstack.rb +110 -0
- data/lib/impression/request_extensions/responses.rb +48 -0
- data/lib/impression/request_extensions/routing.rb +52 -0
- data/lib/impression/request_extensions.rb +4 -2
- data/lib/impression/resource.rb +29 -2
- data/lib/impression/version.rb +1 -1
- data/lib/impression.rb +1 -0
- data/test/helper.rb +8 -8
- data/test/jamstack/_layouts/article.rb +9 -0
- data/test/jamstack/_layouts/default.rb +12 -0
- data/test/jamstack/articles/a.md +6 -0
- data/test/jamstack/assets/js/a.js +1 -0
- data/test/jamstack/bar.html +1 -0
- data/test/jamstack/baz/index.md +7 -0
- data/test/jamstack/foo.rb +7 -0
- data/test/jamstack/index.md +4 -0
- data/test/test_app.rb +1 -1
- data/test/test_file_tree.rb +20 -20
- data/test/test_jamstack.rb +208 -0
- data/test/test_resource.rb +81 -9
- metadata +30 -5
- data/lib/impression/request_routing.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5644ebb122c166a8a5579a950b3e64fde5d3d332eea8299aa4c4023af8b85cb6
|
4
|
+
data.tar.gz: b89065d1cd8c14d5ddad28f1fc3ff90cc48d43354698e339715f3b6d172af671
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45ab7c1f4e3c9f920175acc8bce2417932571ceca8946cf1fd0b784a6280413514587bc998d467808023c56e054a0edc2c821e6dc700289a4a02f4e2372dfe05
|
7
|
+
data.tar.gz: d3b57e4089e0473e508f5a67c52db12be7a62850897bc79a27871b4ea7a3d2b3b3062f214980a98d5e842033b62496ae9024416c37b00ca05b527b01c088b53e
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
impression (0.
|
4
|
+
impression (0.3)
|
5
5
|
kramdown (~> 2.3.0)
|
6
6
|
kramdown-parser-gfm (~> 1.1.0)
|
7
|
-
|
7
|
+
modulation (~> 1.1)
|
8
|
+
papercraft (~> 0.14)
|
8
9
|
polyphony (~> 0.73.1)
|
9
10
|
qeweney (~> 0.15)
|
10
11
|
rouge (~> 3.26.0)
|
@@ -51,9 +52,10 @@ GEM
|
|
51
52
|
kramdown (~> 2.0)
|
52
53
|
localhost (1.1.9)
|
53
54
|
minitest (5.11.3)
|
55
|
+
modulation (1.1)
|
54
56
|
msgpack (1.4.2)
|
55
57
|
multipart-post (2.1.1)
|
56
|
-
papercraft (0.
|
58
|
+
papercraft (0.14)
|
57
59
|
escape_utils (= 1.2.1)
|
58
60
|
kramdown (~> 2.3.0)
|
59
61
|
kramdown-parser-gfm (~> 1.1.0)
|
data/README.md
CHANGED
@@ -1,2 +1,44 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
<h1 align="center">
|
2
|
+
Impression
|
3
|
+
</h1>
|
4
|
+
|
5
|
+
<h4 align="center">A modern web framework for Ruby</h4>
|
6
|
+
|
7
|
+
<p align="center">
|
8
|
+
<a href="http://rubygems.org/gems/impression">
|
9
|
+
<img src="https://badge.fury.io/rb/impression.svg" alt="Ruby gem">
|
10
|
+
</a>
|
11
|
+
<a href="https://github.com/digital-fabric/impression/actions?query=workflow%3ATests">
|
12
|
+
<img src="https://github.com/digital-fabric/impression/workflows/Tests/badge.svg" alt="Tests">
|
13
|
+
</a>
|
14
|
+
<a href="https://github.com/digital-fabric/impression/blob/master/LICENSE">
|
15
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
|
16
|
+
</a>
|
17
|
+
</p>
|
18
|
+
|
19
|
+
## What is Impression
|
20
|
+
|
21
|
+
> Impression is still in a very early stage of development. Things might not
|
22
|
+
> correctly, or not at all.
|
23
|
+
|
24
|
+
Impression is a modern web framework for Ruby. Unlike other web framework,
|
25
|
+
Impression does not impose any rigid structure or paradigm, but instead provides
|
26
|
+
a set of tools letting you build any kind of web app, by freely mixing different
|
27
|
+
kinds of web resources, be they static files, structured templates, Jamstack
|
28
|
+
sites, or dynamic APIs.
|
29
|
+
|
30
|
+
In Impression, resources can be composed into a hierarchical tree, allowing
|
31
|
+
combining of multiple web apps, or web subsystems, into a single URL hierarchy.
|
32
|
+
|
33
|
+
Impression is made for running on top of
|
34
|
+
[Tipi](https://github.com/digital-fabric/tipi), a new all-in-one web server for
|
35
|
+
Ruby.
|
36
|
+
|
37
|
+
## I want to know more
|
38
|
+
|
39
|
+
Further documentation is coming real soon (TM)...
|
40
|
+
|
41
|
+
## Contributing
|
42
|
+
|
43
|
+
Contributions in the form of issues, PRs or comments will be greatly
|
44
|
+
appreciated!
|
data/impression.gemspec
CHANGED
@@ -28,7 +28,8 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_runtime_dependency 'kramdown-parser-gfm', '~>1.1.0'
|
29
29
|
|
30
30
|
# s.add_runtime_dependency 'rb-inotify', '~>0.10.1'
|
31
|
-
s.add_runtime_dependency 'papercraft', '~>0.
|
31
|
+
s.add_runtime_dependency 'papercraft', '~>0.14'
|
32
|
+
s.add_runtime_dependency 'modulation', '~>1.1'
|
32
33
|
|
33
34
|
|
34
35
|
s.add_development_dependency 'rake', '~>12.3.3'
|
data/lib/impression/file_tree.rb
CHANGED
@@ -22,9 +22,9 @@ module Impression
|
|
22
22
|
#
|
23
23
|
# @param req [Qeweney::Request] request
|
24
24
|
# @return [void]
|
25
|
-
def
|
25
|
+
def call(req)
|
26
26
|
path_info = get_path_info(req.resource_relative_path)
|
27
|
-
render_from_path_info(req,
|
27
|
+
render_from_path_info(req, path_info)
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
@@ -34,56 +34,91 @@ module Impression
|
|
34
34
|
# @param req [Qeweney::Request] request
|
35
35
|
# @param kind [Symbol] path kind (`:not_found` or `:file`)
|
36
36
|
# @param path [String, nil] file path
|
37
|
-
def render_from_path_info(req,
|
38
|
-
case kind
|
37
|
+
def render_from_path_info(req, path_info)
|
38
|
+
case path_info[:kind]
|
39
39
|
when :not_found
|
40
40
|
req.respond(nil, ':status' => Qeweney::Status::NOT_FOUND)
|
41
41
|
when :file
|
42
|
-
req
|
42
|
+
render_file(req, path_info)
|
43
43
|
else
|
44
44
|
raise "Invalid path info kind #{kind.inspect}"
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
private
|
49
|
+
|
50
|
+
# Renders a file response for the given request and the given path info.
|
51
|
+
#
|
52
|
+
# @param req [Qeweney::Request] request
|
53
|
+
# @param path_info [Hash] path info
|
54
|
+
# @return [void]
|
55
|
+
def render_file(req, path_info)
|
56
|
+
req.serve_file(path_info[:path])
|
57
|
+
end
|
58
|
+
|
48
59
|
# Returns the path info for the given relative path.
|
49
60
|
#
|
50
61
|
# @param path [String] relative path
|
51
|
-
# @return [
|
62
|
+
# @return [Hash] path info
|
52
63
|
def get_path_info(path)
|
53
|
-
@path_info_cache[path]
|
64
|
+
@path_info_cache[path] ||= calculate_path_info(path)
|
54
65
|
end
|
55
66
|
|
56
67
|
# Calculates the path info for the given relative path.
|
57
68
|
#
|
58
69
|
# @param path [String] relative path
|
59
|
-
# @param
|
60
|
-
# @return [
|
61
|
-
def calculate_path_info(path
|
70
|
+
# @param add_ext [bool] whether to add .html extension if not found
|
71
|
+
# @return [Hash] path info
|
72
|
+
def calculate_path_info(path)
|
62
73
|
full_path = File.join(@directory, path)
|
63
74
|
|
64
|
-
|
75
|
+
path_info(full_path) || search_path_info_with_extension(full_path) || { kind: :not_found }
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the path info for the given path. If the path refers to a file,
|
79
|
+
# returns a hash containing the file information. If the path refers to a
|
80
|
+
# directory, performs a search for an index file using #directory_path_info.
|
81
|
+
# Otherwise, returns nil.
|
82
|
+
#
|
83
|
+
# @param path [String] path
|
84
|
+
# @return [Hash, nil] path info
|
85
|
+
def path_info(path)
|
86
|
+
stat = File.stat(path) rescue nil
|
65
87
|
if !stat
|
66
|
-
|
67
|
-
calculate_path_info("#{path}.html", false) : [:not_found]
|
88
|
+
nil
|
68
89
|
elsif stat.directory?
|
69
|
-
return
|
90
|
+
return directory_path_info(path)
|
70
91
|
else
|
71
|
-
return
|
92
|
+
return { kind: :file, path: path, ext: File.extname(path) }
|
72
93
|
end
|
73
94
|
end
|
74
95
|
|
75
|
-
# Calculates the path info for a directory. If an
|
76
|
-
#
|
96
|
+
# Calculates the path info for a directory. If an index file exists, its
|
97
|
+
# path info is returned, otherwise, returns nil.
|
77
98
|
#
|
78
99
|
# @param path [String] directory path
|
79
|
-
# @return [
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
100
|
+
# @return [Hash, nil] path info
|
101
|
+
def directory_path_info(path)
|
102
|
+
search_path_info_with_extension(File.join(path, 'index'))
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns the supported path extensions for paths without extension.
|
106
|
+
#
|
107
|
+
# @return [Array] supported extensions
|
108
|
+
def supported_path_extensions
|
109
|
+
[:html]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Searches for files with extensions for the given path.
|
113
|
+
#
|
114
|
+
# @param path [String] path
|
115
|
+
# @return [Hash, nil] path info
|
116
|
+
def search_path_info_with_extension(path)
|
117
|
+
supported_path_extensions.each do |ext|
|
118
|
+
info = path_info("#{path}.#{ext}")
|
119
|
+
return info if info
|
86
120
|
end
|
121
|
+
nil
|
87
122
|
end
|
88
123
|
end
|
89
124
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'yaml'
|
5
|
+
require 'modulation'
|
6
|
+
require 'papercraft'
|
7
|
+
|
8
|
+
require_relative './resource'
|
9
|
+
require_relative './file_tree'
|
10
|
+
|
11
|
+
module Impression
|
12
|
+
|
13
|
+
# `Jamstack` implements a resource that maps to a Jamstack app directory.
|
14
|
+
class Jamstack < FileTree
|
15
|
+
def initialize(**props)
|
16
|
+
super
|
17
|
+
@layouts = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Renders a file response for the given request and the given path info.
|
23
|
+
#
|
24
|
+
# @param req [Qeweney::Request] request
|
25
|
+
# @param path_info [Hash] path info
|
26
|
+
# @return [void]
|
27
|
+
def render_file(req, path_info)
|
28
|
+
case path_info[:ext]
|
29
|
+
when '.rb'
|
30
|
+
render_papercraft_module(req, path_info[:path])
|
31
|
+
when '.md'
|
32
|
+
render_markdown_file(req, path_info[:path])
|
33
|
+
else
|
34
|
+
req.serve_file(path_info[:path])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Renders a Papercraft module. The module is loaded using Modulation.
|
39
|
+
#
|
40
|
+
# @param req [Qeweney::Request] reqest
|
41
|
+
# @param path [String] file path
|
42
|
+
# @return [void]
|
43
|
+
def render_papercraft_module(req, path)
|
44
|
+
mod = import path
|
45
|
+
|
46
|
+
html = H(mod).render
|
47
|
+
req.respond(html, 'Content-Type' => Qeweney::MimeTypes[:html])
|
48
|
+
end
|
49
|
+
|
50
|
+
# Renders a markdown file using a layout.
|
51
|
+
#
|
52
|
+
# @param req [Qeweney::Request] reqest
|
53
|
+
# @param path [String] file path
|
54
|
+
# @return [void]
|
55
|
+
def render_markdown_file(req, path)
|
56
|
+
attributes, markdown = parse_markdown_file(path)
|
57
|
+
|
58
|
+
layout = get_layout(attributes[:layout])
|
59
|
+
|
60
|
+
html = layout.render(**attributes) { emit_markdown markdown }
|
61
|
+
req.respond(html, 'Content-Type' => Qeweney::MimeTypes[:html])
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns a layout component based on the given name. The given name
|
65
|
+
# defaults to 'default' if nil.
|
66
|
+
#
|
67
|
+
# @param layout [String, nil] layout name
|
68
|
+
# @return [Papercraft::Component] layout component
|
69
|
+
def get_layout(layout)
|
70
|
+
layout ||= 'default'
|
71
|
+
path = File.join(@directory, "_layouts/#{layout}.rb")
|
72
|
+
raise "Layout not found #{path}" unless File.file?(path)
|
73
|
+
|
74
|
+
import path
|
75
|
+
end
|
76
|
+
|
77
|
+
MARKDOWN_PAGE_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m.freeze
|
78
|
+
|
79
|
+
# Parses the markdown file at the given path.
|
80
|
+
#
|
81
|
+
# @param path [String] file path
|
82
|
+
# @return [Array] an tuple containing properties<Hash>, contents<String>
|
83
|
+
def parse_markdown_file(path)
|
84
|
+
data = IO.read(path) || ''
|
85
|
+
if (m = data.match(MARKDOWN_PAGE_REGEXP))
|
86
|
+
front_matter = m[1]
|
87
|
+
|
88
|
+
[symbolize_keys(YAML.load(front_matter)), m.post_match]
|
89
|
+
else
|
90
|
+
[{}, data]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Converts a hash with string keys to one with symbol keys.
|
95
|
+
#
|
96
|
+
# @param hash [Hash] input hash
|
97
|
+
# @return [Hash] output hash
|
98
|
+
def symbolize_keys(hash)
|
99
|
+
hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns the supported path extensions used for searching for files based
|
103
|
+
# on pretty URLs.
|
104
|
+
#
|
105
|
+
# @return [Array] list of supported path extensions
|
106
|
+
def supported_path_extensions
|
107
|
+
[:html, :rb, :md]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Impression
|
6
|
+
|
7
|
+
module RequestExtensions
|
8
|
+
|
9
|
+
# Response extensions for `Qeweney::Request`
|
10
|
+
module Responses
|
11
|
+
|
12
|
+
TEXT_HEADERS = { 'Content-Type' => Qeweney::MimeTypes[:txt] }.freeze
|
13
|
+
HTML_HEADERS = { 'Content-Type' => Qeweney::MimeTypes[:html] }.freeze
|
14
|
+
JSON_HEADERS = { 'Content-Type' => Qeweney::MimeTypes[:json] }.freeze
|
15
|
+
|
16
|
+
# Send an HTTP response with plain text content. The content type is set
|
17
|
+
# to `text/plain`.
|
18
|
+
#
|
19
|
+
# @param text [String] response body
|
20
|
+
# @param **headers [Hash] additional response headers
|
21
|
+
def respond_text(text, **headers)
|
22
|
+
headers = headers.empty? ? TEXT_HEADERS : headers.merge(TEXT_HEADERS)
|
23
|
+
respond(text, headers)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Send an HTTP response with HTML content. The content type is set to
|
27
|
+
# `text/html`.
|
28
|
+
#
|
29
|
+
# @param html [String] response body
|
30
|
+
# @param **headers [Hash] additional response headers
|
31
|
+
def respond_html(html, **headers)
|
32
|
+
headers = headers.empty? ? HTML_HEADERS : headers.merge(HTML_HEADERS)
|
33
|
+
respond(html, headers)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Send an JSON response. The given object is converted to JSON. The
|
37
|
+
# content type is set to `application/json`.
|
38
|
+
#
|
39
|
+
# @param object [any] object to convert to JSON
|
40
|
+
# @param **headers [Hash] additional response headers
|
41
|
+
def respond_json(object, **headers)
|
42
|
+
headers = headers.empty? ? JSON_HEADERS : headers.merge(JSON_HEADERS)
|
43
|
+
respond(object.to_json, headers)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Impression
|
4
|
+
|
5
|
+
# Extensions for `Qeweney::Request`
|
6
|
+
module RequestExtensions
|
7
|
+
|
8
|
+
# Routing extensions for `Qeweney::Request`
|
9
|
+
module Routing
|
10
|
+
|
11
|
+
# Matches a route regexp against the relative request path. The relative
|
12
|
+
# request path is a separate string (stored in `@resource_relative_path`)
|
13
|
+
# that is updated as routes are matched against it. The `route_regexp`
|
14
|
+
# should be either `nil` for root routes (`/`) or a Regexp of the form
|
15
|
+
# `/^#{route}(\/.*)?$/`. See also `Resource#initialize`.
|
16
|
+
#
|
17
|
+
# @param route_regexp [Regexp, nil] Route regexp to match against
|
18
|
+
# @return [String, nil] The remainder of the path (relative to the route)
|
19
|
+
def match_resource_path?(route_regexp)
|
20
|
+
@resource_relative_path ||= path.dup
|
21
|
+
|
22
|
+
return @resource_relative_path unless route_regexp
|
23
|
+
|
24
|
+
# Simplified logic: no match returns nil, otherwise we set the relative path for
|
25
|
+
@resource_relative_path = match_resource_relative_path(
|
26
|
+
@resource_relative_path, route_regexp
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the relative_path for the latest matched resource
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
def resource_relative_path
|
34
|
+
@resource_relative_path ||= path.dup
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Matches the given path against the given route regexp. If the path matches
|
40
|
+
# the regexp, the relative path for the given route is returned. Otherwise,
|
41
|
+
# this method returns `nil`.
|
42
|
+
#
|
43
|
+
# @param path [String] path to match
|
44
|
+
# @param route_regexp [Regexp] route regexp to match against
|
45
|
+
# @return [String, nil] the relative path for the given route, or nil if no match.
|
46
|
+
def match_resource_relative_path(path, route_regexp)
|
47
|
+
match = path.match(route_regexp)
|
48
|
+
match && (match[1] || '/')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -3,11 +3,13 @@
|
|
3
3
|
require 'qeweney'
|
4
4
|
|
5
5
|
# require_relative './pages'
|
6
|
-
require_relative './
|
6
|
+
require_relative './request_extensions/routing'
|
7
|
+
require_relative './request_extensions/responses'
|
7
8
|
|
8
9
|
# Extensions to `Qeweney::Request`
|
9
10
|
class Qeweney::Request
|
10
11
|
|
11
12
|
# include Impression::Pages::RequestMethods
|
12
|
-
include Impression::
|
13
|
+
include Impression::RequestExtensions::Routing
|
14
|
+
include Impression::RequestExtensions::Responses
|
13
15
|
end
|
data/lib/impression/resource.rb
CHANGED
@@ -71,7 +71,7 @@ module Impression
|
|
71
71
|
#
|
72
72
|
# @param req [Qeweney::Request] request
|
73
73
|
# @return [void]
|
74
|
-
def
|
74
|
+
def call(req)
|
75
75
|
req.respond(nil, ':status' => Qeweney::Status::NOT_FOUND)
|
76
76
|
end
|
77
77
|
|
@@ -122,10 +122,37 @@ module Impression
|
|
122
122
|
def to_proc
|
123
123
|
->(req) do
|
124
124
|
resource = route(req) || self
|
125
|
-
resource.
|
125
|
+
resource.call(req)
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
|
+
# Returns a callable that responds with plain text using the given
|
130
|
+
# parameters.
|
131
|
+
#
|
132
|
+
# @param text [String] response body
|
133
|
+
# @param **headers [Hash] additional response headers
|
134
|
+
def text_response(text, **headers)
|
135
|
+
->(req) { req.respond_text(text, **headers) }
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns a callable that responds with HTML using the given
|
139
|
+
# parameters.
|
140
|
+
#
|
141
|
+
# @param html [String] response body
|
142
|
+
# @param **headers [Hash] additional response headers
|
143
|
+
def html_response(html, **headers)
|
144
|
+
->(req) { req.respond_html(html, **headers) }
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns a callable that responds with JSON using the given
|
148
|
+
# parameters.
|
149
|
+
#
|
150
|
+
# @param object [any] object to be converted to JSON
|
151
|
+
# @param **headers [Hash] additional response headers
|
152
|
+
def json_response(object, **headers)
|
153
|
+
->(req) { req.respond_json(object, **headers) }
|
154
|
+
end
|
155
|
+
|
129
156
|
private
|
130
157
|
|
131
158
|
SLASH_PREFIXED_PATH_REGEXP = /^\//.freeze
|
data/lib/impression/version.rb
CHANGED
data/lib/impression.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -41,33 +41,33 @@ module Minitest::Assertions
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def assert_response exp_body, exp_content_type, req
|
44
|
-
|
45
|
-
assert_equal exp_body,
|
44
|
+
actual = req.response_body
|
45
|
+
assert_equal exp_body.gsub("\n", ''), actual&.gsub("\n", '')
|
46
46
|
|
47
47
|
return unless exp_content_type
|
48
48
|
|
49
49
|
if Symbol === exp_content_type
|
50
50
|
exp_content_type = Qeweney::MimeTypes[exp_content_type]
|
51
51
|
end
|
52
|
-
|
53
|
-
assert_equal exp_content_type,
|
52
|
+
actual = req.response_content_type
|
53
|
+
assert_equal exp_content_type, actual
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
57
|
class Impression::Resource
|
58
|
-
def
|
59
|
-
route(req).
|
58
|
+
def route_and_call(req)
|
59
|
+
route(req).call(req)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
class PathRenderingResource < Impression::Resource
|
64
|
-
def
|
64
|
+
def call(req)
|
65
65
|
req.respond(absolute_path)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
69
|
class CompletePathInfoRenderingResource < Impression::Resource
|
70
|
-
def
|
70
|
+
def call(req)
|
71
71
|
req.respond("#{absolute_path} #{req.resource_relative_path}")
|
72
72
|
end
|
73
73
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
console.log(42);
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Bar</h1>
|
data/test/test_app.rb
CHANGED
data/test/test_file_tree.rb
CHANGED
@@ -30,43 +30,43 @@ class FileTreeTest < MiniTest::Test
|
|
30
30
|
|
31
31
|
def test_file_tree_response
|
32
32
|
req = mock_req(':method' => 'GET', ':path' => '/roo')
|
33
|
-
@file_tree.
|
33
|
+
@file_tree.route_and_call(req)
|
34
34
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
35
35
|
|
36
36
|
req = mock_req(':method' => 'GET', ':path' => '/foo2')
|
37
|
-
@file_tree.
|
37
|
+
@file_tree.route_and_call(req)
|
38
38
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
39
39
|
|
40
40
|
req = mock_req(':method' => 'GET', ':path' => '/bar2')
|
41
|
-
@file_tree.
|
41
|
+
@file_tree.route_and_call(req)
|
42
42
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
43
43
|
|
44
44
|
req = mock_req(':method' => 'GET', ':path' => '/js/a.js')
|
45
|
-
@file_tree.
|
45
|
+
@file_tree.route_and_call(req)
|
46
46
|
assert_response static('js/a.js'), :js, req
|
47
47
|
|
48
48
|
req = mock_req(':method' => 'GET', ':path' => '/foo.html')
|
49
|
-
@file_tree.
|
49
|
+
@file_tree.route_and_call(req)
|
50
50
|
assert_response static('foo.html'), :html, req
|
51
51
|
|
52
52
|
req = mock_req(':method' => 'GET', ':path' => '/foo')
|
53
|
-
@file_tree.
|
53
|
+
@file_tree.route_and_call(req)
|
54
54
|
assert_response static('foo.html'), :html, req
|
55
55
|
|
56
56
|
req = mock_req(':method' => 'GET', ':path' => '/index.html')
|
57
|
-
@file_tree.
|
57
|
+
@file_tree.route_and_call(req)
|
58
58
|
assert_response static('index.html'), :html, req
|
59
59
|
|
60
60
|
req = mock_req(':method' => 'GET', ':path' => '/')
|
61
|
-
@file_tree.
|
61
|
+
@file_tree.route_and_call(req)
|
62
62
|
assert_response static('index.html'), :html, req
|
63
63
|
|
64
64
|
req = mock_req(':method' => 'GET', ':path' => '/bar/index.html')
|
65
|
-
@file_tree.
|
65
|
+
@file_tree.route_and_call(req)
|
66
66
|
assert_response static('bar/index.html'), :html, req
|
67
67
|
|
68
68
|
req = mock_req(':method' => 'GET', ':path' => '/bar')
|
69
|
-
@file_tree.
|
69
|
+
@file_tree.route_and_call(req)
|
70
70
|
assert_response static('bar/index.html'), :html, req
|
71
71
|
end
|
72
72
|
|
@@ -74,43 +74,43 @@ class FileTreeTest < MiniTest::Test
|
|
74
74
|
@file_tree = Impression::FileTree.new(path: '/app', directory: STATIC_PATH)
|
75
75
|
|
76
76
|
req = mock_req(':method' => 'GET', ':path' => '/app/roo')
|
77
|
-
@file_tree.
|
77
|
+
@file_tree.route_and_call(req)
|
78
78
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
79
79
|
|
80
80
|
req = mock_req(':method' => 'GET', ':path' => '/app/foo2')
|
81
|
-
@file_tree.
|
81
|
+
@file_tree.route_and_call(req)
|
82
82
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
83
83
|
|
84
84
|
req = mock_req(':method' => 'GET', ':path' => '/app/bar2')
|
85
|
-
@file_tree.
|
85
|
+
@file_tree.route_and_call(req)
|
86
86
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
87
87
|
|
88
88
|
req = mock_req(':method' => 'GET', ':path' => '/app/js/a.js')
|
89
|
-
@file_tree.
|
89
|
+
@file_tree.route_and_call(req)
|
90
90
|
assert_response static('js/a.js'), :js, req
|
91
91
|
|
92
92
|
req = mock_req(':method' => 'GET', ':path' => '/app/foo.html')
|
93
|
-
@file_tree.
|
93
|
+
@file_tree.route_and_call(req)
|
94
94
|
assert_response static('foo.html'), :html, req
|
95
95
|
|
96
96
|
req = mock_req(':method' => 'GET', ':path' => '/app/foo')
|
97
|
-
@file_tree.
|
97
|
+
@file_tree.route_and_call(req)
|
98
98
|
assert_response static('foo.html'), :html, req
|
99
99
|
|
100
100
|
req = mock_req(':method' => 'GET', ':path' => '/app/index.html')
|
101
|
-
@file_tree.
|
101
|
+
@file_tree.route_and_call(req)
|
102
102
|
assert_response static('index.html'), :html, req
|
103
103
|
|
104
104
|
req = mock_req(':method' => 'GET', ':path' => '/app/')
|
105
|
-
@file_tree.
|
105
|
+
@file_tree.route_and_call(req)
|
106
106
|
assert_response static('index.html'), :html, req
|
107
107
|
|
108
108
|
req = mock_req(':method' => 'GET', ':path' => '/app/bar/index.html')
|
109
|
-
@file_tree.
|
109
|
+
@file_tree.route_and_call(req)
|
110
110
|
assert_response static('bar/index.html'), :html, req
|
111
111
|
|
112
112
|
req = mock_req(':method' => 'GET', ':path' => '/app/bar')
|
113
|
-
@file_tree.
|
113
|
+
@file_tree.route_and_call(req)
|
114
114
|
assert_response static('bar/index.html'), :html, req
|
115
115
|
end
|
116
116
|
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
require 'qeweney/test_adapter'
|
5
|
+
|
6
|
+
class JamstackTest < MiniTest::Test
|
7
|
+
JAMSTACK_PATH = File.join(__dir__, 'jamstack')
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@jamstack = Impression::Jamstack.new(path: '/', directory: JAMSTACK_PATH)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_jamstack_routing
|
14
|
+
req = mock_req(':method' => 'GET', ':path' => '/')
|
15
|
+
assert_equal @jamstack, @jamstack.route(req)
|
16
|
+
|
17
|
+
req = mock_req(':method' => 'GET', ':path' => '/nonexistent')
|
18
|
+
assert_equal @jamstack, @jamstack.route(req)
|
19
|
+
|
20
|
+
req = mock_req(':method' => 'GET', ':path' => '/index.html')
|
21
|
+
assert_equal @jamstack, @jamstack.route(req)
|
22
|
+
|
23
|
+
req = mock_req(':method' => 'GET', ':path' => '/foo')
|
24
|
+
assert_equal @jamstack, @jamstack.route(req)
|
25
|
+
end
|
26
|
+
|
27
|
+
def static(path)
|
28
|
+
IO.read(File.join(JAMSTACK_PATH, path))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_jamstack_response
|
32
|
+
req = mock_req(':method' => 'GET', ':path' => '/roo')
|
33
|
+
@jamstack.route_and_call(req)
|
34
|
+
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
35
|
+
|
36
|
+
req = mock_req(':method' => 'GET', ':path' => '/foo2')
|
37
|
+
@jamstack.route_and_call(req)
|
38
|
+
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
39
|
+
|
40
|
+
req = mock_req(':method' => 'GET', ':path' => '/bar2')
|
41
|
+
@jamstack.route_and_call(req)
|
42
|
+
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
43
|
+
|
44
|
+
req = mock_req(':method' => 'GET', ':path' => '/assets/js/a.js')
|
45
|
+
@jamstack.route_and_call(req)
|
46
|
+
assert_response static('assets/js/a.js'), :js, req
|
47
|
+
|
48
|
+
req = mock_req(':method' => 'GET', ':path' => '/foo')
|
49
|
+
@jamstack.route_and_call(req)
|
50
|
+
|
51
|
+
foo = H {
|
52
|
+
html5 {
|
53
|
+
head {
|
54
|
+
title 'Foo title'
|
55
|
+
}
|
56
|
+
body {
|
57
|
+
h1 'foo'
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
assert_response foo.render, :html, req
|
62
|
+
|
63
|
+
req = mock_req(':method' => 'GET', ':path' => '/index')
|
64
|
+
@jamstack.route_and_call(req)
|
65
|
+
|
66
|
+
index = H {
|
67
|
+
html5 {
|
68
|
+
head {
|
69
|
+
title 'Hello'
|
70
|
+
}
|
71
|
+
body {
|
72
|
+
h1 'Index'
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
assert_response index.render, :html, req
|
77
|
+
|
78
|
+
req = mock_req(':method' => 'GET', ':path' => '/')
|
79
|
+
@jamstack.route_and_call(req)
|
80
|
+
assert_response index.render, :html, req
|
81
|
+
|
82
|
+
req = mock_req(':method' => 'GET', ':path' => '/bar')
|
83
|
+
@jamstack.route_and_call(req)
|
84
|
+
assert_response static('bar.html'), :html, req
|
85
|
+
|
86
|
+
req = mock_req(':method' => 'GET', ':path' => '/baz')
|
87
|
+
@jamstack.route_and_call(req)
|
88
|
+
|
89
|
+
baz_index = H {
|
90
|
+
html5 {
|
91
|
+
head {
|
92
|
+
title 'BarBar'
|
93
|
+
}
|
94
|
+
body {
|
95
|
+
h1 'BarIndex'
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
assert_response baz_index.render, :html, req
|
100
|
+
|
101
|
+
req = mock_req(':method' => 'GET', ':path' => '/articles/a')
|
102
|
+
@jamstack.route_and_call(req)
|
103
|
+
|
104
|
+
a = H {
|
105
|
+
html5 {
|
106
|
+
head {
|
107
|
+
title 'AAA'
|
108
|
+
}
|
109
|
+
body {
|
110
|
+
article {
|
111
|
+
h2 'BBB', id: 'bbb'
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
assert_response a.render, :html, req
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_non_root_file_tree_response
|
120
|
+
@jamstack = Impression::Jamstack.new(path: '/app', directory: JAMSTACK_PATH)
|
121
|
+
|
122
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/roo')
|
123
|
+
@jamstack.route_and_call(req)
|
124
|
+
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
125
|
+
|
126
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/foo2')
|
127
|
+
@jamstack.route_and_call(req)
|
128
|
+
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
129
|
+
|
130
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/bar2')
|
131
|
+
@jamstack.route_and_call(req)
|
132
|
+
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
133
|
+
|
134
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/assets/js/a.js')
|
135
|
+
@jamstack.route_and_call(req)
|
136
|
+
assert_response static('assets/js/a.js'), :js, req
|
137
|
+
|
138
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/foo')
|
139
|
+
@jamstack.route_and_call(req)
|
140
|
+
|
141
|
+
foo = H {
|
142
|
+
html5 {
|
143
|
+
head {
|
144
|
+
title 'Foo title'
|
145
|
+
}
|
146
|
+
body {
|
147
|
+
h1 'foo'
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
assert_response foo.render, :html, req
|
152
|
+
|
153
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/index')
|
154
|
+
@jamstack.route_and_call(req)
|
155
|
+
|
156
|
+
index = H {
|
157
|
+
html5 {
|
158
|
+
head {
|
159
|
+
title 'Hello'
|
160
|
+
}
|
161
|
+
body {
|
162
|
+
h1 'Index'
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
assert_response index.render, :html, req
|
167
|
+
|
168
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/')
|
169
|
+
@jamstack.route_and_call(req)
|
170
|
+
assert_response index.render, :html, req
|
171
|
+
|
172
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/bar')
|
173
|
+
@jamstack.route_and_call(req)
|
174
|
+
assert_response static('bar.html'), :html, req
|
175
|
+
|
176
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/baz')
|
177
|
+
@jamstack.route_and_call(req)
|
178
|
+
|
179
|
+
baz_index = H {
|
180
|
+
html5 {
|
181
|
+
head {
|
182
|
+
title 'BarBar'
|
183
|
+
}
|
184
|
+
body {
|
185
|
+
h1 'BarIndex'
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
assert_response baz_index.render, :html, req
|
190
|
+
|
191
|
+
req = mock_req(':method' => 'GET', ':path' => '/app/articles/a')
|
192
|
+
@jamstack.route_and_call(req)
|
193
|
+
|
194
|
+
a = H {
|
195
|
+
html5 {
|
196
|
+
head {
|
197
|
+
title 'AAA'
|
198
|
+
}
|
199
|
+
body {
|
200
|
+
article {
|
201
|
+
h2 'BBB', id: 'bbb'
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
assert_response a.render, :html, req
|
207
|
+
end
|
208
|
+
end
|
data/test/test_resource.rb
CHANGED
@@ -78,16 +78,16 @@ class ResourceTest < MiniTest::Test
|
|
78
78
|
assert_nil r1.route(req)
|
79
79
|
|
80
80
|
req = mock_req(':method' => 'GET', ':path' => '/foo')
|
81
|
-
r1.
|
81
|
+
r1.route_and_call(req)
|
82
82
|
# default reply
|
83
83
|
assert_equal Qeweney::Status::NOT_FOUND, req.response_status
|
84
84
|
|
85
85
|
req = mock_req(':method' => 'GET', ':path' => '/foo/bar')
|
86
|
-
r1.
|
86
|
+
r1.route_and_call(req)
|
87
87
|
assert_equal '/foo/bar', req.response_body
|
88
88
|
|
89
89
|
req = mock_req(':method' => 'GET', ':path' => '/foo/baz')
|
90
|
-
r1.
|
90
|
+
r1.route_and_call(req)
|
91
91
|
assert_equal '/foo/baz', req.response_body
|
92
92
|
|
93
93
|
req = mock_req(':method' => 'GET', ':path' => '/foo/bbb')
|
@@ -103,27 +103,99 @@ class ResourceTest < MiniTest::Test
|
|
103
103
|
assert_nil r1.route(req)
|
104
104
|
|
105
105
|
req = mock_req(':method' => 'GET', ':path' => '/foo')
|
106
|
-
r1.
|
106
|
+
r1.route_and_call(req)
|
107
107
|
assert_equal '/foo /', req.response_body
|
108
108
|
|
109
109
|
req = mock_req(':method' => 'GET', ':path' => '/foo/zzz')
|
110
|
-
r1.
|
110
|
+
r1.route_and_call(req)
|
111
111
|
assert_equal '/foo /zzz', req.response_body
|
112
112
|
|
113
113
|
req = mock_req(':method' => 'GET', ':path' => '/foo/bar')
|
114
|
-
r1.
|
114
|
+
r1.route_and_call(req)
|
115
115
|
assert_equal '/foo/bar /', req.response_body
|
116
116
|
|
117
117
|
req = mock_req(':method' => 'GET', ':path' => '/foo/bar/zzz')
|
118
|
-
r1.
|
118
|
+
r1.route_and_call(req)
|
119
119
|
assert_equal '/foo/bar /zzz', req.response_body
|
120
120
|
|
121
121
|
req = mock_req(':method' => 'GET', ':path' => '/foo/baz')
|
122
|
-
r1.
|
122
|
+
r1.route_and_call(req)
|
123
123
|
assert_equal '/foo/baz /', req.response_body
|
124
124
|
|
125
125
|
req = mock_req(':method' => 'GET', ':path' => '/foo/baz/xxx/yyy')
|
126
|
-
r1.
|
126
|
+
r1.route_and_call(req)
|
127
127
|
assert_equal '/foo/baz /xxx/yyy', req.response_body
|
128
128
|
end
|
129
|
+
|
130
|
+
class CallableResource < Impression::Resource
|
131
|
+
def initialize(**props, &block)
|
132
|
+
super(**props)
|
133
|
+
@block = block
|
134
|
+
end
|
135
|
+
|
136
|
+
def call(req)
|
137
|
+
@block.call(req)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_callable_resource
|
142
|
+
r1 = CompletePathInfoRenderingResource.new(path: 'foo')
|
143
|
+
r2 = CallableResource.new(parent: r1, path: 'bar') { |req| req.respond('hi') }
|
144
|
+
|
145
|
+
req = mock_req(':method' => 'GET', ':path' => '/foo/bar')
|
146
|
+
r1.route_and_call(req)
|
147
|
+
assert_equal 'hi', req.response_body
|
148
|
+
end
|
149
|
+
|
150
|
+
class CallableRouteResource < Impression::Resource
|
151
|
+
def initialize(**props, &block)
|
152
|
+
super(**props)
|
153
|
+
@block = block
|
154
|
+
end
|
155
|
+
|
156
|
+
def route(req)
|
157
|
+
@block
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_callable_from_route_method
|
162
|
+
r1 = CompletePathInfoRenderingResource.new(path: 'foo')
|
163
|
+
r2 = CallableRouteResource.new(parent: r1, path: 'bar') { |req| req.respond('bye') }
|
164
|
+
|
165
|
+
req = mock_req(':method' => 'GET', ':path' => '/foo/bar')
|
166
|
+
r1.route_and_call(req)
|
167
|
+
assert_equal 'bye', req.response_body
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_text_response
|
171
|
+
c = Class.new(Impression::Resource) do
|
172
|
+
def route(req)
|
173
|
+
case req.path
|
174
|
+
when '/text'
|
175
|
+
text_response('foo')
|
176
|
+
when '/html'
|
177
|
+
html_response('bar')
|
178
|
+
when '/json'
|
179
|
+
json_response({ :baz => 123 })
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
r = c.new(path: '/')
|
185
|
+
|
186
|
+
req = mock_req(':method' => 'GET', ':path' => '/text')
|
187
|
+
r.route_and_call(req)
|
188
|
+
assert_equal 'foo', req.response_body
|
189
|
+
assert_equal 'text/plain', req.response_content_type
|
190
|
+
|
191
|
+
req = mock_req(':method' => 'GET', ':path' => '/html')
|
192
|
+
r.route_and_call(req)
|
193
|
+
assert_equal 'bar', req.response_body
|
194
|
+
assert_equal 'text/html', req.response_content_type
|
195
|
+
|
196
|
+
req = mock_req(':method' => 'GET', ':path' => '/json')
|
197
|
+
r.route_and_call(req)
|
198
|
+
assert_equal '{"baz":123}', req.response_body
|
199
|
+
assert_equal 'application/json', req.response_content_type
|
200
|
+
end
|
129
201
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: impression
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-01-
|
11
|
+
date: 2022-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: polyphony
|
@@ -100,14 +100,28 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0.
|
103
|
+
version: '0.14'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0.
|
110
|
+
version: '0.14'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: modulation
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.1'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.1'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rake
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,12 +191,22 @@ files:
|
|
177
191
|
- lib/impression/errors.rb
|
178
192
|
- lib/impression/file_tree.rb
|
179
193
|
- lib/impression/file_watcher.rb
|
194
|
+
- lib/impression/jamstack.rb
|
180
195
|
- lib/impression/pages.rb
|
181
196
|
- lib/impression/request_extensions.rb
|
182
|
-
- lib/impression/
|
197
|
+
- lib/impression/request_extensions/responses.rb
|
198
|
+
- lib/impression/request_extensions/routing.rb
|
183
199
|
- lib/impression/resource.rb
|
184
200
|
- lib/impression/version.rb
|
185
201
|
- test/helper.rb
|
202
|
+
- test/jamstack/_layouts/article.rb
|
203
|
+
- test/jamstack/_layouts/default.rb
|
204
|
+
- test/jamstack/articles/a.md
|
205
|
+
- test/jamstack/assets/js/a.js
|
206
|
+
- test/jamstack/bar.html
|
207
|
+
- test/jamstack/baz/index.md
|
208
|
+
- test/jamstack/foo.rb
|
209
|
+
- test/jamstack/index.md
|
186
210
|
- test/run.rb
|
187
211
|
- test/static/bar/index.html
|
188
212
|
- test/static/foo.html
|
@@ -191,6 +215,7 @@ files:
|
|
191
215
|
- test/test_app.rb
|
192
216
|
- test/test_file_tree.rb
|
193
217
|
- test/test_file_watcher.rb
|
218
|
+
- test/test_jamstack.rb
|
194
219
|
- test/test_resource.rb
|
195
220
|
homepage: http://github.com/digital-fabric/impression
|
196
221
|
licenses:
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'fileutils'
|
4
|
-
|
5
|
-
module Impression
|
6
|
-
|
7
|
-
# Request routing extensions for `Qeweney::Request`
|
8
|
-
module RequestRouting
|
9
|
-
|
10
|
-
# Matches a route regexp against the relative request path. The relative
|
11
|
-
# request path is a separate string (stored in `@resource_relative_path`)
|
12
|
-
# that is updated as routes are matched against it. The `route_regexp`
|
13
|
-
# should be either `nil` for root routes (`/`) or a Regexp of the form
|
14
|
-
# `/^#{route}(\/.*)?$/`. See also `Resource#initialize`.
|
15
|
-
#
|
16
|
-
# @param route_regexp [Regexp, nil] Route regexp to match against
|
17
|
-
# @return [String, nil] The remainder of the path (relative to the route)
|
18
|
-
def match_resource_path?(route_regexp)
|
19
|
-
@resource_relative_path ||= path.dup
|
20
|
-
|
21
|
-
return @resource_relative_path unless route_regexp
|
22
|
-
|
23
|
-
# Simplified logic: no match returns nil, otherwise we set the relative path for
|
24
|
-
@resource_relative_path = match_resource_relative_path(
|
25
|
-
@resource_relative_path, route_regexp
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
# Returns the relative_path for the latest matched resource
|
30
|
-
#
|
31
|
-
# @return [String]
|
32
|
-
def resource_relative_path
|
33
|
-
@resource_relative_path ||= path.dup
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
# Matches the given path against the given route regexp. If the path matches
|
39
|
-
# the regexp, the relative path for the given route is returned. Otherwise,
|
40
|
-
# this method returns `nil`.
|
41
|
-
#
|
42
|
-
# @param path [String] path to match
|
43
|
-
# @param route_regexp [Regexp] route regexp to match against
|
44
|
-
# @return [String, nil] the relative path for the given route, or nil if no match.
|
45
|
-
def match_resource_relative_path(path, route_regexp)
|
46
|
-
match = path.match(route_regexp)
|
47
|
-
match && (match[1] || '/')
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|