tep 0.11.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.
Files changed (193) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/Makefile +134 -0
  4. data/README.md +247 -0
  5. data/SINATRA_COMPAT.md +376 -0
  6. data/bin/tep +2156 -0
  7. data/examples/agentic_chat/README.md +103 -0
  8. data/examples/agentic_chat/app.rb +310 -0
  9. data/examples/api_gateway/README.md +49 -0
  10. data/examples/api_gateway/app.rb +66 -0
  11. data/examples/blog/app.rb +367 -0
  12. data/examples/blog/views/index.erb +36 -0
  13. data/examples/blog/views/login.erb +28 -0
  14. data/examples/blog/views/new_post.erb +25 -0
  15. data/examples/blog/views/show.erb +16 -0
  16. data/examples/chat/app.rb +278 -0
  17. data/examples/chat/assets/logo.svg +13 -0
  18. data/examples/chat/assets/style.css +209 -0
  19. data/examples/chat/views/index.erb +142 -0
  20. data/examples/chatbot/README.md +111 -0
  21. data/examples/chatbot/app.rb +1024 -0
  22. data/examples/chatbot/assets/chat.js +249 -0
  23. data/examples/chatbot/assets/compare.js +93 -0
  24. data/examples/chatbot/assets/markdown.js +84 -0
  25. data/examples/chatbot/assets/style.css +215 -0
  26. data/examples/chatbot/schema.sql +25 -0
  27. data/examples/chatbot/views/compare.erb +43 -0
  28. data/examples/chatbot/views/index.erb +42 -0
  29. data/examples/chatbot/views/login.erb +22 -0
  30. data/examples/chatbot/views/setup.erb +23 -0
  31. data/examples/counter/README.md +68 -0
  32. data/examples/counter/app.rb +85 -0
  33. data/examples/experiments/AGENTS.md +91 -0
  34. data/examples/experiments/README.md +99 -0
  35. data/examples/experiments/app.rb +225 -0
  36. data/examples/geohash/Gemfile +11 -0
  37. data/examples/geohash/Gemfile.lock +17 -0
  38. data/examples/geohash/README.md +58 -0
  39. data/examples/geohash/app.rb +33 -0
  40. data/examples/hello.rb +120 -0
  41. data/examples/llm_gateway/README.md +73 -0
  42. data/examples/llm_gateway/app.rb +91 -0
  43. data/examples/maidenhead/Gemfile +7 -0
  44. data/examples/maidenhead/Gemfile.lock +17 -0
  45. data/examples/maidenhead/README.md +47 -0
  46. data/examples/maidenhead/app.rb +46 -0
  47. data/examples/pg_hello.rb +76 -0
  48. data/examples/qdrant/Gemfile +11 -0
  49. data/examples/qdrant/Gemfile.lock +29 -0
  50. data/examples/qdrant/README.md +54 -0
  51. data/examples/sinatra_style.rb +32 -0
  52. data/examples/websocket_echo.rb +37 -0
  53. data/lib/tep/agent_delegation.rb +35 -0
  54. data/lib/tep/app.rb +291 -0
  55. data/lib/tep/assets.rb +52 -0
  56. data/lib/tep/auth.rb +78 -0
  57. data/lib/tep/auth_bearer_token.rb +126 -0
  58. data/lib/tep/auth_oauth2.rb +189 -0
  59. data/lib/tep/auth_oauth2_client.rb +29 -0
  60. data/lib/tep/auth_oauth2_code.rb +40 -0
  61. data/lib/tep/auth_session_cookie.rb +132 -0
  62. data/lib/tep/broadcast.rb +265 -0
  63. data/lib/tep/broadcast_subscription.rb +42 -0
  64. data/lib/tep/cache.rb +49 -0
  65. data/lib/tep/events.rb +257 -0
  66. data/lib/tep/filter.rb +21 -0
  67. data/lib/tep/handler.rb +35 -0
  68. data/lib/tep/http.rb +599 -0
  69. data/lib/tep/identity.rb +67 -0
  70. data/lib/tep/job.rb +186 -0
  71. data/lib/tep/json.rb +572 -0
  72. data/lib/tep/jwt.rb +126 -0
  73. data/lib/tep/live_view.rb +219 -0
  74. data/lib/tep/llm.rb +505 -0
  75. data/lib/tep/logger.rb +85 -0
  76. data/lib/tep/mcp.rb +203 -0
  77. data/lib/tep/multipart.rb +98 -0
  78. data/lib/tep/net.rb +155 -0
  79. data/lib/tep/openai_server.rb +725 -0
  80. data/lib/tep/parallel.rb +168 -0
  81. data/lib/tep/parser.rb +81 -0
  82. data/lib/tep/password.rb +102 -0
  83. data/lib/tep/pg.rb +1128 -0
  84. data/lib/tep/presence.rb +589 -0
  85. data/lib/tep/presence_entry.rb +52 -0
  86. data/lib/tep/proxy.rb +801 -0
  87. data/lib/tep/request.rb +194 -0
  88. data/lib/tep/response.rb +134 -0
  89. data/lib/tep/router.rb +137 -0
  90. data/lib/tep/scheduler.rb +342 -0
  91. data/lib/tep/security.rb +140 -0
  92. data/lib/tep/server.rb +276 -0
  93. data/lib/tep/server_scheduled.rb +375 -0
  94. data/lib/tep/session.rb +98 -0
  95. data/lib/tep/shell.rb +62 -0
  96. data/lib/tep/sphttp.c +858 -0
  97. data/lib/tep/sqlite.rb +215 -0
  98. data/lib/tep/streamer.rb +31 -0
  99. data/lib/tep/tep_pg.c +769 -0
  100. data/lib/tep/tep_sqlite.c +320 -0
  101. data/lib/tep/url.rb +161 -0
  102. data/lib/tep/version.rb +3 -0
  103. data/lib/tep/websocket/connection.rb +171 -0
  104. data/lib/tep/websocket/driver.rb +169 -0
  105. data/lib/tep/websocket/frame.rb +238 -0
  106. data/lib/tep/websocket/handshake.rb +159 -0
  107. data/lib/tep/websocket.rb +68 -0
  108. data/lib/tep.rb +981 -0
  109. data/public/hello.txt +1 -0
  110. data/public/style.css +4 -0
  111. data/spinel-ext.json +33 -0
  112. data/test/helper.rb +248 -0
  113. data/test/real_world/01_simple.rb +5 -0
  114. data/test/real_world/02_lifecycle.rb +20 -0
  115. data/test/real_world/03_chat.rb +75 -0
  116. data/test/real_world/04_health_api.rb +25 -0
  117. data/test/real_world/05_todo_api.rb +57 -0
  118. data/test/real_world/06_basic_auth.rb +25 -0
  119. data/test/real_world/07_bbc_rest_api.rb +228 -0
  120. data/test/real_world/07_sklise_things.rb +109 -0
  121. data/test/real_world/08_jwd83_helloworld.rb +56 -0
  122. data/test/run_all.rb +7 -0
  123. data/test/run_parallel.rb +89 -0
  124. data/test/spinel_scheduled_burst_segv_repro.rb +33 -0
  125. data/test/test_api_gateway.rb +76 -0
  126. data/test/test_auth.rb +223 -0
  127. data/test/test_auth_oauth2.rb +208 -0
  128. data/test/test_auth_session_cookie.rb +198 -0
  129. data/test/test_broadcast.rb +197 -0
  130. data/test/test_broadcast_pg.rb +135 -0
  131. data/test/test_cache.rb +98 -0
  132. data/test/test_cache_static.rb +48 -0
  133. data/test/test_cookies.rb +52 -0
  134. data/test/test_erb.rb +53 -0
  135. data/test/test_erb_ivars.rb +58 -0
  136. data/test/test_events.rb +114 -0
  137. data/test/test_filters.rb +41 -0
  138. data/test/test_geohash_example.rb +89 -0
  139. data/test/test_http.rb +137 -0
  140. data/test/test_http_pool.rb +122 -0
  141. data/test/test_http_pool_send.rb +57 -0
  142. data/test/test_identity.rb +165 -0
  143. data/test/test_inbound_tls.rb +101 -0
  144. data/test/test_inbound_tls_scheduled.rb +101 -0
  145. data/test/test_job.rb +108 -0
  146. data/test/test_json.rb +168 -0
  147. data/test/test_jwt.rb +143 -0
  148. data/test/test_live_view.rb +324 -0
  149. data/test/test_llm.rb +250 -0
  150. data/test/test_llm_gateway.rb +95 -0
  151. data/test/test_logger.rb +101 -0
  152. data/test/test_maidenhead_example.rb +86 -0
  153. data/test/test_mcp.rb +264 -0
  154. data/test/test_misc_v02.rb +54 -0
  155. data/test/test_modular.rb +43 -0
  156. data/test/test_multi_filters.rb +40 -0
  157. data/test/test_mustache.rb +57 -0
  158. data/test/test_openai_server.rb +598 -0
  159. data/test/test_optional_segments.rb +45 -0
  160. data/test/test_parallel.rb +102 -0
  161. data/test/test_params.rb +99 -0
  162. data/test/test_pass.rb +42 -0
  163. data/test/test_password.rb +101 -0
  164. data/test/test_pg.rb +673 -0
  165. data/test/test_presence.rb +374 -0
  166. data/test/test_presence_pg.rb +309 -0
  167. data/test/test_proxy.rb +556 -0
  168. data/test/test_proxy_dsl.rb +119 -0
  169. data/test/test_proxy_streaming.rb +146 -0
  170. data/test/test_real_world.rb +397 -0
  171. data/test/test_regex_routes.rb +52 -0
  172. data/test/test_request_methods.rb +102 -0
  173. data/test/test_response.rb +123 -0
  174. data/test/test_routing.rb +109 -0
  175. data/test/test_scheduler.rb +153 -0
  176. data/test/test_security.rb +72 -0
  177. data/test/test_server_scheduled.rb +56 -0
  178. data/test/test_sessions.rb +59 -0
  179. data/test/test_shell.rb +54 -0
  180. data/test/test_sqlite.rb +148 -0
  181. data/test/test_sqlite_cached.rb +171 -0
  182. data/test/test_static.rb +57 -0
  183. data/test/test_streaming.rb +96 -0
  184. data/test/test_unsupported.rb +32 -0
  185. data/test/test_websocket.rb +152 -0
  186. data/test/test_websocket_echo.rb +138 -0
  187. data/test/views/greet.erb +5 -0
  188. data/test/views/hello.erb +5 -0
  189. data/test/views/list.erb +5 -0
  190. data/test/views/m_ivars.mustache +3 -0
  191. data/test/views/m_simple.mustache +4 -0
  192. data/test/views/mixed.erb +3 -0
  193. metadata +264 -0
