tina4ruby 3.11.13 → 3.11.15
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 +80 -80
- data/LICENSE.txt +21 -21
- data/README.md +137 -137
- data/exe/tina4ruby +5 -5
- data/lib/tina4/ai.rb +696 -696
- data/lib/tina4/api.rb +189 -189
- data/lib/tina4/auth.rb +305 -305
- data/lib/tina4/auto_crud.rb +244 -244
- data/lib/tina4/cache.rb +154 -154
- data/lib/tina4/cli.rb +1449 -1449
- data/lib/tina4/constants.rb +46 -46
- data/lib/tina4/container.rb +74 -74
- data/lib/tina4/cors.rb +74 -74
- data/lib/tina4/crud.rb +692 -692
- data/lib/tina4/database/sqlite3_adapter.rb +165 -165
- data/lib/tina4/database.rb +625 -625
- data/lib/tina4/database_result.rb +208 -208
- data/lib/tina4/debug.rb +8 -8
- data/lib/tina4/dev.rb +14 -14
- data/lib/tina4/dev_admin.rb +935 -935
- data/lib/tina4/dev_mailbox.rb +191 -191
- data/lib/tina4/drivers/firebird_driver.rb +124 -110
- data/lib/tina4/drivers/mongodb_driver.rb +561 -561
- data/lib/tina4/drivers/mssql_driver.rb +112 -112
- data/lib/tina4/drivers/mysql_driver.rb +90 -90
- data/lib/tina4/drivers/odbc_driver.rb +191 -191
- data/lib/tina4/drivers/postgres_driver.rb +116 -106
- data/lib/tina4/drivers/sqlite_driver.rb +122 -122
- data/lib/tina4/env.rb +95 -95
- data/lib/tina4/error_overlay.rb +252 -252
- data/lib/tina4/events.rb +109 -109
- data/lib/tina4/field_types.rb +154 -154
- data/lib/tina4/frond.rb +2025 -2025
- data/lib/tina4/gallery/auth/meta.json +1 -1
- data/lib/tina4/gallery/auth/src/routes/api/gallery_auth.rb +114 -114
- data/lib/tina4/gallery/database/meta.json +1 -1
- data/lib/tina4/gallery/database/src/routes/api/gallery_db.rb +43 -43
- data/lib/tina4/gallery/error-overlay/meta.json +1 -1
- data/lib/tina4/gallery/error-overlay/src/routes/api/gallery_crash.rb +17 -17
- data/lib/tina4/gallery/orm/meta.json +1 -1
- data/lib/tina4/gallery/orm/src/routes/api/gallery_products.rb +16 -16
- data/lib/tina4/gallery/queue/meta.json +1 -1
- data/lib/tina4/gallery/queue/src/routes/api/gallery_queue.rb +325 -325
- data/lib/tina4/gallery/rest-api/meta.json +1 -1
- data/lib/tina4/gallery/rest-api/src/routes/api/gallery_hello.rb +14 -14
- data/lib/tina4/gallery/templates/meta.json +1 -1
- data/lib/tina4/gallery/templates/src/routes/gallery_page.rb +12 -12
- data/lib/tina4/gallery/templates/src/templates/gallery_page.twig +257 -257
- data/lib/tina4/graphql.rb +966 -966
- data/lib/tina4/health.rb +39 -39
- data/lib/tina4/html_element.rb +170 -170
- data/lib/tina4/job.rb +80 -80
- data/lib/tina4/localization.rb +168 -168
- data/lib/tina4/log.rb +203 -203
- data/lib/tina4/mcp.rb +696 -696
- data/lib/tina4/messenger.rb +587 -587
- data/lib/tina4/metrics.rb +793 -793
- data/lib/tina4/middleware.rb +445 -445
- data/lib/tina4/migration.rb +451 -451
- data/lib/tina4/orm.rb +790 -790
- data/lib/tina4/public/css/tina4.css +2463 -2463
- data/lib/tina4/public/css/tina4.min.css +1 -1
- data/lib/tina4/public/images/logo.svg +5 -5
- data/lib/tina4/public/js/frond.min.js +2 -2
- data/lib/tina4/public/js/tina4-dev-admin.js +565 -565
- data/lib/tina4/public/js/tina4-dev-admin.min.js +480 -480
- data/lib/tina4/public/js/tina4.min.js +92 -92
- data/lib/tina4/public/js/tina4js.min.js +48 -48
- data/lib/tina4/public/swagger/index.html +90 -90
- data/lib/tina4/public/swagger/oauth2-redirect.html +63 -63
- data/lib/tina4/query_builder.rb +380 -380
- data/lib/tina4/queue.rb +366 -366
- data/lib/tina4/queue_backends/kafka_backend.rb +80 -80
- data/lib/tina4/queue_backends/lite_backend.rb +298 -298
- data/lib/tina4/queue_backends/mongo_backend.rb +126 -126
- data/lib/tina4/queue_backends/rabbitmq_backend.rb +73 -73
- data/lib/tina4/rack_app.rb +817 -817
- data/lib/tina4/rate_limiter.rb +130 -130
- data/lib/tina4/request.rb +268 -255
- data/lib/tina4/response.rb +346 -346
- data/lib/tina4/response_cache.rb +551 -551
- data/lib/tina4/router.rb +406 -406
- data/lib/tina4/scss/tina4css/_alerts.scss +34 -34
- data/lib/tina4/scss/tina4css/_badges.scss +22 -22
- data/lib/tina4/scss/tina4css/_buttons.scss +69 -69
- data/lib/tina4/scss/tina4css/_cards.scss +49 -49
- data/lib/tina4/scss/tina4css/_forms.scss +156 -156
- data/lib/tina4/scss/tina4css/_grid.scss +81 -81
- data/lib/tina4/scss/tina4css/_modals.scss +84 -84
- data/lib/tina4/scss/tina4css/_nav.scss +149 -149
- data/lib/tina4/scss/tina4css/_reset.scss +94 -94
- data/lib/tina4/scss/tina4css/_tables.scss +54 -54
- data/lib/tina4/scss/tina4css/_typography.scss +55 -55
- data/lib/tina4/scss/tina4css/_utilities.scss +197 -197
- data/lib/tina4/scss/tina4css/_variables.scss +117 -117
- data/lib/tina4/scss/tina4css/base.scss +1 -1
- data/lib/tina4/scss/tina4css/colors.scss +48 -48
- data/lib/tina4/scss/tina4css/tina4.scss +17 -17
- data/lib/tina4/scss_compiler.rb +178 -178
- data/lib/tina4/seeder.rb +567 -567
- data/lib/tina4/service_runner.rb +303 -303
- data/lib/tina4/session.rb +297 -297
- data/lib/tina4/session_handlers/database_handler.rb +72 -72
- data/lib/tina4/session_handlers/file_handler.rb +67 -67
- data/lib/tina4/session_handlers/mongo_handler.rb +49 -49
- data/lib/tina4/session_handlers/redis_handler.rb +43 -43
- data/lib/tina4/session_handlers/valkey_handler.rb +43 -43
- data/lib/tina4/shutdown.rb +84 -84
- data/lib/tina4/sql_translation.rb +158 -158
- data/lib/tina4/swagger.rb +124 -124
- data/lib/tina4/template.rb +894 -894
- data/lib/tina4/templates/base.twig +26 -26
- data/lib/tina4/templates/errors/302.twig +14 -14
- data/lib/tina4/templates/errors/401.twig +9 -9
- data/lib/tina4/templates/errors/403.twig +29 -29
- data/lib/tina4/templates/errors/404.twig +29 -29
- data/lib/tina4/templates/errors/500.twig +38 -38
- data/lib/tina4/templates/errors/502.twig +9 -9
- data/lib/tina4/templates/errors/503.twig +12 -12
- data/lib/tina4/templates/errors/base.twig +37 -37
- data/lib/tina4/test_client.rb +159 -159
- data/lib/tina4/testing.rb +340 -340
- data/lib/tina4/validator.rb +174 -174
- data/lib/tina4/version.rb +1 -1
- data/lib/tina4/webserver.rb +312 -312
- data/lib/tina4/websocket.rb +343 -343
- data/lib/tina4/websocket_backplane.rb +190 -190
- data/lib/tina4/wsdl.rb +564 -564
- data/lib/tina4.rb +458 -458
- data/lib/tina4ruby.rb +4 -4
- metadata +3 -3
data/lib/tina4/health.rb
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
|
-
module Tina4
|
|
6
|
-
module Health
|
|
7
|
-
START_TIME = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
8
|
-
|
|
9
|
-
class << self
|
|
10
|
-
def register!
|
|
11
|
-
Tina4::Router.add("GET", "/health", method(:handle))
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def handle(_request, response)
|
|
15
|
-
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
16
|
-
uptime = (now - START_TIME).round(2)
|
|
17
|
-
|
|
18
|
-
payload = {
|
|
19
|
-
status: "ok",
|
|
20
|
-
version: Tina4::VERSION,
|
|
21
|
-
uptime: uptime,
|
|
22
|
-
framework: "tina4-ruby"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
response.json(payload)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def status
|
|
29
|
-
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
30
|
-
{
|
|
31
|
-
status: "ok",
|
|
32
|
-
version: Tina4::VERSION,
|
|
33
|
-
uptime: (now - START_TIME).round(2),
|
|
34
|
-
framework: "tina4-ruby"
|
|
35
|
-
}
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Tina4
|
|
6
|
+
module Health
|
|
7
|
+
START_TIME = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def register!
|
|
11
|
+
Tina4::Router.add("GET", "/health", method(:handle))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def handle(_request, response)
|
|
15
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
16
|
+
uptime = (now - START_TIME).round(2)
|
|
17
|
+
|
|
18
|
+
payload = {
|
|
19
|
+
status: "ok",
|
|
20
|
+
version: Tina4::VERSION,
|
|
21
|
+
uptime: uptime,
|
|
22
|
+
framework: "tina4-ruby"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
response.json(payload)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def status
|
|
29
|
+
now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
30
|
+
{
|
|
31
|
+
status: "ok",
|
|
32
|
+
version: Tina4::VERSION,
|
|
33
|
+
uptime: (now - START_TIME).round(2),
|
|
34
|
+
framework: "tina4-ruby"
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/tina4/html_element.rb
CHANGED
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Tina4
|
|
4
|
-
# Programmatic HTML builder — avoids string concatenation.
|
|
5
|
-
#
|
|
6
|
-
# Usage:
|
|
7
|
-
# el = Tina4::HtmlElement.new("div", { class: "card" }, ["Hello"])
|
|
8
|
-
# el.to_s # => '<div class="card">Hello</div>'
|
|
9
|
-
#
|
|
10
|
-
# # Builder pattern (via call)
|
|
11
|
-
# el = Tina4::HtmlElement.new("div").call(Tina4::HtmlElement.new("p").call("Text"))
|
|
12
|
-
#
|
|
13
|
-
# # Helper functions
|
|
14
|
-
# include Tina4::HtmlHelpers
|
|
15
|
-
# html = _div({ class: "card" }, _p("Hello"))
|
|
16
|
-
#
|
|
17
|
-
class HtmlElement
|
|
18
|
-
VOID_TAGS = %w[
|
|
19
|
-
area base br col embed hr img input
|
|
20
|
-
link meta param source track wbr
|
|
21
|
-
].freeze
|
|
22
|
-
|
|
23
|
-
HTML_TAGS = %w[
|
|
24
|
-
a abbr address area article aside audio
|
|
25
|
-
b base bdi bdo blockquote body br button
|
|
26
|
-
canvas caption cite code col colgroup
|
|
27
|
-
data datalist dd del details dfn dialog div dl dt
|
|
28
|
-
em embed
|
|
29
|
-
fieldset figcaption figure footer form
|
|
30
|
-
h1 h2 h3 h4 h5 h6 head header hgroup hr html
|
|
31
|
-
i iframe img input ins
|
|
32
|
-
kbd
|
|
33
|
-
label legend li link
|
|
34
|
-
main map mark menu meta meter
|
|
35
|
-
nav noscript
|
|
36
|
-
object ol optgroup option output
|
|
37
|
-
p param picture pre progress
|
|
38
|
-
q
|
|
39
|
-
rp rt ruby
|
|
40
|
-
s samp script section select slot small source span
|
|
41
|
-
strong style sub summary sup
|
|
42
|
-
table tbody td template textarea tfoot th thead time
|
|
43
|
-
title tr track
|
|
44
|
-
u ul
|
|
45
|
-
var video
|
|
46
|
-
wbr
|
|
47
|
-
].freeze
|
|
48
|
-
|
|
49
|
-
attr_reader :tag, :attrs, :children
|
|
50
|
-
|
|
51
|
-
# @param tag [String] HTML tag name
|
|
52
|
-
# @param attrs [Hash] attribute => value
|
|
53
|
-
# @param children [Array] child elements (strings or HtmlElement instances)
|
|
54
|
-
def initialize(tag, attrs = {}, children = [])
|
|
55
|
-
@tag = tag.to_s.downcase
|
|
56
|
-
@attrs = attrs
|
|
57
|
-
@children = children
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Builder pattern — appends children and/or merges attributes.
|
|
61
|
-
#
|
|
62
|
-
# @param args [Array] Strings, HtmlElements, Hashes (treated as attrs), or Arrays
|
|
63
|
-
# @return [HtmlElement] a new HtmlElement with the appended children
|
|
64
|
-
def call(*args)
|
|
65
|
-
new_attrs = @attrs.dup
|
|
66
|
-
new_children = @children.dup
|
|
67
|
-
|
|
68
|
-
args.each do |arg|
|
|
69
|
-
case arg
|
|
70
|
-
when Hash
|
|
71
|
-
new_attrs = new_attrs.merge(arg)
|
|
72
|
-
when Array
|
|
73
|
-
new_children.concat(arg)
|
|
74
|
-
else
|
|
75
|
-
new_children << arg
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
self.class.new(@tag, new_attrs, new_children)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Render to HTML string.
|
|
83
|
-
def to_s
|
|
84
|
-
html = "<#{@tag}"
|
|
85
|
-
|
|
86
|
-
@attrs.each do |key, value|
|
|
87
|
-
case value
|
|
88
|
-
when true
|
|
89
|
-
html << " #{key}"
|
|
90
|
-
when false, nil
|
|
91
|
-
next
|
|
92
|
-
else
|
|
93
|
-
escaped = value.to_s
|
|
94
|
-
.gsub("&", "&")
|
|
95
|
-
.gsub('"', """)
|
|
96
|
-
.gsub("<", "<")
|
|
97
|
-
.gsub(">", ">")
|
|
98
|
-
html << " #{key}=\"#{escaped}\""
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
if VOID_TAGS.include?(@tag)
|
|
103
|
-
html << ">"
|
|
104
|
-
return html
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
html << ">"
|
|
108
|
-
|
|
109
|
-
@children.each do |child|
|
|
110
|
-
html << child.to_s
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
html << "</#{@tag}>"
|
|
114
|
-
html
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# Module providing _div, _p, _span, etc. helper methods.
|
|
119
|
-
# Include in any class or use extend on a module.
|
|
120
|
-
module HtmlHelpers
|
|
121
|
-
HtmlElement::HTML_TAGS.each do |tag|
|
|
122
|
-
define_method("_#{tag}") do |*args|
|
|
123
|
-
attrs = {}
|
|
124
|
-
children = []
|
|
125
|
-
|
|
126
|
-
args.each do |arg|
|
|
127
|
-
case arg
|
|
128
|
-
when Hash
|
|
129
|
-
attrs = attrs.merge(arg)
|
|
130
|
-
when Array
|
|
131
|
-
children.concat(arg)
|
|
132
|
-
when HtmlElement
|
|
133
|
-
children << arg
|
|
134
|
-
else
|
|
135
|
-
children << arg
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
HtmlElement.new(tag, attrs, children)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# Module-level convenience: Tina4.html_helpers returns a module you can include.
|
|
145
|
-
def self.html_helpers
|
|
146
|
-
HtmlHelpers
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Inject _div(), _p(), _a(), etc. helper methods into the given namespace (hash or object).
|
|
150
|
-
#
|
|
151
|
-
# Usage:
|
|
152
|
-
# h = {}
|
|
153
|
-
# Tina4.add_html_helpers(h)
|
|
154
|
-
# h[:_div].call({ class: "card" }, h[:_p].call("Hello"))
|
|
155
|
-
#
|
|
156
|
-
def self.add_html_helpers(namespace)
|
|
157
|
-
helper = Object.new.extend(HtmlHelpers)
|
|
158
|
-
|
|
159
|
-
HtmlElement::HTML_TAGS.each do |tag|
|
|
160
|
-
name = "_#{tag}"
|
|
161
|
-
fn = helper.method(name.to_sym)
|
|
162
|
-
|
|
163
|
-
if namespace.is_a?(Hash)
|
|
164
|
-
namespace[name.to_sym] = fn
|
|
165
|
-
else
|
|
166
|
-
namespace.define_singleton_method(name.to_sym, &fn)
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Tina4
|
|
4
|
+
# Programmatic HTML builder — avoids string concatenation.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# el = Tina4::HtmlElement.new("div", { class: "card" }, ["Hello"])
|
|
8
|
+
# el.to_s # => '<div class="card">Hello</div>'
|
|
9
|
+
#
|
|
10
|
+
# # Builder pattern (via call)
|
|
11
|
+
# el = Tina4::HtmlElement.new("div").call(Tina4::HtmlElement.new("p").call("Text"))
|
|
12
|
+
#
|
|
13
|
+
# # Helper functions
|
|
14
|
+
# include Tina4::HtmlHelpers
|
|
15
|
+
# html = _div({ class: "card" }, _p("Hello"))
|
|
16
|
+
#
|
|
17
|
+
class HtmlElement
|
|
18
|
+
VOID_TAGS = %w[
|
|
19
|
+
area base br col embed hr img input
|
|
20
|
+
link meta param source track wbr
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
HTML_TAGS = %w[
|
|
24
|
+
a abbr address area article aside audio
|
|
25
|
+
b base bdi bdo blockquote body br button
|
|
26
|
+
canvas caption cite code col colgroup
|
|
27
|
+
data datalist dd del details dfn dialog div dl dt
|
|
28
|
+
em embed
|
|
29
|
+
fieldset figcaption figure footer form
|
|
30
|
+
h1 h2 h3 h4 h5 h6 head header hgroup hr html
|
|
31
|
+
i iframe img input ins
|
|
32
|
+
kbd
|
|
33
|
+
label legend li link
|
|
34
|
+
main map mark menu meta meter
|
|
35
|
+
nav noscript
|
|
36
|
+
object ol optgroup option output
|
|
37
|
+
p param picture pre progress
|
|
38
|
+
q
|
|
39
|
+
rp rt ruby
|
|
40
|
+
s samp script section select slot small source span
|
|
41
|
+
strong style sub summary sup
|
|
42
|
+
table tbody td template textarea tfoot th thead time
|
|
43
|
+
title tr track
|
|
44
|
+
u ul
|
|
45
|
+
var video
|
|
46
|
+
wbr
|
|
47
|
+
].freeze
|
|
48
|
+
|
|
49
|
+
attr_reader :tag, :attrs, :children
|
|
50
|
+
|
|
51
|
+
# @param tag [String] HTML tag name
|
|
52
|
+
# @param attrs [Hash] attribute => value
|
|
53
|
+
# @param children [Array] child elements (strings or HtmlElement instances)
|
|
54
|
+
def initialize(tag, attrs = {}, children = [])
|
|
55
|
+
@tag = tag.to_s.downcase
|
|
56
|
+
@attrs = attrs
|
|
57
|
+
@children = children
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Builder pattern — appends children and/or merges attributes.
|
|
61
|
+
#
|
|
62
|
+
# @param args [Array] Strings, HtmlElements, Hashes (treated as attrs), or Arrays
|
|
63
|
+
# @return [HtmlElement] a new HtmlElement with the appended children
|
|
64
|
+
def call(*args)
|
|
65
|
+
new_attrs = @attrs.dup
|
|
66
|
+
new_children = @children.dup
|
|
67
|
+
|
|
68
|
+
args.each do |arg|
|
|
69
|
+
case arg
|
|
70
|
+
when Hash
|
|
71
|
+
new_attrs = new_attrs.merge(arg)
|
|
72
|
+
when Array
|
|
73
|
+
new_children.concat(arg)
|
|
74
|
+
else
|
|
75
|
+
new_children << arg
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
self.class.new(@tag, new_attrs, new_children)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Render to HTML string.
|
|
83
|
+
def to_s
|
|
84
|
+
html = "<#{@tag}"
|
|
85
|
+
|
|
86
|
+
@attrs.each do |key, value|
|
|
87
|
+
case value
|
|
88
|
+
when true
|
|
89
|
+
html << " #{key}"
|
|
90
|
+
when false, nil
|
|
91
|
+
next
|
|
92
|
+
else
|
|
93
|
+
escaped = value.to_s
|
|
94
|
+
.gsub("&", "&")
|
|
95
|
+
.gsub('"', """)
|
|
96
|
+
.gsub("<", "<")
|
|
97
|
+
.gsub(">", ">")
|
|
98
|
+
html << " #{key}=\"#{escaped}\""
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if VOID_TAGS.include?(@tag)
|
|
103
|
+
html << ">"
|
|
104
|
+
return html
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
html << ">"
|
|
108
|
+
|
|
109
|
+
@children.each do |child|
|
|
110
|
+
html << child.to_s
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
html << "</#{@tag}>"
|
|
114
|
+
html
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Module providing _div, _p, _span, etc. helper methods.
|
|
119
|
+
# Include in any class or use extend on a module.
|
|
120
|
+
module HtmlHelpers
|
|
121
|
+
HtmlElement::HTML_TAGS.each do |tag|
|
|
122
|
+
define_method("_#{tag}") do |*args|
|
|
123
|
+
attrs = {}
|
|
124
|
+
children = []
|
|
125
|
+
|
|
126
|
+
args.each do |arg|
|
|
127
|
+
case arg
|
|
128
|
+
when Hash
|
|
129
|
+
attrs = attrs.merge(arg)
|
|
130
|
+
when Array
|
|
131
|
+
children.concat(arg)
|
|
132
|
+
when HtmlElement
|
|
133
|
+
children << arg
|
|
134
|
+
else
|
|
135
|
+
children << arg
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
HtmlElement.new(tag, attrs, children)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Module-level convenience: Tina4.html_helpers returns a module you can include.
|
|
145
|
+
def self.html_helpers
|
|
146
|
+
HtmlHelpers
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Inject _div(), _p(), _a(), etc. helper methods into the given namespace (hash or object).
|
|
150
|
+
#
|
|
151
|
+
# Usage:
|
|
152
|
+
# h = {}
|
|
153
|
+
# Tina4.add_html_helpers(h)
|
|
154
|
+
# h[:_div].call({ class: "card" }, h[:_p].call("Hello"))
|
|
155
|
+
#
|
|
156
|
+
def self.add_html_helpers(namespace)
|
|
157
|
+
helper = Object.new.extend(HtmlHelpers)
|
|
158
|
+
|
|
159
|
+
HtmlElement::HTML_TAGS.each do |tag|
|
|
160
|
+
name = "_#{tag}"
|
|
161
|
+
fn = helper.method(name.to_sym)
|
|
162
|
+
|
|
163
|
+
if namespace.is_a?(Hash)
|
|
164
|
+
namespace[name.to_sym] = fn
|
|
165
|
+
else
|
|
166
|
+
namespace.define_singleton_method(name.to_sym, &fn)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
data/lib/tina4/job.rb
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
require "json"
|
|
3
|
-
require "securerandom"
|
|
4
|
-
|
|
5
|
-
module Tina4
|
|
6
|
-
class Job
|
|
7
|
-
attr_reader :id, :topic, :payload, :created_at, :attempts, :priority, :available_at
|
|
8
|
-
attr_accessor :status
|
|
9
|
-
|
|
10
|
-
def initialize(topic:, payload:, id: nil, priority: 0, available_at: nil, attempts: 0, queue: nil)
|
|
11
|
-
@id = id || SecureRandom.uuid
|
|
12
|
-
@topic = topic
|
|
13
|
-
@payload = payload
|
|
14
|
-
@created_at = Time.now
|
|
15
|
-
@attempts = attempts
|
|
16
|
-
@priority = priority
|
|
17
|
-
@available_at = available_at
|
|
18
|
-
@status = :pending
|
|
19
|
-
@queue = queue
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Re-queue this message with incremented attempts.
|
|
23
|
-
# Uses the stored queue reference (set at construction time).
|
|
24
|
-
def retry(delay_seconds: 0)
|
|
25
|
-
q = @queue
|
|
26
|
-
raise ArgumentError, "No queue reference — set at construction" unless q
|
|
27
|
-
|
|
28
|
-
@attempts += 1
|
|
29
|
-
@status = :pending
|
|
30
|
-
@available_at = delay_seconds > 0 ? Time.now + delay_seconds : nil
|
|
31
|
-
q.backend.enqueue(self)
|
|
32
|
-
self
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def to_array
|
|
36
|
-
[@id, @topic, @payload, @priority, @attempts]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def to_hash
|
|
40
|
-
h = {
|
|
41
|
-
id: @id,
|
|
42
|
-
topic: @topic,
|
|
43
|
-
payload: @payload,
|
|
44
|
-
created_at: @created_at.iso8601,
|
|
45
|
-
attempts: @attempts,
|
|
46
|
-
status: @status,
|
|
47
|
-
priority: @priority
|
|
48
|
-
}
|
|
49
|
-
h[:available_at] = @available_at.iso8601 if @available_at
|
|
50
|
-
h
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def to_json(*_args)
|
|
54
|
-
JSON.generate(to_hash)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def increment_attempts!
|
|
58
|
-
@attempts += 1
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Mark this job as completed.
|
|
62
|
-
def complete
|
|
63
|
-
@status = :completed
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Mark this job as failed with a reason.
|
|
67
|
-
def fail(reason = "")
|
|
68
|
-
@status = :failed
|
|
69
|
-
@error = reason
|
|
70
|
-
@attempts += 1
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Reject this job with a reason. Alias for fail().
|
|
74
|
-
def reject(reason = "")
|
|
75
|
-
fail(reason)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
attr_reader :error
|
|
79
|
-
end
|
|
80
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "json"
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module Tina4
|
|
6
|
+
class Job
|
|
7
|
+
attr_reader :id, :topic, :payload, :created_at, :attempts, :priority, :available_at
|
|
8
|
+
attr_accessor :status
|
|
9
|
+
|
|
10
|
+
def initialize(topic:, payload:, id: nil, priority: 0, available_at: nil, attempts: 0, queue: nil)
|
|
11
|
+
@id = id || SecureRandom.uuid
|
|
12
|
+
@topic = topic
|
|
13
|
+
@payload = payload
|
|
14
|
+
@created_at = Time.now
|
|
15
|
+
@attempts = attempts
|
|
16
|
+
@priority = priority
|
|
17
|
+
@available_at = available_at
|
|
18
|
+
@status = :pending
|
|
19
|
+
@queue = queue
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Re-queue this message with incremented attempts.
|
|
23
|
+
# Uses the stored queue reference (set at construction time).
|
|
24
|
+
def retry(delay_seconds: 0)
|
|
25
|
+
q = @queue
|
|
26
|
+
raise ArgumentError, "No queue reference — set at construction" unless q
|
|
27
|
+
|
|
28
|
+
@attempts += 1
|
|
29
|
+
@status = :pending
|
|
30
|
+
@available_at = delay_seconds > 0 ? Time.now + delay_seconds : nil
|
|
31
|
+
q.backend.enqueue(self)
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_array
|
|
36
|
+
[@id, @topic, @payload, @priority, @attempts]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_hash
|
|
40
|
+
h = {
|
|
41
|
+
id: @id,
|
|
42
|
+
topic: @topic,
|
|
43
|
+
payload: @payload,
|
|
44
|
+
created_at: @created_at.iso8601,
|
|
45
|
+
attempts: @attempts,
|
|
46
|
+
status: @status,
|
|
47
|
+
priority: @priority
|
|
48
|
+
}
|
|
49
|
+
h[:available_at] = @available_at.iso8601 if @available_at
|
|
50
|
+
h
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def to_json(*_args)
|
|
54
|
+
JSON.generate(to_hash)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def increment_attempts!
|
|
58
|
+
@attempts += 1
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Mark this job as completed.
|
|
62
|
+
def complete
|
|
63
|
+
@status = :completed
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Mark this job as failed with a reason.
|
|
67
|
+
def fail(reason = "")
|
|
68
|
+
@status = :failed
|
|
69
|
+
@error = reason
|
|
70
|
+
@attempts += 1
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Reject this job with a reason. Alias for fail().
|
|
74
|
+
def reject(reason = "")
|
|
75
|
+
fail(reason)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
attr_reader :error
|
|
79
|
+
end
|
|
80
|
+
end
|