stipa 0.2.2 → 0.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44e8a86e067f00d98d94e1ac514d0969f6e1d79cb6ff1daa2af9660bb81d0ea0
4
- data.tar.gz: 5fa375199a8fc3c5dd13e15e42c57b379edccfbf710d64cc58d75f06c8460abf
3
+ metadata.gz: 035d22e299975a792e6b72649c0160e6a9af69c1b50f5b529503e35e772f5cf6
4
+ data.tar.gz: df2d1f4bd439bb41f008e4468c19c0c9538f56ca820570e3afc46fce7b1f6bc0
5
5
  SHA512:
6
- metadata.gz: 42eda5ad003db0db62f75e87a4e4ee4de386bd1770a9aac217e539a88b19ae9e4b9d49f84f01c32bdb1d64d2f190fac66aacff800952f7b203a876f4755bdc4a
7
- data.tar.gz: e9ff02cd8fb6c8a10818304148de906c4011f010ab4f0bbba890acbd8406dbb49daac17feede3c9f9196a352b332e5361d09c97e0f2e1a9e94cf2608196982a3
6
+ metadata.gz: 23b23d3954f3801027e4c396334cab70e3d3091e0ba4a305f740374172a160d489c7ba91eab9a37274f326c0d616bb0caf0d10e619b4ce0cd2e6f82f215d64da
7
+ data.tar.gz: e858a068ada0a89e2a7fb256718679fb55a428c1fd3da570bad18618851f50a922baa4dc015a81ef21d7709952e4569d7741ce2356028536b9efc659fe8f2d9f
@@ -54,8 +54,7 @@ module Stipa
54
54
  Stipa::Database.connect!
55
55
 
56
56
  # Models must be loaded after the database connection is established.
57
- # If tables don't exist yet, run: rake db:migrate
58
- require_relative 'models/application_model' rescue warn "⚠ Run 'rake db:migrate' to set up the database."
57
+ require_relative 'models/application_model'
59
58
 
60
59
  app = Stipa::App.new
61
60
 
@@ -93,20 +92,68 @@ module Stipa
93
92
 
94
93
  private
95
94
 
95
+ # ── Success helpers ──────────────────────────────
96
+
96
97
  def json(data, status: 200)
97
98
  res.status = status
98
99
  res.json(data)
99
100
  end
100
101
 
101
- def not_found!(message = 'Not found')
102
- res.status = 404
103
- res.json(error: message)
104
- throw :halt
102
+ def created!(data = nil)
103
+ res.status = 201
104
+ data ? res.json(data) : res.tap { _1.body = '' }
105
+ end
106
+
107
+ def no_content!
108
+ res.status = 204
109
+ res.body = ''
110
+ end
111
+
112
+ # ── Redirection ──────────────────────────────────
113
+
114
+ def redirect_to(path, status: 302)
115
+ res.status = status
116
+ res['Location'] = path
117
+ res.body = ''
105
118
  end
106
119
 
107
- def unprocessable!(errors)
108
- res.status = 422
109
- res.json(errors: errors)
120
+ # ── Error helpers ────────────────────────────────
121
+
122
+ def bad_request!(message = 'Bad Request')
123
+ error(400, message)
124
+ end
125
+
126
+ def unauthorized!(message = 'Unauthorized')
127
+ error(401, message)
128
+ end
129
+
130
+ def forbidden!(message = 'Forbidden')
131
+ error(403, message)
132
+ end
133
+
134
+ def not_found!(message = 'Not Found')
135
+ error(404, message)
136
+ end
137
+
138
+ def conflict!(message = 'Conflict')
139
+ error(409, message)
140
+ end
141
+
142
+ def unprocessable_entity!(message = 'Unprocessable Entity')
143
+ error(422, message)
144
+ end
145
+
146
+ def too_many_requests!(message = 'Too Many Requests')
147
+ error(429, message)
148
+ end
149
+
150
+ def internal_server_error!(message = 'Internal Server Error')
151
+ error(500, message)
152
+ end
153
+
154
+ def error(status, message)
155
+ res.status = status
156
+ res.json(error: { message: message })
110
157
  throw :halt
