acrylic 0.5.2 → 0.6.1
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/lib/acrylic.rb +26 -1
- data/lib/cascade/errors.rb +85 -72
- data/lib/cascade.rb +28 -9
- data/lib/version.rb +2 -2
- metadata +19 -6
- data/COPYING.md +0 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 580055a09b23911e2449a8a676b3fa9889914a67c1d28582db1f569ec31c9713
|
|
4
|
+
data.tar.gz: 55db4c45b279807036c3bfde7174849bf196e485f46d6c4d4eddaf5264d025c0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4c8309dbd48e90a28078e1fbff90993b1914bc667d3a6ffb64ce6e4c0c200cb753154577073b97011bc60bf2e0e8dc55525d3495109b100f25a66dfea24a4c3e
|
|
7
|
+
data.tar.gz: b406bc59fb25686c0f6836bef6dbcb874f3842453ea4298b23b75ee7c479967d623621fb1cf38c6c5883e8b3febc18d68a20efda119e23d3dd8844d36f0d3944
|
data/lib/acrylic.rb
CHANGED
|
@@ -4,7 +4,32 @@ require_relative 'cascade'
|
|
|
4
4
|
require_relative 'validator'
|
|
5
5
|
require_relative 'palette'
|
|
6
6
|
|
|
7
|
+
require 'tilt'
|
|
7
8
|
require 'yaml'
|
|
8
9
|
|
|
10
|
+
module Acrylic
|
|
11
|
+
TEMPLATE_CACHE = {}
|
|
12
|
+
INITIALIZERS = Queue.new
|
|
13
|
+
|
|
14
|
+
def self.init!
|
|
15
|
+
until INITIALIZERS.empty?
|
|
16
|
+
INITIALIZERS.deq.call
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# creates an initializer.
|
|
22
|
+
def on_init &proc
|
|
23
|
+
Acrylic::INITIALIZERS << proc
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# load config
|
|
9
27
|
CONFIG = YAML.load File.read "data/config.yml" rescue {}
|
|
10
|
-
|
|
28
|
+
|
|
29
|
+
def render path, args
|
|
30
|
+
if Acrylic::TEMPLATE_CACHE[path].nil?
|
|
31
|
+
Acrylic::TEMPLATE_CACHE[path] = Tilt.new path
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
return Acrylic::TEMPLATE_CACHE.render args
|
|
35
|
+
end
|
data/lib/cascade/errors.rb
CHANGED
|
@@ -11,90 +11,103 @@ require_relative '../version'
|
|
|
11
11
|
Rack::Utils::HTTP_STATUS_CODES[418] = "I'm a Teapot"
|
|
12
12
|
|
|
13
13
|
module Acrylic
|
|
14
|
-
|
|
14
|
+
ERROR_ROUTES = []
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
class ErrorRoute < Route
|
|
17
|
+
attr_reader :code
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
def initialize code, args, handler
|
|
20
|
+
@code = code
|
|
21
|
+
super args, handler
|
|
22
|
+
end
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
end
|
|
24
|
+
def match? code, req
|
|
25
|
+
(@code == code) and super req
|
|
27
26
|
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class Cascade
|
|
30
|
+
def self.default_error_body code, req, *args
|
|
31
|
+
mab = Markaby::Builder.new
|
|
32
|
+
|
|
33
|
+
mab.html do
|
|
34
|
+
style <<-CSS
|
|
35
|
+
body,html { font-family:"arial"; background-color:#fed; height:100%; display:flex; justify-content:center; align-items:center }
|
|
36
|
+
.pane { padding:10px 20px; width:500px; background:#F004; border:5px solid #F006; border-radius:20px; position:absolute }
|
|
37
|
+
.pane .description { padding:10px; background-color:#FFF4; display:flex;gap:5px; flex-direction:column; }
|
|
38
|
+
.pane .description p { margin:0 }
|
|
39
|
+
CSS
|
|
40
|
+
|
|
41
|
+
meta charset: 'utf-8'
|
|
42
|
+
body do
|
|
43
|
+
div.pane do
|
|
44
|
+
p do
|
|
45
|
+
span code, style: "font-size: 5em"
|
|
46
|
+
sub do
|
|
47
|
+
span (Rack::Utils::HTTP_STATUS_CODES[code]&.downcase), style: "font-size: 2em"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
28
50
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
p
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
when 418
|
|
66
|
-
p do "You pathetic attempt at an HTTP Request was so humerous, it even made the webserver laugh." end
|
|
67
|
-
|
|
68
|
-
when 451
|
|
69
|
-
p do "Sorry, but you live in an authoritarian dystopia, and they do not allow you to access this website." end
|
|
70
|
-
|
|
71
|
-
when 429
|
|
72
|
-
h1 do "IT'S TIME TO STOP." end
|
|
73
|
-
h1 do "IT'S TIME TO STOP, OKAY!???" end
|
|
74
|
-
|
|
75
|
-
else
|
|
76
|
-
p do "An error has occured. I have no idea what it is though. ¯\\_(ツ)_/¯" end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
small style: "color: #844; font-weight: bold; padding-top: 20px" do
|
|
81
|
-
em "served by acrylic #{Acrylic::Version.version}"
|
|
82
|
-
end
|
|
83
|
-
end
|
|
51
|
+
div.description do
|
|
52
|
+
case code
|
|
53
|
+
when 400
|
|
54
|
+
p do "Your browser (or HTTP client) sent a request that completely bamboozled the server." end
|
|
55
|
+
p do "If you're a developer, please <strong>RTFM</strong>. If you're a user, please tell the developer to fix their app." end
|
|
56
|
+
|
|
57
|
+
when 403
|
|
58
|
+
p do "You are not allowed to access the resource at this address." end
|
|
59
|
+
p do "A solution would be to mind your own damn business." end
|
|
60
|
+
|
|
61
|
+
when 404
|
|
62
|
+
p do "You've stumbled on a path which maps to <em>nothing</em>." end
|
|
63
|
+
p do "If someone sent you here, please tell them to <strong>fix their hyperlinks</strong>." end
|
|
64
|
+
|
|
65
|
+
when 410
|
|
66
|
+
p "This resource has been deleted. Reduced to ashes. Thrown into the bit bucket - you get my point!"
|
|
67
|
+
|
|
68
|
+
when 418
|
|
69
|
+
p "Your pathetic attempt at an HTTP Request was so humerous, it even made the webserver laugh."
|
|
70
|
+
|
|
71
|
+
when 429
|
|
72
|
+
h1 "IT'S TIME TO STOP."
|
|
73
|
+
h1 "IT'S TIME TO STOP, OKAY!???"
|
|
74
|
+
|
|
75
|
+
when 500
|
|
76
|
+
p "This is fine."
|
|
77
|
+
|
|
78
|
+
when 501
|
|
79
|
+
p "i forgor 💀"
|
|
80
|
+
|
|
81
|
+
when 502
|
|
82
|
+
p "One of the applications that power this website probably imploded on itself."
|
|
83
|
+
|
|
84
|
+
else
|
|
85
|
+
p do "An error has occured. I have no idea what it is though. ¯\\_(ツ)_/¯" end
|
|
84
86
|
end
|
|
85
87
|
end
|
|
86
|
-
end
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
small style: "color: #844; font-weight: bold; padding-top: 20px" do
|
|
90
|
+
em "served by acrylic #{Acrylic::Version.version}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
92
93
|
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# returns body of response.
|
|
98
|
+
def self.error_body code, req, *args
|
|
99
|
+
route = ERROR_ROUTES.find do |route| route.match? code, req end
|
|
100
|
+
if route.nil?
|
|
101
|
+
default_error_body code, req, *args
|
|
102
|
+
else
|
|
103
|
+
route.call req, *args
|
|
104
|
+
end
|
|
93
105
|
end
|
|
106
|
+
end
|
|
94
107
|
end
|
|
95
108
|
|
|
96
109
|
# route should return body of response
|
|
97
110
|
def error_handler code, *wargs, **kwargs, &route
|
|
98
|
-
|
|
99
|
-
|
|
111
|
+
args = (Hash.from_keys wargs).merge kwargs
|
|
112
|
+
Acrylic::ERROR_ROUTES << (Acrylic::ErrorRoute.new code, args, route)
|
|
100
113
|
end
|
data/lib/cascade.rb
CHANGED
|
@@ -8,12 +8,13 @@ module Acrylic
|
|
|
8
8
|
# list of path rules (wildcards or regexps)
|
|
9
9
|
attr_reader :paths
|
|
10
10
|
attr_reader :priority
|
|
11
|
+
attr_reader :name
|
|
11
12
|
|
|
12
13
|
def initialize args, handler
|
|
13
|
-
@handler
|
|
14
|
-
|
|
15
|
-
@priority = args[:priority]
|
|
16
|
-
@paths
|
|
14
|
+
@handler = handler
|
|
15
|
+
@name = args[:name]
|
|
16
|
+
@priority = args[:priority] || 0
|
|
17
|
+
@paths = args[:path].containerize
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
# transforms a rule from string (e.g. "/User/<id>") to wildcard
|
|
@@ -62,16 +63,18 @@ module Acrylic
|
|
|
62
63
|
def self.handle req
|
|
63
64
|
headers = {}
|
|
64
65
|
config = OpenStruct.new
|
|
66
|
+
config.route_chain = []
|
|
65
67
|
|
|
66
68
|
# loop through all the routes to find a final one
|
|
67
69
|
# (and sort them by priority descending and index)
|
|
68
|
-
Acrylic::ROUTES.sort_by_stable
|
|
70
|
+
Acrylic::ROUTES.sort_by_stable { |route| (0 - route.priority) }.each do |route|
|
|
69
71
|
next unless route.match? req
|
|
70
|
-
puts route.priority
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
config.route_chain << route
|
|
74
|
+
res = catch(:response) { invoke route, config, req, *(route.args_for_path req.path) }
|
|
73
75
|
|
|
74
76
|
res = case true
|
|
77
|
+
when (res.is_a? Exception) then return error_body 500, req, config, res # also give it the exception
|
|
75
78
|
when (res.is_a? Rack::Response) then res
|
|
76
79
|
when (res.respond_to? :to_h) then res.to_h
|
|
77
80
|
when (res.is_a? Integer) then Rack::Response.new nil, res
|
|
@@ -103,19 +106,35 @@ module Acrylic
|
|
|
103
106
|
# 1. if res has an empty body, transform it into a full response with cascade/errors
|
|
104
107
|
# why rack uses a goddamn empty array instead of nil i have no clue of
|
|
105
108
|
# (it doesnt give a fuck about strings, but it TURNS NILS INTO ARRAYS!? WHY!? WHY!!!!!!?)
|
|
106
|
-
if res.body == [] then res.body = error_body res.status, req end
|
|
109
|
+
if res.body == [] then res.body = error_body res.status, nil, req end
|
|
107
110
|
|
|
108
111
|
# 3. transform every header key of res into a string
|
|
109
|
-
headers = res.headers.map
|
|
112
|
+
headers = res.headers.map { |k, v| [k.to_s, v] }.to_h
|
|
110
113
|
|
|
111
114
|
Rack::Response.new res.body, res.status, headers
|
|
112
115
|
end
|
|
113
116
|
end
|
|
114
117
|
end
|
|
115
118
|
|
|
119
|
+
# finds the route with a given name
|
|
120
|
+
def route_with_name name
|
|
121
|
+
Acrylic::ROUTES.find { |route| route.name = name }
|
|
122
|
+
end
|
|
123
|
+
|
|
116
124
|
def route *wargs, **kwargs, &route
|
|
117
125
|
args = (Hash.from_keys wargs).merge kwargs
|
|
118
126
|
Acrylic::ROUTES << (Acrylic::Route.new args, Proc.new(&route))
|
|
119
127
|
end
|
|
120
128
|
|
|
129
|
+
def invoke route, conf, req, *args
|
|
130
|
+
begin
|
|
131
|
+
res = (route.call conf, req, *args)
|
|
132
|
+
rescue => error
|
|
133
|
+
throw :response, error
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
throw :response, res unless res.nil?
|
|
137
|
+
throw :response, nil
|
|
138
|
+
end
|
|
139
|
+
|
|
121
140
|
require_relative 'cascade/errors'
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: acrylic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fmixolydian
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-01-
|
|
10
|
+
date: 2026-01-14 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rack
|
|
@@ -65,14 +65,27 @@ dependencies:
|
|
|
65
65
|
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '5.99'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: tilt
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '2.6'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '2.6'
|
|
68
82
|
description: |2
|
|
69
|
-
Acrylic is a web framework
|
|
70
|
-
|
|
83
|
+
Acrylic is a web micro-framework (akin to Sinatra) that simplifies and expedites
|
|
84
|
+
development by using cascading routes.
|
|
71
85
|
executables: []
|
|
72
86
|
extensions: []
|
|
73
87
|
extra_rdoc_files: []
|
|
74
88
|
files:
|
|
75
|
-
- COPYING.md
|
|
76
89
|
- README.md
|
|
77
90
|
- VERSION.md
|
|
78
91
|
- lib/acrylic.rb
|
|
@@ -84,7 +97,7 @@ files:
|
|
|
84
97
|
- lib/version.rb
|
|
85
98
|
homepage: https://codeberg.org/fmixolydian/acrylic
|
|
86
99
|
licenses:
|
|
87
|
-
-
|
|
100
|
+
- BSD-3-Clause
|
|
88
101
|
metadata: {}
|
|
89
102
|
rdoc_options: []
|
|
90
103
|
require_paths:
|
data/COPYING.md
DELETED