tina4ruby 3.10.40 → 3.10.41

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: 1589dd895958b33a59e56a16719b858cf4229324981cd4383712887696197405
4
- data.tar.gz: dc5783a2cf29a39a512d5373c7fafea25ad74630a3c21f85e7a0ae2a02b33037
3
+ metadata.gz: 9ce1c810129bd38cc0cb779f3f9dd1c63914e9cccbf9e5c704b85502da5e8255
4
+ data.tar.gz: 19dd3a30fc0a16c65824867829448a96a75e3eccdda4548540dcd84c7b8b18a1
5
5
  SHA512:
6
- metadata.gz: e99a9a39e34b1a9df2b880e66ab5679d0ac4b6cfa96725f4cb03ab9cd3499105c64e93cf097d1a4c6f5031e832ea3641fdf5220c3b28a753c4778a9540303f00
7
- data.tar.gz: d12d055badd206b42ae421c64683ce8a5dc4fa4efd6822ea5f275286fcad3c58c1ef8b40cda0bc589a4430e910af0a5fc87cd7bdbc39740e94db91d8ea1f4b9a
6
+ metadata.gz: 410b5805f04b18011d4a7b4bd4cf09c66f457c837d3a65ebe7b71ef849f4b089b0900072fd0a0172c8c93757cce6306db1c535ec558a71dd28148f211fc62b38
7
+ data.tar.gz: 539f1b4dc7e0aa29c4ae3a5a9ef3dea49f9bb91381772ccbd490e7a254d33550247f2a17177f7caabc8ec72dbdda8648e24c576388aef574404553da4e8cba84
data/README.md CHANGED
@@ -1,635 +1,112 @@
1
1
  <p align="center">
2
2
  <img src="https://tina4.com/logo.svg" alt="Tina4" width="200">
3
3
  </p>
4
-
5
4
  <h1 align="center">Tina4 Ruby</h1>
6
5
  <h3 align="center">This Is Now A 4Framework</h3>
7
-
8
- <p align="center">
9
- Laravel joy. Ruby speed. 10x less code. Zero third-party dependencies.
10
- </p>
11
-
6
+ <p align="center">54 built-in features. Zero runtime dependencies. One require, everything works.</p>
12
7
  <p align="center">
13
- <a href="https://rubygems.org/gems/tina4"><img src="https://img.shields.io/gem/v/tina4?color=7b1fa2&label=RubyGems" alt="Gem"></a>
14
- <img src="https://img.shields.io/badge/tests-1%2C578%20passing-brightgreen" alt="Tests">
15
- <img src="https://img.shields.io/badge/features-38-blue" alt="Features">
8
+ <a href="https://rubygems.org/gems/tina4ruby"><img src="https://img.shields.io/gem/v/tina4ruby?color=7b1fa2&label=RubyGems" alt="RubyGems"></a>
9
+ <img src="https://img.shields.io/badge/tests-1%2C793%20passing-brightgreen" alt="Tests">
10
+ <img src="https://img.shields.io/badge/features-54-blue" alt="Features">
16
11
  <img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="Zero Deps">
17
12
  <a href="https://tina4.com"><img src="https://img.shields.io/badge/docs-tina4.com-7b1fa2" alt="Docs"></a>
18
13
  </p>
19
14
 
20
- <p align="center">
21
- <a href="https://tina4.com">Documentation</a> &bull;
22
- <a href="#getting-started">Getting Started</a> &bull;
23
- <a href="#features">Features</a> &bull;
24
- <a href="#cli-reference">CLI Reference</a> &bull;
25
- <a href="https://tina4.com">tina4.com</a>
26
- </p>
27
-
28
15
  ---
29
16
 
30
17
  ## Quick Start
31
18
 