111
158
  end
112
159
 
@@ -5,7 +5,7 @@ require 'pathname'
5
5
  module Stipa
6
6
  module Generators
7
7
  class Base
8
- GEM_JS = File.expand_path('../../js', __dir__)
8
+ GEM_JS = File.expand_path('../../js', __dir__)
9
9
  GEM_MEDIA = File.expand_path('../../../media', __dir__)
10
10
  GEM_ROOT = File.expand_path('../..', GEM_JS)
11
11
 
@@ -51,7 +51,7 @@ module Stipa
51
51
  system('git', 'commit', '-q', '-m', 'Initial commit')
52
52
  end
53
53
  say ' git initialized repository with initial commit'
54
- rescue => e
54
+ rescue StandardError => e
55
55
  say " warn git init failed: #{e.message}"
56
56
  end
57
57
 
@@ -150,7 +150,7 @@ module Stipa
150
150
  %w[get post put patch delete].each do |verb|
151
151
  define_method(verb) do |pattern, to:|
152
152
  klass, action = resolve(to)
153
- @app.public_send(verb, pattern) { |req, res| klass.new(req, res).public_send(action) }
153
+ @app.public_send(verb, pattern) { |req, res| catch(:halt) { klass.new(req, res).public_send(action) } }
154
154
  end
155
155
  end
156
156
  end
@@ -190,8 +190,18 @@ module Stipa
190
190
 
191
191
  require 'stipa/model'
192
192
 
193
- class ApplicationModel < Sequel::Model
194
- include Stipa::Model
193
+ # Include this in any Sequel::Model subclass to get
194
+ # timestamps, UUID, soft delete, and serialization.
195
+ #
196
+ # Usage:
197
+ # class Post < Sequel::Model
198
+ # include ApplicationModel
199
+ # end
200
+
201
+ module ApplicationModel
202
+ def self.included(base)
203
+ base.include Stipa::Model
204
+ end
195
205
  end
196
206
  RUBY
197
207
  end
@@ -217,7 +227,7 @@ module Stipa
217
227
  RUBY
218
228
  end
219
229
 
220
- def t_rakefile
230
+ def t_rakefile(config_path: 'config')
221
231
  <<~RUBY
222
232
  # frozen_string_literal: true
223
233
 
@@ -251,7 +261,7 @@ module Stipa
251
261
  task default: 'db:migrate'
252
262
 
253
263
  def load_config
254
- require_relative 'config/database'
264
+ require_relative '#{config_path}/database'
255
265
  Stipa::Database.connect!
256
266
  end
257
267
 
@@ -21,7 +21,7 @@ module Stipa
21
21
  end
22
22
 
23
23
  def post_generate
24
- copy_asset 'stipa-vue.js', from: GEM_JS
24
+ copy_asset 'stipa-vue.js', from: GEM_JS
25
25
  copy_asset 'logo.png', from: GEM_MEDIA
26
26
  copy_asset 'favicon.ico', from: GEM_MEDIA
27
27
  end
@@ -54,30 +54,30 @@ module Stipa
54
54
 
55
55
  def files
