hyraft 0.1.0.alpha1

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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/CODE_OF_CONDUCT.md +132 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +231 -0
  6. data/exe/hyraft +5 -0
  7. data/lib/hyraft/boot/asset_preloader.rb +185 -0
  8. data/lib/hyraft/boot/preloaded_static.rb +46 -0
  9. data/lib/hyraft/boot/preloader.rb +206 -0
  10. data/lib/hyraft/cli.rb +187 -0
  11. data/lib/hyraft/compiler/compiler.rb +34 -0
  12. data/lib/hyraft/compiler/html_purifier.rb +181 -0
  13. data/lib/hyraft/compiler/javascript_library.rb +281 -0
  14. data/lib/hyraft/compiler/javascript_obfuscator.rb +141 -0
  15. data/lib/hyraft/compiler/parser.rb +27 -0
  16. data/lib/hyraft/compiler/renderer.rb +217 -0
  17. data/lib/hyraft/engine/circuit.rb +35 -0
  18. data/lib/hyraft/engine/port.rb +17 -0
  19. data/lib/hyraft/engine/source.rb +19 -0
  20. data/lib/hyraft/engine.rb +11 -0
  21. data/lib/hyraft/router/api_router.rb +65 -0
  22. data/lib/hyraft/router/web_router.rb +136 -0
  23. data/lib/hyraft/system_info.rb +26 -0
  24. data/lib/hyraft/version.rb +5 -0
  25. data/lib/hyraft.rb +48 -0
  26. data/templates/do_app/Gemfile +50 -0
  27. data/templates/do_app/Rakefile +88 -0
  28. data/templates/do_app/adapter-intake/web-app/display/pages/home/home.hyr +174 -0
  29. data/templates/do_app/adapter-intake/web-app/request/home_web_adapter.rb +19 -0
  30. data/templates/do_app/boot.rb +41 -0
  31. data/templates/do_app/framework/adapters/server/server_api_adapter.rb +51 -0
  32. data/templates/do_app/framework/adapters/server/server_web_adapter.rb +178 -0
  33. data/templates/do_app/framework/compiler/style_resolver.rb +33 -0
  34. data/templates/do_app/framework/errors/error_handler.rb +75 -0
  35. data/templates/do_app/framework/errors/templates/304.html +22 -0
  36. data/templates/do_app/framework/errors/templates/400.html +22 -0
  37. data/templates/do_app/framework/errors/templates/401.html +22 -0
  38. data/templates/do_app/framework/errors/templates/403.html +22 -0
  39. data/templates/do_app/framework/errors/templates/404.html +62 -0
  40. data/templates/do_app/framework/errors/templates/500.html +73 -0
  41. data/templates/do_app/framework/middleware/cors_middleware.rb +37 -0
  42. data/templates/do_app/infra/config/environment.rb +86 -0
  43. data/templates/do_app/infra/config/error_config.rb +80 -0
  44. data/templates/do_app/infra/config/routes/api_routes.rb +2 -0
  45. data/templates/do_app/infra/config/routes/web_routes.rb +10 -0
  46. data/templates/do_app/infra/database/sequel_connection.rb +62 -0
  47. data/templates/do_app/infra/gems/database.rb +7 -0
  48. data/templates/do_app/infra/gems/load_all.rb +4 -0
  49. data/templates/do_app/infra/gems/utilities.rb +1 -0
  50. data/templates/do_app/infra/gems/web.rb +3 -0
  51. data/templates/do_app/infra/server/api-server.ru +13 -0
  52. data/templates/do_app/infra/server/web-server.ru +32 -0
  53. data/templates/do_app/package.json +9 -0
  54. data/templates/do_app/public/favicon.ico +0 -0
  55. data/templates/do_app/public/icons/docs.svg +10 -0
  56. data/templates/do_app/public/icons/expli.svg +13 -0
  57. data/templates/do_app/public/icons/git-repo.svg +13 -0
  58. data/templates/do_app/public/icons/hexagonal-arch.svg +15 -0
  59. data/templates/do_app/public/icons/template-engine.svg +26 -0
  60. data/templates/do_app/public/images/hyr-logo.png +0 -0
  61. data/templates/do_app/public/images/hyr-logo.webp +0 -0
  62. data/templates/do_app/public/index.html +22 -0
  63. data/templates/do_app/public/styles/css/main.css +418 -0
  64. data/templates/do_app/public/styles/css/spa.css +171 -0
  65. data/templates/do_app/shared/helpers/pagination_helper.rb +44 -0
  66. data/templates/do_app/shared/helpers/response_formatter.rb +25 -0
  67. data/templates/do_app/test/acceptance/api/articles_api_acceptance_test.rb +43 -0
  68. data/templates/do_app/test/acceptance/web/articles_acceptance_test.rb +31 -0
  69. data/templates/do_app/test/acceptance/web/home_acceptance_test.rb +17 -0
  70. data/templates/do_app/test/db.rb +106 -0
  71. data/templates/do_app/test/integration/adapter-exhaust/data-gateway/sequel_articles_gateway_test.rb +79 -0
  72. data/templates/do_app/test/integration/adapter-intake/api-app/request/articles_api_adapter_test.rb +61 -0
  73. data/templates/do_app/test/integration/adapter-intake/web-app/request/articles_web_adapter_test.rb +20 -0
  74. data/templates/do_app/test/integration/adapter-intake/web-app/request/home_web_adapter_test.rb +17 -0
  75. data/templates/do_app/test/integration/database/migration_test.rb +35 -0
  76. data/templates/do_app/test/support/mock_api_adapter.rb +82 -0
  77. data/templates/do_app/test/support/mock_articles_gateway.rb +41 -0
  78. data/templates/do_app/test/support/mock_web_adapter.rb +85 -0
  79. data/templates/do_app/test/support/test_patches.rb +33 -0
  80. data/templates/do_app/test/test_helper.rb +526 -0
  81. data/templates/do_app/test/unit/engine/circuit/articles_circuit_test.rb +167 -0
  82. data/templates/do_app/test/unit/engine/port/articles_gateway_port_test.rb +12 -0
  83. data/templates/do_app/test/unit/engine/source/article_test.rb +37 -0
  84. metadata +291 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyraft
