ru.Bee 1.5.3 → 1.6.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rubee +9 -4
  3. data/lib/config/base_configuration.rb +25 -4
  4. data/lib/config/routes.rb +0 -1
  5. data/lib/db/create_addresses.rb +17 -0
  6. data/lib/inits/charged_string.rb +6 -6
  7. data/lib/package.json +1 -1
  8. data/lib/rubee/async/fiber_queue.rb +27 -0
  9. data/lib/rubee/async/thread_pool.rb +28 -22
  10. data/lib/rubee/autoload.rb +73 -0
  11. data/lib/rubee/configuration.rb +60 -0
  12. data/lib/rubee/extensions/hookable.rb +9 -2
  13. data/lib/rubee/generator.rb +152 -0
  14. data/lib/rubee/logger.rb +83 -0
  15. data/lib/rubee/models/sequel_object.rb +5 -2
  16. data/lib/rubee/router.rb +41 -0
  17. data/lib/rubee.rb +7 -310
  18. data/lib/tests/async/thread_async_test.rb +36 -0
  19. data/lib/tests/{auth_tokenable_test.rb → controllers/auth_tokenable_test.rb} +2 -2
  20. data/lib/tests/controllers/base_controller_test.rb +23 -0
  21. data/lib/tests/controllers/hookable_test.rb +220 -0
  22. data/lib/tests/{rubeeapp_test.rb → controllers/rubeeapp_test.rb} +2 -1
  23. data/lib/tests/example_models/address.rb +5 -0
  24. data/lib/tests/example_models/user.rb +1 -0
  25. data/lib/tests/logger_test.rb +76 -0
  26. data/lib/tests/{account_model_test.rb → models/account_model_test.rb} +1 -1
  27. data/lib/tests/{comment_model_test.rb → models/comment_model_test.rb} +13 -1
  28. data/lib/tests/models/db_objectable_test.rb +21 -0
  29. data/lib/tests/models/seralizable_test.rb +36 -0
  30. data/lib/tests/{user_model_test.rb → models/user_model_test.rb} +32 -1
  31. data/lib/tests/rubee_generator_test.rb +66 -62
  32. data/lib/tests/test.db +0 -0
  33. data/lib/tests/test_helper.rb +28 -0
  34. data/readme.md +77 -11
  35. metadata +20 -8
  36. data/lib/app/views/apples_.erb +0 -1
  37. data/lib/app/views/s_.erb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2d3eeef6e3b96839595387ebc209aac312e5d9b5d7759f677242d7e615bdb17
4
- data.tar.gz: 13186d7aef77fb4e1c8c4dd173798c61be2eee5e07bee4280b37cb4f060943b8
3
+ metadata.gz: 400c70fb533f9935fb838941de26bd78875f64a62e1d86bed2a817904ca63a7d
4
+ data.tar.gz: 23fe0b3b9334a0c34b5fb671806a58dfa0e7f2aeb48f487fe988eec2354bcdc0
5
5
  SHA512:
6
- metadata.gz: 3c335127b4999f214b181bdc8e970a969be1b8f54e3ec091184b300cd996f5705bd110f33aab364947af25c61e35b38fcbca39aadbc433bf2721bb69aee5d88a
7
- data.tar.gz: 45c05634109187a1a3b7cd107584e8906024c8ee7e5f295c2f420441a53d112cd6bb3d1ef876385388caa1c86dd5aeeb89456cb43a96a718105cadfea951cb34
6
+ metadata.gz: c2d8526cbce129652658679cc1edf861e33f8479b2c8e9e3849c640fc527dd6116dfe314fc7f1fa79f8d188655a1463320a701dc46f13166b870733ef1d3bc35
7
+ data.tar.gz: 386b45c69e6513448adf1ab10f6b9caf4cfc15d588b26f920dc6518489cbf6c9abc5f6404b007d65b6e9aaf71cb806cac391b3023156113e8f3e5958f3430868
data/bin/rubee CHANGED
@@ -60,8 +60,8 @@ elsif command == 'react'
60
60
  exec('npm run watch')
61
61
  end
62
62
  else
63
- color_puts "Unknown command: #{command}", color: :red
64
- exit 1
63
+ color_puts("Unknown command: #{command}", color: :red)
64
+ exit(1)
65
65
  end
66
66
  elsif command == 'project'