56
56
  {
57
- '.gitignore' => t_gitignore,
58
- 'Gemfile' => t_gemfile,
59
- 'Rakefile' => t_rakefile,
60
- 'package.json' => t_package_json,
61
- 'rollup.config.js' => t_rollup_config,
62
- 'tsconfig.json' => t_tsconfig,
63
- 'server.rb' => t_server,
64
- 'app/config/database.rb' => t_database_config,
65
- 'app/config/routes.rb' => t_routes(
57
+ '.gitignore' => t_gitignore,
58
+ 'Gemfile' => t_gemfile,
59
+ 'Rakefile' => t_rakefile(config_path: 'app/config'),
60
+ 'package.json' => t_package_json,
61
+ 'rollup.config.js' => t_rollup_config,
62
+ 'tsconfig.json' => t_tsconfig,
63
+ 'server.rb' => t_server,
64
+ 'app/config/database.rb' => t_database_config,
65
+ 'app/config/routes.rb' => t_routes(
66
66
  extra_requires: ['../controllers/home_controller', '../controllers/health_controller'],
67
- extra_routes: ["get '/', to: 'home#index'", "get '/api/health', to: 'health#show'"],
68
- method_override: true,
67
+ extra_routes: ["get '/', to: 'home#index'", "get '/api/health', to: 'health#show'"],
68
+ method_override: true
69
69
  ),
70
- 'app/controllers/application_controller.rb' => t_application_controller,
71
- 'app/controllers/home_controller.rb' => t_home_controller,
72
- 'app/controllers/health_controller.rb' => t_health_controller,
73
- 'app/models/application_model.rb' => t_application_model,
74
- 'db/migrate/001_create_posts.rb' => t_migration_create_posts,
75
- 'app/views/layouts/application.html.erb' => t_layout,
76
- 'app/views/home/index.html.erb' => t_home_index,
77
- 'public/app.css' => t_app_css,
78
- 'app/components/RequestCard.vue' => t_request_card_vue,
79
- 'app/main.ts' => t_main_ts,
80
- 'app/shims-vue.d.ts' => t_shims_vue,
70
+ 'app/controllers/application_controller.rb' => t_application_controller,
71
+ 'app/controllers/home_controller.rb' => t_home_controller,
72
+ 'app/controllers/health_controller.rb' => t_health_controller,
73
+ 'app/models/application_model.rb' => t_application_model,
74
+ 'db/migrate/001_create_posts.rb' => t_migration_create_posts,
75
+ 'app/views/layouts/application.html.erb' => t_layout,
76
+ 'app/views/home/index.html.erb' => t_home_index,
77
+ 'public/app.css' => t_app_css,
78
+ 'app/components/RequestCard.vue' => t_request_card_vue,
79
+ 'app/main.ts' => t_main_ts,
80
+ 'app/shims-vue.d.ts' => t_shims_vue
81
81
  }
82
82
  end
83
83
 
@@ -101,22 +101,22 @@ module Stipa
101
101
  private: true,
102
102
  type: 'module',
103
103
  scripts: {
104
- 'copy:vue' => 'cp node_modules/vue/dist/vue.esm-browser.prod.js public/vendor/vue.esm-browser.prod.js',
105
- build: 'npm run copy:vue && rollup -c',
106
- watch: 'rollup -c --watch',
107
- dev: 'npm run copy:vue && concurrently "STIPA_RELOAD=1 bundle exec ruby server.rb" "rollup -c --watch"',
108
- typecheck: 'vue-tsc --noEmit',
104
+ 'copy:vue' => 'cp node_modules/vue/dist/vue.esm-browser.prod.js public/vendor/vue.esm-browser.prod.js',
105
+ build: 'npm run copy:vue && rollup -c',
106
+ watch: 'rollup -c --watch',
107
+ dev: 'npm run copy:vue && concurrently "STIPA_RELOAD=1 bundle exec ruby server.rb" "rollup -c --watch"',
108
+ typecheck: 'vue-tsc --noEmit'
109
109
  },
110
110
  devDependencies: {
111
- 'concurrently' => '^8.0.0',
112
- 'rollup' => '^4.0.0',
113
- 'rollup-plugin-vue' => '^6.0.0',
111
+ 'concurrently' => '^8.0.0',
112
+ 'rollup' => '^4.0.0',
113
+ 'rollup-plugin-vue' => '^6.0.0',
114
114
  '@rollup/plugin-typescript' => '^11.0.0',
115
- '@vue/compiler-sfc' => '^3.4.0',
116
- 'typescript' => '^5.0.0',
117
- 'vue' => '^3.4.0',
118
- 'vue-tsc' => '^2.0.0',
119
- },
115
+ '@vue/compiler-sfc' => '^3.4.0',
116
+ 'typescript' => '^5.0.0',
117
+ 'vue' => '^3.4.0',
118
+ 'vue-tsc' => '^2.0.0'
119
+ }
120
120
  ) + "\n"