4
+ class Port
5
+ def implementor=(adapter)
6
+ @implementor = adapter
7
+ end
8
+
9
+ def method_missing(method, *args, &block)
10
+ if @implementor&.respond_to?(method)
11
+ @implementor.send(method, *args, &block)
12
+ else
13
+ super
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyraft
4
+ class Source
5
+ attr_accessor :id
6
+
7
+ def initialize(attributes = {})
8
+ @id = attributes[:id]
9
+ end
10
+
11
+ def to_hash
12
+ { id: @id }
13
+ end
14
+
15
+ def persisted?
16
+ !@id.nil?
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "engine/source"
4
+ require_relative "engine/circuit"
5
+ require_relative "engine/port"
6
+
7
+ module Engine
8
+ Source = Hyraft::Source
9
+ Circuit = Hyraft::Circuit
10
+ Port = Hyraft::Port
11
+ end
@@ -0,0 +1,65 @@
1
+ # lib/hyraft/router/api_router.rb
2
+ module Hyraft
3
+ module Router
4
+ class ApiRouter
5
+ Route = Struct.new(:http_method, :path, :handler_class, :action_name, :regex)
6
+
7
+ def initialize
8
+ @routes = []
9
+ end
10
+
11
+ def self.draw(&block)
12
+ router = new
13
+ router.instance_eval(&block)
14
+ router
15
+ end
16
+
17
+ def GET(path, to:)
18
+ add_route('GET', path, to)
19
+ end
20
+
21
+ def POST(path, to:)
22
+ add_route('POST', path, to)
23
+ end
24
+
25
+ def PUT(path, to:)
26
+ add_route('PUT', path, to)
27
+ end
28
+
29
+ def DELETE(path, to:)
30
+ add_route('DELETE', path, to)
31
+ end
32
+
33
+ def resolve(http_method, path_info)
34
+ path = path_info.split('?').first
35
+
36
+ # Try exact matches first
37
+ exact_match = @routes.find do |r|
38
+ r.http_method == http_method && r.path == path
39
+ end
40
+ return [exact_match, []] if exact_match
41
+
42
+ # Then try regex matches
43
+ @routes.each do |r|
44
+ if r.http_method == http_method && (match = r.regex.match(path))
45
+ return [r, match.captures]
46
+ end
47
+ end
48
+
49
+ nil
50
+ end
51
+
52
+ def add_route(http_method, path, to)
53
+ handler_class, action_name = to
54
+ regex = compile(path)
55
+ @routes << Route.new(http_method, path, handler_class, action_name, regex)
56
+ end
57
+
58
+ private
59
+
60
+ def compile(path)
61
+ Regexp.new("^" + path.gsub(/:([a-zA-Z_]\w*)/, '([^/]+)') + "$")
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,136 @@
1
+ # lib/hyraft/router/web_router.rb
2
+ module Hyraft
3
+ module Router
4
+ class WebRouter
5
+ Route = Struct.new(:path, :method, :handler_class, :action, :template)
6
+
7
+ def self.draw(&block)
8
+ router = new
9
+ router.instance_eval(&block)
10
+ router
11
+ end
12
+
13
+ def initialize
14
+ @routes = []
15
+ end
16
+
17
+ def GET(path, to:, template: nil)
18
+ add_route('GET', path, to, template)
19
+ end
20
+
21
+ def POST(path, to:, template: nil)
22
+ add_route('POST', path, to, template)
23
+ end
24
+
25
+ def PUT(path, to:, template: nil)
26
+ add_route('PUT', path, to, template)
27
+ end
28
+
29
+ def DELETE(path, to:, template: nil)
30
+ add_route('DELETE', path, to, template)
31
+ end
32
+
33
+ def add_route(method, path, to, template = nil)
34
+ handler_class, action = to
35
+ @routes << Route.new(path, method, handler_class, action, template)
36
+ end
37
+
38
+ def resolve(method, path)
39
+ # Normalize path - remove trailing slashes except for root
40
+ normalized_path = path.gsub(%r{/+$}, '')
41
+ normalized_path = '/' if normalized_path.empty?
42
+
43
+ # puts "DEBUG: Resolving #{method} #{path} -> normalized: #{normalized_path}"
44
+
45
+ # First, try to find exact matches (non-parameter routes)
46
+ exact_match = @routes.find do |r|
47
+ r.method == method && !r.path.include?(':') && !r.path.include?('*') && r.path == normalized_path
48
+ end
49
+
50
+ if exact_match
51
+ # puts "DEBUG: Exact match found: #{exact_match.path}"
52
+ return [exact_match, []]
53
+ end
54
+
55
+ # Then try parameter routes (routes with :)
56
+ param_match = @routes.find do |r|
57
+ r.method == method && r.path.include?(':') && !r.path.include?('*') && match_path(r.path, normalized_path)
58
+ end
59
+
60
+ if param_match
61
+ # puts "DEBUG: Parameter match found: #{param_match.path}"
62
+ params = extract_params(param_match.path, normalized_path)
63
+ return [param_match, params]
64
+ end
65
+
66
+ # Finally try wildcard routes
67
+ wildcard_match = @routes.find do |r|
68
+ r.method == method && r.path.include?('*') && match_path(r.path, normalized_path)
69
+ end
70
+
71
+ if wildcard_match
72
+ # puts "DEBUG: Wildcard match found: #{wildcard_match.path}"
73
+ params = extract_params(wildcard_match.path, normalized_path)
74
+ return [wildcard_match, params]
75
+ end
76
+
77
+ # puts "DEBUG: No route found for #{method} #{normalized_path}"
78
+ nil
79
+ end
80
+
81
+ private
82
+
83
+ def match_path(route_path, request_path)
84
+ route_segments = route_path.split('/')
85
+ request_segments = request_path.split('/')
86
+
87
+ # Handle wildcard routes
88
+ if route_path.include?('*')
89
+ # For wildcard routes, check if the beginning matches
90
+ wildcard_index = route_segments.index('*')
91
+ return false unless wildcard_index
92
+
93
+ # Check if all segments before the wildcard match
94
+ (0...wildcard_index).each do |i|
95
+ return false unless route_segments[i] == request_segments[i]
96
+ end
97
+
98
+ return true # Wildcard matches everything after
99
+ end
100
+
101
+ # For parameter routes, check segment count
102
+ return false unless route_segments.length == request_segments.length
103
+
104
+ # Check each segment
105
+ route_segments.zip(request_segments).all? do |r, req|
106
+ r.start_with?(':') || r == req
107
+ end
108
+ end
109
+
110
+ def extract_params(route_path, request_path)
111
+ route_segments = route_path.split('/')
112
+ request_segments = request_path.split('/')
113
+
114
+ params = []
115
+
116
+ # Handle wildcard routes
117
+ if route_path.include?('*')
118
+ wildcard_index = route_segments.index('*')
119
+ if wildcard_index
120
+ # Capture everything after the wildcard as a single parameter
121
+ captured_path = request_segments[wildcard_index..-1]&.join('/') || ''
122
+ params << captured_path
123
+ end
124
+ return params
125
+ end
126
+
127
+ # Normal parameter extraction
128
+ route_segments.zip(request_segments).each do |r, req|
129
+ params << req if r.start_with?(':')
130
+ end
131
+
132
+ params
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,26 @@
1
+ # lib/hyraft/system_info.rb
2
+ require 'rbconfig'
3
+
4
+ module Hyraft
5
+ module SystemInfo
6
+ def self.os_name
7
+ host = RbConfig::CONFIG['host_os']
8
+ if host =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
9
+ begin
10
+ require 'win32/registry'
11
+ Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Microsoft\Windows NT\CurrentVersion') do |reg|
12
+ reg['ProductName'] # => "Ex. Windows 11 Pro?"
13
+ end
14
+ rescue LoadError
15
+ "Windows (version unknown)"
16
+ end
17
+ elsif host =~ /darwin|mac os/
18
+ "macOS"
19
+ elsif host =~ /linux/
20
+ "Linux"
21
+ else
22
+ host
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyraft
4
+ VERSION = "0.1.0.alpha1"
5
+ end
data/lib/hyraft.rb ADDED
@@ -0,0 +1,48 @@
1
+ # lib/hyraft.rb
2
+ # frozen_string_literal: true
3
+
4
+ require 'fileutils'
5
+ require_relative "hyraft/system_info"
6
+ require_relative "hyraft/cli"
7
+ require_relative "hyraft/version"
8
+
9
+ require_relative "hyraft/engine/source"
10
+ require_relative "hyraft/engine/circuit"
11
+ require_relative "hyraft/engine/port"
12
+ require_relative "hyraft/engine"
13
+
14
+ # compiler components
15
+ require_relative "hyraft/compiler/compiler"
16
+ require_relative "hyraft/compiler/parser"
17
+ require_relative "hyraft/compiler/renderer"
18
+ require_relative "hyraft/compiler/javascript_library"
19
+
20
+ # router components
21
+ require_relative "hyraft/router/api_router"
22
+ require_relative "hyraft/router/web_router"
23
+
24
+ # PRELOADER
25
+ require_relative "hyraft/boot/preloader"
26
+ require_relative "hyraft/boot/asset_preloader"
27
+ require_relative "hyraft/boot/preloaded_static"
28
+
29
+ require_relative "hyraft/compiler/javascript_obfuscator"
30
+
31
+ module Hyraft
32
+ class Error < StandardError; end
33
+ end
34
+
35
+ # Define the standard top-level constants
36
+ HyraftCompiler = Hyraft::Compiler::HyraftCompiler
37
+ HyraftParser = Hyraft::Compiler::HyraftParser
38
+ HyraftRenderer = Hyraft::Compiler::HyraftRenderer
39
+
40
+ # Top-level aliases for backward compatibility
41
+ ApiRouter = Hyraft::Router::ApiRouter
42
+ WebRouter = Hyraft::Router::WebRouter
43
+
44
+ # ADD PRELOADER ALIAS
45
+ HyraftPreloader = Hyraft::Preloader
46
+ HyraftAssetPreloader = Hyraft::AssetPreloader
47
+ HyraftPreloadedStatic = Hyraft::PreloadedStatic
48
+
@@ -0,0 +1,50 @@
1
+ # Gemfile
2
+ source 'https://rubygems.org'
3
+
4
+ #_________________________#
5
+ # #
6
+ # FRAMEWORK #
7
+
8
+ gem 'hyraft'
9
+ gem 'hyraft-rule'
10
+
11
+ #_________________________#
12
+
13
+
14
+
15
+
16
+ #_________________________#
17
+ # #
18
+ # SERVER #
19
+ gem "fiddle" #/ for windows
20
+ gem 'thin'
21
+ # gem 'puma'
22
+ # gem 'falcon', '~> 0.52.3'
23
+ # gem 'async-http' # for http 3 (via Falcon)
24
+ # gem 'iodine'
25
+
26
+ #_________________________#
27
+
28
+
29
+ #_________________________#
30
+ # #
31
+ # DATABASE #
32
+ # gem 'pg'
33
+ # gem 'mysql2', '~> 0.5.7'
34
+ #_________________________#
35
+
36
+
37
+ # Test gems compatible with Ruby 3.4
38
+
39
+ =begin
40
+
41
+ gem 'minitest', '~> 5.26', '>= 5.26.1'
42
+ gem 'minitest-reporters', '~> 1.7', '>= 1.7.1'
43
+ gem 'minitest-focus', '~> 1.4'
44
+ gem 'mocha', '~> 2.8'
45
+ gem 'rack-test', '~> 2.2', group: :test
46
+
47
+ end
48
+
49
+ =end
50
+
@@ -0,0 +1,88 @@
1
+ # Rakefile
2
+ require 'rake/testtask'
3
+
4
+ namespace :test do
5
+ desc "Run all tests"
6
+ Rake::TestTask.new(:all) do |t|
7
+ t.libs << "test"
8
+ t.test_files = FileList[
9
+ "test/unit/**/*_test.rb",
10
+ "test/integration/**/*_test.rb",
11
+ "test/acceptance/**/*_test.rb"
12
+ ]
13
+ t.verbose = true
14
+ t.warning = false
15
+ end
16
+
17
+ desc "Run API tests only"
18
+ Rake::TestTask.new(:api) do |t|
19
+ t.libs << "test"
20
+ t.test_files = FileList[
21
+ "test/integration/adapter-intake/api-app/**/*_test.rb",
22
+ "test/acceptance/api/**/*_test.rb"
23
+ ]
24
+ t.verbose = true
25
+ t.warning = false
26
+ end
27
+
28
+ desc "Run unit tests only"
29
+ Rake::TestTask.new(:unit) do |t|
30
+ t.libs << "test"
31
+ t.test_files = FileList["test/unit/**/*_test.rb"]
32
+ t.verbose = true
33
+ t.warning = false
34
+ end
35
+
36
+ desc "Run integration tests only"
37
+ Rake::TestTask.new(:integration) do |t|
38
+ t.libs << "test"
39
+ t.test_files = FileList["test/integration/**/*_test.rb"]
40
+ t.verbose = true
41
+ t.warning = false
42
+ end
43
+
44
+ desc "Run acceptance tests only"
45
+ Rake::TestTask.new(:acceptance) do |t|
46
+ t.libs << "test"
47
+ t.test_files = FileList["test/acceptance/web/**/*_test.rb"]
48
+ t.verbose = true
49
+ t.warning = false
50
+ end
51
+
52
+ desc "Test database connection"
53
+ task :test_db do
54
+ require 'yaml'
55
+ require 'sequel'
56
+
57
+ config = YAML.load_file('env.yml')
58
+ test_config = config['test']
59
+
60
+ puts "Testing connection to: #{test_config['DB_DATABASE']}"
61
+
62
+ begin
63
+ # Map 'mysql' to 'mysql2' for Sequel
64
+ adapter = test_config['DB_CONNECTION'] == 'mysql' ? 'mysql2' : test_config['DB_CONNECTION']
65
+
66
+ db = Sequel.connect(
67
+ adapter: adapter,
68
+ host: test_config['DB_HOST'],
69
+ database: test_config['DB_DATABASE'],
70
+ username: test_config['DB_USERNAME'],
71
+ password: test_config['DB_PASSWORD'],
72
+ socket: test_config['DB_SOCKET']
73
+ )
74
+
75
+ db.test_connection
76
+ puts "✅ Connection successful!"
77
+ puts "📊 Tables: #{db.tables.join(', ')}"
78
+
79
+ rescue => e
80
+ puts "❌ Connection failed: #{e.message}"
81
+ end
82
+ end
83
+ end
84
+
85
+ desc "Run all tests"
86
+ task test: 'test:all'
87
+
88
+ task default: :test
@@ -0,0 +1,174 @@
1
+ <metadata html>
2
+ <require file="lib/neonpulse" />
3
+ <title>[.page_title.]</title>
4
+ <meta name="description" content="[.page_description.]">
5
+ <meta name="keywords" content="[.page_keywords.]">
6
+ <link rel="canonical" href="[.page_url.]">
7
+ <meta name="robots" content="index, follow">
8
+ <meta property="og:title" content="[.page_title.]">
9
+ <meta property="og:description" content="[.page_description.]">
10
+ <meta property="og:type" content="website">
11
+ <meta property="og:url" content="[.page_url.]">
12
+ <meta property="og:image" content="[.page_image.]">
13
+
14
+ <script type="application/ld+json">
15
+ {
16
+ "@context": "https://schema.org",
17
+ "@type": "Home",
18
+ "headline": "[.page_title.]",
19
+ "description": "[.page_description.]",
20
+ "author": { "@type": "Person", "name": "[.author_name.]" },
21
+ "datePublished": "[.publish_date.]"
22
+ }
23
+ </script>
24
+ </metadata>
25
+
26
+ <displayer html>
27
+ <div class="main-container">
28
+ <!-- main-header -->
29
+ <div class="main-header">
30
+ <picture>
31
+ <source srcset="/images/hyr-logo.webp" type="image/webp">
32
+ <img src="/images/hyr-logo.png" alt="Hyr Logo" class="logo">
33
+ </picture>
34
+ <h1>Hyraft</h1> Version: [.hyraft_version.]
35
+
36
+
37
+ <welcome-message anyword="the new" framework="framework!"/>
38
+
39
+
40
+
41
+
42
+ <hr>
43
+ <p class="home-subtitle">
44
+ <span style="font-weight:bold; color:black;">Hexagonal Ruby framework (not MVC) </span> with reactive front-end support and full-stack capabilities. Hybrid SSR/CSR with Single-File Components ensures lightning-fast performance, scalability, maintainability, and SEO friendliness.</p>
45
+
46
+
47
+
48
+
49
+ <div class="counter">
50
+ <button data-pulse="counter.decrease" class="counter-btn">-</button>
51
+ <span data-neon="count" class="count-display">10</span>
52
+ <button data-pulse="counter.increase" class="counter-btn">+</button>
53
+ </div>
54
+ <small data-neon="countStatus" class="status-text">Count: 10</small>
55
+ </div>
56
+
57
+
58
+ <br>
59
+
60
+ <!-- home-features -->
61
+ <div class="main-feature">
62
+ <p class="home-subtitle">
63
+ <span style="font-weight:bold; color:red;">Find me:</span> adapter-intake/web-app/display/pages/home/home.hyr</p>
64
+
65
+
66
+
67
+ <div class="home-feature-grid">
68
+ <div class="home-feature">
69
+ <div class="home-feature-icon"><img src="/icons/expli.svg" alt="No Magic" class="icon-home-feature"></div>
70
+ <h3>Explicit Code (No Magic)</h3>
71
+ <p>Enjoy a framework with explicit behavior—no hidden magic.</p>
72
+ </div>
73
+ <div class="home-feature">
74
+ <div class="home-feature-icon"><img src="/icons/hexagonal-arch.svg" alt="Hexagonal Architecture" class="icon-home-feature"></div>
75
+ <h3>Hexagonal Architecture</h3>
76
+ <p>Clean separation with ports, adapters, and use cases</p>
77
+ </div>
78
+ <div class="home-feature">
79
+ <div class="home-feature-icon"><img src="/icons/template-engine.svg" alt="Template Engine" class="icon-home-feature"></div>
80
+ <h3>Custom Template Engine</h3>
81
+ <p>.hyr files with metadata, displayer, transmuters, and manifestors</p>
82
+ </div>
83
+
84
+ </div>
85
+ </div>
86
+ <p style="text-align:center;">Ruby Version: [.ruby_version.] | Platform: [.ruby_platform.] | OS: [.os_name.]</p>
87
+ <!-- Footer Section -->
88
+ <footer class="site-footer">
89
+ <div class="footer-container">
90
+ <div class="footer-info">
91
+
92
+ </div>
93
+
94
+ <div class="footer-links">
95
+
96
+ <div class="social-buttons">
97
+ <a href="https://github.com/demjhonsilver/hyraft" target="_blank" class="social-btn">
98
+ <img src="/icons/git-repo.svg" alt="Git" class="icon-footer"> Git Repository
99
+ </a>
100
+ <a href="https://hyraft.com" target="_blank" class="social-btn">
101
+ <img src="/icons/docs.svg" alt="Docs" class="icon-footer"> Documentation
102
+ </a>
103
+
104
+ </div>
105
+ </div>
106
+
107
+ <div class="footer-meta">
108
+ <p>&copy; <span id="current-year"></span> Hyraft Web Framework • Built by Demjhon Silver • MIT Licensed</p>
109
+ </div>
110
+ </div>
111
+ </footer>
112
+
113
+
114
+
115
+
116
+ </div>
117
+ </displayer>
118
+
119
+ <transmuter rb>
120
+ def page_title = @page_title || "Hyraft - Ruby framework"
121
+ def page_description = @page_description || "Hexagonal Ruby framework with reactive front-end support and full-stack capabilities.
122
+ Hybrid SSR/CSR with Single-File Components ensures performance, maintainability, and SEO friendliness."
123
+ def page_keywords = @page_keywords || "ruby, framework, SFC, components, hyraft, hyr"
124
+ def page_url = @page_url || "http://localhost:1091/"
125
+ def page_image = @page_image || "http://localhost:1091/favicon.ico"
126
+ def author_name = @author_name || "Hyraft Team"
127
+ def publish_date = @publish_date || Time.now.strftime("%Y-%m-%d")
128
+
129
+ def ruby_version = RUBY_VERSION
130
+ def ruby_platform = RUBY_PLATFORM
131
+ def os_name = Hyraft::SystemInfo.os_name
132
+ def hyraft_version = defined?(Hyraft::VERSION) ? Hyraft::VERSION : "Unknown"
133
+
134
+ def display_welcome_message(anyword:, framework:)
135
+ "<div class='home-tagline'>Welcome to #{anyword} Ruby #{framework}</div>"
136
+ end
137
+
138
+ </transmuter>
139
+
140
+ <manifestor js>
141
+ // Your JavaScript code
142
+ // Set current year automatically
143
+ document.getElementById('current-year').textContent = new Date().getFullYear();
144
+
145
+ // Reactive state management
146
+ const appState = neonPulse.neonBatch({
147
+ count: 10,
148
+ countStatus: 'Count: 10',
149
+ });
150
+
151
+
152
+ // Counter pulses
153
+ neonPulse.pulse('counter', {
154
+ increase: function() {
155
+ console.log('🔷 Pulse: Increasing count');
156
+ appState.count.value++;
157
+ appState.countStatus.value = `Count: ${appState.count.value}`;
158
+ },
159
+
160
+ decrease: function() {
161
+ console.log('🔶 Pulse: Decreasing count');
162
+ appState.count.value--;
163
+ appState.countStatus.value = `Count: ${appState.count.value}`;
164
+ }
165
+ });
166
+
167
+
168
+ </manifestor>
169
+
170
+
171
+
172
+
173
+
174
+ <style src="/styles/css/main.css" />
@@ -0,0 +1,19 @@
1
+ # adapters-intake/web-app/request/home_web_adapter.rb
2
+
3
+ class HomeWebAdapter
4
+ def initialize
5
+ end
6
+
7
+ def home_page(_request)
8
+ metadata = {
9
+ page_title: "Welcome to Hyraft",
10
+ page_description: "Hyraft is a full-stack Ruby web framework that combines high-performance hexagonal architecture with modern reactive frontend."
11
+ }
12
+ # puts "DEBUG: Metadata: #{metadata}" # Check if the metadata is correct
13
+ {
14
+ status: 200,
15
+ locals: metadata,
16
+ display: 'home/home.hyr'
17
+ }
18
+ end
19
+ end