ru.Bee 1.1.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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/bin/rubee +259 -0
- data/lib/Dockerfile +33 -0
- data/lib/app/controllers/welcome_controller.rb +5 -0
- data/lib/app/models/user.rb +6 -0
- data/lib/app/views/welcome_show.erb +52 -0
- data/lib/config/base_configuration.rb +11 -0
- data/lib/config/routes.rb +3 -0
- data/lib/config.ru +3 -0
- data/lib/db/create_users.rb +16 -0
- data/lib/db/structure.rb +34 -0
- data/lib/db/test.db +0 -0
- data/lib/images/rubee.svg +6 -0
- data/lib/inits/print_colors.rb +24 -0
- data/lib/rubee/async/asyncable.rb +17 -0
- data/lib/rubee/async/sidekiq_async.rb +15 -0
- data/lib/rubee/async/thread_async.rb +8 -0
- data/lib/rubee/async/thread_pool.rb +53 -0
- data/lib/rubee/controllers/base_controller.rb +78 -0
- data/lib/rubee/controllers/extensions/auth_tokenable.rb +81 -0
- data/lib/rubee/controllers/extensions/middlewarable.rb +31 -0
- data/lib/rubee/controllers/middlewares/auth_token_middleware.rb +42 -0
- data/lib/rubee/extensions/hookable.rb +85 -0
- data/lib/rubee/extensions/serializable.rb +28 -0
- data/lib/rubee/models/database_object.rb +50 -0
- data/lib/rubee/models/sequel_object.rb +86 -0
- data/lib/rubee/tests/auth_tokenable_test.rb +29 -0
- data/lib/rubee/tests/rubeeapp_test.rb +24 -0
- data/lib/rubee/tests/test_helper.rb +11 -0
- data/lib/rubee/tests/user_model_test.rb +51 -0
- data/lib/rubee.rb +259 -0
- data/lib/version.rb +1 -0
- data/readme.md +353 -0
- metadata +95 -0
data/lib/rubee.rb
ADDED
@@ -0,0 +1,259 @@
|
|
1
|
+
require "singleton"
|
2
|
+
require "bundler/setup"
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
Bundler.require(:default) rescue nil
|
6
|
+
|
7
|
+
module Rubee
|
8
|
+
APP_ROOT = File.expand_path(Dir.pwd) unless defined?(APP_ROOT)
|
9
|
+
IMAGE_DIR = File.join(APP_ROOT, 'images') unless defined?(IMAGE_DIR)
|
10
|
+
PROJECT_NAME = File.basename(APP_ROOT) unless defined?(PROJECT_NAME)
|
11
|
+
|
12
|
+
class Application
|
13
|
+
include Singleton
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
# autoload rb files
|
17
|
+
Autoload.call
|
18
|
+
# register images paths
|
19
|
+
request = Rack::Request.new(env)
|
20
|
+
# Add default path for images
|
21
|
+
Router.draw { |route| route.get "/images/{path}", to: "base#image", namespace: "Rubee"}
|
22
|
+
# define route
|
23
|
+
route = Router.route_for(request)
|
24
|
+
# init controller class
|
25
|
+
return [404, { "content-type" => "text/plain" }, ["Route not found"]] unless route
|
26
|
+
|
27
|
+
if route[:namespace]
|
28
|
+
controller_class = "#{route[:namespace]}::#{route[:controller].capitalize}Controller"
|
29
|
+
else
|
30
|
+
controller_class = "#{route[:controller].capitalize}Controller"
|
31
|
+
end
|
32
|
+
# instantiate controller
|
33
|
+
controller = Object.const_get(controller_class).new(request, route)
|
34
|
+
# get the action
|
35
|
+
action = route[:action]
|
36
|
+
# fire the action
|
37
|
+
controller.send(action)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Configuration
|
42
|
+
include Singleton
|
43
|
+
|
44
|
+
@configuraiton = {
|
45
|
+
development: {
|
46
|
+
database_url: "",
|
47
|
+
port: 7000
|
48
|
+
},
|
49
|
+
production: {},
|
50
|
+
test: {}
|
51
|
+
}
|
52
|
+
|
53
|
+
class << self
|
54
|
+
def setup(env)
|
55
|
+
yield(self)
|
56
|
+
end
|
57
|
+
|
58
|
+
def database_url=(args)
|
59
|
+
@configuraiton[args[:env].to_sym][:database_url] = args[:url]
|
60
|
+
end
|
61
|
+
|
62
|
+
def async_adapter=(args)
|
63
|
+
@configuraiton[args[:env].to_sym][:async_adapter] = args[:async_adapter]
|
64
|
+
end
|
65
|
+
|
66
|
+
def method_missing(method_name, *args, &block)
|
67
|
+
if method_name.to_s.start_with?("get_")
|
68
|
+
@configuraiton[ENV['RACK_ENV']&.to_sym || :development]&.[](method_name.to_s.delete_prefix("get_").to_sym)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def envs
|
73
|
+
@configuraiton.keys
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Router
|
79
|
+
include Singleton
|
80
|
+
|
81
|
+
HTTP_METHODS = [:get, :post, :put, :patch, :delete, :head, :connect, :options, :trace].freeze
|
82
|
+
|
83
|
+
attr_reader :request, :routes
|
84
|
+
|
85
|
+
@routes = []
|
86
|
+
|
87
|
+
class << self
|
88
|
+
def draw
|
89
|
+
yield(self) if block_given?
|
90
|
+
end
|
91
|
+
|
92
|
+
def route_for(request)
|
93
|
+
puts request.request_method
|
94
|
+
method = (request.params["_method"] || request.request_method).downcase.to_sym
|
95
|
+
@routes.find do |route|
|
96
|
+
return route if request.path == route[:path] && request.request_method&.downcase&.to_sym == route[:method]
|
97
|
+
|
98
|
+
pattern = route[:path].gsub(/{.*?}/, '([^/]+)')
|
99
|
+
regex = %r{^#{pattern}$}
|
100
|
+
regex.match?(request.path) && method.to_s == route[:method].to_s
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_route(path, to:, method: __method__, **args)
|
105
|
+
controller, action = to.split("#")
|
106
|
+
@routes.delete_if { |route| route[:path] == path && route[:method] == method }
|
107
|
+
@routes << { path:, controller:, action:, method:, **args }
|
108
|
+
end
|
109
|
+
|
110
|
+
HTTP_METHODS.each do |method|
|
111
|
+
define_method method do |path, to:, **args|
|
112
|
+
set_route(path, to:, method: method, **args)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
class Autoload
|
120
|
+
class << self
|
121
|
+
def call(black_list=[])
|
122
|
+
# autoload all rbs
|
123
|
+
root_directory = File.dirname(__FILE__)
|
124
|
+
priority_order_require(root_directory, black_list)
|
125
|
+
|
126
|
+
Dir.glob(File.join(APP_ROOT, '**', '*.rb')).sort.each do |file|
|
127
|
+
base_name = File.basename(file)
|
128
|
+
|
129
|
+
unless base_name.end_with?('_test.rb') || (black_list + ['rubee.rb', 'test_helper.rb']).include?(base_name)
|
130
|
+
require_relative file
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def priority_order_require(root_directory, black_list)
|
136
|
+
# rubee inits
|
137
|
+
Dir[File.join(root_directory, 'inits/**', '*.rb')].each do |file|
|
138
|
+
require_relative file unless black_list.include?("#{file}.rb")
|
139
|
+
end
|
140
|
+
# app inits
|
141
|
+
lib_dir = PROJECT_NAME == 'rubee' ? 'lib' : ''
|
142
|
+
Dir[File.join(APP_ROOT, lib_dir, 'inits/**', '*.rb')].each do |file|
|
143
|
+
require_relative file unless black_list.include?("#{file}.rb")
|
144
|
+
end
|
145
|
+
# rubee async
|
146
|
+
Dir[File.join(root_directory, 'rubee/async/**', '*.rb')].each do |file|
|
147
|
+
require_relative file unless black_list.include?("#{file}.rb")
|
148
|
+
end
|
149
|
+
# app config and routes
|
150
|
+
require_relative File.join(APP_ROOT, lib_dir, "config/base_configuration") unless black_list.include?('base_configuration.rb')
|
151
|
+
require_relative File.join(APP_ROOT, lib_dir, "config/routes") unless black_list.include?('routes.rb')
|
152
|
+
# rubee extensions
|
153
|
+
Dir[File.join(root_directory, "rubee/extensions/**", '*.rb')].each do |file|
|
154
|
+
require_relative file unless black_list.include?("#{file}.rb")
|
155
|
+
end
|
156
|
+
# rubee controllers
|
157
|
+
Dir[File.join(root_directory, 'rubee/controllers/middlewares/**', '*.rb')].each do |file|
|
158
|
+
require_relative file unless black_list.include?("#{file}.rb")
|
159
|
+
end
|
160
|
+
Dir[File.join(root_directory, 'rubee/controllers/extensions/**', '*.rb')].each do |file|
|
161
|
+
require_relative file unless black_list.include?("#{file}.rb")
|
162
|
+
end
|
163
|
+
require_relative File.join(root_directory, "rubee/controllers/base_controller") unless black_list.include?('base_controller.rb')
|
164
|
+
# rubee models
|
165
|
+
require_relative File.join(root_directory, "rubee/models/database_object") unless black_list.include?('database_object.rb')
|
166
|
+
require_relative File.join(root_directory, "rubee/models/sequel_object") unless black_list.include?('sequel_object.rb')
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class Generator
|
172
|
+
def initialize(model_name, attributes, controller_name, action_name)
|
173
|
+
@model_name = model_name&.downcase
|
174
|
+
@attributes = attributes
|
175
|
+
@plural_name = "#{controller_name.to_s.gsub("Controller", "").downcase}"
|
176
|
+
@action_name = action_name
|
177
|
+
@controller_name = controller_name
|
178
|
+
end
|
179
|
+
|
180
|
+
def call
|
181
|
+
generate_model if @model_name
|
182
|
+
generate_db_file if @model_name
|
183
|
+
generate_controller if @controller_name && @action_name
|
184
|
+
generate_view if @controller_name
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
def generate_model
|
190
|
+
model_file = File.join("app/models/#{@model_name}.rb")
|
191
|
+
if File.exist?(model_file)
|
192
|
+
puts "Model #{@model_name} already exists. Remove it if you want to regenerate"
|
193
|
+
return
|
194
|
+
end
|
195
|
+
|
196
|
+
content = <<~RUBY
|
197
|
+
class #{@model_name.capitalize} < Rubee::SequelObject
|
198
|
+
attr_accessor #{@attributes.map { |hash| ":#{hash[:name]}" }.join(", ")}
|
199
|
+
end
|
200
|
+
RUBY
|
201
|
+
|
202
|
+
File.open(model_file, 'w') { |file| file.write(content) }
|
203
|
+
color_puts "Model #{@model_name} created", color: :green
|
204
|
+
end
|
205
|
+
|
206
|
+
def generate_controller
|
207
|
+
controller_file = File.join("app/controllers/#{@plural_name}_controller.rb")
|
208
|
+
if File.exist?(controller_file)
|
209
|
+
puts "Controller #{@plural_name} already exists. Remove it if you want to regenerate"
|
210
|
+
return
|
211
|
+
end
|
212
|
+
|
213
|
+
content = <<~RUBY
|
214
|
+
class #{@plural_name.capitalize}Controller < Rubee::BaseController
|
215
|
+
def #{@action_name}
|
216
|
+
response_with
|
217
|
+
end
|
218
|
+
end
|
219
|
+
RUBY
|
220
|
+
|
221
|
+
File.open(controller_file, 'w') { |file| file.write(content) }
|
222
|
+
color_puts "Controller #{@plural_name} created", color: :green
|
223
|
+
end
|
224
|
+
|
225
|
+
def generate_view
|
226
|
+
view_file = File.join("app/views/#{@plural_name}_#{@action_name}.erb")
|
227
|
+
if File.exist?(view_file)
|
228
|
+
puts "View #{@plural_name}_#{@action_name} already exists. Remove it if you want to regenerate"
|
229
|
+
return
|
230
|
+
end
|
231
|
+
|
232
|
+
content = <<~ERB
|
233
|
+
<h1>#{@plural_name}_#{@action_name} View</h1>
|
234
|
+
ERB
|
235
|
+
|
236
|
+
File.open(view_file, 'w') { |file| file.write(content) }
|
237
|
+
color_puts "View #{@plural_name}_#{@action_name} created", color: :green
|
238
|
+
end
|
239
|
+
|
240
|
+
def generate_db_file
|
241
|
+
db_file = File.join("db/create_#{@plural_name}.rb")
|
242
|
+
if File.exist?(db_file)
|
243
|
+
puts "DB file for #{@plural_name} already exists. Remove it if you want to regenerate"
|
244
|
+
return
|
245
|
+
end
|
246
|
+
|
247
|
+
content = <<~RUBY
|
248
|
+
class Create#{@plural_name.capitalize}
|
249
|
+
def call
|
250
|
+
end
|
251
|
+
end
|
252
|
+
RUBY
|
253
|
+
|
254
|
+
File.open(db_file, 'w') { |file| file.write(content) }
|
255
|
+
color_puts "DB file for #{@plural_name} created", color: :green
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
data/lib/version.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
VERSION = '1.1.0'
|
data/readme.md
ADDED
@@ -0,0 +1,353 @@
|
|
1
|
+

|
2
|
+

|
3
|
+

|
4
|
+
|
5
|
+
|
6
|
+
# <img src="images/rubee.svg" alt="Rubee" height="40"> ... ruBee
|
7
|
+
|
8
|
+
ruBee is a fast and lightweight Ruby application server designed for minimalism and flexibility .
|
9
|
+
|
10
|
+
The main philosophy of ruBee is to focus on Ruby language explicit implementation of the MVC web application.
|
11
|
+
|
12
|
+
Want to get a quick API server up and runing? You can do it for real quick!
|
13
|
+
<br />
|
14
|
+
Laoding ... (demo is on its way)
|
15
|
+
|
16
|
+
All greaet features are yet to come!
|
17
|
+
|
18
|
+
## Features
|
19
|
+
|
20
|
+
- **Lightweight**: A minimal footprint that focuses on serving Ruby applications efficiently.
|
21
|
+
- **Contract driven**: Define your API contracts in a simple, declarative manner. And generate the files for you.
|
22
|
+
- **Fast**: Optimized for speed, providing a quick response to requests. Everything is relative, I know!
|
23
|
+
- **Rack**: Rack backed. All Rack api is available for integration.
|
24
|
+
- **Router**: Router driven - generates all required files from the routes.
|
25
|
+
- **Databases**: Sqlite3, Postgres, Mysql and many more supported by sequel gem.
|
26
|
+
- **Views**: Json, ERB and plain HTML
|
27
|
+
- **Bundlable** Charge your ruBee with any gem you need and update your project with bundle.
|
28
|
+
- **ORM** All models are natively ORM objects, however you can use it as a blueurpint for any datasources.
|
29
|
+
- **Authentificatable** Add JWT authentification easily to any controller action.
|
30
|
+
- **Hooks** Add logic before, after and around any action.
|
31
|
+
- **Test** Run all or selected tests witin minitest.
|
32
|
+
- **Asyncable** Add async adapter and pick any popular background job queue enginee
|
33
|
+
|
34
|
+
## Installation
|
35
|
+
|
36
|
+
1. Install ruBee
|
37
|
+
```bash
|
38
|
+
gem install rubee
|
39
|
+
```
|
40
|
+
|
41
|
+
2. Create your first project
|
42
|
+
```bash
|
43
|
+
rubee project my_project
|
44
|
+
cd my_project
|
45
|
+
```
|
46
|
+
|
47
|
+
3. Install dependencies
|
48
|
+
|
49
|
+
***Prerequisites***<br />
|
50
|
+
**ruBee** is using **Sqlite** as a default database. However you can pick up any other database supported by sequel gem.
|
51
|
+
Aside that, make sure:
|
52
|
+
**Ruby** language (3+) is installed
|
53
|
+
**Bundler** is installed
|
54
|
+
|
55
|
+
```bash
|
56
|
+
bundle install
|
57
|
+
```
|
58
|
+
|
59
|
+
4. Run ruBee server. Default port is 7000
|
60
|
+
```bash
|
61
|
+
rubee start
|
62
|
+
```
|
63
|
+
|
64
|
+
5. Open your browser and go to http://localhost:7000
|
65
|
+
|
66
|
+
## Create API contract and generate files from the routes
|
67
|
+
1. Add the routes to the routes.rb
|
68
|
+
```bash
|
69
|
+
Rubee::Router.draw do |router|
|
70
|
+
...
|
71
|
+
# draw the contract
|
72
|
+
router.get "/apples", to: "apples#index",
|
73
|
+
model: {
|
74
|
+
name: "apple",
|
75
|
+
attributes: [
|
76
|
+
{ name: 'id', type: :integer },
|
77
|
+
{ name: 'colour', type: :string },
|
78
|
+
{ name: 'weight', type: :integer }
|
79
|
+
]
|
80
|
+
}
|
81
|
+
end
|
82
|
+
```
|
83
|
+
2. genrate the files
|
84
|
+
```bash
|
85
|
+
rubee generate get /apples
|
86
|
+
```
|
87
|
+
3. This will generate the following files
|
88
|
+
```bash
|
89
|
+
./app/controllers/apples_controller.rb # Controller with respective action
|
90
|
+
./app/models/apple.rb # Model that acts as ORM
|
91
|
+
./app/views/apples_index.erb # ERB view that is rendered by the controller right away
|
92
|
+
./db/create_items.rb # Database migration file needed for creating repsective table
|
93
|
+
```
|
94
|
+
4. Fill those files with the logic you need and run the server again!
|
95
|
+
|
96
|
+
## Model
|
97
|
+
Model in ruBee is just simple ruby object that can be serilalized in the view
|
98
|
+
in the way it required (ie json).
|
99
|
+
|
100
|
+
Here below is a simple example on how it can be used by rendering json from in memory object
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
#ApplesController
|
104
|
+
|
105
|
+
def show
|
106
|
+
# in memory example
|
107
|
+
apples = [Apple.new(colour: 'red', weight: '1lb'), Apple.new(colour: 'green', weight: '1lb')]
|
108
|
+
apple = apples.find { |apple| apple.colour = params[:colour] }
|
109
|
+
|
110
|
+
response_with object: apple, type: :json
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
Just make sure Serializable module included in the target class.
|
115
|
+
```ruby
|
116
|
+
class Apple
|
117
|
+
include Serializable
|
118
|
+
attr_accessor :id, :colour, :weight
|
119
|
+
end
|
120
|
+
```
|
121
|
+
However, you can simply turn it to ORM object by extending database class.
|
122
|
+
|
123
|
+
```Ruby
|
124
|
+
class Apple < Rubee::SequelObject
|
125
|
+
attr_accessor :id, :colour, :weight
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
So in the controller you would need to query your target object now.
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
#ApplesController
|
133
|
+
|
134
|
+
def show
|
135
|
+
apple = Apple.where(colour: params[:colour])&.last
|
136
|
+
|
137
|
+
if apple
|
138
|
+
response_with object: apple, type: :json
|
139
|
+
else
|
140
|
+
response_with object: { error: "apple with colour #{params[:colour]} not found" }, status: 422, type: :json
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
## Views
|
146
|
+
View in ruBee is just a plain html/erb file that can be rendered from the controller.
|
147
|
+
|
148
|
+
## Object hooks
|
149
|
+
|
150
|
+
In ruBee by extending Hookable module any Ruby object can be charged with hooks (logic),
|
151
|
+
that can be executed before, after and around a specific method execution.
|
152
|
+
|
153
|
+
Here below a controller example. However it can be used in any Ruby object, like Model etc.
|
154
|
+
```ruby
|
155
|
+
# base conrteoller is hopokable by Default
|
156
|
+
class ApplesController < Rubee::BaseController
|
157
|
+
before :index, :print_hello # you can useinstance method as a handler
|
158
|
+
after :index, -> { puts "after index" }, if: -> { true } # or you can use lambda
|
159
|
+
after :index, -> { puts "after index2" }, unless: -> { false } # if, unless guards may accept method or lambda
|
160
|
+
around :index, :log
|
161
|
+
|
162
|
+
def index
|
163
|
+
response_with object: { test: "hooks" }
|
164
|
+
end
|
165
|
+
|
166
|
+
def print_hello
|
167
|
+
puts "hello!"
|
168
|
+
end
|
169
|
+
|
170
|
+
def log
|
171
|
+
puts "before log aroud"
|
172
|
+
res = yield
|
173
|
+
puts "after log around"
|
174
|
+
res
|
175
|
+
end
|
176
|
+
...
|
177
|
+
end
|
178
|
+
```
|
179
|
+
Then, in the server logs we could see next execution stack
|
180
|
+
|
181
|
+
```bash
|
182
|
+
before log aroud
|
183
|
+
hello!
|
184
|
+
after index
|
185
|
+
after index2
|
186
|
+
after log around
|
187
|
+
127.0.0.1 - - [17/Feb/2025:11:42:14 -0500] "GET /apples HTTP/1.1" 401 - 0.0359
|
188
|
+
```
|
189
|
+
|
190
|
+
## JWT based authentification
|
191
|
+
Charge you rpoject with token based authentification system and customize it for your needs.
|
192
|
+
include AuthTokenable module to your controller and authentificate any action you need.
|
193
|
+
|
194
|
+
Make sure you have initiated User model which is a part of the logic.
|
195
|
+
```bash
|
196
|
+
rubee db run:create_users
|
197
|
+
```
|
198
|
+
This will create table users and initiate first user with demo credentials.
|
199
|
+
email: "ok@ok.com", password: "password"
|
200
|
+
Feel free to customize it in the /db/create_users.rb file before running migration.
|
201
|
+
|
202
|
+
Then in the controller you can include the AuthTokenable module and use its methods:
|
203
|
+
```ruby
|
204
|
+
class UsersController < Rubee::BaseController
|
205
|
+
include AuthTokenable
|
206
|
+
# List methods you want to restrict
|
207
|
+
auth_methods :index # unless the user is authentificated it will return unauthentificated
|
208
|
+
|
209
|
+
# GET /users/login (login form page)
|
210
|
+
def edit
|
211
|
+
response_with
|
212
|
+
end
|
213
|
+
|
214
|
+
# POST /users/login (login logic)
|
215
|
+
def login
|
216
|
+
if authentificate! # AuthTokenable method that init @token_header
|
217
|
+
# Redirect to restricted area, make sure headers: @token_header is passed
|
218
|
+
response_with type: :redirect, to: "/users", headers: @token_header
|
219
|
+
else
|
220
|
+
@error = "Wrong email or password"
|
221
|
+
response_with render_view: "users_edit"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# POST /usres/logout (logout logic)
|
226
|
+
def logout
|
227
|
+
unauthentificate! # AuthTokenable method aimed to handle logout action.
|
228
|
+
# Make sure @zeroed_token_header is passed within headers options
|
229
|
+
response_with type: :redirect, to: "/users/login", headers: @zeroed_token_header
|
230
|
+
end
|
231
|
+
|
232
|
+
# GET /users (restricted endpoint)
|
233
|
+
def index
|
234
|
+
response_with object: User.all, type: :json
|
235
|
+
end
|
236
|
+
end
|
237
|
+
```
|
238
|
+
|
239
|
+
## Rubee commands
|
240
|
+
```bash
|
241
|
+
rubee start # start the server
|
242
|
+
rubee start_dev # start the server in dev mode, which restart server on changes
|
243
|
+
rubee stop # stop the server
|
244
|
+
rubee restart # restart the server
|
245
|
+
```
|
246
|
+
|
247
|
+
## Generate commands
|
248
|
+
```bash
|
249
|
+
rubee generate get /apples # generate controller view, model and migration if set in the routes
|
250
|
+
```
|
251
|
+
|
252
|
+
## Migraiton commands
|
253
|
+
```bash
|
254
|
+
rubee db run:create_apples # where create_apples is the name of the migration file, located in /db folder
|
255
|
+
rubee db structure # generate migration file for the database structure
|
256
|
+
```
|
257
|
+
|
258
|
+
## Rubee console
|
259
|
+
```bash
|
260
|
+
rubee console # start the console
|
261
|
+
```
|
262
|
+
|
263
|
+
## Testing
|
264
|
+
```bash
|
265
|
+
rubee test # run all tests
|
266
|
+
rubee test auth_tokenable_test.rb # run specific tests
|
267
|
+
```
|
268
|
+
If you want to run any ruBee command within a specific ENV make sure you added it before a command.
|
269
|
+
For instance if you want to run console in test environment you need to run the following command
|
270
|
+
|
271
|
+
```bash
|
272
|
+
RACK_ENV=test rubee console
|
273
|
+
```
|
274
|
+
|
275
|
+
## Background jobs
|
276
|
+
Set your background job engine with ease!
|
277
|
+
|
278
|
+
### Sidekiq engine
|
279
|
+
1. Add sidekiq to your Gemfile
|
280
|
+
```bash
|
281
|
+
gem 'sidekiq'
|
282
|
+
```
|
283
|
+
2. Configure adapter for desired env
|
284
|
+
```ruby
|
285
|
+
# config/base_configuration.rb
|
286
|
+
|
287
|
+
Rubee::Configuration.setup(env=:development) do |config|
|
288
|
+
config.database_url = { url: "sqlite://db/development.db", env: }
|
289
|
+
config.async_adapter = { async_adapter: SidekiqAsync, env: }
|
290
|
+
end
|
291
|
+
```
|
292
|
+
3. Bundle up
|
293
|
+
```bash
|
294
|
+
bundle install
|
295
|
+
```
|
296
|
+
4. Make sure redis is installed and running
|
297
|
+
```bash
|
298
|
+
redis-server
|
299
|
+
```
|
300
|
+
5. Add sidekiq configuration file
|
301
|
+
```bash
|
302
|
+
# config/sidekiq.yml
|
303
|
+
|
304
|
+
development:
|
305
|
+
redis: redis://localhost:6379/0
|
306
|
+
concurrency: 5
|
307
|
+
queues:
|
308
|
+
default:
|
309
|
+
low:
|
310
|
+
high:
|
311
|
+
```
|
312
|
+
6. Create sidekiq worker
|
313
|
+
```ruby
|
314
|
+
# app/async/test_async_runner.rb
|
315
|
+
require_relative 'extensions/asyncable' unless defined? Asyncable
|
316
|
+
|
317
|
+
class TestAsyncRunnner
|
318
|
+
include Rubee::Asyncable
|
319
|
+
include Sidekiq::Worker
|
320
|
+
|
321
|
+
sidekiq_options queue: :default
|
322
|
+
|
323
|
+
def perform(options)
|
324
|
+
User.create(email: options['email'], password: options['password'])
|
325
|
+
end
|
326
|
+
end
|
327
|
+
```
|
328
|
+
7. Use it in the code base
|
329
|
+
```ruby
|
330
|
+
TestAsyncRunnner.new.perform_async(options: {"email"=> "new@new.com", "password"=> "123"})
|
331
|
+
```
|
332
|
+
### Default engine is ThreadAsync
|
333
|
+
However it is not yet recommended for production. Use it with cautions!
|
334
|
+
1. Do not define any adapter in the /config/base_configuration.rb file, so default ThreadAsync will be taken.
|
335
|
+
2. Just create a worker and process it.
|
336
|
+
```ruby
|
337
|
+
# test_async_runner.rb
|
338
|
+
class TestAsyncRunnner
|
339
|
+
include Rubee::Asyncable
|
340
|
+
|
341
|
+
def perform(options)
|
342
|
+
User.create(email: options['email'], password: options['password'])
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
TestAsyncRunnner.new.perform_async(options: {"email"=> "new@new.com", "password"=> "123"})
|
347
|
+
```
|
348
|
+
|
349
|
+
## TODOs
|
350
|
+
- [x] Token authorization API
|
351
|
+
- [ ] Document authorization API
|
352
|
+
- [ ] Add test coverage
|
353
|
+
- [ ] Fix bugs
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ru.Bee
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Oleg Saltykov
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-03-16 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: bundler
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '2.1'
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.1.4
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '2.1'
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 2.1.4
|
32
|
+
description: Application web server written on Ruby
|
33
|
+
email:
|
34
|
+
- oleg.saltykov@gmail.com
|
35
|
+
executables:
|
36
|
+
- rubee
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- LICENSE
|
41
|
+
- bin/rubee
|
42
|
+
- lib/Dockerfile
|
43
|
+
- lib/app/controllers/welcome_controller.rb
|
44
|
+
- lib/app/models/user.rb
|
45
|
+
- lib/app/views/welcome_show.erb
|
46
|
+
- lib/config.ru
|
47
|
+
- lib/config/base_configuration.rb
|
48
|
+
- lib/config/routes.rb
|
49
|
+
- lib/db/create_users.rb
|
50
|
+
- lib/db/structure.rb
|
51
|
+
- lib/db/test.db
|
52
|
+
- lib/images/rubee.svg
|
53
|
+
- lib/inits/print_colors.rb
|
54
|
+
- lib/rubee.rb
|
55
|
+
- lib/rubee/async/asyncable.rb
|
56
|
+
- lib/rubee/async/sidekiq_async.rb
|
57
|
+
- lib/rubee/async/thread_async.rb
|
58
|
+
- lib/rubee/async/thread_pool.rb
|
59
|
+
- lib/rubee/controllers/base_controller.rb
|
60
|
+
- lib/rubee/controllers/extensions/auth_tokenable.rb
|
61
|
+
- lib/rubee/controllers/extensions/middlewarable.rb
|
62
|
+
- lib/rubee/controllers/middlewares/auth_token_middleware.rb
|
63
|
+
- lib/rubee/extensions/hookable.rb
|
64
|
+
- lib/rubee/extensions/serializable.rb
|
65
|
+
- lib/rubee/models/database_object.rb
|
66
|
+
- lib/rubee/models/sequel_object.rb
|
67
|
+
- lib/rubee/tests/auth_tokenable_test.rb
|
68
|
+
- lib/rubee/tests/rubeeapp_test.rb
|
69
|
+
- lib/rubee/tests/test_helper.rb
|
70
|
+
- lib/rubee/tests/user_model_test.rb
|
71
|
+
- lib/version.rb
|
72
|
+
- readme.md
|
73
|
+
homepage: https://github.com/nucleom42/rubee
|
74
|
+
licenses:
|
75
|
+
- MIT
|
76
|
+
metadata: {}
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 3.2.1
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubygems_version: 3.6.6
|
92
|
+
specification_version: 4
|
93
|
+
summary: Fast and lightweight Ruby application server designed for minimalism and
|
94
|
+
flexibility
|
95
|
+
test_files: []
|