121
121
  end
122
122
 
@@ -142,14 +142,14 @@ module Stipa
142
142
  def t_tsconfig
143
143
  JSON.pretty_generate(
144
144
  compilerOptions: {
145
- target: 'ESNext',
146
- module: 'ESNext',
145
+ target: 'ESNext',
146
+ module: 'ESNext',
147
147
  moduleResolution: 'bundler',
148
- strict: true,
149
- skipLibCheck: true,
150
- allowJs: true,
148
+ strict: true,
149
+ skipLibCheck: true,
150
+ allowJs: true
151
151
  },
152
- include: ['app/**/*'],
152
+ include: ['app/**/*']
153
153
  ) + "\n"
154
154
  end
155
155
 
@@ -164,8 +164,7 @@ module Stipa
164
164
  Stipa::Database.connect!
165
165
 
166
166
  # Models must be loaded after the database connection is established.
167
- # If tables don't exist yet, run: rake db:migrate
168
- require_relative 'app/models/application_model' rescue warn "⚠ Run 'rake db:migrate' to set up the database."
167
+ require_relative 'app/models/application_model'
169
168
 
170
169
  APP_DIR = __dir__
171
170
 
@@ -210,15 +209,68 @@ module Stipa
210
209
  res.render(template, locals: locals, layout: layout)
211
210
  end
212
211
 
212
+ # ── Success helpers ──────────────────────────────
213
+
214
+ def json(data, status: 200)
215
+ res.status = status
216
+ res.json(data)
217
+ end
218
+
219
+ def created!(data = nil)
220
+ res.status = 201
221
+ data ? res.json(data) : res.tap { _1.body = '' }
222
+ end
223
+
224
+ def no_content!
225
+ res.status = 204
226
+ res.body = ''
227
+ end
228
+
229
+ # ── Redirection ──────────────────────────────────
230
+
213
231
  def redirect_to(path, status: 302)
214
232
  res.status = status
215
233
  res['Location'] = path
216
234
  res.body = ''
217
235
  end
218
236
 
237
+ # ── Error helpers ────────────────────────────────
238
+
239
+ def bad_request!(message = 'Bad Request')
240
+ error(400, message)
241
+ end
242
+
243
+ def unauthorized!(message = 'Unauthorized')
244
+ error(401, message)
245
+ end
246
+
247
+ def forbidden!(message = 'Forbidden')
248
+ error(403, message)
249
+ end
250
+
219
251
  def not_found!(message = 'Not Found')
220
- res.status = 404
221
- res.body = message
252
+ error(404, message)
253
+ end
254
+
255
+ def conflict!(message = 'Conflict')
256
+ error(409, message)
257
+ end
258
+
259
+ def unprocessable_entity!(message = 'Unprocessable Entity')
260
+ error(422, message)
261
+ end
262
+
263
+ def too_many_requests!(message = 'Too Many Requests')
264
+ error(429, message)
265
+ end
266
+
267
+ def internal_server_error!(message = 'Internal Server Error')
268
+ error(500, message)
269
+ end
270
+
271
+ def error(status, message)
272
+ res.status = status
273
+ res.json(error: { message: message })
222
274
  throw :halt
223
275
  end
224
276
 
@@ -238,6 +290,8 @@ module Stipa
238
290
  k, v = pair.split('=', 2)
239
291
  p[k.to_sym] = URI.decode_www_form_component(v.to_s)
240
292
  end
293
+ elsif req['content-type']&.include?('application/json')
294
+ JSON.parse(req.body).each { |k, v| p[k.to_sym] = v }
241
295
  end
242
296
 
243
297
  p
@@ -424,8 +478,6 @@ module Stipa
424
478
  CSS
425
479
  end
426
480
 
427
-
428
-
429
481
  def t_shims_vue
430
482
  <<~TS
431
483
  declare module '*.vue' {
data/lib/stipa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Stipa
2
- VERSION = '0.2.2'
2
+ VERSION = '0.2.4'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stipa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jānis Harbs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-26 00:00:00.000000000 Z
11
+ date: 2026-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest