tina4ruby 3.10.55 → 3.10.60

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: 25b4d9017318ffe796da35f53d7865bd5ce5cad601a25d6dbffa512c649cd019
4
- data.tar.gz: 6ee84f47f431b714ff0b4ac84ff606c3406ca5e2896d17a0835b98f23ac9385f
3
+ metadata.gz: ddb9c534659e0d305415603e274260d767bc4970a35522a810953265096d3749
4
+ data.tar.gz: 81fcaba8b3541777f3211b4e9972004b08718e97821debdb534fad71f06a1796
5
5
  SHA512:
6
- metadata.gz: eb0387a9321fb64193433c5d975bce3f7cfb2d25af20dcf9786cf361f6471cfecbbecad9a026e60f95f34446aa1fef65d77d93d19acb14ca7b1b6e615924cbb4
7
- data.tar.gz: 73a21f6cd92dda7b2a747d824b68685e827d87b4e42ae92fb2313e69af5fef4e3704e7bca70674045ed5f149926ff4a9fc2ae8a1de2ea2a6bd41e70d4de14aa6
6
+ metadata.gz: 80aae860b1a396277acbd1c6157f3d463f8345e803c8a70d1e89a3a0915ab609bda1eb6825fc73e107681105ada1a226b77f85e2e782af5940c6ba634a4e1582
7
+ data.tar.gz: 46f3e5b59f8d98e1c7574093e3ecb2e5dbc0160bc3565b04cbd086beaf2a43ea74005c530de5a70bd3f0108965d3ada5e902328a58fcb75c5d6a12d067d57c66
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
  <img src="https://tina4.com/logo.svg" alt="Tina4" width="200">
3
3
  </p>
4
4
  <h1 align="center">Tina4 Ruby</h1>
5
- <h3 align="center">This Is Now A 4Framework</h3>
5
+ <h3 align="center">TINA4 The Intelligent Native Application 4ramework</h3>
6
+ <p align="center"><em>Simple. Fast. Human. &nbsp;|&nbsp; Built for AI. Built for you.</em></p>
6
7
  <p align="center">54 built-in features. Zero runtime dependencies. One require, everything works.</p>
7
8
  <p align="center">
8
9
  <a href="https://rubygems.org/gems/tina4ruby"><img src="https://img.shields.io/gem/v/tina4ruby?color=7b1fa2&label=RubyGems" alt="RubyGems"></a>
data/lib/tina4/metrics.rb CHANGED
@@ -406,11 +406,13 @@ module Tina4
406
406
 
407
407
  def self._has_matching_test(rel_path)
408
408
  name = File.basename(rel_path, '.rb')
409
- ['spec', 'test'].any? do |dir|
410
- File.exist?("#{dir}/#{name}_spec.rb") ||
411
- File.exist?("#{dir}/#{name}_test.rb") ||
412
- File.exist?("#{dir}/test_#{name}.rb")
413
- end
409
+ File.exist?("spec/#{name}_spec.rb") ||
410
+ File.exist?("spec/#{name}s_spec.rb") ||
411
+ File.exist?("spec/tina4/#{name}_spec.rb") ||
412
+ File.exist?("test/#{name}_test.rb") ||
413
+ File.exist?("spec/#{name}_test.rb") ||
414
+ File.exist?("test/test_#{name}.rb") ||
415
+ File.exist?("test/#{name}_spec.rb")
414
416
  end
415
417
 
416
418
  def self._files_hash(root)
@@ -460,7 +460,8 @@ module Tina4
460
460
  <div class="hero">
461
461
  <img src="/images/tina4-logo-icon.webp" class="logo" alt="Tina4">
462
462
  <h1>Tina4Ruby</h1>
463
- <p class="tagline">This Is Now A 4Framework</p>
463
+ <p class="tagline">The Intelligent Native Application 4ramework</p>
464
+ <p class="tagline" style="font-size:0.95rem;margin-top:-1rem">Simple. Fast. Human. &nbsp;|&nbsp; Built for AI. Built for you.</p>
464
465
  <div class="actions">
465
466
  <a href="https://tina4.com/ruby" class="btn" target="_blank">Website</a>
466
467
  <a href="/__dev" class="btn">Dev Admin</a>
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.55"
4
+ VERSION = "3.10.60"
5
5
  end
@@ -8,10 +8,71 @@ module Tina4
8
8
  @port = port
9
9
  end
10
10
 