67
67
  project_name = ARGV[1]
@@ -89,7 +89,7 @@ elsif command == 'project'
89
89
  # Define blacklist
90
90
  blacklist_files = %w[rubee.rb print_colors.rb version.rb config.ru test_helper.rb Gemfile.lock test.yml test.db
91
91
  development.db production.db]
92
- blacklist_dirs = %w[rubee tests .git .github .idea node_modules db]
92
+ blacklist_dirs = %w[rubee tests .git .github .idea node_modules db inits]
93
93
 
94
94
  # Copy files, excluding blacklisted ones
95
95
  Dir.glob("#{source_dir}/**/*", File::FNM_DOTMATCH).each do |file|
@@ -112,13 +112,18 @@ elsif command == 'project'
112
112
 
113
113
  # create tests dir and copy test_helper.rb and user_model_test.rb
114
114
  FileUtils.mkdir_p("#{target_dir}/tests")
115
- FileUtils.cp("#{source_dir}/tests/user_model_test.rb", "#{target_dir}/tests/user_model_test.rb")
115
+ FileUtils.mkdir_p("#{target_dir}/tests/models")
116
+ FileUtils.mkdir_p("#{target_dir}/tests/controllers")
117
+ FileUtils.cp("#{source_dir}/tests/models/user_model_test.rb", "#{target_dir}/tests/models/user_model_test.rb")
116
118
 
117
119
  # create db dir
118
120
  FileUtils.mkdir_p("#{target_dir}/db")
119
121
  FileUtils.cp("#{source_dir}/db/structure.rb", "#{target_dir}/db/structure.rb")
120
122
  FileUtils.cp("#{source_dir}/db/create_users.rb", "#{target_dir}/db/create_users.rb")
121
123
 
124
+ # create inits dir
125
+ FileUtils.mkdir_p("#{target_dir}/inits")
126
+
122
127
  # create a gemfile context
123
128
  gemfile = <<~GEMFILE
124
129
  source 'https://rubygems.org'
@@ -1,20 +1,41 @@
1
1
  Rubee::Configuration.setup(env = :development) do |config|
2
2
  config.database_url = { url: 'sqlite://db/development.db', env: }
3
3
 
4
- # Uncomment, if you want to use react
5
- # 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: }
6
13
  end
7
14
 
8
15
  Rubee::Configuration.setup(env = :test) do |config|
9
16
  config.database_url = { url: 'sqlite://db/test.db', env: }
10
17
 
11
- # 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
12
23
  # config.react = { on: true, env: } # required if you want to use react
24
+
25
+ ## configure logger
26
+ # config.logger = { logger: MyLogger, env: }
13
27
  end
14
28
 
15
29
  Rubee::Configuration.setup(env = :production) do |config|
16
30
  config.database_url = { url: 'sqlite://db/production.db', env: }
17
31
 
18
- # 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
19
37
  # config.react = { on: true, env: } # required if you want to use react
38
+
39
+ ## configure logger
40
+ # config.logger = { logger: MyLogger, env: }
20
41
  end
data/lib/config/routes.rb CHANGED
@@ -1,4 +1,3 @@
1
1
  Rubee::Router.draw do |router|
2
2
  router.get('/', to: 'welcome#show') # override it for your app
3
3
  end
4
-
@@ -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
@@ -1,9 +1,9 @@
1
1
  module ChargedString
2
2
  refine String do
3
3
  def pluralize
4
- if self.end_with?('y') && !%w[a e i o u].include?(self[-2])
4
+ if end_with?('y') && !%w[a e i o u].include?(self[-2])
5
5
  "#{self[0..-2]}ies" # Replace "y" with "ies"
6
- elsif self.end_with?('s', 'x', 'z', 'ch', 'sh')
6
+ elsif end_with?('s', 'x', 'z', 'ch', 'sh')
7
7
  "#{self}es" # Add "es" for certain endings
8
8
  else
9
9
  "#{self}s" # Default to adding "s"
@@ -11,7 +11,7 @@ module ChargedString
11
11
  end
12
12
 
13
13
  def plural?
14
- return true if self.end_with?('s') && !self.end_with?('ss')
14
+ return true if end_with?('s') && !end_with?('ss')
15
15
 
16
16
  false
17
17
  end
@@ -21,11 +21,11 @@ module ChargedString
21
21
  end
