mk_framework 0.2.2 → 0.2.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/CHANGELOG.md +7 -0
- data/README.md +5 -5
- data/lib/mk_framework/generator/templates/README.md.erb +1 -1
- data/lib/mk_framework/generator/templates/handler.rb.erb +2 -2
- data/lib/mk_framework/generator/templates/request_spec.rb.erb +55 -49
- data/lib/mk_framework/generator/templates/spec_helper.rb.erb +1 -1
- data/lib/mk_framework/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c68f913eebaf1aa8a9b4d423b528e4720a6508b5f0f130c03b15d039458ec6d1
|
|
4
|
+
data.tar.gz: be858c42ce6d158eb5e658bb9a7e20ec9a775795f0f5956b03100ee733dd4c2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 79a22c1dcd019cfcb8ad3653a9fdd84c4246de7cdc95faa21132be72dc1306285c49bc5a37f29a3bdd64342718024ac126fcf33e7fe38dcdbde673dca3e73536
|
|
7
|
+
data.tar.gz: f42544ff916968bf3cfc5152b9ed3cd866050b301407e5f1b840637db4b73226f1a3a604b36102b0195b8a9e584c4e7ab90cb590afee744bf9462b1b0ac79538
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.3 — 2026-09-12
|
|
4
|
+
|
|
5
|
+
- Use `rack-test` and `Rack::Test::Methods` in generated request specs.
|
|
6
|
+
- Simplify generated update specs to use PUT and serialize request bodies with
|
|
7
|
+
`.to_json`.
|
|
8
|
+
- Format generated Ruby hashes with spaces inside nonempty braces.
|
|
9
|
+
|
|
3
10
|
## 0.2.2 — 2026-09-08
|
|
4
11
|
|
|
5
12
|
- Generate full CRUD resources: index, show, create, update (PATCH and PUT), and
|
data/README.md
CHANGED
|
@@ -21,14 +21,14 @@ require `mk_framework/sequel`.
|
|
|
21
21
|
## Install
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
gem install mk_framework -v 0.2.
|
|
24
|
+
gem install mk_framework -v 0.2.3
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Or add it to your application's Gemfile:
|
|
28
28
|
|
|
29
29
|
```ruby
|
|
30
30
|
source 'https://rubygems.org'
|
|
31
|
-
gem 'mk_framework', '~> 0.2.
|
|
31
|
+
gem 'mk_framework', '~> 0.2.3'
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Run `bundle install`. Add `sequel` and your database driver if you use
|
|
@@ -36,11 +36,11 @@ Run `bundle install`. Add `sequel` and your database driver if you use
|
|
|
36
36
|
|
|
37
37
|
## Generate an app with `mk_frame_init`
|
|
38
38
|
|
|
39
|
-
Version 0.2.
|
|
39
|
+
Version 0.2.3 generates full CRUD apps with the `mk_frame_init` executable. Install the gem, then run
|
|
40
40
|
it from the parent directory where you want your new app:
|
|
41
41
|
|
|
42
42
|
```sh
|
|
43
|
-
gem install mk_framework -v 0.2.
|
|
43
|
+
gem install mk_framework -v 0.2.3
|
|
44
44
|
mk_frame_init
|
|
45
45
|
```
|
|
46
46
|
|
|
@@ -632,7 +632,7 @@ bundle exec rake
|
|
|
632
632
|
bundle exec rake build
|
|
633
633
|
```
|
|
634
634
|
|
|
635
|
-
The gem is written to `pkg/mk_framework-0.2.
|
|
635
|
+
The gem is written to `pkg/mk_framework-0.2.3.gem`. See
|
|
636
636
|
[deployment](docs/deployment.md) for migrations, connections, authentication,
|
|
637
637
|
timeouts, logging, and release verification, and [upgrading](docs/upgrading.md)
|
|
638
638
|
for changes from the prototype. CI runs on Ruby 4.0 on Linux.
|
|
@@ -12,7 +12,7 @@ Each action has its own controller and handler.
|
|
|
12
12
|
| DELETE | `/<%= config.resource %>/:id` | delete |
|
|
13
13
|
|
|
14
14
|
Create returns 201; the other actions return 200. Index returns
|
|
15
|
-
`{<%= config.resource %>: [...]}`; member actions return `{<%= config.model_name %>: {...}}`,
|
|
15
|
+
`{ <%= config.resource %>: [...] }`; member actions return `{ <%= config.model_name %>: { ... } }`,
|
|
16
16
|
including the deleted record for DELETE. Missing records return 404.
|
|
17
17
|
|
|
18
18
|
## Setup
|
|
@@ -7,9 +7,9 @@ module <%= config.namespace %>
|
|
|
7
7
|
r.response.status = 201
|
|
8
8
|
<% end -%>
|
|
9
9
|
<% if action == 'index' -%>
|
|
10
|
-
{<%= config.resource %>: model.map { |record| record.slice(*<%= config.model_class %>.public_attributes_list) }}
|
|
10
|
+
{ <%= config.resource %>: model.map { |record| record.slice(*<%= config.model_class %>.public_attributes_list) } }
|
|
11
11
|
<% else -%>
|
|
12
|
-
{<%= config.model_name %>: model.slice(*<%= config.model_class %>.public_attributes_list)}
|
|
12
|
+
{ <%= config.model_name %>: model.slice(*<%= config.model_class %>.public_attributes_list) }
|
|
13
13
|
<% end -%>
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -3,105 +3,111 @@
|
|
|
3
3
|
require_relative '../spec_helper'
|
|
4
4
|
|
|
5
5
|
RSpec.describe '<%= config.model_class %> CRUD' do
|
|
6
|
-
|
|
7
|
-
let(:attributes) { JSON.parse(<%= JSON.generate(config.example).inspect %>) }
|
|
6
|
+
include Rack::Test::Methods
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
let(:app) { Rack::Builder.parse_file(File.join(<%= config.namespace %>::ROOT, 'config.ru')) }
|
|
9
|
+
let(:attributes) { JSON.parse(<%= config.example.to_json.inspect %>) }
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
<%= config.namespace %>::<%= config.model_class %>.dataset.delete
|
|
13
|
+
header 'CONTENT_TYPE', 'application/json'
|
|
14
|
+
end
|
|
10
15
|
|
|
11
16
|
it 'persists permitted fields and returns a 201 response through the Rack entrypoint' do
|
|
12
|
-
|
|
13
|
-
'CONTENT_TYPE' => 'application/json')
|
|
17
|
+
post('/<%= config.resource %>', attributes.merge('id' => 999).to_json)
|
|
14
18
|
|
|
15
|
-
expect(
|
|
19
|
+
expect(last_response.status).to eq(201)
|
|
16
20
|
record = <%= config.namespace %>::<%= config.model_class %>.first
|
|
17
21
|
expect(record).not_to be_nil
|
|
18
22
|
expect(record.id).not_to eq(999)
|
|
19
|
-
payload = JSON.parse(
|
|
23
|
+
payload = JSON.parse(last_response.body).fetch('<%= config.model_name %>')
|
|
20
24
|
expect(payload.fetch('id')).to eq(record.id)
|
|
21
25
|
expect(payload.keys).to match_array(%w[id <%= config.field_names.join(' ') %> created_at updated_at])
|
|
22
26
|
end
|
|
23
27
|
|
|
24
28
|
it 'rejects missing required fields without inserting a record' do
|
|
25
|
-
|
|
29
|
+
post('/<%= config.resource %>', {}.to_json)
|
|
26
30
|
|
|
27
|
-
expect(
|
|
31
|
+
expect(last_response.status).to eq(422)
|
|
28
32
|
expect(<%= config.namespace %>::<%= config.model_class %>.count).to eq(0)
|
|
29
33
|
end
|
|
30
34
|
|
|
31
35
|
it 'rejects an invalid field type without inserting a record' do
|
|
32
36
|
attributes['<%= config.fields.first[:name] %>'] = []
|
|
33
|
-
|
|
37
|
+
post('/<%= config.resource %>', attributes.to_json)
|
|
34
38
|
|
|
35
|
-
expect(
|
|
39
|
+
expect(last_response.status).to eq(400)
|
|
36
40
|
expect(<%= config.namespace %>::<%= config.model_class %>.count).to eq(0)
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
def create_record
|
|
40
|
-
|
|
41
|
-
expect(
|
|
42
|
-
JSON.parse(
|
|
44
|
+
post('/<%= config.resource %>', attributes.to_json)
|
|
45
|
+
expect(last_response.status).to eq(201)
|
|
46
|
+
JSON.parse(last_response.body).fetch('<%= config.model_name %>')
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
it 'lists records in ID order, including an empty collection' do
|
|
46
|
-
|
|
50
|
+
get('/<%= config.resource %>')
|
|
51
|
+
expect(JSON.parse(last_response.body)).to eq('<%= config.resource %>' => [])
|
|
47
52
|
records = [create_record, create_record]
|
|
48
|
-
|
|
49
|
-
expect(
|
|
50
|
-
expect(JSON.parse(
|
|
53
|
+
get('/<%= config.resource %>')
|
|
54
|
+
expect(last_response.status).to eq(200)
|
|
55
|
+
expect(JSON.parse(last_response.body).fetch('<%= config.resource %>')).to eq(records)
|
|
51
56
|
end
|
|
52
57
|
|
|
53
58
|
it 'shows a single record' do
|
|
54
59
|
record = create_record
|
|
55
|
-
|
|
56
|
-
expect(
|
|
57
|
-
expect(JSON.parse(
|
|
60
|
+
get("/<%= config.resource %>/#{record.fetch('id')}")
|
|
61
|
+
expect(last_response.status).to eq(200)
|
|
62
|
+
expect(JSON.parse(last_response.body).fetch('<%= config.model_name %>')).to eq(record)
|
|
58
63
|
end
|
|
59
64
|
|
|
60
|
-
<% updated_value = {'string' => 'Updated', 'text' => 'Updated text', 'integer' => 2, 'float' => 2.5, 'boolean' => true, 'date' => '2027-02-03', 'datetime' => '2027-02-03T14:30:00Z'}.fetch(config.fields.first[:type]) -%>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
expect(payload.fetch('id')).to eq(record.fetch('id'))
|
|
65
|
+
<% updated_value = { 'string' => 'Updated', 'text' => 'Updated text', 'integer' => 2, 'float' => 2.5, 'boolean' => true, 'date' => '2027-02-03', 'datetime' => '2027-02-03T14:30:00Z' }.fetch(config.fields.first[:type]) -%>
|
|
66
|
+
it 'updates permitted fields with PUT, preserving omitted fields and the ID' do
|
|
67
|
+
record = create_record
|
|
68
|
+
changes = { '<%= config.fields.first[:name] %>' => <%= updated_value.inspect %>, 'id' => 999 }
|
|
69
|
+
put("/<%= config.resource %>/#{record.fetch('id')}",
|
|
70
|
+
changes.to_json)
|
|
71
|
+
expect(last_response.status).to eq(200)
|
|
72
|
+
payload = JSON.parse(last_response.body).fetch('<%= config.model_name %>')
|
|
73
|
+
expect(payload.fetch('id')).to eq(record.fetch('id'))
|
|
70
74
|
<% if config.fields.first[:type] == 'datetime' -%>
|
|
71
|
-
|
|
75
|
+
expect(DateTime.parse(payload.fetch('<%= config.fields.first[:name] %>'))).to eq(DateTime.iso8601(<%= updated_value.inspect %>))
|
|
72
76
|
<% else -%>
|
|
73
|
-
|
|
77
|
+
expect(payload.fetch('<%= config.fields.first[:name] %>')).to eq(<%= updated_value.inspect %>)
|
|
74
78
|
<% end -%>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
expect(payload.except('<%= config.fields.first[:name] %>', 'updated_at')).to eq(record.except('<%= config.fields.first[:name] %>', 'updated_at'))
|
|
80
|
+
get("/<%= config.resource %>/#{record.fetch('id')}")
|
|
81
|
+
expect(JSON.parse(last_response.body).fetch('<%= config.model_name %>')).to eq(payload)
|
|
82
|
+
expect(<%= config.namespace %>::<%= config.model_class %>.count).to eq(1)
|
|
79
83
|
end
|
|
80
84
|
|
|
81
85
|
it 'rejects invalid updates without changing stored data' do
|
|
82
86
|
record = create_record
|
|
83
87
|
<%= %w[string text].include?(config.fields.first[:type]) ? "[[[], 400], [nil, 400], ['', 422]]" : '[[[], 400], [nil, 400]]' %>.each do |value, status|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
expect(
|
|
87
|
-
|
|
88
|
+
put("/<%= config.resource %>/#{record.fetch('id')}",
|
|
89
|
+
{ '<%= config.fields.first[:name] %>' => value }.to_json)
|
|
90
|
+
expect(last_response.status).to eq(status)
|
|
91
|
+
get("/<%= config.resource %>/#{record.fetch('id')}")
|
|
92
|
+
expect(JSON.parse(last_response.body).fetch('<%= config.model_name %>')).to eq(record)
|
|
88
93
|
end
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
it 'deletes a record and returns its public attributes' do
|
|
92
97
|
record = create_record
|
|
93
|
-
|
|
94
|
-
expect(
|
|
95
|
-
expect(JSON.parse(
|
|
98
|
+
delete("/<%= config.resource %>/#{record.fetch('id')}")
|
|
99
|
+
expect(last_response.status).to eq(200)
|
|
100
|
+
expect(JSON.parse(last_response.body).fetch('<%= config.model_name %>')).to eq(record)
|
|
96
101
|
expect(<%= config.namespace %>::<%= config.model_class %>.count).to eq(0)
|
|
97
|
-
|
|
102
|
+
get("/<%= config.resource %>/#{record.fetch('id')}")
|
|
103
|
+
expect(last_response.status).to eq(404)
|
|
98
104
|
end
|
|
99
105
|
|
|
100
|
-
%w[get
|
|
106
|
+
%w[get put delete].each do |verb|
|
|
101
107
|
it "returns 404 for #{verb.upcase} of a missing record" do
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
expect(
|
|
108
|
+
public_send(verb, '/<%= config.resource %>/999999',
|
|
109
|
+
attributes.to_json)
|
|
110
|
+
expect(last_response.status).to eq(404)
|
|
105
111
|
expect(<%= config.namespace %>::<%= config.model_class %>.count).to eq(0)
|
|
106
112
|
end
|
|
107
113
|
end
|
data/lib/mk_framework/version.rb
CHANGED