32
- ```bash
33
- # Install the Tina4 CLI
34
- cargo install tina4 # or download binary from https://github.com/tina4stack/tina4/releases
35
-
36
- # Create a project
37
- tina4 init ruby ./my-app
38
-
39
- # Run it
40
- cd my-app && tina4 serve
41
- ```
42
-
43
- Open http://localhost:7147 — your app is running.
44
-
45
- <details>
46
- <summary><strong>Without the Tina4 CLI</strong></summary>
47
-
48
- ```bash
49
- # 1. Create project
50
- mkdir my-app && cd my-app
51
- echo 'source "https://rubygems.org"' > Gemfile
52
- echo 'gem "tina4-ruby", "~> 3.0"' >> Gemfile
53
- bundle install
54
-
55
- # 2. Create entry point
56
- cat > app.rb << 'EOF'
57
- require "tina4"
58
- Tina4.initialize!(__dir__)
59
- app = Tina4::RackApp.new
60
- Tina4::WebServer.new(app, host: "0.0.0.0", port: 7147).start
61
- EOF
62
-
63
- # 3. Create .env
64
- echo 'TINA4_DEBUG=true' > .env
65
- echo 'TINA4_LOG_LEVEL=ALL' >> .env
66
-
67
- # 4. Create route directory
68
- mkdir -p src/routes
69
-
70
- # 5. Run
71
- bundle exec ruby app.rb
72
- ```
73
-
74
- Open http://localhost:7147
75
-
76
- </details>
77
-
78
- ---
79
-
80
- ## What's Included
81
-
82
- Every feature is built from scratch -- no gem install, no node_modules, no third-party runtime dependencies in core.
83
-
84
- | Category | Features |
85
- |----------|----------|
86
- | **HTTP** | Rack 3 server, block routing, path params (`{id:int}`, `{p:path}`), middleware pipeline, CORS, rate limiting, graceful shutdown |
87
- | **Templates** | Frond engine (Twig-compatible), inheritance, partials, 35+ filters, macros, fragment caching, sandboxing |
88
- | **ORM** | Active Record, typed fields with validation, soft delete, relationships (`has_one`/`has_many`/`belongs_to`), scopes, result caching, multi-database |
89
- | **Database** | SQLite, PostgreSQL, MySQL, MSSQL, Firebird -- unified adapter interface, query caching (TINA4_DB_CACHE=true for 4x speedup) |
90
- | **Auth** | Zero-dep JWT (HS256/RS256), sessions (file/Redis/Valkey/MongoDB/database), password hashing, form tokens |
91
- | **API** | Swagger/OpenAPI auto-generation, GraphQL with ORM auto-schema and GraphiQL IDE, WSDL/SOAP with auto WSDL |
92
- | **Background** | Queue (SQLite/RabbitMQ/Kafka/MongoDB) with priority, delayed jobs, retry, batch processing |
93
- | **Real-time** | Native WebSocket (RFC 6455), per-path routing, connection manager |
94
- | **Frontend** | tina4-css (~24 KB), frond.js helper, SCSS compiler, live reload, CSS hot-reload |
95
- | **DX** | Dev admin dashboard, error overlay, request inspector, AI tool integration, Carbonah green benchmarks |
96
- | **Data** | Migrations with rollback, 50+ fake data generators, ORM and table seeders |
97
- | **Other** | REST client, localization (6 languages), cache (memory/Redis/file), event system, inline testing, messenger (.env driven), configurable error pages |
98
-
99
- **1,578 tests across 38 built-in features. Zero dependencies. All Carbonah benchmarks rated A+.**
100
-
101
- For full documentation visit **[tina4.com](https://tina4.com)**.
102
-
103
- ---
104
-
105
- ## Install
106
-
107
19
  ```bash
108
20
  gem install tina4ruby
109
- ```
110
-
111
- ### Optional database drivers
112
-
113
- Install only what you need:
114
-
115
- ```bash
116
- gem install pg # PostgreSQL
117
- gem install mysql2 # MySQL / MariaDB (driver name: mysql)
118
- gem install tiny_tds # Microsoft SQL Server
119
- gem install fb # Firebird
120
- ```
121
-
122
- ---
123
-
124
- ## Getting Started
125
-
126
- ### 1. Create a project
127
-
128
- ```bash
129
21
  tina4ruby init my-app
130
- cd my-app
22
+ cd my-app && tina4ruby serve
131
23
  ```
132
24
 
133
- This creates:
134
-
135
- ```
136
- my-app/
137
- ├── app.rb # Entry point
138
- ├── .env # Configuration
139
- ├── Gemfile
140
- ├── src/
141
- │ ├── routes/ # API + page routes (auto-discovered)
142
- │ ├── orm/ # Database models
143
- │ ├── app/ # Service classes and shared helpers
144
- │ ├── templates/ # Frond/Twig templates
145
- │ ├── seeds/ # Database seeders
146
- │ ├── scss/ # SCSS (auto-compiled to public/css/)
147
- │ └── public/ # Static assets served at /
148
- ├── migrations/ # SQL migration files
149
- └── tests/ # RSpec tests
150
- ```
25
+ Open http://localhost:7147
151
26
 
152
- ### 2. Create a route
27
+ ---
153
28
 
154
- Create `src/routes/hello.rb`:
29
+ ## Code Examples
155
30
 
156
31
  ```ruby
157
32
  Tina4.get "/api/hello" do |request, response|
158
- response.json({ message: "Hello from Tina4!" })
159
- end
160
-
161
- Tina4.get "/api/hello/{name}" do |request, response|
162
- response.json({ message: "Hello, #{request.params["name"]}!" })
33
+ response.call({ message: "Hello from Tina4!" }, Tina4::HTTP_OK)
163
34
  end
164
- ```
165
-
166
- Visit `http://localhost:7147/api/hello` -- routes are auto-discovered, no requires needed.
167
-
168
- ### 3. Add a database
169
-
170
- Edit `.env`:
171
-
172
- ```bash
173
- DATABASE_URL=sqlite://data/app.db
174
- DATABASE_USERNAME=
175
- DATABASE_PASSWORD=
176
- ```
177
35
 
178
- Create and run a migration:
179
-
180
- ```bash
181
- tina4ruby migrate --create "create users table"
182
- ```
183
-
184
- Edit the generated SQL:
185
-
186
- ```sql
187
- CREATE TABLE IF NOT EXISTS users (
188
- id INTEGER PRIMARY KEY AUTOINCREMENT,
189
- name TEXT NOT NULL,
190
- email TEXT NOT NULL,
191
- created_at TEXT DEFAULT CURRENT_TIMESTAMP
192
- );
193
- ```
194
-
195
- ```bash
196
- tina4ruby migrate
197
- ```
198
-
199
- ### 4. Create an ORM model
200
-
201
- Create `src/orm/user.rb`:
202
-
203
- ```ruby
204
36
  class User < Tina4::ORM
205
37
  integer_field :id, primary_key: true, auto_increment: true
206
- string_field :name, nullable: false, length: 100
207
- string_field :email, length: 255
208
- datetime_field :created_at
38
+ string_field :name
39
+ string_field :email
209
40
  end
210
- ```
211
41
 
212
- ### 5. Build a REST API
213
-
214
- Create `src/routes/users.rb`:
215
-
216
- ```ruby
217
- Tina4.get "/api/users" do |request, response|
218
- response.json(User.all(limit: 100).map(&:to_hash))
219
- end
220
-
221
- Tina4.get "/api/users/{id}" do |request, response|
222
- user = User.find(request.params["id"])
223
- if user
224
- response.json(user.to_hash)
225
- else
226
- response.json({ error: "Not found" }, 404)
227
- end
228
- end
229
-
230
- Tina4.post "/api/users", auth: false do |request, response|
231
- user = User.create(request.json_body)
232
- response.json(user.to_hash, 201)
233
- end
234
- ```
235
-
236
- ### 6. Add a template
237
-
238
- Create `src/templates/base.twig`:
239
-
240
- ```twig
241
- <!DOCTYPE html>
242
- <html>
243
- <head>
244
- <title>{% block title %}My App{% endblock %}</title>
245
- <link rel="stylesheet" href="/css/tina4.min.css">
246
- {% block stylesheets %}{% endblock %}
247
- </head>
248
- <body>
249
- {% block content %}{% endblock %}
250
- <script src="/js/frond.js"></script>
251
- {% block javascripts %}{% endblock %}
252
- </body>
253
- </html>
42
+ db = Tina4::Database.new("sqlite://app.db")
254
43
  ```
255
44
 
256
- Create `src/templates/pages/home.twig`:
257
-
258
- ```twig
259
- {% extends "base.twig" %}
260
- {% block content %}
261
- <div class="container mt-4">
262
- <h1>{{ title }}</h1>
263
- <ul>
264
- {% for user in users %}
265
- <li>{{ user.name }} -- {{ user.email }}</li>
266
- {% endfor %}
267
- </ul>
268
- </div>
269
- {% endblock %}
270
- ```
271
-
272
- Render it from a route:
273
-
274
- ```ruby
275
- Tina4.get "/" do |request, response|
276
- users = User.all(limit: 20).map(&:to_hash)
277
- response.render("pages/home.twig", { title: "Users", users: users })
278
- end
279
- ```
280
-
281
- ### 7. Seed, test, deploy
282
-
283
- ```bash
284
- tina4ruby seed # Run seeders from src/seeds/
285
- tina4ruby test # Run test suite
286
- tina4ruby build # Build distributable
287
- ```
288
-
289
- For the complete step-by-step guide, visit **[tina4.com](https://tina4.com)**.
290
-
291
45
  ---
292
46
 
293
- ## Features
294
-
295
- ### Routing
296
-
297
- ```ruby
298
- Tina4.get "/api/items" do |request, response| # Public by default
299
- response.json({ items: [] })
300
- end
301
-
302
- Tina4.post "/api/webhook", auth: false do |request, response| # Make a write route public
303
- response.json({ ok: true })
304
- end
305
-
306
- Tina4.secure_get "/api/admin/stats" do |request, response| # Protect a GET route
307
- response.json({ secret: true })
308
- end
309
- ```
310
-
311
- Path parameter types: `{id}` (string), `{id:int}`, `{price:float}`, `{path:path}` (greedy).
312
-
313
- ### ORM
314
-
315
- Active Record with typed fields, validation, soft delete, relationships, scopes, and multi-database support.
316
-
317
- ```ruby
318
- class User < Tina4::ORM
319
- integer_field :id, primary_key: true, auto_increment: true
320
- string_field :name, nullable: false, length: 100
321
- string_field :email, length: 255
322
- string_field :role, default: "user"
323
- integer_field :age, default: 0
324
- end
325
-
326
- # CRUD
327
- user = User.new(name: "Alice", email: "alice@example.com")
328
- user.save
329
- user = User.find(1)
330
- user.delete
331
-
332
- # Relationships
333
- orders = user.has_many("Order", "user_id")
334
- profile = user.has_one("Profile", "user_id")
335
-
336
- # Soft delete, scopes, caching
337
- user.soft_delete
338
- active_admins = User.scope("active").scope("admin").select
339
- users = User.cached("SELECT * FROM users", ttl: 300)
340
-
341
- # Multi-database
342
- Tina4.database = Tina4::Database.new("sqlite://app.db") # Default
343
- Tina4.database("audit", Tina4::Database.new("sqlite://audit.db")) # Named
344
-
345
- class AuditLog < Tina4::ORM
346
- self.db_name = "audit" # Uses named connection
347
- end
348
- ```
349
-
350
- ### Database
351
-
352
- Unified interface across 5 engines:
353
-
354
- ```ruby
355
- db = Tina4::Database.new("sqlite://data/app.db")
356
- db = Tina4::Database.new("postgres://localhost:5432/mydb", username: "user", password: "pass")
357
- db = Tina4::Database.new("mysql://localhost:3306/mydb", username: "user", password: "pass")
358
- db = Tina4::Database.new("mssql://localhost:1433/mydb", username: "sa", password: "pass")
359
- db = Tina4::Database.new("firebird://localhost:3050/path/to/db", username: "SYSDBA", password: "masterkey")
360
-
361
- result = db.fetch("SELECT * FROM users WHERE age > ?", [18], limit: 20, offset: 0)
362
- row = db.fetch_one("SELECT * FROM users WHERE id = ?", [1])
363
- db.insert("users", { name: "Alice", email: "alice@test.com" })
364
- db.commit
365
- ```
366
-
367
- ### Middleware
368
-
369
- ```ruby
370
- Tina4.before("/protected") do |request, response|
371
- unless request.headers["authorization"]
372
- return request, response.json({ error: "Unauthorized" }, 401)
373
- end
374
- end
375
-
376
- Tina4.get "/protected" do |request, response|
377
- response.json({ secret: true })
378
- end
379
- ```
380
-
381
- ### JWT Authentication
382
-
383
- ```ruby
384
- token = Tina4::Auth.get_token({ user_id: 42 })
385
- result = Tina4::Auth.valid_token(token)
386
- payload = Tina4::Auth.get_payload(token)
387
- ```
388
-
389
- POST/PUT/PATCH/DELETE routes require `Authorization: Bearer <token>` by default. Use `auth: false` to make public, `secure_get` to protect GET routes.
390
-
391
- ### Sessions
392
-
393
- ```ruby
394
- request.session["user_id"] = 42
395
- user_id = request.session["user_id"]
396
- ```
397
-
398
- Backends: file (default), Redis, MongoDB. Set via `TINA4_SESSION_HANDLER` in `.env`.
399
-
400
- ### Queues
401
-
402
- ```ruby
403
- queue = Tina4::Queue.new(topic: "emails")
404
- queue.produce("emails", { to: "alice@example.com" })
405
-
406
- queue.consume("emails") { |msg| send_email(msg.payload) }
407
- ```
408
-
409
- ### GraphQL
410
-
411
- ```ruby
412
- gql = Tina4::GraphQL.new
413
- gql.schema.from_orm(User)
414
- gql.register_route("/graphql") # GET = GraphiQL IDE, POST = queries
415
- ```
416
-
417
- ### WebSocket
418
-
419
- ```ruby
420
- ws = Tina4::WebSocketManager.new
421
-
422
- ws.route "/ws/chat" do |connection, message|
423
- ws.broadcast("/ws/chat", "User said: #{message}")
424
- end
425
- ```
426
-
427
- ### Swagger / OpenAPI
428
-
429
- Auto-generated at `/swagger`:
430
-
431
- ```ruby
432
- Tina4.get "/api/users", swagger_meta: {
433
- summary: "Get all users",
434
- tags: ["users"]
435
- } do |request, response|
436
- response.json(User.all.map(&:to_hash))
437
- end
438
- ```
439
-
440
- ### Event System
441
-
442
- ```ruby
443
- Tina4.on("user.created", priority: 10) do |user|
444
- send_notification("New user: #{user[:name]}")
445
- end
446
-
447
- Tina4.emit("user.created", { name: "Alice" })
448
- ```
449
-
450
- ### Template Engine (Frond)
451
-
452
- Twig-compatible, 35+ filters, macros, inheritance, fragment caching, sandboxing:
453
-
454
- ```twig
455
- {% extends "base.twig" %}
456
- {% block content %}
457
- <h1>{{ title | upper }}</h1>
458
- {% for item in items %}
459
- <p>{{ item.name }} -- {{ item.price | number_format(2) }}</p>
460
- {% endfor %}
461
-
462
- {% cache "sidebar" 300 %}
463
- {% include "partials/sidebar.twig" %}
464
- {% endcache %}
465
- {% endblock %}
466
- ```
467
-
468
- ### CRUD Scaffolding
469
-
470
- ```ruby
471
- Tina4.get "/admin/users" do |request, response|
472
- response.json(Tina4::CRUD.to_crud(request, {
473
- sql: "SELECT id, name, email FROM users",
474
- title: "User Management",
475
- primary_key: "id"
476
- }))
477
- end
478
- ```
479
-
480
- ### REST Client
481
-
482
- ```ruby
483
- api = Tina4::API.new("https://api.example.com", headers: {
484
- "Authorization" => "Bearer xyz"
485
- })
486
- result = api.get("/users/42")
487
- ```
488
-
489
- ### Data Seeder
490
-
491
- ```ruby
492
- fake = Tina4::FakeData.new
493
- fake.name # "Alice Johnson"
494
- fake.email # "alice.johnson@example.com"
495
-
496
- Tina4.seed_orm(User, count: 50)
497
- ```
498
-
499
- ### Email / Messenger
500
-
501
- ```ruby
502
- mail = Tina4::Messenger.new
503
- mail.send(to: "user@test.com", subject: "Welcome", body: "<h1>Hi!</h1>", html: true)
504
- ```
505
-
506
- ### In-Memory Cache
507
-
508
- ```ruby
509
- cache = Tina4::Cache.new
510
- cache.set("key", "value", ttl: 300)
511
- cache.tag("users").flush
512
- ```
513
-
514
- ### SCSS, Localization, Inline Testing
515
-
516
- - **SCSS**: Drop `.scss` in `src/scss/` -- auto-compiled to CSS. Variables, nesting, mixins, `@import`, `@extend`.
517
- - **i18n**: JSON translation files, 6 languages (en, fr, af, zh, ja, es), placeholder interpolation.
518
- - **Inline tests**: `test_method :add, assert_equal: [[5, 3], 8]` on any method.
519
-
520
- ---
521
-
522
- ## Dev Mode
523
-
524
- Set `TINA4_DEBUG=true` in `.env` to enable:
47
+ ## What's Included
525
48
 
526
- - **Live reload** -- browser auto-refreshes on code changes
527
- - **CSS hot-reload** -- SCSS changes apply without page refresh
528
- - **Error overlay** -- rich error display in the browser
529
- - **Dev admin** at `/__dev/` with tabs: Routes, Queue, Mailbox, Messages, Database, Requests, Errors, WebSocket, System, Tools, Tina4
49
+ | Category | Features |
50
+ |----------|----------|
51
+ | **Core HTTP** (7) | Router with path params (`{id:int}`, `{p:path}`), Server, Request/Response, Middleware pipeline, Static file serving, CORS |
52
+ | **Database** (6) | SQLite, PostgreSQL, MySQL, MSSQL, Firebird — unified adapter, connection pooling, query cache, transactions, race-safe ID generation, SQL dialect translation |
53
+ | **ORM** (7) | Active Record with typed fields, relationships (`has_one`/`has_many`/`belongs_to`), soft delete, QueryBuilder + MongoDB support, Auto-CRUD generator, migrations with rollback |
54
+ | **Auth & Security** (5) | JWT (HS256/RS256), password hashing (PBKDF2-SHA256), API key validation, rate limiting, CSRF form tokens |
55
+ | **Templating** (3) | Frond engine (Twig/Jinja2-compatible, pre-compiled 2.8× faster), SCSS auto-compilation, built-in CSS (~24 KB) |
56
+ | **API & Integration** (5) | HTTP client (zero-dep), GraphQL with ORM auto-schema + GraphiQL IDE, WSDL/SOAP with auto WSDL, WebSocket (RFC 6455) + Redis backplane, MCP server (24 dev tools) |
57
+ | **Background** (3) | Job queue (File/RabbitMQ/Kafka/MongoDB) with priority, delay, retry, dead letters — service runner — event system (on/emit/once/off) |
58
+ | **Data & Storage** (4) | Session (File/Redis/Valkey/MongoDB/DB), response cache (LRU, TTL), seeder + 50+ fake data generators, messenger (SMTP/IMAP) |
59
+ | **Developer Tools** (7) | Dev dashboard (11 tabs), dev toolbar, error overlay (Catppuccin Mocha), dev mailbox, hot reload + CSS hot-reload, code metrics (complexity, coupling, maintainability), AI context installer (7 tools) |
60
+ | **Utilities** (7) | DI container (transient + singleton), HtmlElement builder, inline testing (`@tests` decorator), i18n (6 languages), Swagger/OpenAPI auto-generation, CLI scaffolding (`generate model/route/migration/middleware`), structured logging |
61
+
62
+ **1,793 tests. Zero runtime dependencies. Full parity across Python, PHP, Ruby, and Node.js.**
530
63
 
531
64
  ---
532
65
 
533
66
  ## CLI Reference
534
67
 
535
68
  ```bash
536
- tina4ruby init [dir] # Scaffold a new project
537
- tina4ruby serve [port] # Start dev server (default: 7147)
538
- tina4ruby serve --production # Auto-install and use Puma production server
539
- tina4ruby migrate # Run pending migrations
540
- tina4ruby migrate --create <desc># Create a migration file
541
- tina4ruby migrate --rollback # Rollback last batch
542
- tina4ruby generate model <name> # Generate ORM model scaffold
543
- tina4ruby generate route <name> # Generate route scaffold
544
- tina4ruby generate migration <d> # Generate migration file
545
- tina4ruby generate middleware <n># Generate middleware scaffold
546
- tina4ruby seed # Run seeders from src/seeds/
547
- tina4ruby routes # List all registered routes
548
- tina4ruby test # Run test suite
549
- tina4ruby build # Build distributable gem
550
- tina4ruby ai [--all] # Detect AI tools and install context
551
- ```
552
-
553
- ### Production Server Auto-Detection
554
-
555
- `tina4 serve` automatically detects and uses the best available production server:
556
-
557
- - **Ruby**: Puma (if installed), otherwise WEBrick -- Puma gives 2.8x improvement
558
- - Use `tina4ruby serve --production` to auto-install Puma
559
-
560
- ### Scaffolding with `tina4 generate`
561
-
562
- Quickly scaffold new components:
563
-
564
- ```bash
565
- tina4ruby generate model User # Creates src/orm/user.rb with field stubs
566
- tina4ruby generate route users # Creates src/routes/users.rb with CRUD stubs
567
- tina4ruby generate migration "add age" # Creates migration SQL file
568
- tina4ruby generate middleware AuthLog # Creates middleware class
569
- ```
570
-
571
- ### ORM Relationships & Eager Loading
572
-
573
- ```ruby
574
- # Relationships
575
- orders = user.has_many("Order", "user_id")
576
- profile = user.has_one("Profile", "user_id")
577
- customer = order.belongs_to("Customer", "customer_id")
578
-
579
- # Eager loading with include:
580
- users = User.all(include: ["orders", "profile"])
69
+ tina4ruby serve [--port PORT]
70
+ tina4ruby migrate
71
+ tina4ruby seed
72
+ tina4ruby ai [--all]
73
+ tina4ruby generate model <name>
581
74
  ```
582
75
 
583
- ### DB Query Caching
584
-
585
- Enable query caching for up to 4x speedup on read-heavy workloads:
586
-
587
- ```bash
588
- # .env
589
- TINA4_DB_CACHE=true
590
- ```
76
+ ---
591
77
 
592
- ### Frond Pre-Compilation
78
+ ## Performance
593
79
 
594
- Templates are pre-compiled for 2.8x faster rendering.
80
+ Benchmarked with `wrk` 5,000 requests, 50 concurrent, median of 3 runs:
595
81
 
596
- ### Gallery
82
+ | Framework | JSON req/s | Deps | Features |
83
+ |-----------|-----------|------|----------|
84
+ | **Tina4 Ruby** | **10,243** | 0 | 54 |
85
+ | Sinatra | 9,548 | 5+ | ~4 |
597
86
 
598
- 7 interactive examples with **Try It** deploy.
87
+ Tina4 Ruby outperforms Sinatra while delivering **54 features vs ~4** — with zero runtime dependencies.
599
88
 
600
- ## Environment
89
+ **Across all 4 Tina4 implementations:**
601
90
 
602
- ```bash
603
- SECRET=your-jwt-secret
604
- DATABASE_URL=sqlite://data/app.db
605
- DATABASE_USERNAME=
606
- DATABASE_PASSWORD=
607
- TINA4_DEBUG=true # Enable dev toolbar, error overlay
608
- TINA4_LOG_LEVEL=ALL # ALL, DEBUG, INFO, WARNING, ERROR
609
- TINA4_LOCALE=en # en, fr, af, zh, ja, es
610
- TINA4_SESSION_HANDLER=SessionFileHandler
611
- SWAGGER_TITLE=My API
612
- ```
91
+ | | Python | PHP | Ruby | Node.js |
92
+ |---|--------|-----|------|---------|
93
+ | **JSON req/s** | 6,508 | 29,293 | 10,243 | 84,771 |
94
+ | **Dependencies** | 0 | 0 | 0 | 0 |
95
+ | **Features** | 54 | 54 | 54 | 54 |
613
96
 
614
- ## Carbonah Green Benchmarks
97
+ ---
615
98
 
616
- All 9 benchmarks rated **A+** (South Africa grid, 1000 iterations each):
99
+ ## Cross-Framework Parity
617
100
 
618
- | Benchmark | SCI (gCO2eq) | Grade |
619
- |-----------|-------------|-------|
620
- | JSON Hello World | 0.000897 | A+ |
621
- | Single DB Query | 0.000561 | A+ |
622
- | Multiple DB Queries | 0.001402 | A+ |
623
- | Template Rendering | 0.003351 | A+ |
624
- | Large JSON Payload | 0.001019 | A+ |
625
- | Plaintext Response | 0.000391 | A+ |
626
- | CRUD Cycle | 0.000473 | A+ |
627
- | Paginated Query | 0.001027 | A+ |
628
- | Framework Startup | 0.00267 | A+ |
101
+ Tina4 ships identical features across four languages — same architecture, same conventions, same 54 features:
629
102
 
630
- Startup: 37ms | Memory: 34.9MB | SCI: 0.00267
103
+ | | Python | PHP | Ruby | Node.js |
104
+ |---|--------|-----|------|---------|
105
+ | **Package** | `tina4-python` | `tina4stack/tina4php` | `tina4ruby` | `tina4-nodejs` |
106
+ | **Tests** | 2,066 | 1,427 | 1,793 | 1,950 |
107
+ | **Default port** | 7145 | 7146 | 7147 | 7148 |
631
108
 
632
- Run locally: `ruby benchmarks/run_carbonah.rb`
109
+ **7,236 tests** across all 4 frameworks. See [tina4.com](https://tina4.com).
633
110
 
634
111
  ---
635
112
 
@@ -644,14 +121,10 @@ https://opensource.org/licenses/MIT
644
121
 
645
122
  ---
646
123
 
647
- <p align="center"><b>Tina4</b> -- The framework that keeps out of the way of your coding.</p>
648
-
649
- ---
650
-
651
124
  ## Our Sponsors
652
125
 
653
126
  **Sponsored with 🩵 by Code Infinity**
654
127
 
655
128
  [<img src="https://codeinfinity.co.za/wp-content/uploads/2025/09/c8e-logo-github.png" alt="Code Infinity" width="100">](https://codeinfinity.co.za/about-open-source-policy?utm_source=github&utm_medium=website&utm_campaign=opensource_campaign&utm_id=opensource)
656
129
 
657
- *Supporting open source communities <span style="color: #1DC7DE;">•</span> Innovate <span style="color: #1DC7DE;">•</span> Code <span style="color: #1DC7DE;">•</span> Empower*
130
+ *Supporting open source communities Innovate Code Empower*
data/lib/tina4/orm.rb CHANGED
@@ -248,6 +248,11 @@ module Tina4
248
248
  instances
249
249
  end
250
250
 
251
+ def select_one(sql, params = [], include: nil)
252
+ results = select(sql, params, limit: 1, include: include)
253
+ results.first
254
+ end
255
+
251
256
  def count(conditions = nil, params = [])
252
257
  sql = "SELECT COUNT(*) as cnt FROM #{table_name}"
253
258
  where_parts = []
@@ -346,9 +351,7 @@ module Tina4
346
351
  if soft_delete
347
352
  sql += " AND (#{soft_delete_field} IS NULL OR #{soft_delete_field} = 0)"
348
353
  end
349
- result = db.fetch_one(sql, [id])
350
- return nil unless result
351
- from_hash(result)
354
+ select_one(sql, [id])
352
355
  end
353
356
 
354
357
  def find_by_filter(filter)
data/lib/tina4/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tina4
4
- VERSION = "3.10.40"
4
+ VERSION = "3.10.41"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.40
4
+ version: 3.10.41
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team
@@ -262,7 +262,8 @@ dependencies:
262
262
  - - "~>"
263
263
  - !ruby/object:Gem::Version
264
264
  version: '1.50'
265
- description: A lightweight, zero-configuration, Windows-friendly Ruby web framework.
265
+ description: Tina4 for Ruby — 54 built-in features, zero dependencies. Full parity
266
+ with Python, PHP, and Node.js.
266
267
  email:
267
268
  - info@tina4.com
268
269
  executables:
@@ -421,5 +422,5 @@ requirements: []
421
422
  rubygems_version: 3.4.19
422
423
  signing_key:
423
424
  specification_version: 4
424
- summary: Simple. Fast. Human. This is not a framework.
425
+ summary: Tina4 for Ruby 54 built-in features, zero dependencies
425
426
  test_files: []