22
22
 
23
23
  def singularize
24
- if self.end_with?('ies') && self.length > 3
24
+ if end_with?('ies') && length > 3
25
25
  "#{self[0..-4]}y" # Convert "ies" to "y"
26
- elsif self.end_with?('es') && %w[s x z ch sh].any? { |ending| self[-(ending.length + 2)..-3] == ending }
26
+ elsif end_with?('es') && %w[s x z ch sh].any? { |ending| self[-(ending.length + 2)..-3] == ending }
27
27
  self[0..-3] # Remove "es" for selfs like "foxes", "buses"
28
- elsif self.end_with?('s') && self.length > 1
28
+ elsif end_with?('s') && length > 1
29
29
  self[0..-2] # Remove "s" for regular plurals
30
30
  else
31
31
  self # Return as-is if no plural form is detected
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
+
@@ -3,48 +3,54 @@ require 'singleton'
3
3
  module Rubee
4
4
  class ThreadPool
5
5
  include Singleton
6
- THREADS_LIMIT = 4 # adjust as needed
6
+ THREADS_LIMIT = Rubee::Configuration.get_threads_limit || 4
7
+ FIBERS_LIMIT = Rubee::Configuration.get_fibers_limit || 4
7
8
 
8
9
  def initialize
9
- @queue = Queue.new
10
- @workers = []
10
+ @tasks = Queue.new
11
+ @threads = []
11
12
  @running = true
12
13
  @mutex = Mutex.new
13
- spawn_workers
14
- end
15
14
 
16
- def enqueue(task, args)
17
- @queue << { task: task, args: args }
15
+ spawn_workers
18
16
  end
19
17
 
20
- def bulk_enqueue(tasks)
21
- @queue << tasks
18
+ def enqueue(task, args = {})
19
+ @tasks << [task, args]
22
20
  end
23
21
 
24
22
  def shutdown
25
23
  @running = false
26
- THREADS_LIMIT.times { @queue << { task: :stop, args: nil } }
27
- @workers.each(&:join)
24
+ THREADS_LIMIT.times { @tasks << :shutdown } # Unblock threads
25
+ @threads.each(&:join)
28
26
  end
29
27
 
30
28
  private
31
29
 
32
30
  def spawn_workers
33
31
  THREADS_LIMIT.times do
34
- @workers << Thread.new do
35
- while @running
36
- task_hash = @mutex.synchronize { @queue.pop }
37
- if task_hash
38
- task = task_hash[:task]
39
- args = task_hash[:args]
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
40
47
  end
41
- break if task == :stop
42
48
 
43
- begin
44
- task.new.perform(**args)
45
- rescue StandardError => e
46
- puts "ThreadPool Error: #{e.message}"
49
+ until fiber_queue.done?
50
+ fiber_queue.fan_out!
47
51
  end
52
+
53
+ sleep(0.05)
48
54
  end
49
55
  end
50
56
  end
