ru.Bee 1.5.4 → 1.7.0

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rubee +6 -295
  3. data/lib/app/views/index.html +1 -1
  4. data/lib/config/base_configuration.rb +25 -7
  5. data/lib/db/create_addresses.rb +17 -0
  6. data/lib/inits/charged_hash.rb +16 -0
  7. data/lib/inits/charged_string.rb +12 -0
  8. data/lib/js/app.js +3 -3
  9. data/lib/package.json +1 -1
  10. data/lib/rubee/async/fiber_queue.rb +27 -0
  11. data/lib/rubee/async/thread_async.rb +1 -1
  12. data/lib/rubee/async/thread_pool.rb +32 -34
  13. data/lib/rubee/autoload.rb +86 -0
  14. data/lib/rubee/cli/attach.rb +124 -0
  15. data/lib/rubee/cli/command.rb +41 -0
  16. data/lib/rubee/cli/console.rb +39 -0
  17. data/lib/rubee/cli/db.rb +105 -0
  18. data/lib/rubee/cli/generate.rb +33 -0
  19. data/lib/rubee/cli/project.rb +124 -0
  20. data/lib/rubee/cli/react.rb +28 -0
  21. data/lib/rubee/cli/routes.rb +18 -0
  22. data/lib/rubee/cli/server.rb +52 -0
  23. data/lib/rubee/cli/test.rb +24 -0
  24. data/lib/rubee/cli/version.rb +15 -0
  25. data/lib/rubee/configuration.rb +83 -0
  26. data/lib/rubee/controllers/base_controller.rb +12 -6
  27. data/lib/rubee/controllers/extensions/auth_tokenable.rb +2 -2
  28. data/lib/rubee/extensions/hookable.rb +9 -2
  29. data/lib/rubee/generator.rb +160 -0
  30. data/lib/rubee/logger.rb +83 -0
  31. data/lib/rubee/models/database_objectable.rb +1 -1
  32. data/lib/rubee/models/sequel_object.rb +3 -3
  33. data/lib/rubee/router.rb +40 -0
  34. data/lib/rubee.rb +13 -317
  35. data/lib/tests/async/thread_async_test.rb +9 -5
  36. data/lib/tests/cli/attach_test.rb +36 -0
  37. data/lib/tests/{auth_tokenable_test.rb → controllers/auth_tokenable_test.rb} +2 -2
  38. data/lib/tests/controllers/base_controller_test.rb +23 -0
  39. data/lib/tests/controllers/hookable_test.rb +220 -0
  40. data/lib/tests/{rubeeapp_test.rb → controllers/rubeeapp_test.rb} +3 -2
  41. data/lib/tests/example_models/address.rb +5 -0
  42. data/lib/tests/example_models/user.rb +1 -0
  43. data/lib/tests/logger_test.rb +76 -0
  44. data/lib/tests/{account_model_test.rb → models/account_model_test.rb} +1 -1
  45. data/lib/tests/{comment_model_test.rb → models/comment_model_test.rb} +13 -1
  46. data/lib/tests/models/db_objectable_test.rb +21 -0
  47. data/lib/tests/models/seralizable_test.rb +36 -0
  48. data/lib/tests/{user_model_test.rb → models/user_model_test.rb} +32 -1
  49. data/lib/tests/rubee_attach_test.rb +0 -0
  50. data/lib/tests/test.db +0 -0
  51. data/lib/tests/test_helper.rb +20 -2
  52. data/readme.md +174 -15
  53. metadata +34 -9
  54. data/lib/app/views/apples_.erb +0 -1
  55. data/lib/app/views/s_.erb +0 -1
  56. /data/lib/app/views/{app.tsx → App.tsx} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb5cbb674c5bfbfd6bc0d577039a3ca53fb46f013b62e5e004ef4a9f2c500514
