hyraft 0.1.0.alpha2 → 1.0.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +63 -100
  3. data/{templates/do_app → do_app}/Gemfile +15 -14
  4. data/do_app/Rakefile +29 -0
  5. data/do_app/app/web/display/pages/errors/404.hyr +8 -0
  6. data/do_app/app/web/display/pages/home/home.hyr +555 -0
  7. data/do_app/app/web/display/pages/layouts/application.hyr +9 -0
  8. data/do_app/app/web/display/pages/segments/footer.hyr +5 -0
  9. data/do_app/app/web/display/pages/segments/navbar.hyr +26 -0
  10. data/do_app/boot.rb +35 -0
  11. data/do_app/connectors/helpers/paginate_helper.rb +86 -0
  12. data/do_app/framework/adapters/display/global_display_adapter.rb +38 -0
  13. data/do_app/framework/adapters/display/spa_adapter.rb +170 -0
  14. data/do_app/framework/adapters/display/traditional_adapter.rb +367 -0
  15. data/do_app/framework/adapters/server/server_api_adapter.rb +140 -0
  16. data/do_app/framework/adapters/server/server_api_adapter_old.rb +143 -0
  17. data/do_app/framework/adapters/server/server_web_adapter.rb +382 -0
  18. data/{templates/do_app/framework/adapters/server/server_web_adapter.rb → do_app/framework/adapters/server/server_web_adapterWork.rb} +80 -63
  19. data/{templates/do_app → do_app}/framework/middleware/cors_middleware.rb +8 -5
  20. data/do_app/framework/ports/display_resolver_port.rb +36 -0
  21. data/do_app/public/favicon.ico +0 -0
  22. data/do_app/public/images/hyr-logo.png +0 -0
  23. data/do_app/public/images/hyr-logo.webp +0 -0
  24. data/do_app/public/index.html +20 -0
  25. data/do_app/public/styles/css/articles.css +106 -0
  26. data/do_app/public/styles/css/styles.css +14 -0
  27. data/do_app/routes/api_routes.rb +7 -0
  28. data/do_app/routes/web_routes.rb +27 -0
  29. data/do_app/setup/database/migrations/20260301210926_create_users.rb +23 -0
  30. data/{templates/do_app/infra → do_app/setup}/database/sequel_connection.rb +2 -2
  31. data/do_app/setup/environment.rb +218 -0
  32. data/{templates/do_app/infra/config → do_app/setup}/error_config.rb +7 -7
  33. data/{templates/do_app/infra → do_app/setup}/gems/database.rb +1 -1
  34. data/do_app/setup/gems/load_all.rb +4 -0
  35. data/do_app/setup/gems/utilities.rb +1 -0
  36. data/do_app/setup/gems/web.rb +3 -0
  37. data/{templates/do_app/infra → do_app/setup}/server/web-server.ru +1 -1
  38. data/{templates/do_app → do_app}/test/db.rb +1 -1
  39. data/do_app/test/test_helper.rb +37 -0
  40. data/exe/hyraft +0 -0
  41. data/lib/hyraft/application.rb +6 -0
  42. data/lib/hyraft/boot/preloader.rb +34 -65
  43. data/lib/hyraft/circuit/origin.rb +124 -0
  44. data/lib/hyraft/circuit/port.rb +184 -0
  45. data/lib/hyraft/circuit.rb +10 -0
  46. data/lib/hyraft/cli.rb +147 -128
  47. data/lib/hyraft/compiler/compiler.rb +71 -19
  48. data/lib/hyraft/compiler/encryptor.rb +10 -0
  49. data/lib/hyraft/compiler/{html_purifier.rb → html_safety.rb} +12 -12
  50. data/lib/hyraft/compiler/import_processor.rb +19 -0
  51. data/lib/hyraft/compiler/javascript_library.rb +21 -280
  52. data/lib/hyraft/compiler/join_processor.rb +238 -0
  53. data/lib/hyraft/compiler/page_processor.rb +226 -0
  54. data/lib/hyraft/compiler/parser.rb +33 -16
  55. data/lib/hyraft/compiler/renderer.rb +339 -178
  56. data/lib/hyraft/pathway.rb +24 -0
  57. data/lib/hyraft/response.rb +46 -0
  58. data/lib/hyraft/router/api_router.rb +36 -28
  59. data/lib/hyraft/router/web_router.rb +119 -78
  60. data/lib/hyraft/system_info.rb +46 -9
  61. data/lib/hyraft/version.rb +1 -3
  62. data/lib/hyraft.rb +34 -15
  63. metadata +146 -111
  64. data/lib/hyraft/compiler/javascript_obfuscator.rb +0 -141
  65. data/lib/hyraft/engine/circuit.rb +0 -35
  66. data/lib/hyraft/engine/port.rb +0 -17
  67. data/lib/hyraft/engine/source.rb +0 -19
  68. data/lib/hyraft/engine.rb +0 -11
  69. data/templates/do_app/Rakefile +0 -88
  70. data/templates/do_app/adapter-intake/web-app/display/pages/home/home.hyr +0 -174
  71. data/templates/do_app/adapter-intake/web-app/request/home_web_adapter.rb +0 -19
  72. data/templates/do_app/boot.rb +0 -41
  73. data/templates/do_app/framework/adapters/server/server_api_adapter.rb +0 -51
  74. data/templates/do_app/framework/compiler/style_resolver.rb +0 -33
  75. data/templates/do_app/infra/config/environment.rb +0 -86
  76. data/templates/do_app/infra/config/routes/api_routes.rb +0 -2
  77. data/templates/do_app/infra/config/routes/web_routes.rb +0 -10
  78. data/templates/do_app/infra/gems/load_all.rb +0 -4
  79. data/templates/do_app/infra/gems/utilities.rb +0 -1
  80. data/templates/do_app/infra/gems/web.rb +0 -3
  81. data/templates/do_app/public/favicon.ico +0 -0
  82. data/templates/do_app/public/images/hyr-logo.png +0 -0
  83. data/templates/do_app/public/images/hyr-logo.webp +0 -0
  84. data/templates/do_app/public/index.html +0 -22
  85. data/templates/do_app/shared/helpers/pagination_helper.rb +0 -44
  86. data/templates/do_app/shared/helpers/response_formatter.rb +0 -25
  87. data/templates/do_app/test/acceptance/api/articles_api_acceptance_test.rb +0 -43
  88. data/templates/do_app/test/acceptance/web/articles_acceptance_test.rb +0 -31
  89. data/templates/do_app/test/acceptance/web/home_acceptance_test.rb +0 -17
  90. data/templates/do_app/test/integration/adapter-exhaust/data-gateway/sequel_articles_gateway_test.rb +0 -79
  91. data/templates/do_app/test/integration/adapter-intake/api-app/request/articles_api_adapter_test.rb +0 -61
  92. data/templates/do_app/test/integration/adapter-intake/web-app/request/articles_web_adapter_test.rb +0 -20
  93. data/templates/do_app/test/integration/adapter-intake/web-app/request/home_web_adapter_test.rb +0 -17
  94. data/templates/do_app/test/integration/database/migration_test.rb +0 -35
  95. data/templates/do_app/test/support/mock_api_adapter.rb +0 -82
  96. data/templates/do_app/test/support/mock_articles_gateway.rb +0 -41
  97. data/templates/do_app/test/support/mock_web_adapter.rb +0 -85
  98. data/templates/do_app/test/support/test_patches.rb +0 -33
  99. data/templates/do_app/test/test_helper.rb +0 -526
  100. data/templates/do_app/test/unit/engine/circuit/articles_circuit_test.rb +0 -167
  101. data/templates/do_app/test/unit/engine/port/articles_gateway_port_test.rb +0 -12
  102. data/templates/do_app/test/unit/engine/source/article_test.rb +0 -37
  103. /data/{templates/do_app → do_app}/framework/errors/error_handler.rb +0 -0
  104. /data/{templates/do_app → do_app}/framework/errors/templates/304.html +0 -0
  105. /data/{templates/do_app → do_app}/framework/errors/templates/400.html +0 -0
  106. /data/{templates/do_app → do_app}/framework/errors/templates/401.html +0 -0
  107. /data/{templates/do_app → do_app}/framework/errors/templates/403.html +0 -0
  108. /data/{templates/do_app → do_app}/framework/errors/templates/404.html +0 -0
  109. /data/{templates/do_app → do_app}/framework/errors/templates/500.html +0 -0
  110. /data/{templates/do_app → do_app}/package.json +0 -0
  111. /data/{templates/do_app → do_app}/public/icons/docs.svg +0 -0
  112. /data/{templates/do_app → do_app}/public/icons/expli.svg +0 -0
  113. /data/{templates/do_app → do_app}/public/icons/git-repo.svg +0 -0
  114. /data/{templates/do_app → do_app}/public/icons/hexagonal-arch.svg +0 -0
  115. /data/{templates/do_app → do_app}/public/icons/template-engine.svg +0 -0
  116. /data/{templates/do_app → do_app}/public/styles/css/main.css +0 -0
  117. /data/{templates/do_app → do_app}/public/styles/css/spa.css +0 -0
  118. /data/{templates/do_app/infra → do_app/setup}/server/api-server.ru +0 -0