@@ -0,0 +1,73 @@
1
+ module Rubee
2
+ class Autoload
3
+ class << self
4
+ def call(black_list = [])
5
+ # autoload all rbs
6
+ root_directory = File.expand_path(File.join(__dir__, '..',))
7
+ priority_order_require(root_directory, black_list)
8
+ # ensure sequel object is connected
9
+ Rubee::SequelObject.reconnect!
10
+
11
+ Dir.glob(File.join(APP_ROOT, '**', '*.rb')).sort.each do |file|
12
+ base_name = File.basename(file)
13
+
14
+ unless base_name.end_with?('_test.rb') || (black_list + ['rubee.rb', 'test_helper.rb']).include?(base_name)
15
+ require_relative file
16
+ end
17
+ end
18
+ end
19
+
20
+ def priority_order_require(root_directory, black_list)
21
+ # rubee inits
22
+ Dir[File.join(root_directory, 'inits/**', '*.rb')].each do |file|
23
+ require_relative file unless black_list.include?("#{file}.rb")
24
+ end
25
+ # app inits
26
+ Dir[File.join(APP_ROOT, 'inits/**', '*.rb')].each do |file|
27
+ require_relative file unless black_list.include?("#{file}.rb")
28
+ end
29
+ # rubee async
30
+ Dir[File.join(root_directory, 'rubee/async/**', '*.rb')].each do |file|
31
+ require_relative file unless black_list.include?("#{file}.rb")
32
+ end
33
+ # app config and routes
34
+ unless black_list.include?('base_configuration.rb')
35
+ require_relative File.join(APP_ROOT, LIB,
36
+ 'config/base_configuration')
37
+ end
38
+ # This is necessary prerequisitedb init step
39
+ if !defined?(Rubee::SequelObject::DB) && (PROJECT_NAME == 'rubee')
40
+ Rubee::Configuration.setup(env = :test) do |config|
41
+ config.database_url = { url: 'sqlite://lib/tests/test.db', env: }
42
+ end
43
+ end
44
+
45
+ require_relative File.join(APP_ROOT, LIB, 'config/routes') unless black_list.include?('routes.rb')
46
+ # rubee extensions
47
+ Dir[File.join(root_directory, 'rubee/extensions/**', '*.rb')].each do |file|
48
+ require_relative file unless black_list.include?("#{file}.rb")
49
+ end
50
+ # rubee controllers
51
+ Dir[File.join(root_directory, 'rubee/controllers/middlewares/**', '*.rb')].each do |file|
52
+ require_relative file unless black_list.include?("#{file}.rb")
53
+ end
54
+ Dir[File.join(root_directory, 'rubee/controllers/extensions/**', '*.rb')].each do |file|
55
+ require_relative file unless black_list.include?("#{file}.rb")
56
+ end
57
+ unless black_list.include?('base_controller.rb')
58
+ require_relative File.join(root_directory,
59
+ 'rubee/controllers/base_controller')
60
+ end
61
+ # rubee models
62
+ unless black_list.include?('database_objectable.rb')
63
+ require_relative File.join(root_directory,
64
+ 'rubee/models/database_objectable')
65
+ end
66
+ return if black_list.include?('sequel_object.rb')
67
+
68
+ require_relative File.join(root_directory,
69
+ 'rubee/models/sequel_object')
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,60 @@
1
+ module Rubee
2
+ class Configuration
3
+ include Singleton
4
+
5
+ @configuraiton = {
6
+ development: {
7
+ database_url: '',
8
+ port: 7000,
9
+ },
10
+ production: {},
11
+ test: {},
12
+ }
13
+
14
+ class << self
15
+ def setup(_env)
16
+ yield(self)
17
+ end
18
+
19
+ def database_url=(args)
20
+ @configuraiton[args[:env].to_sym][:database_url] = args[:url]
21
+ end
22
+
23
+ def async_adapter=(args)
24
+ @configuraiton[args[:env].to_sym][:async_adapter] = args[:async_adapter]
25
+ end
26
+
27
+ def threads_limit=(args)
28
+ @configuraiton[args[:env].to_sym][:thread_pool_limit] = args[:value]
29
+ end
30
+
31
+ def fibers_limit=(args)
32
+ @configuraiton[args[:env].to_sym][:fiber_pool_limit] = args[:value]
33
+ end
34
+
35
+ def logger=(args)
36
+ @configuraiton[args[:env].to_sym][:logger] = args[:logger]
37
+ end
38
+
39
+
40
+ def react=(args)
41
+ @configuraiton[args[:env].to_sym][:react] ||= { on: false }
42
+ @configuraiton[args[:env].to_sym][:react].merge!(on: args[:on])
43
+ end
44
+
45
+ def react
46
+ @configuraiton[ENV['RACK_ENV']&.to_sym || :development][:react] || {}
47
+ end
48
+
49
+ def method_missing(method_name, *_args)
50
+ return unless method_name.to_s.start_with?('get_')
51
+
52
+ @configuraiton[ENV['RACK_ENV']&.to_sym || :development]&.[](method_name.to_s.delete_prefix('get_').to_sym)
53
+ end
54
+
55
+ def envs
56
+ @configuraiton.keys
57
+ end
58
+ end
59
+ end
60
+ end
@@ -39,9 +39,16 @@ module Rubee
39
39
  define_method(method) do |*args, &block|
40
40
  if conditions_met?(options[:if], options[:unless])
41
41
  if handler.respond_to?(:call)
42
- handler.call { super(*args, &block) }
42
+ result = nil
43
+ handler.call do
44
+ result = super(*args, &block)
45
+ end
46
+
47
+ result
43
48
  else
44
- send(handler) { super(*args, &block) }
49
+ return send(handler) do
50
+ super(*args, &block)
51
+ end
45
52
  end