4
- data.tar.gz: abd0447b9655b22a85fed893e74c524f97d2d0ecf757eeb3b1730c799ae0e3d4
3
+ metadata.gz: d4ecb77e79daf38768a10a5da26f7f1e3013734c864774e128ffb767d5d6d9a1
4
+ data.tar.gz: 1f9a6de22160db7ac4deb411278f4bb53bb94ee0a58893a9089a5eb99fd061fa
5
5
  SHA512:
6
- metadata.gz: 53195541a6b75bb6bf98ff8e8d54cc6d9fea4c5a8d5232f79c0e5cbe085b0afa48e06e17e717a314fb44fbac92c6ae375e18cbc8f4cc2aba8152fec568c59545
7
- data.tar.gz: 193de59c021b3ca2265e816f6c80fc54a0b714c37f02b59194a4dafb6d01b1bc2edf9180d0c932d8a9b2d4dc23954b052926874a691f0a1aaedfbc5870906c34
6
+ metadata.gz: 312f2143e4244dec12bdd6e40a815eeb9a2cf70af31bea3ef2c5211ae4a491dc8532931ca4d0ef4529979d579f2c17e3ade73fd09c3f9f75a0b79697e3c93200
7
+ data.tar.gz: d53621c81d31e8b7e48b030762d5f58726756e3946da14a2774fd8c6239f96ccb87a4f8d4c533b862981a792a5c90a0755d22a66d6b5b5428d4df75d46ac8265
data/bin/rubee CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'fileutils'
4
-
4
+ require 'rubygems'
5
5
  require_relative '../lib/inits/print_colors'
6
6
  require_relative '../lib/rubee'
7
7
 
@@ -19,299 +19,10 @@ LOGO = <<-'LOGO'
19
19
  Ver: %s
20
20
  LOGO
21
21
 
