rsodx 0.0.1 → 0.0.3
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 +4 -4
- data/README.md +219 -55
- data/bin/console +6 -4
- data/bin/rsodx +3 -6
- data/lib/rsodx/action.rb +63 -0
- data/lib/rsodx/boot.rb +2 -1
- data/lib/rsodx/cli/cli.rb +56 -0
- data/lib/rsodx/cli/commands/generator.rb +60 -0
- data/lib/rsodx/cli/commands/generators/action.rb +13 -0
- data/lib/rsodx/cli/commands/generators/controller.rb +12 -0
- data/lib/rsodx/cli/commands/generators/migration.rb +52 -0
- data/lib/rsodx/cli/commands/generators/presenter.rb +11 -0
- data/lib/rsodx/cli/commands/generators/serializer.rb +11 -0
- data/lib/rsodx/cli/commands/scaffold.rb +63 -0
- data/lib/rsodx/cli/commands/scaffold_common.rb +107 -0
- data/lib/rsodx/cli/commands/server.rb +27 -0
- data/lib/rsodx/constants.rb +16 -0
- data/lib/rsodx/controller.rb +4 -0
- data/lib/rsodx/delegate.rb +16 -0
- data/lib/rsodx/error.rb +1 -3
- data/lib/rsodx/headers.rb +31 -0
- data/lib/rsodx/presenter.rb +19 -0
- data/lib/rsodx/request.rb +39 -0
- data/lib/rsodx/router_dsl.rb +8 -18
- data/lib/rsodx/serializer.rb +24 -0
- data/lib/rsodx/{interactor.rb → service.rb} +5 -2
- data/lib/rsodx/tasks.rb +0 -5
- data/lib/rsodx/version.rb +1 -1
- data/lib/rsodx.rb +12 -2
- metadata +43 -18
- data/lib/rsodx/cli/generate.rb +0 -17
- data/lib/rsodx/cli/generate_interactor.rb +0 -34
- data/lib/rsodx/cli/generate_migration.rb +0 -43
- data/lib/rsodx/cli/handler.rb +0 -26
- data/lib/rsodx/cli/scaffold.rb +0 -133
- data/lib/rsodx/cli/server.rb +0 -12
- data/lib/rsodx/interactors/healthcheck.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74be3af36e2f6319995f69ec786e1067923306f658d57147902cbaca1e285387
|
4
|
+
data.tar.gz: 8434da27ab813e8b757f4d5a3c6acc71cf9b9522987aea52b119c97aa8dcfda6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40244cd860d2e0e3f9010a2abca202c3c4f87720b2f99122071c240330e9d54ad82398c0f78fef94388ed6336dbdd162c0956bb24ba847c5270966488539b21a
|
7
|
+
data.tar.gz: 72f2e95d4a9ed42bbe82f3c013471a9b3aa4789568013dcb038edf9e514249e2b06591cfa99be7c14408c1a6f7b5bded9fa99118cfbaf430157bc37568d990d3
|
data/README.md
CHANGED
@@ -1,21 +1,37 @@
|
|
1
1
|
# Rsodx
|
2
2
|
|
3
|
-
>
|
3
|
+
<p align="left">
|
4
|
+
<img src="docs/banner.jpg" width="300px" alt="Rsodx banner">
|
5
|
+
</p>
|
6
|
+
|
7
|
+
`rsodx` is a minimal, modular framework for building fast and maintainable Ruby microservices.
|
8
|
+
Inspired by the best of Rails, Sinatra, and Sequel — it gives you just enough structure to scale, without the overhead.
|
9
|
+
|
10
|
+
No magic. Just clean code and powerful tools.
|
11
|
+
|
12
|
+
|
13
|
+
```bash
|
14
|
+
$ rsodx new my_rail_company
|
15
|
+
🛤️ Initializing Transport Empire...
|
16
|
+
📦 Creating folders...
|
17
|
+
✅ Done! Start building your microservice railway!
|
18
|
+
```
|
4
19
|
|
5
|
-
Rsodx is a lightweight, modular microservice framework for Ruby — designed to be fast, clean, and scalable. It provides a minimal architecture inspired by Rails, Sinatra, and Sequel, allowing you to focus on writing business logic without boilerplate.
|
6
20
|
|
7
21
|
---
|
8
22
|
|
9
23
|
## 🧠 Philosophy
|
10
24
|
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
-
|
25
|
+
- **Micro-first** — focus on small, single-purpose services
|
26
|
+
- **Explicit over implicit** — no hidden behavior, no global state
|
27
|
+
- **Modular by design** — include only what you need
|
28
|
+
- **Ruby-native** — use familiar patterns, no learning curve
|
29
|
+
- **Production-oriented** — simple to develop, easy to deploy
|
15
30
|
|
16
31
|
---
|
17
32
|
|
18
|
-
|
33
|
+
> ✅ `rsodx` includes routing, interactors, validation, and service structure —
|
34
|
+
all wrapped into a fast and lightweight toolkit made for modern Ruby apps.
|
19
35
|
|
20
36
|
---
|
21
37
|
|
@@ -39,84 +55,195 @@ bundle add rsodx
|
|
39
55
|
gem install rsodx
|
40
56
|
```
|
41
57
|
|
42
|
-
|
58
|
+
---
|
59
|
+
|
60
|
+
## 🚀 CLI Commands
|
61
|
+
|
62
|
+
`rsodx` ships with a powerful and lightweight CLI tool for generating services and scaffolding applications.
|
63
|
+
|
64
|
+
You can run CLI commands via:
|
65
|
+
|
66
|
+
```bash
|
67
|
+
bin/rsodx [command] [args]
|
68
|
+
```
|
43
69
|
|
44
70
|
---
|
45
71
|
|
72
|
+
## 🔧 Generators
|
46
73
|
|
47
|
-
|
74
|
+
Generate various application components using simple commands:
|
48
75
|
|
49
|
-
```
|
50
|
-
|
76
|
+
```bash
|
77
|
+
bin/rsodx generate controller v1/users/index
|
78
|
+
bin/rsodx generate presenter v1/users/index
|
79
|
+
bin/rsodx generate serializer v1/users/index
|
80
|
+
```
|
81
|
+
|
82
|
+
Or using aliases:
|
83
|
+
|
84
|
+
```bash
|
85
|
+
bin/rsodx g controller v1/users/index
|
86
|
+
```
|
87
|
+
|
88
|
+
To generate **all three** at once (controller, presenter, serializer):
|
89
|
+
|
90
|
+
```bash
|
91
|
+
bin/rsodx g action v1/users/index
|
92
|
+
```
|
93
|
+
|
94
|
+
This creates:
|
95
|
+
|
96
|
+
- `app/controllers/v1/users/index_controller.rb`
|
97
|
+
- `app/presenters/v1/users/index_presenter.rb`
|
98
|
+
- `app/serializers/v1/users/index_serializer.rb`
|
99
|
+
|
100
|
+
---
|
101
|
+
|
102
|
+
## 🛠 Scaffold New App
|
103
|
+
|
104
|
+
Create a full Rsodx project with:
|
105
|
+
|
106
|
+
```bash
|
107
|
+
bin/rsodx new my_app
|
108
|
+
```
|
109
|
+
|
110
|
+
Or using alias:
|
111
|
+
|
112
|
+
```bash
|
113
|
+
bin/rsodx n my_app
|
114
|
+
```
|
115
|
+
|
116
|
+
This will create a new directory `my_app` with:
|
117
|
+
|
118
|
+
- `Gemfile`, `.env`, `.ruby-version`
|
119
|
+
- `config.ru`, `Rakefile`, environment loader
|
120
|
+
- `app/` structure (`controllers`, `services`, etc.)
|
121
|
+
- `bin/console` and `bin/rsodx` CLI entrypoints
|
122
|
+
|
123
|
+
It will be immediately runnable:
|
124
|
+
|
125
|
+
```bash
|
126
|
+
cd my_app
|
127
|
+
bundle install
|
128
|
+
bin/rsodx server
|
129
|
+
```
|
130
|
+
|
131
|
+
---
|
132
|
+
|
133
|
+
## 🌐 Server Command
|
134
|
+
|
135
|
+
Run a local Rack-based Puma server:
|
136
|
+
|
137
|
+
```bash
|
138
|
+
bin/rsodx server
|
139
|
+
```
|
140
|
+
|
141
|
+
Available options:
|
142
|
+
|
143
|
+
- `--port=PORT` – default: `9292`
|
144
|
+
- `--env=ENV` – default: `development`
|
145
|
+
|
146
|
+
Example:
|
147
|
+
|
148
|
+
```bash
|
149
|
+
bin/rsodx server --port=3000 --env=production
|
150
|
+
```
|
151
|
+
|
152
|
+
### 🔍 How it works
|
153
|
+
|
154
|
+
This command launches Puma via `rackup`:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
pid = spawn("bundle exec rackup --port=#{port} --host=0.0.0.0")
|
158
|
+
Process.wait(pid)
|
159
|
+
```
|
160
|
+
|
161
|
+
It ensures that your `config.ru` is used correctly and delegates the full startup to Rack.
|
162
|
+
|
163
|
+
---
|
164
|
+
|
165
|
+
## ✅ Command Summary
|
166
|
+
|
167
|
+
| Command | Description |
|
168
|
+
|--------|-------------|
|
169
|
+
| `rsodx new NAME` | Scaffold a new Rsodx project |
|
170
|
+
| `rsodx server` | Run the Rack/Puma development server |
|
171
|
+
| `rsodx generate controller PATH` | Generate a controller |
|
172
|
+
| `rsodx generate presenter PATH` | Generate a presenter |
|
173
|
+
| `rsodx generate serializer PATH` | Generate a serializer |
|
174
|
+
| `rsodx generate action PATH` | Generate controller + presenter + serializer |
|
175
|
+
| Aliases: `g`, `n`, `s` | All commands support short versions |
|
176
|
+
|
177
|
+
---
|
178
|
+
|
179
|
+
## 📁 Folder Structure (Generated App)
|
180
|
+
|
181
|
+
```
|
182
|
+
my_app/
|
51
183
|
├── app/
|
52
|
-
│ ├──
|
53
|
-
│ ├── interactors/
|
54
|
-
│ ├── models/
|
184
|
+
│ ├── controllers/
|
55
185
|
│ ├── presenters/
|
56
186
|
│ ├── serializers/
|
57
|
-
│ ├──
|
58
|
-
|
187
|
+
│ ├── services/
|
188
|
+
├── bin/
|
189
|
+
│ ├── console
|
190
|
+
│ └── rsodx
|
59
191
|
├── config/
|
60
192
|
│ ├── environment.rb
|
61
|
-
│
|
62
|
-
│ └── initializers/
|
193
|
+
│ └── environments/
|
63
194
|
├── db/
|
64
195
|
│ └── migrations/
|
65
|
-
├──
|
66
|
-
│ └── console
|
67
|
-
├── .env
|
196
|
+
├── spec/
|
68
197
|
├── config.ru
|
198
|
+
├── .env
|
69
199
|
├── Gemfile
|
70
200
|
└── Rakefile
|
71
201
|
```
|
72
202
|
|
73
203
|
---
|
74
204
|
|
75
|
-
##
|
205
|
+
## 🗄️ PostgreSQL Setup
|
76
206
|
|
77
|
-
|
207
|
+
Your application connects to PostgreSQL using the `DATABASE_URL` defined in `.env`:
|
78
208
|
|
79
|
-
```
|
80
|
-
rsodx
|
209
|
+
```
|
210
|
+
DATABASE_URL=postgres://rsodx:paSs4321@localhost:5432/rsodx_development
|
81
211
|
```
|
82
212
|
|
83
|
-
|
213
|
+
### 📌 To create this database manually:
|
84
214
|
|
85
|
-
|
215
|
+
1. Open your terminal and run the PostgreSQL client:
|
86
216
|
|
87
217
|
```bash
|
88
|
-
|
218
|
+
psql -U postgres
|
89
219
|
```
|
90
|
-
Creates `app/interactors/create_user.rb`:
|
91
220
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
221
|
+
2. Then, execute the following SQL commands:
|
222
|
+
|
223
|
+
```sql
|
224
|
+
-- Create the user
|
225
|
+
CREATE USER rsodx WITH PASSWORD 'paSs4321';
|
226
|
+
|
227
|
+
-- Create the database
|
228
|
+
CREATE DATABASE rsodx_development;
|
229
|
+
|
230
|
+
-- Grant privileges
|
231
|
+
GRANT ALL PRIVILEGES ON DATABASE rsodx_development TO rsodx;
|
98
232
|
```
|
99
233
|
|
234
|
+
> 📍 If your system uses a different PostgreSQL superuser, adjust `-U postgres` accordingly.
|
235
|
+
|
100
236
|
---
|
101
237
|
|
102
|
-
|
238
|
+
## ✅ Quick Check
|
239
|
+
|
240
|
+
You can test the connection:
|
103
241
|
|
104
242
|
```bash
|
105
|
-
|
243
|
+
psql postgres://rsodx:paSs4321@localhost:5432/rsodx_development
|
106
244
|
```
|
107
|
-
Creates `db/migrations/20240413_create_users.rb`:
|
108
245
|
|
109
|
-
|
110
|
-
Sequel.migration do
|
111
|
-
change do
|
112
|
-
# create_table :users do
|
113
|
-
# primary_key :id
|
114
|
-
# String :email
|
115
|
-
# DateTime :created_at
|
116
|
-
# end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
```
|
246
|
+
If it connects successfully, your database is ready for development!
|
120
247
|
|
121
248
|
---
|
122
249
|
|
@@ -125,7 +252,7 @@ end
|
|
125
252
|
```ruby
|
126
253
|
class Router < Rsodx::Router
|
127
254
|
namespace "/v1" do
|
128
|
-
post "/users",
|
255
|
+
post "/users", V1::Users::Create
|
129
256
|
end
|
130
257
|
end
|
131
258
|
```
|
@@ -168,11 +295,48 @@ CreateUser.call(params: {...})
|
|
168
295
|
|
169
296
|
---
|
170
297
|
|
171
|
-
##
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
298
|
+
## 🛣️ Roadmap
|
299
|
+
|
300
|
+
Planned features and improvements for upcoming versions of `rsodx`.
|
301
|
+
|
302
|
+
### 🔄 Inter-service Communication
|
303
|
+
|
304
|
+
- ✅ **Add RabbitMQ support** for event-driven microservices
|
305
|
+
- CLI: `rsodx g subscriber user/created`
|
306
|
+
- DSL: `on_event "user.created", with: HandleUserCreated`
|
307
|
+
|
308
|
+
### 🐳 Docker Support
|
309
|
+
|
310
|
+
- ✅ Dockerfile and docker-compose.yml templates
|
311
|
+
- PostgreSQL, RabbitMQ, App
|
312
|
+
|
313
|
+
### 📦 Generators & Tooling
|
314
|
+
|
315
|
+
- [ ] `rsodx g worker fetch_data`
|
316
|
+
- [ ] `rsodx g subscriber event_name`
|
317
|
+
- [ ] CLI flags: `--dry-run`, `--force`, `--skip`
|
318
|
+
- [ ] Generate test stubs with each component
|
319
|
+
|
320
|
+
### 🌐 Web Server Improvements
|
321
|
+
|
322
|
+
- [ ] Auto-discovery of config.ru or App class
|
323
|
+
- [ ] `rsodx server --daemon`, `--log`
|
324
|
+
|
325
|
+
### 📚 Documentation & API
|
326
|
+
|
327
|
+
- [ ] Auto-generate OpenAPI / Swagger docs from declared routes and schemas
|
328
|
+
- [ ] DRY validation + schema → Swagger with types and examples
|
329
|
+
- [ ] `rsodx g docs` or `rsodx docs generate`
|
330
|
+
|
331
|
+
### 🛠 Developer Experience
|
332
|
+
|
333
|
+
- [ ] `rsodx console` (IRB + app preload)
|
334
|
+
- [ ] `rsodx doctor` for environment diagnostics
|
335
|
+
- [ ] Starter project templates (`--template=api`, `--template=evented`)
|
336
|
+
|
337
|
+
---
|
338
|
+
|
339
|
+
If you’d like to contribute or suggest new features — feel free to open an issue or PR. Let’s make `rsodx` fast, lean and production-ready together! ❤️
|
176
340
|
|
177
341
|
---
|
178
342
|
|
data/bin/console
CHANGED
@@ -3,10 +3,12 @@
|
|
3
3
|
|
4
4
|
require "bundler/setup"
|
5
5
|
require "rsodx"
|
6
|
-
|
6
|
+
puts Rsodx::LOGO
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
def reload!
|
9
|
+
puts "♻️ Reloading lib/rsodx..."
|
10
|
+
load File.expand_path("../lib/rsodx.rb", __dir__)
|
11
|
+
end
|
10
12
|
|
11
13
|
require "irb"
|
12
|
-
IRB.start
|
14
|
+
IRB.start
|
data/bin/rsodx
CHANGED
data/lib/rsodx/action.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Rsodx
|
2
|
+
class Action < Rsodx::Service
|
3
|
+
delegate :request, :options, :handler_class, to: :context
|
4
|
+
|
5
|
+
before do
|
6
|
+
context.options ||= {}
|
7
|
+
raise "Missing handler_class in context" unless context.handler_class
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
run_handler
|
12
|
+
rescue StandardError => e
|
13
|
+
handle_exception(e)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def run_handler
|
19
|
+
result = context.handler_class.call(
|
20
|
+
options.merge(request: request, params: request.params)
|
21
|
+
)
|
22
|
+
|
23
|
+
return error_result(result) if result.failure?
|
24
|
+
|
25
|
+
serializer = resolve_serializer
|
26
|
+
serialized = serializer.call(object: result.object)
|
27
|
+
return error_result(serialized) if serialized.failure?
|
28
|
+
|
29
|
+
if presenter_class
|
30
|
+
context.json_response = presenter_class.new(serialized.dto).call
|
31
|
+
elsif request.request_method == 'POST'
|
32
|
+
context.code = 201
|
33
|
+
else
|
34
|
+
context.code = 204
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def resolve_serializer
|
39
|
+
from_handler_with_suffix("Serializer") || AppSerializer
|
40
|
+
end
|
41
|
+
|
42
|
+
def presenter_class
|
43
|
+
from_handler_with_suffix("Presenter")
|
44
|
+
end
|
45
|
+
|
46
|
+
def from_handler_with_suffix(suffix)
|
47
|
+
klass_name = handler_class.name.sub(/Controller$/, suffix)
|
48
|
+
Object.const_get(klass_name)
|
49
|
+
rescue NameError
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def error_result(result)
|
54
|
+
code = result.error_code || 500
|
55
|
+
error = result.error || 'Unknown error'
|
56
|
+
halt(code, error)
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_exception(e)
|
60
|
+
halt(500, e.message)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/rsodx/boot.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Rsodx
|
2
2
|
module Boot
|
3
3
|
def self.load_app_structure(app_root)
|
4
|
-
%w[models
|
4
|
+
%w[models controllers services serializers presenters].each do |folder|
|
5
5
|
path = File.join(app_root, "app", folder)
|
6
6
|
$LOAD_PATH.unshift(path) if Dir.exist?(path)
|
7
|
+
Dir["#{path}/*.rb"].sort.each { |file| require file }
|
7
8
|
Dir["#{path}/**/*.rb"].sort.each { |file| require file }
|
8
9
|
end
|
9
10
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "dry/cli"
|
2
|
+
|
3
|
+
module Rsodx::Cli
|
4
|
+
module Commands
|
5
|
+
end
|
6
|
+
module Commands::Generators
|
7
|
+
end
|
8
|
+
|
9
|
+
extend Dry::CLI::Registry
|
10
|
+
|
11
|
+
def self.setup!
|
12
|
+
register_commands_with_alias(
|
13
|
+
group: "",
|
14
|
+
alias_prefix: "",
|
15
|
+
commands: {
|
16
|
+
"new" => ::Rsodx::Cli::Commands::Scaffold,
|
17
|
+
"n" => ::Rsodx::Cli::Commands::Scaffold
|
18
|
+
}
|
19
|
+
)
|
20
|
+
|
21
|
+
register_commands_with_alias(
|
22
|
+
group: "generate",
|
23
|
+
alias_prefix: "g",
|
24
|
+
commands: {
|
25
|
+
"migration" => ::Rsodx::Cli::Commands::Generators::Migration,
|
26
|
+
"controller" => ::Rsodx::Cli::Commands::Generators::Controller,
|
27
|
+
"presenter" => ::Rsodx::Cli::Commands::Generators::Presenter,
|
28
|
+
"serializer" => ::Rsodx::Cli::Commands::Generators::Serializer,
|
29
|
+
"action" => ::Rsodx::Cli::Commands::Generators::Action
|
30
|
+
}
|
31
|
+
)
|
32
|
+
|
33
|
+
register_commands_with_alias(
|
34
|
+
group: "",
|
35
|
+
alias_prefix: "",
|
36
|
+
commands: {
|
37
|
+
"server" => ::Rsodx::Cli::Commands::Server,
|
38
|
+
"s" => ::Rsodx::Cli::Commands::Server
|
39
|
+
}
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.register_commands_with_alias(group:, alias_prefix:, commands:)
|
44
|
+
commands.each do |name, klass|
|
45
|
+
full_name = group && !group.empty? ? "#{group} #{name}" : name
|
46
|
+
alias_name = alias_prefix && !alias_prefix.empty? ? "#{alias_prefix} #{name}" : name
|
47
|
+
|
48
|
+
register full_name.strip, klass
|
49
|
+
register alias_name.strip, klass
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module Rsodx
|
55
|
+
CLI = Dry::CLI.new(::Rsodx::Cli)
|
56
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module Rsodx::Cli
|
4
|
+
class Generator
|
5
|
+
ROOT_MAP = {
|
6
|
+
controller: "app/controllers",
|
7
|
+
presenter: "app/presenters",
|
8
|
+
serializer: "app/serializers"
|
9
|
+
}
|
10
|
+
|
11
|
+
SUFFIX_MAP = {
|
12
|
+
controller: "Controller",
|
13
|
+
presenter: "Presenter",
|
14
|
+
serializer: "Serializer"
|
15
|
+
}
|
16
|
+
|
17
|
+
def self.generate(type, args)
|
18
|
+
path = args[:path]
|
19
|
+
type = type.to_sym
|
20
|
+
raise "Unknown type: #{type}" unless ROOT_MAP.key?(type)
|
21
|
+
|
22
|
+
segments = path.split("/")
|
23
|
+
file_name = segments.pop
|
24
|
+
file_path = "#{ROOT_MAP[type]}/#{segments.join("/")}/#{file_name}_#{type}.rb"
|
25
|
+
namespace = segments.map { |seg| camelize(seg) }.join("::")
|
26
|
+
class_name = "#{camelize(file_name)}#{SUFFIX_MAP[type]}"
|
27
|
+
full_class = [namespace, class_name].reject(&:empty?).join("::")
|
28
|
+
|
29
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
30
|
+
File.write(file_path, template(full_class, type))
|
31
|
+
|
32
|
+
puts "✅ Created #{file_path}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.camelize(str)
|
36
|
+
str.split(/[_-]/).map { |part| part.capitalize }.join
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.template(full_class, type)
|
40
|
+
base_class = {
|
41
|
+
controller: "AppController",
|
42
|
+
presenter: "AppPresenter",
|
43
|
+
serializer: "AppSerializer"
|
44
|
+
}[type]
|
45
|
+
|
46
|
+
namespace = full_class.split("::")[0..-2].join("::")
|
47
|
+
class_name = full_class.split("::").last
|
48
|
+
|
49
|
+
<<~RUBY
|
50
|
+
module #{namespace}
|
51
|
+
class #{class_name} < #{base_class}
|
52
|
+
def call
|
53
|
+
# TODO: implement
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
RUBY
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Rsodx::Cli::Commands::Generators
|
2
|
+
class Action < Dry::CLI::Command
|
3
|
+
desc "Generate full action (controller + serializer + presenter)"
|
4
|
+
|
5
|
+
argument :path, desc: "Path to endpoint (e.g. v1/users/index)"
|
6
|
+
|
7
|
+
def call(args)
|
8
|
+
%i[controller serializer presenter].each do |type|
|
9
|
+
Rsodx::Cli::Generator.generate(type, args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Rsodx::Cli::Commands::Generators
|
2
|
+
class Controller < Dry::CLI::Command
|
3
|
+
desc "Generate a controller"
|
4
|
+
|
5
|
+
argument :path, desc: "Path to controller, e.g. v1/users/index"
|
6
|
+
|
7
|
+
def call(args)
|
8
|
+
Rsodx::Cli::Generator.generate(:controller, args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "time"
|
3
|
+
|
4
|
+
module Rsodx
|
5
|
+
module Cli
|
6
|
+
module Commands
|
7
|
+
module Generators
|
8
|
+
class Migration < Dry::CLI::Command
|
9
|
+
desc "Generate a Sequel migration"
|
10
|
+
|
11
|
+
argument :name, required: true, desc: "Name of the migration"
|
12
|
+
|
13
|
+
def call(name:)
|
14
|
+
timestamp = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
15
|
+
file_name = File.join("db/migrations", "#{timestamp}_#{snake_case(name)}.rb")
|
16
|
+
|
17
|
+
puts "📦 Creating migration: #{file_name}"
|
18
|
+
FileUtils.mkdir_p("db/migrations")
|
19
|
+
File.write(file_name, MIGRATION_TEMPLATE)
|
20
|
+
|
21
|
+
puts "✅ Done"
|
22
|
+
rescue => e
|
23
|
+
abort "❌ Failed to generate migration: #{e.message}"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
MIGRATION_TEMPLATE = <<~MIGRATION_TEMPLATE.freeze
|
29
|
+
Sequel.migration do
|
30
|
+
change do
|
31
|
+
# create_table(:example) do
|
32
|
+
# primary_key :id
|
33
|
+
# String :name
|
34
|
+
# DateTime :created_at
|
35
|
+
# DateTime :updated_at
|
36
|
+
# end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
MIGRATION_TEMPLATE
|
40
|
+
|
41
|
+
def snake_case(str)
|
42
|
+
str.gsub(/::/, '/')
|
43
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/,'\\1_\\2')
|
44
|
+
.gsub(/([a-z\\d])([A-Z])/,'\\1_\\2')
|
45
|
+
.tr("-", "_")
|
46
|
+
.downcase
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Rsodx::Cli::Commands::Generators
|
2
|
+
class Presenter < Dry::CLI::Command
|
3
|
+
desc "Generate presenter"
|
4
|
+
|
5
|
+
argument :path, desc: "Path to presenter (e.g. v1/users/index)"
|
6
|
+
|
7
|
+
def call(args)
|
8
|
+
Rsodx::Cli::Generator.generate(:presenter, args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Rsodx::Cli::Commands::Generators
|
2
|
+
class Serializer < Dry::CLI::Command
|
3
|
+
desc "Generate serializer"
|
4
|
+
|
5
|
+
argument :path, desc: "Path to serializer (e.g. v1/users/index)"
|
6
|
+
|
7
|
+
def call(args)
|
8
|
+
Rsodx::Cli::Generator.generate(:serializer, args)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|