@@ -0,0 +1,138 @@
1
+ # End-to-end smoke test for the bin/tep `websocket '/path' do ... end`
2
+ # DSL hook. Boots a translated echo app on a random port, opens a raw
3
+ # TCP socket, performs the RFC 6455 handshake, sends a masked TEXT
4
+ # frame, asserts the unmasked echo comes back.
5
+ #
6
+ # Lives next to the unit-level test/test_websocket.rb (which covers
7
+ # the codec + handshake math in isolation). This file covers the
8
+ # Driver+Connection+Server integration path that those tests skipped.
9
+ require "minitest/autorun"
10
+ require "socket"
11
+ require "securerandom"
12
+ require "base64"
13
+ require "digest/sha1"
14
+
15
+ class TestWebSocketEcho < Minitest::Test
16
+ GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".freeze
17
+ ROOT = File.expand_path("..", __dir__)
18
+ BIN = File.join(ROOT, "examples", "websocket_echo")
19
+
20
+ def setup
21
+ skip "examples/websocket_echo not built" unless File.executable?(BIN)
22
+ @port = 40000 + rand(10_000)
23
+ @pid = spawn(BIN, "-p", @port.to_s, "-q", out: "/dev/null", err: "/dev/null")
24
+ deadline = Time.now + 5
25
+ loop do
26
+ begin
27
+ s = TCPSocket.new("127.0.0.1", @port)
28
+ s.close
29
+ break
30
+ rescue Errno::ECONNREFUSED
31
+ raise "server failed to start" if Time.now > deadline
32
+ sleep 0.05
33
+ end
34
+ end
35
+ end
36
+
37
+ def teardown
38
+ return unless @pid
39
+ # Bounded reap: TERM, wait up to 5s, then SIGKILL. A bare
40
+ # Process.wait can hang forever if the server ignores TERM
41
+ # (single-process here, so the pid signal suffices -- no pgroup).
42
+ Process.kill("TERM", @pid) rescue nil
43
+ deadline = Time.now + 5
44
+ reaped = false
45
+ until Time.now > deadline
46
+ got = (Process.waitpid(@pid, Process::WNOHANG) rescue :gone)
47
+ if got
48
+ reaped = true
49
+ break
50
+ end
51
+ sleep 0.02
52
+ end
53
+ unless reaped
54
+ Process.kill("KILL", @pid) rescue nil
55
+ Process.wait(@pid) rescue nil
56
+ end
57
+ end
58
+
59
+ def expected_accept(key)
60
+ Base64.strict_encode64(Digest::SHA1.digest(key + GUID))
61
+ end
62
+
63
+ def send_handshake(sock, key)
64
+ req =
65
+ "GET /echo HTTP/1.1\r\n" \
66
+ "Host: 127.0.0.1:#{@port}\r\n" \
67
+ "Upgrade: websocket\r\n" \
68
+ "Connection: Upgrade\r\n" \
69
+ "Sec-WebSocket-Key: #{key}\r\n" \
70
+ "Sec-WebSocket-Version: 13\r\n" \
71
+ "\r\n"
72
+ sock.write(req)
73
+ end
74
+
75
+ def read_until_double_crlf(sock)
76
+ buf = String.new
77
+ while !buf.include?("\r\n\r\n")
78
+ chunk = sock.readpartial(4096)
79
+ buf << chunk
80
+ end
81
+ head, rest = buf.split("\r\n\r\n", 2)
82
+ [head, rest || ""]
83
+ end
84
+
85
+ def encode_masked_text(payload)
86
+ mask = SecureRandom.bytes(4)
87
+ masked = payload.bytes.each_with_index.map { |b, i| b ^ mask.bytes[i & 3] }.pack("C*")
88
+ [0x81, 0x80 | payload.bytesize].pack("C*") + mask + masked
89
+ end
90
+
91
+ def parse_unmasked_text_frame(buf)
92
+ raise "frame too short" if buf.bytesize < 2
93
+ b0 = buf.getbyte(0)
94
+ b1 = buf.getbyte(1)
95
+ raise "expected FIN+text (0x81), got 0x#{b0.to_s(16)}" unless b0 == 0x81
96
+ raise "server frame must not be masked" if (b1 & 0x80) != 0
97
+ len = b1 & 0x7f
98
+ pos = 2
99
+ if len == 126
100
+ len = (buf.getbyte(pos) << 8) | buf.getbyte(pos + 1)
101
+ pos += 2
102
+ elsif len == 127
103
+ raise "64-bit length not expected in this test"
104
+ end
105
+ buf.byteslice(pos, len)
106
+ end
107
+
108
+ def test_handshake_and_echo_round_trip
109
+ sock = TCPSocket.new("127.0.0.1", @port)
110
+ key = Base64.strict_encode64(SecureRandom.bytes(16))
111
+ send_handshake(sock, key)
112
+
113
+ head, leftover = read_until_double_crlf(sock)
114
+ assert_includes head, "HTTP/1.1 101 Switching Protocols", "handshake failed: #{head}"
115
+ assert_includes head, "Upgrade: websocket"
116
+ assert_includes head, "Sec-WebSocket-Accept: #{expected_accept(key)}"
117
+
118
+ # Server emits a synthetic "welcome" on open.
119
+ buf = leftover.dup
120
+ deadline = Time.now + 2
121
+ while buf.bytesize < 9 && Time.now < deadline
122
+ buf << sock.readpartial(4096)
123
+ end
124
+ welcome = parse_unmasked_text_frame(buf)
125
+ assert_equal "welcome", welcome
126
+
127
+ sock.write(encode_masked_text("hello"))
128
+ buf2 = String.new
129
+ deadline = Time.now + 2
130
+ while buf2.bytesize < 13 && Time.now < deadline
131
+ buf2 << sock.readpartial(4096)
132
+ end
133
+ echo = parse_unmasked_text_frame(buf2)
134
+ assert_equal "echo: hello", echo
135
+
136
+ sock.close
137
+ end
138
+ end
@@ -0,0 +1,5 @@
1
+ <h1>hi, <%= @name %>!</h1>
2
+ <p>you visited <%= @count %> times.</p>
3
+ <% if @count == "1" %>
4
+ <p>welcome.</p>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <h1>hello, <%= locals["name"] %>!</h1>
2
+ <% if locals["mood"] == "happy" %>
3
+ <p>You seem cheerful.</p>
4
+ <% end %>
5
+ <p>Thanks <%= locals["name"] %>.</p>
@@ -0,0 +1,5 @@
1
+ <ul>
2
+ <% (locals["count"]).to_i.times do |i| %>
3
+ <li>item <%= i.to_s %></li>
4
+ <% end %>
5
+ </ul>
@@ -0,0 +1,3 @@
1
+ <h1>hi, {{@name}}</h1>
2
+ <p>visited: {{@count}}</p>
3
+ <p>raw ivar: {{{@raw}}}</p>
@@ -0,0 +1,4 @@
1
+ <h1>hello, {{name}}!</h1>
2
+ <p>greeting: {{greeting}}</p>
3
+ {{! this comment is dropped }}
4
+ <p>raw html: {{{snippet}}}</p>
@@ -0,0 +1,3 @@
1
+ <h1>hello, <%= @name %></h1>
2
+ <p>locals greeting: <%= locals["greeting"] %></p>
3
+ <p>ivar greeting: <%= @greeting %></p>
metadata ADDED
@@ -0,0 +1,264 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tep
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.11.0
5
+ platform: ruby
6
+ authors:
7
+ - Ori Pekelman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-06-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: prism
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ description: |-
28
+ tep is a small Sinatra-style DSL targeting the Spinel AOT Ruby
29
+ compiler. The translator turns a Sinatra-classic source file into
30
+ a self-contained native binary -- ~80 KB on Linux, no Ruby runtime.
31
+ Pre-alpha: primary purpose is exercising Spinel against real-world
32
+ Ruby usage; the framework is the test vehicle.
33
+ email:
34
+ - ori@pekelman.com
35
+ executables:
36
+ - tep
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - LICENSE
41
+ - Makefile
42
+ - README.md
43
+ - SINATRA_COMPAT.md
44
+ - bin/tep
45
+ - examples/agentic_chat/README.md
46
+ - examples/agentic_chat/app.rb
47
+ - examples/api_gateway/README.md
48
+ - examples/api_gateway/app.rb
49
+ - examples/blog/app.rb
50
+ - examples/blog/views/index.erb
51
+ - examples/blog/views/login.erb
52
+ - examples/blog/views/new_post.erb
53
+ - examples/blog/views/show.erb
54
+ - examples/chat/app.rb
55
+ - examples/chat/assets/logo.svg
56
+ - examples/chat/assets/style.css
57
+ - examples/chat/views/index.erb
58
+ - examples/chatbot/README.md
59
+ - examples/chatbot/app.rb
60
+ - examples/chatbot/assets/chat.js
61
+ - examples/chatbot/assets/compare.js
62
+ - examples/chatbot/assets/markdown.js
63
+ - examples/chatbot/assets/style.css
64
+ - examples/chatbot/schema.sql
65
+ - examples/chatbot/views/compare.erb
66
+ - examples/chatbot/views/index.erb
67
+ - examples/chatbot/views/login.erb
68
+ - examples/chatbot/views/setup.erb
69
+ - examples/counter/README.md
70
+ - examples/counter/app.rb
71
+ - examples/experiments/AGENTS.md
72
+ - examples/experiments/README.md
73
+ - examples/experiments/app.rb
74
+ - examples/geohash/Gemfile
75
+ - examples/geohash/Gemfile.lock
76
+ - examples/geohash/README.md
77
+ - examples/geohash/app.rb
78
+ - examples/hello.rb
79
+ - examples/llm_gateway/README.md
80
+ - examples/llm_gateway/app.rb
81
+ - examples/maidenhead/Gemfile
82
+ - examples/maidenhead/Gemfile.lock
83
+ - examples/maidenhead/README.md
84
+ - examples/maidenhead/app.rb
85
+ - examples/pg_hello.rb
86
+ - examples/qdrant/Gemfile
87
+ - examples/qdrant/Gemfile.lock
88
+ - examples/qdrant/README.md
89
+ - examples/sinatra_style.rb
90
+ - examples/websocket_echo.rb
91
+ - lib/tep.rb
92
+ - lib/tep/agent_delegation.rb
93
+ - lib/tep/app.rb
94
+ - lib/tep/assets.rb
95
+ - lib/tep/auth.rb
96
+ - lib/tep/auth_bearer_token.rb
97
+ - lib/tep/auth_oauth2.rb
98
+ - lib/tep/auth_oauth2_client.rb
99
+ - lib/tep/auth_oauth2_code.rb
100
+ - lib/tep/auth_session_cookie.rb
101
+ - lib/tep/broadcast.rb
102
+ - lib/tep/broadcast_subscription.rb
103
+ - lib/tep/cache.rb
104
+ - lib/tep/events.rb
105
+ - lib/tep/filter.rb
106
+ - lib/tep/handler.rb
107
+ - lib/tep/http.rb
108
+ - lib/tep/identity.rb
109
+ - lib/tep/job.rb
110
+ - lib/tep/json.rb
111
+ - lib/tep/jwt.rb
112
+ - lib/tep/live_view.rb
113
+ - lib/tep/llm.rb
114
+ - lib/tep/logger.rb
115
+ - lib/tep/mcp.rb
116
+ - lib/tep/multipart.rb
117
+ - lib/tep/net.rb
118
+ - lib/tep/openai_server.rb
119
+ - lib/tep/parallel.rb
120
+ - lib/tep/parser.rb
121
+ - lib/tep/password.rb
122
+ - lib/tep/pg.rb
123
+ - lib/tep/presence.rb
124
+ - lib/tep/presence_entry.rb
125
+ - lib/tep/proxy.rb
126
+ - lib/tep/request.rb
127
+ - lib/tep/response.rb
128
+ - lib/tep/router.rb
129
+ - lib/tep/scheduler.rb
130
+ - lib/tep/security.rb
131
+ - lib/tep/server.rb
132
+ - lib/tep/server_scheduled.rb
133
+ - lib/tep/session.rb
134
+ - lib/tep/shell.rb
135
+ - lib/tep/sphttp.c
136
+ - lib/tep/sqlite.rb
137
+ - lib/tep/streamer.rb
138
+ - lib/tep/tep_pg.c
139
+ - lib/tep/tep_sqlite.c
140
+ - lib/tep/url.rb
141
+ - lib/tep/version.rb
142
+ - lib/tep/websocket.rb
143
+ - lib/tep/websocket/connection.rb
144
+ - lib/tep/websocket/driver.rb
145
+ - lib/tep/websocket/frame.rb
146
+ - lib/tep/websocket/handshake.rb
147
+ - public/hello.txt
148
+ - public/style.css
149
+ - spinel-ext.json
150
+ - test/helper.rb
151
+ - test/real_world/01_simple.rb
152
+ - test/real_world/02_lifecycle.rb
153
+ - test/real_world/03_chat.rb
154
+ - test/real_world/04_health_api.rb
155
+ - test/real_world/05_todo_api.rb
156
+ - test/real_world/06_basic_auth.rb
157
+ - test/real_world/07_bbc_rest_api.rb
158
+ - test/real_world/07_sklise_things.rb
159
+ - test/real_world/08_jwd83_helloworld.rb
160
+ - test/run_all.rb
161
+ - test/run_parallel.rb
162
+ - test/spinel_scheduled_burst_segv_repro.rb
163
+ - test/test_api_gateway.rb
164
+ - test/test_auth.rb
165
+ - test/test_auth_oauth2.rb
166
+ - test/test_auth_session_cookie.rb
167
+ - test/test_broadcast.rb
168
+ - test/test_broadcast_pg.rb
169
+ - test/test_cache.rb
170
+ - test/test_cache_static.rb
171
+ - test/test_cookies.rb
172
+ - test/test_erb.rb
173
+ - test/test_erb_ivars.rb
174
+ - test/test_events.rb
175
+ - test/test_filters.rb
176
+ - test/test_geohash_example.rb
177
+ - test/test_http.rb
178
+ - test/test_http_pool.rb
179
+ - test/test_http_pool_send.rb
180
+ - test/test_identity.rb
181
+ - test/test_inbound_tls.rb
182
+ - test/test_inbound_tls_scheduled.rb
183
+ - test/test_job.rb
184
+ - test/test_json.rb
185
+ - test/test_jwt.rb
186
+ - test/test_live_view.rb
187
+ - test/test_llm.rb
188
+ - test/test_llm_gateway.rb
189
+ - test/test_logger.rb
190
+ - test/test_maidenhead_example.rb
191
+ - test/test_mcp.rb
192
+ - test/test_misc_v02.rb
193
+ - test/test_modular.rb
194
+ - test/test_multi_filters.rb
195
+ - test/test_mustache.rb
196
+ - test/test_openai_server.rb
197
+ - test/test_optional_segments.rb
198
+ - test/test_parallel.rb
199
+ - test/test_params.rb
200
+ - test/test_pass.rb
201
+ - test/test_password.rb
202
+ - test/test_pg.rb
203
+ - test/test_presence.rb
204
+ - test/test_presence_pg.rb
205
+ - test/test_proxy.rb
206
+ - test/test_proxy_dsl.rb
207
+ - test/test_proxy_streaming.rb
208
+ - test/test_real_world.rb
209
+ - test/test_regex_routes.rb
210
+ - test/test_request_methods.rb
211
+ - test/test_response.rb
212
+ - test/test_routing.rb
213
+ - test/test_scheduler.rb
214
+ - test/test_security.rb
215
+ - test/test_server_scheduled.rb
216
+ - test/test_sessions.rb
217
+ - test/test_shell.rb
218
+ - test/test_sqlite.rb
219
+ - test/test_sqlite_cached.rb
220
+ - test/test_static.rb
221
+ - test/test_streaming.rb
222
+ - test/test_unsupported.rb
223
+ - test/test_websocket.rb
224
+ - test/test_websocket_echo.rb
225
+ - test/views/greet.erb
226
+ - test/views/hello.erb
227
+ - test/views/list.erb
228
+ - test/views/m_ivars.mustache
229
+ - test/views/m_simple.mustache
230
+ - test/views/mixed.erb
231
+ homepage: https://github.com/OriPekelman/tep
232
+ licenses:
233
+ - MIT
234
+ metadata:
235
+ source_code_uri: https://github.com/OriPekelman/tep
236
+ bug_tracker_uri: https://github.com/OriPekelman/tep/issues
237
+ documentation_uri: https://github.com/OriPekelman/tep#readme
238
+ rubygems_mfa_required: 'true'
239
+ post_install_message: |
240
+ tep is a Spinel-AOT framework: it compiles your Sinatra-style app to
241
+ a native binary -- there is no `require "tep"` runtime under CRuby.
242
+ build an app: tep build app.rb && ./app -p 4567
243
+ or vendor it: declare `gem "tep"` in a bundler-spinel (spinelgems)
244
+ Gemfile, then `spinel-compat vendor`.
245
+ Docs: https://github.com/OriPekelman/tep
246
+ rdoc_options: []
247
+ require_paths:
248
+ - lib
249
+ required_ruby_version: !ruby/object:Gem::Requirement
250
+ requirements:
251
+ - - ">="
252
+ - !ruby/object:Gem::Version
253
+ version: 3.2.0
254
+ required_rubygems_version: !ruby/object:Gem::Requirement
255
+ requirements:
256
+ - - ">="
257
+ - !ruby/object:Gem::Version
258
+ version: '0'
259
+ requirements: []
260
+ rubygems_version: 3.4.20
261
+ signing_key:
262
+ specification_version: 4
263
+ summary: A Sinatra-flavoured web framework that compiles to a native binary via Spinel
264
+ test_files: []