22
- command = ARGV.first
23
-
24
- def print_logo
25
- puts "\e[36m#{LOGO % Rubee::VERSION}\e[0m" # Cyan color
26
- end
27
-
28
- if command =~ /^(start)$|^(start:(\d+))$/
29
- _, port = ARGV.first&.split(':')
30
-
31
- port ||= '7000'
32
- print_logo
33
- color_puts "Starting takeoff of ruBee server on port #{port}...", color: :yellow
34
- exec("rackup #{ENV['RACKUP_FILE']} -p #{port}")
35
- elsif command =~ /^(start_dev)$|^(start_dev:(\d+))$/
36
- _, port = ARGV.first&.split(':')
37
-
38
- port ||= '7000'
39
- print_logo
40
-
41
- color_puts "Starting takeoff of ruBee server on port #{port} in dev mode...", color: :yellow
42
-
43
- exec("rerun -- rackup --port #{port} #{ENV['RACKUP_FILE']}")
44
- elsif command == 'stop'
45
- exec('pkill -f rubee')
46
- elsif command == 'status'
47
- exec('ps aux | grep rubee')
48
- elsif command == 'react'
49
- case ARGV[1]
50
- when 'prepare'
51
- if Rubee::PROJECT_NAME == 'rubee'
52
- exec('cd ./lib && npm run prepare')
53
- else
54
- exec('npm run prepare')
55
- end
56
- when 'watch'
57
- if Rubee::PROJECT_NAME == 'rubee'
58
- exec('cd ./lib && npm run watch')
59
- else
60
- exec('npm run watch')
61
- end
62
- else
63
- color_puts("Unknown command: #{command}", color: :red)
64
- exit(1)
65
- end
66
- elsif command == 'project'
67
- project_name = ARGV[1]
68
- if project_name.nil?
69
- color_puts 'Please indicate project name.', color: :red
70
- exit 1
71
- end
72
-
73
- if project_name == 'rubee'
74
- color_puts "Error: Project 'rubee' is reserved", color: :red
75
- exit 1
76
- end
77
-
78
- source_dir = File.expand_path('../lib', __dir__)
79
- target_dir = File.expand_path("./#{project_name}", Dir.pwd)
80
-
81
- if Dir.exist?(target_dir)
82
- color_puts "Error: Project #{project_name} already exists!", color: :red
83
- exit 1
84
- end
85
-
86
- # Create target directory
87
- FileUtils.mkdir_p(target_dir)
88
-
89
- # Define blacklist
90
- blacklist_files = %w[rubee.rb print_colors.rb version.rb config.ru test_helper.rb Gemfile.lock test.yml test.db
91
- development.db production.db]
92
- blacklist_dirs = %w[rubee tests .git .github .idea node_modules db]
93
-
94
- # Copy files, excluding blacklisted ones
95
- Dir.glob("#{source_dir}/**/*", File::FNM_DOTMATCH).each do |file|
96
- relative_path = file.sub("#{source_dir}/", '')
97
-
98
- # Skip blacklisted directories
99
- next if blacklist_dirs.any? { |dir| relative_path.split('/').include?(dir) }
100
-
101
- # Skip blacklisted files
102
- next if blacklist_files.include?(File.basename(file))
103
-
104
- target_path = File.join(target_dir, relative_path)
105
-
106
- if File.directory?(file)
107
- FileUtils.mkdir_p(target_path)
108
- else
109
- FileUtils.cp(file, target_path)
110
- end
111
- end
112
-
113
- # create tests dir and copy test_helper.rb and user_model_test.rb
114
- FileUtils.mkdir_p("#{target_dir}/tests")
115
- FileUtils.cp("#{source_dir}/tests/user_model_test.rb", "#{target_dir}/tests/user_model_test.rb")
116
-
117
- # create db dir
118
- FileUtils.mkdir_p("#{target_dir}/db")
119
- FileUtils.cp("#{source_dir}/db/structure.rb", "#{target_dir}/db/structure.rb")
120
- FileUtils.cp("#{source_dir}/db/create_users.rb", "#{target_dir}/db/create_users.rb")
121
-
122
- # create a gemfile context
123
- gemfile = <<~GEMFILE
124
- source 'https://rubygems.org'
125
-
126
- gem 'ru.Bee'
127
- gem 'sequel'
128
- gem 'sqlite3'
129
- gem 'rake'
130
- gem 'rack'
131
- gem 'rackup'
132
- gem 'pry'
133
- gem 'pry-byebug'
134
- gem 'puma'
135
- gem 'json'
136
-
137
- group :development do
138
- gem 'rerun'
139
- gem 'minitest'
140
- gem 'rack-test'
141
- end
142
- GEMFILE
143
- # create a gemfile
144
- File.open("#{target_dir}/Gemfile", 'w') do |file|
145
- file.puts gemfile
146
- end
147
-
148
- # create test_helper.rb file
149
- test_helper = <<~TESTHELPER
150
- require "bundler/setup"
151
- Bundler.require(:test)
152
-
153
- require 'minitest/autorun'
154
- require 'rack/test'
155
- require 'rubee'
156
-
157
- Rubee::Autoload.call
158
- TESTHELPER
159
-
160
- File.open("#{target_dir}/tests/test_helper.rb", 'w') do |file|
161
- file.puts test_helper
162
- end
163
-
164
- color_puts "Project #{project_name} created successfully at #{target_dir}", color: :green
165
-
166
- elsif command == 'version'
167
- color_puts "ruBee v#{Rubee::VERSION}", color: :yellow
168
- elsif command == 'routes'
169
- file = Rubee::PROJECT_NAME == 'rubee' ? File.join('/lib', 'config/routes.rb') : 'config/routes.rb'
170
- routes = eval(File.read(file))
171
-
172
- puts routes
173
- elsif command == 'test'
174
-
175
- ENV['RACK_ENV'] = 'test'
176
- file_name = ARGV[1] # Get the first argument
177
- lib = Rubee::PROJECT_NAME == 'rubee' ? '/lib' : ''
178
- if file_name
179
- color_puts "Running #{file_name} test ...", color: :yellow
180
- exec("ruby -Itest -e \"require '.#{lib}/tests/#{file_name}'\"")
181
- else
182
- color_puts 'Running all tests ...', color: :yellow
183
- exec("ruby -Itest -e \"Dir.glob('.#{lib}/tests/**/*_test.rb').each { |file| require file }\"")
184
- end
185
- elsif %w[generate gen].include?(command)
186
- method, path = ARGV[1..2]
187
- ENV['RACK_ENV'] ||= 'development'
188
- file = Rubee::PROJECT_NAME == 'rubee' ? File.join('/lib', 'config/routes.rb') : 'config/routes.rb'
189
- routes = eval(File.read(file))
190
- route = routes.find { |route| route[:path] == path.to_s && route[:method] == method.to_sym }
191
- color_puts("Route not found with path: #{path} and method: #{method}", color: :red) unless route
192
- Rubee::Generator.new(
193
- route[:model]&.[](:name),
194
- route[:model]&.[](:attributes),
195
- "#{route[:controller]&.capitalize}Controller",
196
- route[:action],
197
- react: route[:react]
198
- ).call
199
- elsif command == 'db'
200
- Rubee::Autoload.call
201
- ENV['RACK_ENV'] ||= 'development'
202
-
203
- command, file_name = ARGV[1]&.split(':')
204
- if Rubee::PROJECT_NAME == 'rubee'
205
- Rubee::Configuration.setup(env = :test) do |config|
206
- config.database_url = { url: 'sqlite://lib/tests/test.db', env: }
207
- end
208
- Rubee::SequelObject.reconnect! unless command == 'init'
209
- end
210
-
211
- def ensure_database_exists(db_url)
212
- uri = URI.parse(db_url)
213
- case uri.scheme
214
- when 'sqlite'
215
- begin
216
- Sequel.connect(db_url)
217
- color_puts("Database #{ENV['RACK_ENV']} exists", color: :cyan)
218
- rescue Exception
219
- if File.exist?(db_path = db_url.sub(%r{^sqlite://}, ''))
220
- color_puts("Database #{ENV['RACK_ENV']} exists", color: :cyan)
221
- else
222
- Sequel.sqlite(db_path)
223
- color_puts("Database #{ENV['RACK_ENV']} created", color: :green)
224
- end
225
- end
226
- when 'postgres'
227
- begin
228
- Sequel.connect(db_url)
229
- color_puts("Database #{ENV['RACK_ENV']} exists", color: :cyan)
230
- rescue StandardError => _e
231
- con = Sequel.connect(Rubee::Configuration.get_database_url.gsub(%r{(/test|/development|/production)}, ''))
232
- con.run("CREATE DATABASE #{ENV['RACK_ENV']}")
233
- color_puts("Database #{ENV['RACK_ENV']} created", color: :green)
234
- end
235
- else
236
- color_puts("Unsupported database type: #{db_url}", color: :red)
237
- end
238
- end
239
-
240
- def generate_structure
241
- schema_hash = {}
242
-
243
- Rubee::SequelObject::DB.tables.each do |table|
244
- schema_hash[table] = {}
245
-
246
- Rubee::SequelObject::DB.schema(table).each do |column, details|
247
- schema_hash[table][column] = details
248
- end
249
- end
250
- formatted_hash = JSON.pretty_generate(schema_hash)
251
- .gsub(/"(\w+)":/, '\1:') # Convert keys to symbols
252
- .gsub(': null', ': nil') # Convert `null` to `nil`
253
-
254
- File.open('db/structure.rb', 'w') do |file|
255
- file.puts "STRUCTURE = #{formatted_hash}"
256
- end
257
-
258
- color_puts('db/structure.rb updated', color: :green)
259
- end
260
-
261
- case command
262
- when 'run'
263
- Rubee::Autoload.call
264
- file_names = if file_name == 'all'
265
- lib = Rubee::PROJECT_NAME == 'rubee' ? '/lib' : ''
266
- Dir.glob(".#{lib}/db/*.rb").map do |file|
267
- File.basename(file, '.rb')
268
- end.reject { |file| file == 'structure' }
269
- else
270
- [file_name]
271
- end
272
- Rubee::Configuration.envs.each do |env|
273
- ENV['RACK_ENV'] = env.to_s
274
- file_names.each do |file_name|
275
- color_puts("Run #{file_name} file for #{env} env", color: :cyan)
276
- Object.const_get(file_name.split('_').map(&:capitalize).join).new.call
277
- end
278
- end
279
- color_puts("Migration for #{file_name} completed", color: :green)
280
- unless Rubee::PROJECT_NAME == 'rubee'
281
- color_puts('Regenerate schema file', color: :cyan)
282
- generate_structure
283
- end
284
- when 'init'
285
- ensure_database_exists(Rubee::Configuration.get_database_url)
286
- when 'structure'
287
- generate_structure
288
- else
289
- color_puts("Unknown command: #{command}", color: :red)
290
- end
291
- elsif ['console'].include?(command)
292
- ARGV.clear
293
- ENV['RACK_ENV'] ||= 'development'
294
-
295
- Rubee::Autoload.call
296
- if Rubee::PROJECT_NAME == 'rubee'
297
- Rubee::Configuration.setup(env = :test) do |config|
298
- config.database_url = { url: 'sqlite://lib/tests/test.db', env: }
299
- end
300
- Rubee::Autoload.call
301
- Rubee::SequelObject.reconnect!
302
- end
303
-
304
- def reload
305
- app_files = Dir["./#{Rubee::APP_ROOT}/**/*.rb"]
306
- app_files.each { |file| load(file) }
307
- color_puts('Reloaded ..', color: :green)
308
- end
309
- begin
310
- # Start IRB
311
- IRB.start
312
- rescue Exception
313
- IRB.start
314
- end
22
+ if ['version', 'react', 'project'].include?(ARGV[0])
23
+ Rubee::Autoload.call([], white_list_dirs: ['rubee/cli'])
315
24
  else
316
- color_puts "Unknown command: #{command}", color: :red
25
+ Rubee::Autoload.call
317
26
  end
27
+
28
+ Rubee::CLI::Command.new(ARGV).call
@@ -6,7 +6,7 @@
6
6
  <title>React App</title>
7
7
  </head>
8
8
  <body>
9
- <div id="app"></div>
9
+ <div id="App"></div>
10
10
  <script type="module" src="/js/bundle.js"></script>
11
11
  </body>
12
12
  </html>
@@ -1,23 +1,41 @@
1
1
  Rubee::Configuration.setup(env = :development) do |config|
2
2
  config.database_url = { url: 'sqlite://db/development.db', env: }
3
- config.thread_pool_limit = { env:, value: 5 }
4
3
 
5
- # Uncomment, if you want to use react
6
- # config.react = { on: true, env: }
4
+ ## configure hybrid thread pooling params
5
+ # config.threads_limit = { env:, value: 4 }
6
+ # config.fibers_limit = { env:, value: 4 }
7
+
8
+ # Flag on react as a view
9
+ # config.react = { on: true, env: } # required if you want to use react
10
+
11
+ ## configure logger
12
+ # config.logger = { logger: MyLogger, env: }
7
13
  end
8
14
 
9
15
  Rubee::Configuration.setup(env = :test) do |config|
10
16
  config.database_url = { url: 'sqlite://db/test.db', env: }
11
- config.thread_pool_limit = { env:, value: 5 }
12
17
 
13
- # Uncomment, if you want to use react
18
+ ## configure hybrid thread pooling params
19
+ # config.threads_limit = { env:, value: 4 }
20
+ # config.fibers_limit = { env:, value: 4 }
21
+
22
+ ## Flag on react as a view
14
23
  # config.react = { on: true, env: } # required if you want to use react
24
+
25
+ ## configure logger
26
+ # config.logger = { logger: MyLogger, env: }
15
27
  end
16
28
 
17
29
  Rubee::Configuration.setup(env = :production) do |config|
18
30
  config.database_url = { url: 'sqlite://db/production.db', env: }
19
- config.thread_pool_limit = { env:, value: 5 }
20
31
 
21
- # Uncomment,if you want to use react
32
+ ## configure hybrid thread pooling params
33
+ # config.threads_limit = { env:, value: 4 }
34
+ # config.fibers_limit = { env:, value: 4 }
35
+
36
+ ## Flag on react as a view
22
37
  # config.react = { on: true, env: } # required if you want to use react
38
+
39
+ ## configure logger
40
+ # config.logger = { logger: MyLogger, env: }
23
41
  end
@@ -0,0 +1,17 @@
1
+ class CreateAddresses
2
+ def call
3
+ return if Rubee::SequelObject::DB.tables.include?(:addresses)
4
+
5
+ Rubee::SequelObject::DB.create_table(:addresses) do
6
+ primary_key(:id)
7
+ String(:city)
8
+ String(:state)
9
+ String(:zip)
10
+ String(:street)
11
+ String(:apt)
12
+ foreign_key(:user_id, :users)
13
+ end
14
+
15
+ # Address.create(street: '13th Ave', city: 'NY', state: 'NY', zip: '55555', user_id: User.all.first.id)
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module ChargedHash
2
+ refine Hash do
3
+ def [](key)
4
+ return wrap(super(key)) if key?(key)
5
+
6
+ alt_key = key.is_a?(Symbol) ? key.to_s : key.to_sym
7
+ wrap(super(alt_key))
8
+ end
9
+
10
+ private
11
+
12
+ def wrap(value)
13
+ value.is_a?(Hash) ? value.extend(ChargedHash) : value
14
+ end
15
+ end
16
+ end
@@ -20,6 +20,18 @@ module ChargedString
20
20
  !plural?
21
21
  end
22
22
 
23
+ def camelize
24
+ self.split('_').map { _1.capitalize }.join
25
+ end
26
+
27
+ def snakeize
28
+ self.gsub(/::/, '_')
29
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
30
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
31
+ .tr('-', '_')
32
+ .downcase
33
+ end
34
+
23
35
  def singularize
24
36
  if end_with?('ies') && length > 3
25
37
  "#{self[0..-4]}y" # Convert "ies" to "y"
data/lib/js/app.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import React from "react";
2
2
  import { createRoot } from "react-dom/client";
3
- import { App } from "../app/views/app.tsx";
3
+ import { App } from "../app/views/App.tsx";
4
4
 
5
5
  document.addEventListener("DOMContentLoaded", () => {
6
- const container = document.getElementById("app");
6
+ const container = document.getElementById("App");
7
7
  if (container) {
8
8
  const root = createRoot(container);
9
9
  root.render(<App />);
10
10
  } else {
11
- console.error('React root element "#app" not found in DOM.');
11
+ console.error('React root element "#App" not found in DOM.');
12
12
  }
13
13
  });
data/lib/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "scripts": {
3
3
  "build": "node esbuild.config.js",
4
4
  "watch": "node esbuild.config.js --watch",
5
- "prepare": "npm install react react-dom react-router-dom esbuild-plugin-inline-css"
5
+ "prepare": "npm install esbuild react react-dom react-router-dom esbuild-plugin-inline-css"
6
6
  },
7
7
  "dependencies": {
8
8
  "react": "^18.3.1",
@@ -0,0 +1,27 @@
1
+ class FiberQueue
2
+ def initialize
3
+ @fibers = []
4
+ end
5
+
6
+ def add(task, args = {})
7
+ fiber = Fiber.new do
8
+ task.new.perform(**args)
9
+ rescue => e
10
+ puts "Fiber Error: #{e.message}"
11
+ end
12
+ @fibers << fiber
13
+ end
14
+
15
+ def fan_out!
16
+ while @fibers.any?(&:alive?)
17
+ @fibers.each do |fiber|
18
+ fiber.resume if fiber.alive?
19
+ end
20
+ end
21
+ end
22
+
23
+ def done?
24
+ @fibers.none?(&:alive?)
25
+ end
26
+ end
27
+
@@ -1,7 +1,7 @@
1
1
  module Rubee
2
2
  class ThreadAsync
3
3
  def perform_async(**args)
4
- color_puts('WARN: ThreadAsync engine is not yet recommended for production', color: :yellow)
4
+ color_puts('WARN: ThreadAsync engine is experimental!', color: :yellow)
5
5
  ThreadPool.instance.enqueue(args[:_class], args[:options])
6
6
  end
7
7
  end
@@ -3,58 +3,56 @@ require 'singleton'
3
3
  module Rubee
4
4
  class ThreadPool
5
5
  include Singleton
6
- THREAD_POOL_LIMIT = Rubee::Configuration.get_thread_pool_limit || 10 # adjust as needed
6
+ THREADS_LIMIT = Rubee::Configuration.get_threads_limit || 4 unless defined?(THREADS_LIMIT)
7
+ FIBERS_LIMIT = Rubee::Configuration.get_fibers_limit || 4 unless defined?(FIBERS_LIMIT)
7
8
 
8
9
  def initialize
9
- @queue = Queue.new
10
- @workers = []
10
+ @tasks = Queue.new
11
+ @threads = []
11
12
  @running = true
12
- spawn_workers
13
- end
13
+ @mutex = Mutex.new
14
14
 
15
- def enqueue(task, args)
16
- @queue << { task: task, args: args }
17
- run_next
15
+ spawn_workers
18
16
  end
19
17
 
20
- def bulk_enqueue(tasks)
21
- @queue << tasks
22
- run_next
18
+ def enqueue(task, args = {})
19
+ @tasks << [task, args]
23
20
  end
24
21
 
25
22
  def shutdown
26
23
  @running = false
27
- @queue.clear
24
+ THREADS_LIMIT.times { @tasks << :shutdown } # Unblock threads
25
+ @threads.each(&:join)
28
26
  end
29
27
 
30
28
  private
31
29
 
32
- def run_next
33
- @workers.each do |fiber|
34
- fiber.resume if fiber.alive? && !@queue.empty?
35
- end
36
- end
37
-
38
30
  def spawn_workers
39
- THREAD_POOL_LIMIT.times do
40
- fiber = Fiber.new do
41
- loop do
42
- Fiber.yield unless @running
43
- job = @queue.shift
44
- break unless job
45
-
46
- task = job[:task]
47
- args = job[:args]
48
-
49
- begin
50
- task.new.perform(**args)
51
- rescue => e
52
- puts "ThreadPool Error: #{e.message}"
31
+ THREADS_LIMIT.times do
32
+ @threads << Thread.new do
33
+ while @running && (task = @tasks.pop)
34
+ break if task == :shutdown
35
+
36
+ fiber_queue = FiberQueue.new
37
+ fiber_queue.add(*task)
38
+
39
+ # pull more to fill the chunk
40
+ FIBERS_LIMIT.times do
41
+ next_task = begin
42
+ @mutex.synchronize { @tasks.pop(true) }
43
+ rescue
44
+ nil
45
+ end
46
+ fiber_queue.add(*next_task) if next_task
47
+ end
48
+
49
+ until fiber_queue.done?
50
+ fiber_queue.fan_out!
53
51
  end
52
+
53
+ sleep(0.05)
54
54
  end
55
55
  end
56
-
57
- @workers << fiber
58
56
  end
59
57
  end
60
58
  end
@@ -0,0 +1,86 @@
1
+ module Rubee
2
+ class Autoload
3
+ class << self
4
+ def call(black_list = [], **options)
5
+ load_whitelisted(options[:white_list_dirs]) && return if options[:white_list_dirs]
6
+ # autoload all rbs
7
+ root_directory = File.join(Rubee::ROOT_PATH, '/lib')
8
+ priority_order_require(root_directory, black_list)
9
+ # ensure sequel object is connected
10
+ Rubee::SequelObject.reconnect!
11
+
12
+ Dir.glob(File.join(Rubee::APP_ROOT, '**', '*.rb')).sort.each do |file|
13
+ base_name = File.basename(file)
14
+
15
+ unless base_name.end_with?('_test.rb') || (black_list + ['rubee.rb', 'test_helper.rb']).include?(base_name)
16
+ require_relative file
17
+ end
18
+ end
19
+ end
20
+
21
+ def load_whitelisted(white_list_dirs)
22
+ white_list_dirs.each do |dir|
23
+ Dir[File.join(Rubee::ROOT_PATH, '/lib', "#{dir}/**", '*.rb')].each do |file|
24
+ require_relative file
25
+ end
26
+ end
27
+ end
28
+
29
+ def priority_order_require(root_directory, black_list)
30
+ # rubee inits
31
+ Dir[File.join(root_directory, 'inits/**', '*.rb')].each do |file|
32
+ require_relative file unless black_list.include?("#{file}.rb")
33
+ end
34
+ # app inits
35
+ Dir[File.join(Rubee::APP_ROOT, 'inits/**', '*.rb')].each do |file|
36
+ require_relative file unless black_list.include?("#{file}.rb")
37
+ end
38
+ # rubee async
39
+ Dir[File.join(root_directory, 'rubee/async/**', '*.rb')].each do |file|
40
+ require_relative file unless black_list.include?("#{file}.rb")
41
+ end
42
+ # app config and routes
43
+ unless black_list.include?('base_configuration.rb')
44
+ require_relative File.join(Rubee::APP_ROOT, Rubee::LIB,
45
+ 'config/base_configuration')
46
+ end
47
+ # This is necessary prerequisitedb init step
48
+ if Rubee::PROJECT_NAME == 'rubee'
49
+ Rubee::Configuration.setup(env = :test) do |config|
50
+ config.database_url = { url: 'sqlite://lib/tests/test.db', env: }
51
+ end
52
+ end
53
+
54
+ require_relative File.join(Rubee::APP_ROOT, Rubee::LIB, 'config/routes') unless black_list.include?('routes.rb')
55
+ # rubee extensions
56
+ Dir[File.join(root_directory, 'rubee/extensions/**', '*.rb')].each do |file|
57
+ require_relative file unless black_list.include?("#{file}.rb")
58
+ end
59
+ # rubee controllers
60
+ Dir[File.join(root_directory, 'rubee/controllers/middlewares/**', '*.rb')].each do |file|
61
+ require_relative file unless black_list.include?("#{file}.rb")
62
+ end
63
+ Dir[File.join(root_directory, 'rubee/controllers/extensions/**', '*.rb')].each do |file|
64
+ require_relative file unless black_list.include?("#{file}.rb")
65
+ end
66
+ unless black_list.include?('base_controller.rb')
67
+ require_relative File.join(root_directory,
68
+ 'rubee/controllers/base_controller')
69
+ end
70
+ # rubee models
71
+ unless black_list.include?('database_objectable.rb')
72
+ require_relative File.join(root_directory,
73
+ 'rubee/models/database_objectable')
74
+ end
75
+ return if black_list.include?('sequel_object.rb')
76
+
77
+ require_relative File.join(root_directory,
78
+ 'rubee/models/sequel_object')
79
+
80
+ Dir[File.join(root_directory, 'rubee/cli/**', '*.rb')].each do |file|
81
+ require_relative file
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end