11
+ # Kill whatever process is listening on *port*.
12
+ # Uses lsof on macOS/Linux and netstat + taskkill on Windows.
13
+ # Raises RuntimeError if the port cannot be freed.
14
+ def free_port(port)
15
+ puts " Port #{port} in use — killing existing process..."
16
+
17
+ if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
18
+ output = `netstat -ano 2>&1`
19
+ pid = nil
20
+ output.each_line do |line|
21
+ if line.include?(":#{port}") && (line.include?("LISTENING") || line.include?("ESTABLISHED"))
22
+ parts = line.strip.split(/\s+/)
23
+ candidate = parts.last
24
+ if candidate =~ /^\d+$/
25
+ pid = candidate
26
+ break
27
+ end
28
+ end
29
+ end
30
+ if pid
31
+ system("taskkill /PID #{pid} /F")
32
+ else
33
+ raise "Could not free port #{port}: no PID found"
34
+ end
35
+ else
36
+ pids = `lsof -ti :#{port} 2>/dev/null`.strip.split("\n")
37
+ if pids.empty?
38
+ return # Nothing found — port may have freed itself
39
+ end
40
+ pids.each do |pid|
41
+ pid = pid.strip
42
+ next unless pid =~ /^\d+$/
43
+ begin
44
+ Process.kill("TERM", pid.to_i)
45
+ rescue Errno::ESRCH
46
+ # Process already gone
47
+ end
48
+ end
49
+ end
50
+
51
+ # Give the OS a moment to reclaim the port
52
+ sleep(0.5)
53
+ puts " Port #{port} freed"
54
+ end
55
+
11
56
  def start
12
57
  require "webrick"
13
58
  require "stringio"
14
59
  require "socket"
60
+
61
+ # Ensure the main port is available — kill whatever is on it if needed
62
+ begin
63
+ test = TCPServer.new("0.0.0.0", @port)
64
+ test.close
65
+ rescue Errno::EADDRINUSE
66
+ free_port(@port)
67
+ # Verify the port is now free; raise if still occupied
68
+ begin
69
+ test = TCPServer.new("0.0.0.0", @port)
70
+ test.close
71
+ rescue Errno::EADDRINUSE
72
+ raise "Could not free port #{@port}"
73
+ end
74
+ end
75
+
15
76
  Tina4.print_banner(host: @host, port: @port)
16
77
  Tina4::Log.info("Starting Tina4 WEBrick server on http://#{@host}:#{@port}")
17
78
  @server = WEBrick::HTTPServer.new(
@@ -103,14 +164,14 @@ module Tina4
103
164
 
104
165
  @server.mount("/", servlet, rack_app)
105
166
 
106
- # AI dev port (port + 1) — no-reload, no-browser
167
+ # Test port (port + 1000) — stable, no-browser
107
168
  @ai_server = nil
108
169
  @ai_thread = nil
109
170
  no_ai_port = %w[true 1 yes].include?(ENV.fetch("TINA4_NO_AI_PORT", "").downcase)
110
171
  is_debug = %w[true 1 yes].include?(ENV.fetch("TINA4_DEBUG", "").downcase)
111
172
 
112
173
  if is_debug && !no_ai_port
113
- ai_port = @port + 1
174
+ ai_port = @port + 1000
114
175
  begin
115
176
  test = TCPServer.new("0.0.0.0", ai_port)
116
177
  test.close
@@ -201,9 +262,9 @@ module Tina4
201
262
 
202
263
  @ai_server.mount("/", ai_servlet, ai_rack_app)
203
264
  @ai_thread = Thread.new { @ai_server.start }
204
- puts " AI Port: http://localhost:#{ai_port} (no-reload)"
265
+ puts " Test Port: http://localhost:#{ai_port} (stable — no hot-reload)"
205
266
  rescue Errno::EADDRINUSE
206
- puts " AI Port: SKIPPED (port #{ai_port} in use)"
267
+ puts " Test Port: SKIPPED (port #{ai_port} in use)"
207
268
  end
208
269
  end
209
270
 
data/lib/tina4.rb CHANGED
@@ -138,7 +138,8 @@ module Tina4
138
138
  end
139
139
 
140
140
  puts "#{color}#{BANNER}#{reset}"
141
- puts " Tina4 Ruby v#{VERSION} This Is Now A 4Framework"
141
+ puts " TINA4The Intelligent Native Application 4ramework"
142
+ puts " Simple. Fast. Human. | Built for AI. Built for you."
142
143
  puts ""
143
144
  puts " Server: http://#{display}:#{port} (#{server_name})"
144
145
  puts " Swagger: http://localhost:#{port}/swagger"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.55
4
+ version: 3.10.60
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-02 00:00:00.000000000 Z
11
+ date: 2026-04-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -262,8 +262,9 @@ dependencies:
262
262
  - - "~>"
263
263
  - !ruby/object:Gem::Version
264
264
  version: '1.50'
265
- description: Tina4 for Ruby 54 built-in features, zero dependencies. Full parity
266
- with Python, PHP, and Node.js.
265
+ description: 'TINA4: The Intelligent Native Application 4ramework for Ruby — Simple.
266
+ Fast. Human. Built for AI. Built for you. 54 built-in features, zero dependencies.
267
+ Full parity with Python, PHP, and Node.js.'
267
268
  email:
268
269
  - info@tina4.com
269
270
  executables: