tep 0.11.0 → 0.11.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/README.md +45 -16
- data/bin/tep +62 -6
- data/lib/tep/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed267cb0d611fda2cb1339ea9751dc723c8c8b2eda6c24b10f4ac3e19f0bb530
|
|
4
|
+
data.tar.gz: f1e52b916e06975569e4c1fd50ab2759c167fdc9209d8f4066a24c4da98284aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 980964ad55476805b33d78dc1623d777ee8b0d1205a9b779201ebb8bf71d9a6a5ecd7a2e1966372be11d8583778b026385dfaac56ef2b6d22f5989da34257f39
|
|
7
|
+
data.tar.gz: b0cceac7ec078c154af037c8484ad269a539dfb39c9a98805c7989846d2a6a0dc4be044cb7ae9053856deb9c4281888fe8f786ba7d9c9c22dd2786208f5f58c6
|
data/README.md
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
A Sinatra-flavoured web framework that compiles to a native binary
|
|
8
8
|
via [Spinel][spinel].
|
|
9
9
|
|
|
10
|
-
> **Current release:** [v0.
|
|
11
|
-
> —
|
|
12
|
-
>
|
|
10
|
+
> **Current release:** [v0.11.0](https://github.com/OriPekelman/tep/releases/tag/v0.11.0)
|
|
11
|
+
> — now on [RubyGems](https://rubygems.org/gems/tep) (`gem install tep`):
|
|
12
|
+
> TLS, HTTP caching, connection pooling, PG raise-on-error + embeddings,
|
|
13
|
+
> on top of the agentic surface (Auth, Broadcast, Presence, LiveView, MCP).
|
|
13
14
|
> Pre-alpha; API still in motion.
|
|
14
15
|
|
|
15
16
|
> **Why Tep exists.** Two complementary goals:
|
|
@@ -39,22 +40,25 @@ via [Spinel][spinel].
|
|
|
39
40
|
|
|
40
41
|
## Quick start
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
cd spinel && make all
|
|
46
|
-
export PATH="$PWD:$PATH"
|
|
43
|
+
**A new project (the simple path).** The Spinel toolbelt
|
|
44
|
+
([bundler-spinel](https://github.com/OriPekelman/spinelgems)) scaffolds a
|
|
45
|
+
project and provisions the Spinel compiler for you:
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
./
|
|
47
|
+
```sh
|
|
48
|
+
gem install bundler-spinel
|
|
49
|
+
spinel-compat init my_app && cd my_app
|
|
50
|
+
./bin/build # ensures tep, vendors deps, provisions Spinel, compiles → ./app
|
|
51
|
+
./app -p 4567
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
`spinel-compat init` writes a `Gemfile` (`gem "tep"`), an `app.rb`, and a
|
|
55
|
+
`bin/build`. The build step provisions a pinned Spinel compiler (cached under
|
|
56
|
+
`~/.cache/spinel`), vendors dependencies where Spinel can follow them, and
|
|
57
|
+
compiles `app.rb` to a native binary — no Ruby runtime in the result.
|
|
58
|
+
|
|
59
|
+
Your `app.rb` is plain Sinatra-flavoured Ruby:
|
|
55
60
|
|
|
56
61
|
```ruby
|
|
57
|
-
# hello.rb
|
|
58
62
|
require 'sinatra'
|
|
59
63
|
|
|
60
64
|
get '/' do
|
|
@@ -66,10 +70,35 @@ get '/hi/:name' do
|
|
|
66
70
|
end
|
|
67
71
|
```
|
|
68
72
|
|
|
73
|
+
**Already have a Sinatra app?** Scaffold a project and use your source as its
|
|
74
|
+
`app.rb` — the build reports any Spinel-incompatible patterns:
|
|
75
|
+
|
|
69
76
|
```sh
|
|
70
|
-
|
|
71
|
-
|
|
77
|
+
gem install bundler-spinel
|
|
78
|
+
spinel-compat init my_app && cd my_app
|
|
79
|
+
cp /path/to/your_app.rb app.rb
|
|
80
|
+
./bin/build # → ./app (or a clear report of what won't translate)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The `tep` translator is also on RubyGems on its own (`gem install tep`) for use
|
|
84
|
+
in your own build scripts, once a Spinel engine is on `$SPINEL` / PATH.
|
|
85
|
+
|
|
86
|
+
<details>
|
|
87
|
+
<summary><b>From source</b> (hacking on tep itself, or no bundler)</summary>
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
# 1. Spinel (the AOT compiler)
|
|
91
|
+
git clone https://github.com/matz/spinel && cd spinel && make all
|
|
92
|
+
export PATH="$PWD:$PATH"
|
|
93
|
+
|
|
94
|
+
# 2. tep
|
|
95
|
+
git clone https://github.com/OriPekelman/tep && cd tep && make all
|
|
96
|
+
./examples/hello -p 4567
|
|
97
|
+
|
|
98
|
+
# your own app
|
|
99
|
+
tep build hello.rb # → ./hello (~80 KB binary, no Ruby runtime)
|
|
72
100
|
```
|
|
101
|
+
</details>
|
|
73
102
|
|
|
74
103
|
The translator (`bin/tep`) needs CRuby >= 3.2 with the `prism` gem
|
|
75
104
|
installed (a development-only dependency — `bundle install` brings it
|
data/bin/tep
CHANGED
|
@@ -55,14 +55,23 @@ require "json"
|
|
|
55
55
|
|
|
56
56
|
# Resolve spinel: explicit env var wins, then a sibling
|
|
57
57
|
# `../spinel/spinel` checkout (matches the typical dev layout where
|
|
58
|
-
# tep and spinel are checked out side by side), then
|
|
59
|
-
#
|
|
60
|
-
#
|
|
58
|
+
# tep and spinel are checked out side by side), then the engine
|
|
59
|
+
# provisioned by `spinel-compat install-engine` (spinelgems) at
|
|
60
|
+
# `~/.cache/spinel/current/spinel`, then plain `spinel` on PATH. The
|
|
61
|
+
# Makefile exports SPINEL=spinel by default; treat the literal
|
|
62
|
+
# placeholder as unset so the fallbacks still fire.
|
|
61
63
|
def self.locate_spinel
|
|
62
64
|
e = ENV["SPINEL"]
|
|
63
65
|
return e if e && !e.empty? && e != "spinel"
|
|
64
66
|
sibling = File.expand_path("../../spinel/spinel", __dir__)
|
|
65
67
|
return sibling if File.executable?(sibling)
|
|
68
|
+
# Engine provisioned by `spinel-compat install-engine`. Honor
|
|
69
|
+
# SPINEL_CACHE like bundler-spinel does so a relocated cache resolves
|
|
70
|
+
# for both tools (default ~/.cache/spinel; `current` -> the pinned rev).
|
|
71
|
+
cache_root = ENV["SPINEL_CACHE"]
|
|
72
|
+
cache_root = "~/.cache/spinel" if cache_root.nil? || cache_root.empty?
|
|
73
|
+
provisioned = File.expand_path(cache_root + "/current/spinel")
|
|
74
|
+
return provisioned if File.executable?(provisioned)
|
|
66
75
|
"spinel"
|
|
67
76
|
end
|
|
68
77
|
SPINEL = locate_spinel
|
|
@@ -1928,13 +1937,13 @@ end
|
|
|
1928
1937
|
def tep_ext_subs
|
|
1929
1938
|
ext_path = File.join(REPO_ROOT, "spinel-ext.json")
|
|
1930
1939
|
return {} unless File.exist?(ext_path)
|
|
1940
|
+
entries = JSON.parse(File.read(ext_path))
|
|
1931
1941
|
subs = {}
|
|
1932
|
-
|
|
1942
|
+
entries.each do |entry|
|
|
1933
1943
|
placeholder = entry["placeholder"]
|
|
1934
1944
|
env_var = placeholder.delete("@") # @TEP_SPHTTP_O@ -> TEP_SPHTTP_O
|
|
1935
1945
|
if entry["source"]
|
|
1936
|
-
|
|
1937
|
-
subs[placeholder] = ENV.fetch(env_var, default_o)
|
|
1946
|
+
subs[placeholder] = resolve_ext_o(entry, entries, env_var)
|
|
1938
1947
|
else
|
|
1939
1948
|
cflags = ENV.fetch(env_var, "")
|
|
1940
1949
|
libs_var = env_var.sub(/_CFLAGS\z/, "_LIBS")
|
|
@@ -1946,6 +1955,53 @@ def tep_ext_subs
|
|
|
1946
1955
|
subs
|
|
1947
1956
|
end
|
|
1948
1957
|
|
|
1958
|
+
# Resolve a helper `.o`. An explicit env override or a prebuilt `make helper`
|
|
1959
|
+
# artifact wins; otherwise build it on demand. The published gem ships the C
|
|
1960
|
+
# *sources* but no `.o` (a `gem install tep` user has no `make helper` step), so
|
|
1961
|
+
# without this `tep build` fails at link with `cannot find lib/tep/<x>.o`.
|
|
1962
|
+
# Compiles into a writable per-gem cache (the installed gem's lib/ is often
|
|
1963
|
+
# read-only). Returns the `.o` path, or "" for an optional ext whose system dep
|
|
1964
|
+
# is missing (required exts are fatal).
|
|
1965
|
+
def resolve_ext_o(entry, entries, env_var)
|
|
1966
|
+
if (o = ENV[env_var]) && !o.empty?
|
|
1967
|
+
return o if File.exist?(o)
|
|
1968
|
+
end
|
|
1969
|
+
prebuilt = File.expand_path(entry["source"].sub(/\.c\z/, ".o"), REPO_ROOT)
|
|
1970
|
+
return prebuilt if File.exist?(prebuilt)
|
|
1971
|
+
|
|
1972
|
+
src = File.expand_path(entry["source"], REPO_ROOT)
|
|
1973
|
+
fatal("ext source missing: #{entry["source"]}") unless File.exist?(src)
|
|
1974
|
+
|
|
1975
|
+
# own cflags + any same-name sibling's pkg_config include path (the split
|
|
1976
|
+
# @MOD_O@ / @MOD_CFLAGS@ pair — e.g. pg's libpq lives on @TEP_PG_CFLAGS@).
|
|
1977
|
+
cflags = Array(entry["cflags"]).dup
|
|
1978
|
+
missing = nil
|
|
1979
|
+
entries.each do |sib|
|
|
1980
|
+
next unless sib["name"] == entry["name"] && sib["pkg_config"]
|
|
1981
|
+
pc = `pkg-config --cflags #{sib["pkg_config"]} 2>/dev/null`
|
|
1982
|
+
$?.success? ? cflags.concat(pc.split) : (missing = sib["pkg_config"])
|
|
1983
|
+
end
|
|
1984
|
+
if missing
|
|
1985
|
+
return "" if entry["optional"]
|
|
1986
|
+
fatal("ext '#{entry["name"]}' needs #{missing} — install its -dev headers")
|
|
1987
|
+
end
|
|
1988
|
+
|
|
1989
|
+
cache = File.join(ENV["HOME"] || Dir.tmpdir, ".cache", "tep", "ext", File.basename(REPO_ROOT))
|
|
1990
|
+
FileUtils.mkdir_p(cache)
|
|
1991
|
+
out = File.join(cache, File.basename(prebuilt))
|
|
1992
|
+
return out if File.exist?(out) && File.mtime(out) >= File.mtime(src)
|
|
1993
|
+
|
|
1994
|
+
warn "[tep] building ext '#{entry["name"]}' on demand (#{entry["source"]})"
|
|
1995
|
+
if system(ENV.fetch("CC", "cc"), *cflags, "-c", src, "-o", out) && File.exist?(out)
|
|
1996
|
+
out
|
|
1997
|
+
elsif entry["optional"]
|
|
1998
|
+
warn "[tep] optional ext '#{entry["name"]}' failed to build — disabling"
|
|
1999
|
+
""
|
|
2000
|
+
else
|
|
2001
|
+
fatal("failed to build required ext '#{entry["name"]}' (#{entry["source"]})")
|
|
2002
|
+
end
|
|
2003
|
+
end
|
|
2004
|
+
|
|
1949
2005
|
# Split a Sinatra-style source on `__END__` and parse the trailing
|
|
1950
2006
|
# `@@ name` blocks into a {name => template_body} hash.
|
|
1951
2007
|
def split_inline_views(raw)
|
data/lib/tep/version.rb
CHANGED