@@ -0,0 +1,555 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+
7
+ <title>Welcome to Hyraft</title>
8
+
9
+ <style>
10
+
11
+ *{
12
+ margin:0;
13
+ padding:0;
14
+ box-sizing:border-box;
15
+ }
16
+
17
+
18
+ body{
19
+
20
+ min-height:100vh;
21
+
22
+ display:flex;
23
+
24
+ justify-content:center;
25
+
26
+ align-items:center;
27
+
28
+ padding:40px 0;
29
+
30
+ font-family:
31
+ Inter,
32
+ "Segoe UI",
33
+ Arial,
34
+ sans-serif;
35
+
36
+
37
+ background:
38
+
39
+ radial-gradient(
40
+ circle at top left,
41
+ rgba(12, 60, 161, 0.45),
42
+ transparent 35%
43
+ ),
44
+
45
+ radial-gradient(
46
+ circle at bottom right,
47
+ rgba(249,115,22,.35),
48
+ transparent 35%
49
+ ),
50
+
51
+ #020617;
52
+
53
+
54
+ color:white;
55
+
56
+ }
57
+
58
+
59
+
60
+ .container{
61
+
62
+ width:min(950px,100%);
63
+
64
+ }
65
+
66
+
67
+
68
+ .welcome-card{
69
+
70
+ width:100%;
71
+
72
+ background:
73
+
74
+ rgba(15,23,42,.95);
75
+
76
+
77
+ border:
78
+
79
+ 1px solid #1f41af;
80
+
81
+
82
+ border-radius:24px;
83
+
84
+
85
+ padding:50px;
86
+
87
+
88
+ text-align:center;
89
+
90
+
91
+ box-shadow:
92
+
93
+ 0 30px 80px rgba(0,0,0,.45);
94
+
95
+ }
96
+
97
+
98
+
99
+ /* Logo */
100
+
101
+ .logo{
102
+
103
+ width:85px;
104
+
105
+ height:85px;
106
+
107
+
108
+ margin:0 auto;
109
+
110
+
111
+ display:flex;
112
+
113
+ align-items:center;
114
+
115
+ justify-content:center;
116
+
117
+
118
+ border-radius:22px;
119
+
120
+
121
+ background:
122
+
123
+ linear-gradient(
124
+ 135deg,
125
+ #f97316,
126
+ #ea580c
127
+ );
128
+
129
+
130
+ font-size:42px;
131
+
132
+ font-weight:800;
133
+
134
+
135
+ box-shadow:
136
+
137
+ 0 15px 30px rgba(249,115,22,.35);
138
+
139
+ }
140
+
141
+
142
+
143
+ h1{
144
+
145
+ margin-top:25px;
146
+
147
+
148
+ font-size:3rem;
149
+
150
+ line-height:1.2;
151
+
152
+ }
153
+
154
+
155
+ h1 span{
156
+
157
+ color: #ff6b01; /* brand orange */
158
+
159
+ }
160
+
161
+
162
+
163
+ .subtitle{
164
+
165
+ margin-top:15px;
166
+
167
+
168
+ color:#94a3b8;
169
+
170
+
171
+ font-size:1.15rem;
172
+
173
+ }
174
+
175
+
176
+
177
+ .success{
178
+
179
+ margin:35px auto;
180
+
181
+
182
+ padding:18px;
183
+
184
+
185
+ max-width:600px;
186
+
187
+
188
+ border-radius:14px;
189
+
190
+
191
+ background: #ff6b01; /* brand orange */
192
+
193
+
194
+ border:1px solid #f17025;
195
+
196
+
197
+ color: #ffffff; /* brand blue */
198
+
199
+ }
200
+
201
+
202
+
203
+ /* Cards */
204
+
205
+ .links{
206
+
207
+ width:100%;
208
+
209
+
210
+ display:grid;
211
+
212
+
213
+ grid-template-columns:
214
+
215
+ repeat(3,1fr);
216
+
217
+
218
+ gap:20px;
219
+
220
+
221
+ margin-top:35px;
222
+
223
+ }
224
+
225
+
226
+
227
+ .link-card{
228
+
229
+ display:block;
230
+
231
+
232
+ text-decoration:none;
233
+
234
+
235
+ color:white;
236
+
237
+
238
+ padding:25px;
239
+
240
+
241
+ border-radius:18px;
242
+
243
+
244
+ background:
245
+
246
+ linear-gradient(
247
+ 145deg,
248
+ #1f41af,
249
+ #0f172a
250
+ );
251
+
252
+
253
+ border:1px solid #1e3a8a;
254
+
255
+
256
+ transition:.3s;
257
+
258
+ }
259
+
260
+
261
+
262
+ .link-card:hover{
263
+
264
+ transform:translateY(-7px);
265
+
266
+
267
+ border-color:#f97316;
268
+
269
+
270
+ }
271
+
272
+
273
+
274
+ .icon{
275
+
276
+ font-size:32px;
277
+
278
+ margin-bottom:12px;
279
+
280
+ }
281
+
282
+
283
+
284
+ .link-card p{
285
+
286
+ color:#94a3b8;
287
+
288
+ margin-top:8px;
289
+
290
+ }
291
+
292
+
293
+
294
+ /* Command */
295
+
296
+ .command{
297
+
298
+ margin-top:40px;
299
+
300
+
301
+ text-align:left;
302
+
303
+
304
+ background:#020617;
305
+
306
+
307
+ border-radius:14px;
308
+
309
+
310
+ padding:22px;
311
+
312
+
313
+ border:1px solid #1e293b;
314
+
315
+ }
316
+
317
+
318
+
319
+ .command code{
320
+
321
+ color:#93c5fd;
322
+
323
+
324
+ line-height:1.8;
325
+
326
+ }
327
+
328
+
329
+
330
+ /* Footer */
331
+
332
+ .footer{
333
+
334
+ margin-top:35px;
335
+
336
+
337
+ color:#64748b;
338
+
339
+ }
340
+
341
+
342
+
343
+
344
+
345
+ @media(max-width:700px){
346
+
347
+
348
+ body{
349
+
350
+ padding:20px;
351
+
352
+ }
353
+
354
+
355
+ .welcome-card{
356
+
357
+ padding:30px 20px;
358
+
359
+ }
360
+
361
+
362
+ h1{
363
+
364
+ font-size:2.2rem;
365
+
366
+ }
367
+
368
+
369
+ .links{
370
+
371
+ grid-template-columns:1fr;
372
+
373
+ }
374
+
375
+ }
376
+
377
+
378
+ </style>
379
+
380
+ </head>
381
+
382
+
383
+ <body>
384
+ <hyr>
385
+ @ver = defined?(Hyraft::VERSION) ? Hyraft::VERSION : "Unknown"
386
+ </hyr>
387
+
388
+ <div class="container">
389
+
390
+
391
+ <div class="welcome-card">
392
+
393
+
394
+
395
+ <div class="logo">
396
+
397
+
398
+ <img src="./images/hyr-logo.webp" alt="Hyraft" height="100">
399
+
400
+
401
+
402
+ </div>
403
+
404
+
405
+ <h1>
406
+
407
+ Welcome to
408
+
409
+ <span>
410
+ Hyraft
411
+ </span>
412
+
413
+ </h1>
414
+
415
+
416
+
417
+ <h4>Version: :[ver]</h4>
418
+
419
+ <p class="subtitle">
420
+
421
+ Your Ruby application has been created successfully.
422
+
423
+ <br>
424
+
425
+ Happy coding!
426
+
427
+ </p>
428
+
429
+
430
+
431
+ <div class="success">
432
+
433
+ ✓ Hyraft server is running successfully
434
+
435
+ <br>
436
+
437
+ Environment: Development
438
+
439
+ </div>
440
+
441
+
442
+
443
+ <div class="links">
444
+
445
+
446
+ <a
447
+ href="https://www.hyraft.com/getting-started"
448
+ class="link-card"
449
+ target="_blank"
450
+ rel="noopener noreferrer"
451
+ >
452
+
453
+ <div class="icon">
454
+ 🚀
455
+ </div>
456
+
457
+ <h3>
458
+ Getting Started
459
+ </h3>
460
+
461
+ <p>
462
+ Create your first application
463
+ </p>
464
+
465
+ </a>
466
+
467
+
468
+
469
+ <a
470
+ href="https://www.hyraft.com/"
471
+ class="link-card"
472
+ target="_blank"
473
+ rel="noopener noreferrer"
474
+ >
475
+
476
+ <div class="icon">
477
+ 📚
478
+ </div>
479
+
480
+ <h3>
481
+ Documentation
482
+ </h3>
483
+
484
+ <p>
485
+ Learn Hyraft features
486
+ </p>
487
+
488
+ </a>
489
+
490
+
491
+
492
+ <a
493
+ href="https://www.hyraft.com/"
494
+ class="link-card"
495
+ target="_blank"
496
+ rel="noopener noreferrer"
497
+ >
498
+
499
+ <div class="icon">
500
+ 💎
501
+ </div>
502
+
503
+ <h3>
504
+ Examples
505
+ </h3>
506
+
507
+ <p>
508
+ Explore sample projects
509
+ </p>
510
+
511
+ </a>
512
+
513
+
514
+ </div>
515
+
516
+
517
+
518
+
519
+ <div class="command">
520
+
521
+ <code>
522
+
523
+ $ gem install hyraft --pre<br>
524
+
525
+ $ hyraft do myapp<br>
526
+
527
+ $ cd myapp<br>
528
+
529
+ $ bundle install<br>
530
+
531
+ $ hyraft-server puma<br>
532
+
533
+ $ hyr s puma
534
+
535
+ </code>
536
+
537
+ </div>
538
+
539
+
540
+
541
+ <div class="footer">
542
+
543
+ <p>&copy; <span id="current-year"></span> Hyraft Web Framework • Built by Demjhon Silver • MIT Licensed</p>
544
+
545
+ </div>
546
+
547
+
548
+ </div>
549
+
550
+
551
+ </div>
552
+
553
+
554
+ </body>
555
+ </html>
@@ -0,0 +1,9 @@
1
+ <!-- app/web/display/pages/layouts/application.hyr -->
2
+
3
+ <!-- <join "segments/navbar" /> -->
4
+
5
+ <main class="container mt-4">
6
+ :[mainpage] <!-- app/web/display/pages/home/home.hyr -->
7
+ </main>
8
+
9
+ <!-- <join "segments/footer" /> -->
@@ -0,0 +1,5 @@
1
+ <footer class="footer mt-auto py-3 bg-light">
2
+ <div class="container text-center">
3
+ <span class="text-muted">&copy; 2026 My Application</span>
4
+ </div>
5
+ </footer>
@@ -0,0 +1,26 @@
1
+ <nav class="navbar navbar-expand-lg bg-body-tertiary">
2
+ <div class="container">
3
+ <a class="navbar-brand" href="/">MyApp</a>
4
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
5
+ <span class="navbar-toggler-icon"></span>
6
+ </button>
7
+ <div class="collapse navbar-collapse" id="navbarNav">
8
+ <ul class="navbar-nav ms-auto">
9
+ <li class="nav-item">
10
+ <a class="nav-link" href="/">Home</a>
11
+ </li>
12
+ <li class="nav-item">
13
+ <a class="nav-link" href="/about">About</a>
14
+ </li>
15
+ <li class="nav-item">
16
+ <a class="nav-link" href="/contact">Contact</a>
17
+ </li>
18
+
19
+ <li class="nav-item">
20
+ <a class="nav-link" href="/articles">Articles</a>
21
+ </li>
22
+
23
+ </ul>
24
+ </div>
25
+ </div>
26
+ </nav>
data/do_app/boot.rb ADDED
@@ -0,0 +1,35 @@
1
+ # boot.rb
2
+ require 'bundler/setup'
3
+ require_relative 'setup/gems/load_all'
4
+
5
+ require 'hyraft'
6
+ require 'elevhyra'
7
+ require 'sequel'
8
+
9
+ require_relative 'framework/middleware/cors_middleware'
10
+
11
+ # Define ROOT once
12
+ ROOT = File.expand_path(__dir__) unless defined?(ROOT)
13
+
14
+ # Load environment configuration FIRST
15
+ require_relative 'setup/environment'
16
+
17
+ # Load middleware
18
+ Dir["#{ROOT}/framework/middleware/*.rb"].each { |file| require file }
19
+
20
+ Dir["#{ROOT}/**/*.rb"].each do |file|
21
+ next if file.include?('framework/middleware/') ||
22
+ file.include?('setup/database/migrations/') ||
23
+ file.include?('boot.rb') ||
24
+ file.end_with?('.ru') ||
25
+ file.end_with?('.hyr') ||
26
+ file.include?('test/')
27
+
28
+ require file
29
+ end
30
+
31
+ # Initialize the application after all files are loaded
32
+ Hyraft::Environment.load if defined?(Hyraft::Environment)
33
+
34
+ # Use the Environment module
35
+ puts "Starting #{Environment.environment_color} environment"
@@ -0,0 +1,86 @@
1
+
2
+ # connectors/helpers/paginate_helper.rb
3
+
4
+ module PaginateHelper
5
+ class PaginatedResult
6
+ attr_reader :data, :total_count, :page, :per_page, :total_pages, :next_page, :prev_page, :first_page, :last_page
7
+
8
+ def initialize(data, total_count, page, per_page)
9
+ @data = data
10
+ @total_count = total_count
11
+ @page = page
12
+ @per_page = per_page
13
+ @total_pages = (total_count.to_f / per_page).ceil
14
+ @next_page = page + 1 if page < @total_pages
15
+ @prev_page = page - 1 if page > 1
16
+ @first_page = 1
17
+ @last_page = @total_pages
18
+ end
19
+
20
+ def to_h
21
+ {
22
+ data: @data,
23
+ count: @data.size,
24
+ total: @total_count,
25
+ page: @page,
26
+ per_page: @per_page,
27
+ total_pages: @total_pages,
28
+ next_page: @next_page,
29
+ prev_page: @prev_page,
30
+ first_page: @first_page,
31
+ last_page: @last_page
32
+ }
33
+ end
34
+ end
35
+
36
+ def parse_query_string(query_string)
37
+ params = {}
38
+ return params if query_string.nil? || query_string.empty?
39
+
40
+ query_string.split('&').each do |pair|
41
+ key_value = pair.split('=', 2)
42
+ key = key_value[0]
43
+ value = key_value[1]
44
+ params[key.to_sym] = value if key && !key.empty?
45
+ end
46
+ params
47
+ end
48
+
49
+ def extract_pagination_params(env, default_per_page = 10, max_per_page = 100)
50
+ params = parse_query_string(env['QUERY_STRING'])
51
+
52
+ page = params[:page].to_i
53
+ page = 1 if page < 1
54
+
55
+ per_page = params[:per_page].to_i
56
+ per_page = default_per_page if per_page < 1
57
+ per_page = max_per_page if per_page > max_per_page
58
+
59
+ { page: page, per_page: per_page }
60
+ end
61
+
62
+ def paginate(collection, page: 1, per_page: 10, max_per_page: 100)
63
+ page = page.to_i
64
+ page = 1 if page < 1
65
+
66
+ per_page = per_page.to_i
67
+ per_page = 10 if per_page < 1
68
+ per_page = max_per_page if per_page > max_per_page
69
+
70
+ total_count = collection.is_a?(Array) ? collection.size : collection.count
71
+
72
+ start_index = (page - 1) * per_page
73
+
74
+ paginated_data = if collection.is_a?(Array)
75
+ collection[start_index, per_page] || []
76
+ else
77
+ collection.offset(start_index).limit(per_page).to_a
78
+ end
79
+
80
+ PaginatedResult.new(paginated_data, total_count, page, per_page)
81
+ end
82
+
83
+ def paginate_array(array, page: 1, per_page: 10, max_per_page: 100)
84
+ paginate(array, page: page, per_page: per_page, max_per_page: max_per_page)
85
+ end
86
+ end