acrylic 0.5.2 → 0.6.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e739118d6cf518903dd20c939bd18552f9fcf0699b8648efc863141123aba5e
4
- data.tar.gz: 7ca4592977d596c485a66e5a5c1b274fac907424890db3c2f4dd983895b67ea0
3
+ metadata.gz: e21e606a2d68bf4cc97534f5d0e06c5e9686f0bfa4313179ff239807a90376e2
4
+ data.tar.gz: acd7f1824517fe77cf9dd230e2dfe28912744d33626786e74f4f2ec3ce9215e2
5
5
  SHA512:
6
- metadata.gz: 640a3ba084793e287b67e84218538bbba1cab1d3a5d808d7cbfae9e5c3221584eca5c641292dd5cb239b812eddf7235db951de76905b1e878797385206e45670
7
- data.tar.gz: fe8a542ad92db75e0cab799fea386b88bb193332e4594458a105bbc078f24f7bb5ddae13908610a42c3769dd73b3d77c86cc4107b0d601eff51df2d69940a09a
6
+ metadata.gz: 57e9a45b77cca74f3d4f1294db47be8276c410618334f32c57b38a2ecad563e45b06a8f664b8a3073d55087188e11ba99163f7c5e0d436c995fdea201b58ceeb
7
+ data.tar.gz: fcaae51e13af4d4141738060c2a15f358d972d8397b25728946e69579ba028d1ec082edf2b016e930a700c4b973879ed37c056340a7f4b00e09ac45bf7e63964
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
- module Acrylic; end
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
@@ -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
- ERROR_ROUTES = []
14
+ ERROR_ROUTES = []
15
15
 
16
- class ErrorRoute < Route
17
- attr_reader :code
16
+ class ErrorRoute < Route
17
+ attr_reader :code
18
18
 
19
- def initialize code, args, handler
20
- @code = code
21
- super args, handler
22
- end
19
+ def initialize code, args, handler
20
+ @code = code
21
+ super args, handler
22
+ end
23
23
 
24
- def match? code, req
25
- (@code == code) and super req
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
- class Cascade
30
- def self.default_error_body code, req
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
50
-
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 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
- # returns body of response.
89
- def self.error_body code, req
90
- route = ERROR_ROUTES.find do |route| route.match? code, req end
91
- if route.nil? then default_error_body code, req else route.call req end
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
- args = (Hash.from_keys wargs).merge kwargs
99
- Acrylic::ERROR_ROUTES << (Acrylic::ErrorRoute.new code, args, route)
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 = handler
14
-
15
- @priority = args[:priority] or 0 # defualt priority
16
- @paths = args[:path].containerize
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 do |route| route.priority end.each do |route|
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
- res = route.call config, req, *(route.args_for_path req.path)
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 do |k, v| [k.to_s, v] end.to_h
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
@@ -1,8 +1,8 @@
1
1
  module Acrylic
2
2
  class Version
3
3
  MAJOR = 0
4
- MINOR = 5
5
- HOTFIX = 2
4
+ MINOR = 6
5
+ HOTFIX = 0
6
6
 
7
7
  def self.semver
8
8
  "#{MAJOR}.#{MINOR}.#{HOTFIX}"
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.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fmixolydian
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-01-08 00:00:00.000000000 Z
10
+ date: 2026-01-14 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rack
@@ -65,6 +65,20 @@ 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
83
  Acrylic is a web framework that simplifies your life by automatically generating migrations,
70
84
  as well as providing several macros for repeating common operations (e.g. defining REST APIs).
@@ -72,7 +86,6 @@ 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
- - LicenseRef-COPYING.md OR EUPL-1.2
100
+ - BSD-3-Clause
88
101
  metadata: {}
89
102
  rdoc_options: []
90
103
  require_paths:
data/COPYING.md DELETED
@@ -1,2 +0,0 @@
1
- This project is licensed under any version of the PICO License greater or equal to v2.0.
2
- https://codeberg.org/Pictrel/License/src/branch/v2/PICOLICENSE-2.0