impression 0.2 → 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|