46
53
  else
47
54
  super(*args, &block)
@@ -0,0 +1,152 @@
1
+ module Rubee
2
+ class Generator
3
+ require_relative '../inits/charged_string'
4
+ using ChargedString
5
+ def initialize(model_name, model_attributes, controller_name, action_name, **options)
6
+ @model_name = model_name&.downcase
7
+ @model_attributes = model_attributes || []
8
+ @base_name = controller_name.to_s.gsub('Controller', '').downcase.to_s
9
+ color_puts("base_name: #{@base_name}", color: :gray)
10
+ @plural_name = @base_name.plural? ? @base_name : @base_name.pluralize
11
+ @action_name = action_name
12
+ @react = options[:react] || {}
13
+ end
14
+
15
+ def call
16
+ generate_model if @model_name
17
+ generate_db_file if @model_name
18
+ generate_controller if @base_name && @action_name
19
+ generate_view if @base_name
20
+ end
21
+
22
+ private
23
+
24
+ def generate_model
25
+ model_file = File.join(Rubee::APP_ROOT, Rubee::LIB, "app/models/#{@model_name}.rb")
26
+ if File.exist?(model_file)
27
+ puts "Model #{@model_name} already exists. Remove it if you want to regenerate"
28
+ return
29
+ end
30
+
31
+ content = <<~RUBY
32
+ class #{@model_name.capitalize} < Rubee::SequelObject
33
+ #{'attr_accessor ' + @model_attributes.map { |hash| ":#{hash[:name]}" }.join(', ') unless @model_attributes.empty?}
34
+ end
35
+ RUBY
36
+
37
+ File.open(model_file, 'w') { |file| file.write(content) }
38
+ color_puts("Model #{@model_name} created", color: :green)
39
+ end
40
+
41
+ def generate_controller
42
+ controller_file = File.join(Rubee::APP_ROOT, Rubee::LIB, "app/controllers/#{@base_name}_controller.rb")
43
+ if File.exist?(controller_file)
44
+ puts "Controller #{@base_name} already exists. Remove it if you want to regenerate"
45
+ return
46
+ end
47
+
48
+ content = <<~RUBY
49
+ class #{@base_name.capitalize}Controller < Rubee::BaseController
50
+ def #{@action_name}
51
+ response_with
52
+ end
53
+ end
54
+ RUBY
55
+
56
+ File.open(controller_file, 'w') { |file| file.write(content) }
57
+ color_puts("Controller #{@base_name} created", color: :green)
58
+ end
59
+
60
+ def generate_view
61
+ if @react[:view_name]
62
+ view_file = File.join(Rubee::APP_ROOT, Rubee::LIB, "app/views/#{@react[:view_name]}")
63
+ content = <<~JS
64
+ import React, { useEffect, useState } from "react";
65
+ // 1. Add your logic that fetches data
66
+ // 2. Do not forget to add respective react route
67
+ export function #{@react[:view_name].gsub(/\.(.*)+$/, '').capitalize}() {
68
+
69
+ return (
70
+ <div>
71
+ <h2>#{@react[:view_name]} view</h2>
72
+ </div>
73
+ );
74
+ }
75
+ JS
76
+ else
77
+ view_file = File.join(Rubee::APP_ROOT, Rubee::LIB, "app/views/#{@plural_name}_#{@action_name}.erb")
78
+ content = <<~ERB
79
+ <h1>#{@plural_name}_#{@action_name} View</h1>
80
+ ERB
81
+ end
82
+
83
+ name = @react[:view_name] || "#{@plural_name}_#{@action_name}"
84
+
85
+ if File.exist?(view_file)
86
+ puts "View #{name} already exists. Remove it if you want to regenerate"
87
+ return
88
+ end
89
+
90
+ File.open(view_file, 'w') { |file| file.write(content) }
91
+ color_puts("View #{name} created", color: :green)
92
+ end
93
+
94
+ def generate_db_file
95
+ db_file = File.join(Rubee::APP_ROOT, Rubee::LIB, "db/create_#{@plural_name}.rb")
96
+ if File.exist?(db_file)
97
+ puts "DB file for #{@plural_name} already exists. Remove it if you want to regenerate"
98
+ return
99
+ end
100
+
101
+ content = <<~RUBY
102
+ class Create#{@plural_name.capitalize}
103
+ def call
104
+ return if Rubee::SequelObject::DB.tables.include?(:#{@plural_name})
105
+
106
+ Rubee::SequelObject::DB.create_table(:#{@plural_name}) do
107
+ #{@model_attributes.map { |attribute| generate_sequel_schema(attribute) }.join("\n\t\t\t")}
108
+ end
109
+ end
110
+ end
111
+ RUBY
112
+
113
+ File.open(db_file, 'w') { |file| file.write(content) }
114
+ color_puts("DB file for #{@plural_name} created", color: :green)
115
+ end
116
+
117
+ def generate_sequel_schema(attribute)
118
+ type = attribute[:type]
119
+ name = if attribute[:name].is_a?(Array)
120
+ attribute[:name].map { |nom| ":#{nom}" }.join(", ").prepend('[') + ']'
121
+ else
122
+ ":#{attribute[:name]}"
123
+ end
124
+ table = attribute[:table] || 'replace_with_table_name'
125
+ options = attribute[:options] || {}
126
+
127
+ lookup_hash = {
128
+ primary: "primary_key #{name}",
129
+ string: "String #{name}",
130
+ text: "String #{name}, text: true",
131
+ integer: "Integer #{name}",
132
+ date: "Date #{name}",
133
+ datetime: "DateTime #{name}",
134
+ time: "Time #{name}",
135
+ boolean: "TrueClass #{name}",
136
+ bigint: "Bignum #{name}",
137
+ decimal: "BigDecimal #{name}",
138
+ foreign_key: "foreign_key #{name}, :#{table}",
139
+ index: "index #{name}",
140
+ unique: "unique #",
141
+ }
142
+
143
+ statement = lookup_hash[type.to_sym]
144
+
145
+ options.keys.each do |key|
146
+ statement += ", #{key}: '#{options[key]}'"
147
+ end
148
+
149
+ statement
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,83 @@
1
+ module Rubee
2
+ class Logger
3
+ class << self
4
+ def warn(message:, **options, &block)
5
+ out.warn(message:, **options, &block)
6
+ end
7
+
8
+ def error(message:, **options, &block)
9
+ out.error(message:, **options, &block)
10
+ end
11
+
12
+ def critical(message:, **options, &block)
13
+ out.critical(message:, **options, &block)
14
+ end
15
+
16
+ def info(message:, **options, &block)
17
+ out.info(message:, **options, &block)
18
+ end
19
+
20
+ def debug(object:, **options, &block)
21
+ out.debug(object:, **options, &block)
22
+ end
23
+
24
+ def out
25
+ Rubee::Configuration.get_logger || Stdout
26
+ end
27
+ end
28
+ end
29
+
30
+ class Stdout
31
+ class << self
32
+ def warn(message:, **options, &block)
33
+ log(:warn, message, options, &block)
34
+ end
35
+
36
+ def error(message:, **options, &block)
37
+ log(:error, message, options, &block)
38
+ end
39
+
40
+ def critical(message:, **options, &block)
41
+ log(:critical, message, options, &block)
42
+ end
43
+
44
+ def info(message:, **options, &block)
45
+ log(:info, message, options, &block)
46
+ end
47
+
48
+ def debug(object:, **options, &block)
49
+ log(:debug, object.inspect, options, &block)
50
+ end
51
+
52
+ def print_error(message)
53
+ color_puts(message, color: :red)
54
+ end
55
+
56
+ def print_info(message)
57
+ color_puts(message, color: :gray)
58
+ end
59
+
60
+ def print_warn(message)
61
+ color_puts(message, color: :yellow)
62
+ end
63
+
64
+ def print_debug(message)
65
+ color_puts(message)
66
+ end
67
+
68
+ def print_critical(message)
69
+ color_puts(message, color: :red, style: :blink)
70
+ end
71
+
72
+ def log(severity, message, options = {}, &block)
73
+ time = Time.now.strftime('%Y-%m-%d %H:%M:%S')
74
+ if options.any?
75
+ message = options.map { |k, v| "[#{k}: #{v}]" }.join << " #{message}"
76
+ end
77
+ send("print_#{severity}", "[#{time}] #{severity.upcase} #{message}")
78
+
79
+ block&.call(message, options) if block_given?
80
+ end
81
+ end
82
+ end
83
+ end