sober_swag 0.18.0 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +15 -0
  3. data/.github/workflows/benchmark.yml +39 -0
  4. data/.github/workflows/lint.yml +2 -4
  5. data/.github/workflows/ruby.yml +1 -1
  6. data/.gitignore +3 -0
  7. data/.rubocop.yml +6 -1
  8. data/.yardopts +7 -0
  9. data/CHANGELOG.md +22 -0
  10. data/Gemfile +12 -0
  11. data/README.md +1 -1
  12. data/bench/benchmark.rb +34 -0
  13. data/bench/benchmarks/basic_field_serializer.rb +21 -0
  14. data/bench/benchmarks/view_selection.rb +47 -0
  15. data/bin/console +30 -10
  16. data/docs/reporting.md +190 -0
  17. data/docs/serializers.md +4 -1
  18. data/example/Gemfile +2 -2
  19. data/example/Gemfile.lock +116 -123
  20. data/example/app/controllers/application_controller.rb +4 -0
  21. data/example/app/controllers/people_controller.rb +44 -28
  22. data/example/app/output_objects/identified_output.rb +7 -0
  23. data/example/app/output_objects/person_output_object.rb +37 -11
  24. data/example/app/output_objects/post_output_object.rb +0 -4
  25. data/example/app/output_objects/reporting_post_output.rb +18 -0
  26. data/example/bin/rspec +29 -0
  27. data/example/config/environments/production.rb +1 -1
  28. data/example/spec/requests/people/create_spec.rb +3 -2
  29. data/example/spec/requests/people/index_spec.rb +1 -1
  30. data/lib/sober_swag/compiler/path.rb +45 -4
  31. data/lib/sober_swag/compiler/paths.rb +20 -0
  32. data/lib/sober_swag/compiler/primitive.rb +17 -0
  33. data/lib/sober_swag/compiler/type.rb +105 -22
  34. data/lib/sober_swag/compiler.rb +87 -15
  35. data/lib/sober_swag/controller/route.rb +147 -28
  36. data/lib/sober_swag/controller.rb +57 -17
  37. data/lib/sober_swag/input_object.rb +124 -7
  38. data/lib/sober_swag/nodes/array.rb +19 -0
  39. data/lib/sober_swag/nodes/attribute.rb +45 -4
  40. data/lib/sober_swag/nodes/base.rb +27 -7
  41. data/lib/sober_swag/nodes/binary.rb +30 -13
  42. data/lib/sober_swag/nodes/enum.rb +16 -1
  43. data/lib/sober_swag/nodes/list.rb +20 -0
  44. data/lib/sober_swag/nodes/nullable_primitive.rb +3 -0
  45. data/lib/sober_swag/nodes/object.rb +4 -1
  46. data/lib/sober_swag/nodes/one_of.rb +11 -3
  47. data/lib/sober_swag/nodes/primitive.rb +34 -2
  48. data/lib/sober_swag/nodes/sum.rb +8 -0
  49. data/lib/sober_swag/output_object/definition.rb +57 -1
  50. data/lib/sober_swag/output_object/field.rb +31 -11
  51. data/lib/sober_swag/output_object/field_syntax.rb +19 -3
  52. data/lib/sober_swag/output_object/view.rb +46 -1
  53. data/lib/sober_swag/output_object.rb +40 -19
  54. data/lib/sober_swag/parser.rb +7 -1
  55. data/lib/sober_swag/reporting/compiler.rb +39 -0
  56. data/lib/sober_swag/reporting/input/base.rb +11 -0
  57. data/lib/sober_swag/reporting/input/bool.rb +19 -0
  58. data/lib/sober_swag/reporting/input/converting/bool.rb +24 -0
  59. data/lib/sober_swag/reporting/input/converting/date.rb +30 -0
  60. data/lib/sober_swag/reporting/input/converting/date_time.rb +28 -0
  61. data/lib/sober_swag/reporting/input/converting/decimal.rb +24 -0
  62. data/lib/sober_swag/reporting/input/converting/integer.rb +19 -0
  63. data/lib/sober_swag/reporting/input/converting.rb +16 -0
  64. data/lib/sober_swag/reporting/input/defer.rb +29 -0
  65. data/lib/sober_swag/reporting/input/described.rb +38 -0
  66. data/lib/sober_swag/reporting/input/dictionary.rb +37 -0
  67. data/lib/sober_swag/reporting/input/either.rb +51 -0
  68. data/lib/sober_swag/reporting/input/enum.rb +44 -0
  69. data/lib/sober_swag/reporting/input/format.rb +39 -0
  70. data/lib/sober_swag/reporting/input/interface.rb +87 -0
  71. data/lib/sober_swag/reporting/input/list.rb +44 -0
  72. data/lib/sober_swag/reporting/input/mapped.rb +36 -0
  73. data/lib/sober_swag/reporting/input/merge_objects.rb +72 -0
  74. data/lib/sober_swag/reporting/input/null.rb +34 -0
  75. data/lib/sober_swag/reporting/input/number.rb +19 -0
  76. data/lib/sober_swag/reporting/input/object/property.rb +53 -0
  77. data/lib/sober_swag/reporting/input/object.rb +100 -0
  78. data/lib/sober_swag/reporting/input/pattern.rb +46 -0
  79. data/lib/sober_swag/reporting/input/referenced.rb +38 -0
  80. data/lib/sober_swag/reporting/input/struct.rb +271 -0
  81. data/lib/sober_swag/reporting/input/text.rb +42 -0
  82. data/lib/sober_swag/reporting/input.rb +54 -0
  83. data/lib/sober_swag/reporting/invalid_schema_error.rb +21 -0
  84. data/lib/sober_swag/reporting/output/base.rb +25 -0
  85. data/lib/sober_swag/reporting/output/bool.rb +25 -0
  86. data/lib/sober_swag/reporting/output/defer.rb +69 -0
  87. data/lib/sober_swag/reporting/output/described.rb +42 -0
  88. data/lib/sober_swag/reporting/output/dictionary.rb +46 -0
  89. data/lib/sober_swag/reporting/output/interface.rb +83 -0
  90. data/lib/sober_swag/reporting/output/list.rb +54 -0
  91. data/lib/sober_swag/reporting/output/merge_objects.rb +97 -0
  92. data/lib/sober_swag/reporting/output/null.rb +25 -0
  93. data/lib/sober_swag/reporting/output/number.rb +25 -0
  94. data/lib/sober_swag/reporting/output/object/property.rb +45 -0
  95. data/lib/sober_swag/reporting/output/object.rb +54 -0
  96. data/lib/sober_swag/reporting/output/partitioned.rb +77 -0
  97. data/lib/sober_swag/reporting/output/pattern.rb +50 -0
  98. data/lib/sober_swag/reporting/output/referenced.rb +42 -0
  99. data/lib/sober_swag/reporting/output/struct.rb +262 -0
  100. data/lib/sober_swag/reporting/output/text.rb +25 -0
  101. data/lib/sober_swag/reporting/output/via_map.rb +67 -0
  102. data/lib/sober_swag/reporting/output/viewed.rb +72 -0
  103. data/lib/sober_swag/reporting/output.rb +54 -0
  104. data/lib/sober_swag/reporting/report/base.rb +57 -0
  105. data/lib/sober_swag/reporting/report/either.rb +36 -0
  106. data/lib/sober_swag/reporting/report/error.rb +15 -0
  107. data/lib/sober_swag/reporting/report/list.rb +28 -0
  108. data/lib/sober_swag/reporting/report/merged_object.rb +25 -0
  109. data/lib/sober_swag/reporting/report/object.rb +29 -0
  110. data/lib/sober_swag/reporting/report/output.rb +14 -0
  111. data/lib/sober_swag/reporting/report/value.rb +28 -0
  112. data/lib/sober_swag/reporting/report.rb +16 -0
  113. data/lib/sober_swag/reporting.rb +11 -0
  114. data/lib/sober_swag/serializer/array.rb +27 -3
  115. data/lib/sober_swag/serializer/base.rb +75 -25
  116. data/lib/sober_swag/serializer/conditional.rb +33 -1
  117. data/lib/sober_swag/serializer/field_list.rb +23 -5
  118. data/lib/sober_swag/serializer/hash.rb +53 -0
  119. data/lib/sober_swag/serializer/mapped.rb +10 -1
  120. data/lib/sober_swag/serializer/optional.rb +18 -1
  121. data/lib/sober_swag/serializer/primitive.rb +3 -0
  122. data/lib/sober_swag/serializer.rb +1 -0
  123. data/lib/sober_swag/server.rb +27 -11
  124. data/lib/sober_swag/type/named.rb +14 -0
  125. data/lib/sober_swag/types/comma_array.rb +4 -0
  126. data/lib/sober_swag/version.rb +1 -1
  127. data/lib/sober_swag.rb +7 -1
  128. metadata +72 -2
data/example/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- sober_swag (0.16.0)
4
+ sober_swag (0.21.0)
5
5
  activesupport
6
6
  dry-struct (~> 1.0)
7
7
  dry-types (~> 1.2)
@@ -9,202 +9,195 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- actioncable (6.0.3.2)
13
- actionpack (= 6.0.3.2)
12
+ actioncable (6.0.4.1)
13
+ actionpack (= 6.0.4.1)
14
14
  nio4r (~> 2.0)
15
15
  websocket-driver (>= 0.6.1)
16
- actionmailbox (6.0.3.2)
17
- actionpack (= 6.0.3.2)
18
- activejob (= 6.0.3.2)
19
- activerecord (= 6.0.3.2)
20
- activestorage (= 6.0.3.2)
21
- activesupport (= 6.0.3.2)
16
+ actionmailbox (6.0.4.1)
17
+ actionpack (= 6.0.4.1)
18
+ activejob (= 6.0.4.1)
19
+ activerecord (= 6.0.4.1)
20
+ activestorage (= 6.0.4.1)
21
+ activesupport (= 6.0.4.1)
22
22
  mail (>= 2.7.1)
23
- actionmailer (6.0.3.2)
24
- actionpack (= 6.0.3.2)
25
- actionview (= 6.0.3.2)
26
- activejob (= 6.0.3.2)
23
+ actionmailer (6.0.4.1)
24
+ actionpack (= 6.0.4.1)
25
+ actionview (= 6.0.4.1)
26
+ activejob (= 6.0.4.1)
27
27
  mail (~> 2.5, >= 2.5.4)
28
28
  rails-dom-testing (~> 2.0)
29
- actionpack (6.0.3.2)
30
- actionview (= 6.0.3.2)
31
- activesupport (= 6.0.3.2)
29
+ actionpack (6.0.4.1)
30
+ actionview (= 6.0.4.1)
31
+ activesupport (= 6.0.4.1)
32
32
  rack (~> 2.0, >= 2.0.8)
33
33
  rack-test (>= 0.6.3)
34
34
  rails-dom-testing (~> 2.0)
35
35
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
36
- actiontext (6.0.3.2)
37
- actionpack (= 6.0.3.2)
38
- activerecord (= 6.0.3.2)
39
- activestorage (= 6.0.3.2)
40
- activesupport (= 6.0.3.2)
36
+ actiontext (6.0.4.1)
37
+ actionpack (= 6.0.4.1)
38
+ activerecord (= 6.0.4.1)
39
+ activestorage (= 6.0.4.1)
40
+ activesupport (= 6.0.4.1)
41
41
  nokogiri (>= 1.8.5)
42
- actionview (6.0.3.2)
43
- activesupport (= 6.0.3.2)
42
+ actionview (6.0.4.1)
43
+ activesupport (= 6.0.4.1)
44
44
  builder (~> 3.1)
45
45
  erubi (~> 1.4)
46
46
  rails-dom-testing (~> 2.0)
47
47
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
48
- activejob (6.0.3.2)
49
- activesupport (= 6.0.3.2)
48
+ activejob (6.0.4.1)
49
+ activesupport (= 6.0.4.1)
50
50
  globalid (>= 0.3.6)
51
- activemodel (6.0.3.2)
52
- activesupport (= 6.0.3.2)
53
- activerecord (6.0.3.2)
54
- activemodel (= 6.0.3.2)
55
- activesupport (= 6.0.3.2)
56
- activestorage (6.0.3.2)
57
- actionpack (= 6.0.3.2)
58
- activejob (= 6.0.3.2)
59
- activerecord (= 6.0.3.2)
60
- marcel (~> 0.3.1)
61
- activesupport (6.0.3.2)
51
+ activemodel (6.0.4.1)
52
+ activesupport (= 6.0.4.1)
53
+ activerecord (6.0.4.1)
54
+ activemodel (= 6.0.4.1)
55
+ activesupport (= 6.0.4.1)
56
+ activestorage (6.0.4.1)
57
+ actionpack (= 6.0.4.1)
58
+ activejob (= 6.0.4.1)
59
+ activerecord (= 6.0.4.1)
60
+ marcel (~> 1.0.0)
61
+ activesupport (6.0.4.1)
62
62
  concurrent-ruby (~> 1.0, >= 1.0.2)
63
63
  i18n (>= 0.7, < 2)
64
64
  minitest (~> 5.1)
65
65
  tzinfo (~> 1.1)
66
66
  zeitwerk (~> 2.2, >= 2.2.2)
67
- bootsnap (1.4.6)
67
+ bootsnap (1.9.3)
68
68
  msgpack (~> 1.0)
69
69
  builder (3.2.4)
70
70
  byebug (11.1.3)
71
71
  coderay (1.1.3)
72
- concurrent-ruby (1.1.6)
72
+ concurrent-ruby (1.1.9)
73
73
  crass (1.0.6)
74
74
  diff-lcs (1.4.4)
75
- dry-configurable (0.11.6)
75
+ dry-configurable (0.13.0)
76
76
  concurrent-ruby (~> 1.0)
77
- dry-core (~> 0.4, >= 0.4.7)
78
- dry-equalizer (~> 0.2)
79
- dry-container (0.7.2)
77
+ dry-core (~> 0.6)
78
+ dry-container (0.9.0)
80
79
  concurrent-ruby (~> 1.0)
81
- dry-configurable (~> 0.1, >= 0.1.3)
82
- dry-core (0.4.9)
80
+ dry-configurable (~> 0.13, >= 0.13.0)
81
+ dry-core (0.7.1)
83
82
  concurrent-ruby (~> 1.0)
84
- dry-equalizer (0.3.0)
85
- dry-inflector (0.2.0)
86
- dry-logic (1.0.6)
83
+ dry-inflector (0.2.1)
84
+ dry-logic (1.2.0)
87
85
  concurrent-ruby (~> 1.0)
88
- dry-core (~> 0.2)
89
- dry-equalizer (~> 0.2)
90
- dry-struct (1.3.0)
91
- dry-core (~> 0.4, >= 0.4.4)
92
- dry-equalizer (~> 0.3)
93
- dry-types (~> 1.3)
86
+ dry-core (~> 0.5, >= 0.5)
87
+ dry-struct (1.4.0)
88
+ dry-core (~> 0.5, >= 0.5)
89
+ dry-types (~> 1.5)
94
90
  ice_nine (~> 0.11)
95
- dry-types (1.4.0)
91
+ dry-types (1.5.1)
96
92
  concurrent-ruby (~> 1.0)
97
93
  dry-container (~> 0.3)
98
- dry-core (~> 0.4, >= 0.4.4)
99
- dry-equalizer (~> 0.3)
94
+ dry-core (~> 0.5, >= 0.5)
100
95
  dry-inflector (~> 0.1, >= 0.1.2)
101
96
  dry-logic (~> 1.0, >= 1.0.2)
102
97
  dry-types-rails (0.3.4)
103
98
  dry-types (>= 0.8.1)
104
99
  rails (>= 3)
105
- erubi (1.9.0)
106
- ffi (1.13.1)
107
- globalid (0.4.2)
108
- activesupport (>= 4.2.0)
109
- i18n (1.8.3)
100
+ erubi (1.10.0)
101
+ ffi (1.15.4)
102
+ globalid (1.0.0)
103
+ activesupport (>= 5.0)
104
+ i18n (1.8.11)
110
105
  concurrent-ruby (~> 1.0)
111
106
  ice_nine (0.11.2)
112
- listen (3.1.5)
113
- rb-fsevent (~> 0.9, >= 0.9.4)
114
- rb-inotify (~> 0.9, >= 0.9.7)
115
- ruby_dep (~> 1.2)
116
- loofah (2.6.0)
107
+ listen (3.7.0)
108
+ rb-fsevent (~> 0.10, >= 0.10.3)
109
+ rb-inotify (~> 0.9, >= 0.9.10)
110
+ loofah (2.12.0)
117
111
  crass (~> 1.0.2)
118
112
  nokogiri (>= 1.5.9)
119
113
  mail (2.7.1)
120
114
  mini_mime (>= 0.1.1)
121
- marcel (0.3.3)
122
- mimemagic (~> 0.3.2)
115
+ marcel (1.0.2)
123
116
  method_source (1.0.0)
124
- mimemagic (0.3.5)
125
- mini_mime (1.0.2)
126
- mini_portile2 (2.4.0)
127
- minitest (5.14.1)
128
- msgpack (1.3.3)
129
- nio4r (2.5.2)
130
- nokogiri (1.10.10)
131
- mini_portile2 (~> 2.4.0)
132
- pry (0.13.1)
117
+ mini_mime (1.1.2)
118
+ mini_portile2 (2.6.1)
119
+ minitest (5.14.4)
120
+ msgpack (1.4.2)
121
+ nio4r (2.5.8)
122
+ nokogiri (1.12.5)
123
+ mini_portile2 (~> 2.6.1)
124
+ racc (~> 1.4)
125
+ pry (0.14.1)
133
126
  coderay (~> 1.1)
134
127
  method_source (~> 1.0)
135
- puma (4.3.5)
128
+ puma (5.5.2)
136
129
  nio4r (~> 2.0)
130
+ racc (1.6.0)
137
131
  rack (2.2.3)
138
132
  rack-test (1.1.0)
139
133
  rack (>= 1.0, < 3)
140
- rails (6.0.3.2)
141
- actioncable (= 6.0.3.2)
142
- actionmailbox (= 6.0.3.2)
143
- actionmailer (= 6.0.3.2)
144
- actionpack (= 6.0.3.2)
145
- actiontext (= 6.0.3.2)
146
- actionview (= 6.0.3.2)
147
- activejob (= 6.0.3.2)
148
- activemodel (= 6.0.3.2)
149
- activerecord (= 6.0.3.2)
150
- activestorage (= 6.0.3.2)
151
- activesupport (= 6.0.3.2)
134
+ rails (6.0.4.1)
135
+ actioncable (= 6.0.4.1)
136
+ actionmailbox (= 6.0.4.1)
137
+ actionmailer (= 6.0.4.1)
138
+ actionpack (= 6.0.4.1)
139
+ actiontext (= 6.0.4.1)
140
+ actionview (= 6.0.4.1)
141
+ activejob (= 6.0.4.1)
142
+ activemodel (= 6.0.4.1)
143
+ activerecord (= 6.0.4.1)
144
+ activestorage (= 6.0.4.1)
145
+ activesupport (= 6.0.4.1)
152
146
  bundler (>= 1.3.0)
153
- railties (= 6.0.3.2)
147
+ railties (= 6.0.4.1)
154
148
  sprockets-rails (>= 2.0.0)
155
149
  rails-dom-testing (2.0.3)
156
150
  activesupport (>= 4.2.0)
157
151
  nokogiri (>= 1.6)
158
- rails-html-sanitizer (1.3.0)
152
+ rails-html-sanitizer (1.4.2)
159
153
  loofah (~> 2.3)
160
- railties (6.0.3.2)
161
- actionpack (= 6.0.3.2)
162
- activesupport (= 6.0.3.2)
154
+ railties (6.0.4.1)
155
+ actionpack (= 6.0.4.1)
156
+ activesupport (= 6.0.4.1)
163
157
  method_source
164
158
  rake (>= 0.8.7)
165
159
  thor (>= 0.20.3, < 2.0)
166
- rake (13.0.1)
167
- rb-fsevent (0.10.4)
160
+ rake (13.0.6)
161
+ rb-fsevent (0.11.0)
168
162
  rb-inotify (0.10.1)
169
163
  ffi (~> 1.0)
170
- rspec-core (3.9.2)
171
- rspec-support (~> 3.9.3)
172
- rspec-expectations (3.9.2)
164
+ rspec-core (3.10.1)
165
+ rspec-support (~> 3.10.0)
166
+ rspec-expectations (3.10.1)
173
167
  diff-lcs (>= 1.2.0, < 2.0)
174
- rspec-support (~> 3.9.0)
175
- rspec-mocks (3.9.1)
168
+ rspec-support (~> 3.10.0)
169
+ rspec-mocks (3.10.2)
176
170
  diff-lcs (>= 1.2.0, < 2.0)
177
- rspec-support (~> 3.9.0)
178
- rspec-rails (4.0.1)
179
- actionpack (>= 4.2)
180
- activesupport (>= 4.2)
181
- railties (>= 4.2)
182
- rspec-core (~> 3.9)
183
- rspec-expectations (~> 3.9)
184
- rspec-mocks (~> 3.9)
185
- rspec-support (~> 3.9)
186
- rspec-support (3.9.3)
187
- ruby_dep (1.5.0)
188
- spring (2.1.0)
171
+ rspec-support (~> 3.10.0)
172
+ rspec-rails (5.0.2)
173
+ actionpack (>= 5.2)
174
+ activesupport (>= 5.2)
175
+ railties (>= 5.2)
176
+ rspec-core (~> 3.10)
177
+ rspec-expectations (~> 3.10)
178
+ rspec-mocks (~> 3.10)
179
+ rspec-support (~> 3.10)
180
+ rspec-support (3.10.3)
181
+ spring (2.1.1)
189
182
  spring-watcher-listen (2.0.1)
190
183
  listen (>= 2.7, < 4.0)
191
184
  spring (>= 1.2, < 3.0)
192
185
  sprockets (4.0.2)
193
186
  concurrent-ruby (~> 1.0)
194
187
  rack (> 1, < 3)
195
- sprockets-rails (3.2.1)
196
- actionpack (>= 4.0)
197
- activesupport (>= 4.0)
188
+ sprockets-rails (3.4.1)
189
+ actionpack (>= 5.2)
190
+ activesupport (>= 5.2)
198
191
  sprockets (>= 3.0.0)
199
192
  sqlite3 (1.4.2)
200
- thor (1.0.1)
193
+ thor (1.1.0)
201
194
  thread_safe (0.3.6)
202
- tzinfo (1.2.7)
195
+ tzinfo (1.2.9)
203
196
  thread_safe (~> 0.1)
204
- websocket-driver (0.7.3)
197
+ websocket-driver (0.7.5)
205
198
  websocket-extensions (>= 0.1.0)
206
199
  websocket-extensions (0.1.5)
207
- zeitwerk (2.4.0)
200
+ zeitwerk (2.5.1)
208
201
 
209
202
  PLATFORMS
210
203
  ruby
@@ -214,9 +207,9 @@ DEPENDENCIES
214
207
  bootsnap (>= 1.4.2)
215
208
  byebug
216
209
  dry-types-rails
217
- listen (>= 3.0.5, < 3.2)
210
+ listen (>= 3.0.5, < 3.8)
218
211
  pry
219
- puma (~> 4.3)
212
+ puma (~> 5.4)
220
213
  rails (~> 6.0.2, >= 6.0.2.2)
221
214
  rspec-rails
222
215
  sober_swag!
@@ -4,4 +4,8 @@ class ApplicationController < ActionController::API
4
4
  rescue_from Dry::Struct::Error do
5
5
  head :bad_request
6
6
  end
7
+
8
+ rescue_from SoberSwag::Reporting::Report::Error do |error|
9
+ render json: error.report.path_hash, status: :bad_request
10
+ end
7
11
  end
@@ -5,35 +5,40 @@ class PeopleController < ApplicationController
5
5
 
6
6
  before_action :load_person, only: %i[show update]
7
7
 
8
- PersonBodyParams = SoberSwag.input_object do
9
- identifier 'PersonBodyParams'
8
+ ##
9
+ # Parameters to create or update a person.
10
+ class ReportingPersonParams < SoberSwag::Reporting::Input::Struct
11
+ identifier 'PersonReportingParams'
10
12
 
11
- attribute :first_name, SoberSwag::Types::String
12
- attribute :last_name, SoberSwag::Types::String
13
- attribute? :date_of_birth, SoberSwag::Types::Params::DateTime.optional
13
+ attribute :first_name, SoberSwag::Reporting::Input::Text.new.with_pattern(/.+/)
14
+ attribute :last_name, SoberSwag::Reporting::Input::Text.new.with_pattern(/.+/)
15
+ attribute? :date_of_birth, SoberSwag::Reporting::Input::Converting::DateTime.optional
14
16
  end
15
17
 
16
- PersonBodyPatchParams = SoberSwag.input_object(PersonBodyParams) do
17
- identifier 'PersonBodyPatchParams'
18
+ ##
19
+ # Parameters to create a person.
20
+ class ReportingPersonCreate < SoberSwag::Reporting::Input::Struct
21
+ identifier 'ReportingPersonCreate'
18
22
 
19
- attribute? :first_name, SoberSwag::Types::String
20
- attribute? :last_name, SoberSwag::Types::String
21
- attribute? :date_of_birth, SoberSwag::Types::Params::DateTime.optional
23
+ attribute :person, ReportingPersonParams
22
24
  end
23
25
 
24
- PersonParams = SoberSwag.input_object do
25
- identifier 'PersonParams'
26
- attribute :person, PersonBodyParams
27
- end
26
+ ##
27
+ # Patch body for a person.
28
+ class ReportingPersonPatchParams < SoberSwag::Reporting::Input::Struct
29
+ identifier 'PersonReportingPatchParams'
28
30
 
29
- PersonPatchParams = SoberSwag.input_object do
30
- identifier 'PersonPatchParams'
31
- attribute :person, PersonBodyPatchParams
31
+ attribute? :first_name, SoberSwag::Reporting::Input.text.with_pattern(/.+/)
32
+ attribute? :last_name, SoberSwag::Reporting::Input.text.with_pattern(/.+/)
33
+ attribute? :date_of_birth, SoberSwag::Reporting::Input::Converting::DateTime.optional
32
34
  end
33
35
 
34
36
  define :post, :create, '/people/' do
35
- request_body(PersonParams)
37
+ summary 'Create a person'
38
+
39
+ request_body(ReportingPersonCreate)
36
40
  response(:ok, 'the person created', PersonOutputObject)
41
+ response(:bad_request, 'the parse errors', SoberSwag::Reporting::Report::Output)
37
42
  response(:unprocessable_entity, 'the validation errors', PersonErrorsOutputObject)
38
43
  tags 'people', 'create'
39
44
  end
@@ -47,9 +52,14 @@ class PeopleController < ApplicationController
47
52
  end
48
53
 
49
54
  define :patch, :update, '/people/{id}' do
50
- request_body(PersonPatchParams)
51
- path_params { attribute :id, Types::Params::Integer }
55
+ summary 'Update a person'
56
+
57
+ request_body(reporting: true) do
58
+ attribute :person, ReportingPersonPatchParams
59
+ end
60
+ path_params(reporting: true) { attribute :id, SoberSwag::Reporting::Input::Converting::Integer }
52
61
  response(:ok, 'the person updated', PersonOutputObject)
62
+ response(:bad_request, 'the parse errors', SoberSwag::Reporting::Report::Output)
53
63
  response(:unprocessable_entity, 'the validation errors', PersonErrorsOutputObject)
54
64
  tags 'people', 'update'
55
65
  end
@@ -62,28 +72,34 @@ class PeopleController < ApplicationController
62
72
  end
63
73
 
64
74
  define :get, :index, '/people/' do
65
- query_params do
75
+ summary 'List persons'
76
+
77
+ query_params(reporting: true) do
66
78
  attribute? :filters do
67
- attribute? :first_name, Types::String
68
- attribute? :last_name, Types::String
79
+ attribute? :first_name, SoberSwag::Reporting::Input.text
80
+ attribute? :last_name, SoberSwag::Reporting::Input.text
69
81
  end
70
- attribute :view, Types::String.default('base'.freeze).enum('base', 'detail')
82
+ attribute? :view, SoberSwag::Reporting::Input.text.enum('base', 'detail')
71
83
  end
72
- response(:ok, 'all the people', PersonOutputObject.array)
84
+ response(:ok, 'all the people', PersonOutputObject.list)
85
+ response(:bad_request, 'the parse errors', SoberSwag::Reporting::Report::Output)
73
86
  tags 'people', 'list'
74
87
  end
75
88
  def index
76
89
  @people = Person.all
77
90
  @people = @people.where('UPPER(first_name) LIKE UPPER(?)', "%#{parsed_query.filters.first_name}%") if parsed_query.filters&.first_name
78
91
  @people = @people.where('UPPER(last_name) LIKE UPPER(?)', "%#{parsed_query.filters.last_name}%") if parsed_query.filters&.last_name
79
- respond!(:ok, @people.includes(:posts), serializer_opts: { view: parsed_query.view })
92
+ respond!(:ok, @people.includes(:posts), serializer_opts: { view: parsed_query.view || :base })
80
93
  end
81
94
 
82
95
  define :get, :show, '/people/{id}' do
83
- path_params do
84
- attribute :id, Types::Params::Integer
96
+ summary 'Get a single person by id'
97
+
98
+ path_params(reporting: true) do
99
+ attribute :id, SoberSwag::Reporting::Input::Converting::Integer
85
100
  end
86
101
  response(:ok, 'the person requested', PersonOutputObject)
102
+ response(:bad_request, 'the parse errors', SoberSwag::Reporting::Report::Output)
87
103
  tags 'people', 'show'
88
104
  end
89
105
  def show
@@ -0,0 +1,7 @@
1
+ ##
2
+ # Base serializer for objects with a global id of some variety.
3
+ class IdentifiedOutput < SoberSwag::Reporting::Output::Struct
4
+ field :global_id, SoberSwag::Reporting::Output.text.nilable do
5
+ object_to_serialize.try(:to_global_id).try(:to_s)
6
+ end
7
+ end
@@ -1,15 +1,41 @@
1
- PersonOutputObject = SoberSwag::OutputObject.define do
2
- identifier 'Person'
3
- field :id, primitive(:Integer).meta(description: 'Unique ID')
4
- field :first_name, primitive(:String).meta(description: <<~MARKDOWN)
5
- This is the first name of a person.
6
- Note that you can't use this as a unique identifier, and you really should understand how names work before using this.
7
- [Falsehoods programmers believe about names](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/)
8
- is a good thing to read!
1
+ ##
2
+ # Output object that serializes a person.
3
+ class PersonOutputObject < IdentifiedOutput
4
+ identifier 'PersonOutput'
5
+
6
+ description <<~MARKDOWN
7
+ Basic as hell serializer for a person.
9
8
  MARKDOWN
10
- field :last_name, primitive(:String)
11
9
 
12
- view :detail do
13
- field :posts, -> { PostOutputObject.array }
10
+ field :id, SoberSwag::Reporting::Output::Text.new.via_map(&:to_s)
11
+ field(
12
+ :first_name,
13
+ SoberSwag::Reporting::Output::Text.new,
14
+ description: <<~MARKDOWN
15
+ This is the first name of a person.
16
+ Note that you can't use this as a unique identifier, and you really should understand how names work before using this.
17
+ [Falsehoods programmers believe about names](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/)
18
+ is a good thing to read!
19
+ MARKDOWN
20
+ )
21
+ field(
22
+ :last_name, SoberSwag::Reporting::Output::Text.new
23
+ )
24
+
25
+ define_view :detail do
26
+ field(
27
+ :initials,
28
+ SoberSwag::Reporting::Output::Text.new
29
+ ) do |person|
30
+ [person.first_name[0..0], person.last_name[0..0]].compact.map { |x| "#{x}." }.join(' ')
31
+ end
32
+
33
+ field(
34
+ :posts,
35
+ SoberSwag::Reporting::Output::Defer.defer do
36
+ ReportingPostOutput.view(:base).array
37
+ end,
38
+ description: 'all posts this user has made'
39
+ )
14
40
  end
15
41
  end
@@ -3,8 +3,4 @@ PostOutputObject = SoberSwag::OutputObject.define do
3
3
  field :id, primitive(:Integer)
4
4
  field :title, primitive(:String)
5
5
  field :body, primitive(:String)
6
-
7
- view :detail do
8
- field :person, -> { PersonOutputObject.view(:base) }
9
- end
10
6
  end
@@ -0,0 +1,18 @@
1
+ ##
2
+ # A reporting output object for a post.
3
+ class ReportingPostOutput < SoberSwag::Reporting::Output::Struct
4
+ identifier 'ReportingPostOutput'
5
+
6
+ field :id, SoberSwag::Reporting::Output::Text.new.via_map(&:to_s)
7
+ field :title, SoberSwag::Reporting::Output::Text.new
8
+ field :body, SoberSwag::Reporting::Output::Text.new
9
+
10
+ define_view :detail do
11
+ field(
12
+ :person,
13
+ SoberSwag::Reporting::Output::Defer.defer do
14
+ PersonOutputObject.view(:base)
15
+ end
16
+ )
17
+ end
18
+ end
data/example/bin/rspec ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle', __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require 'rubygems'
27
+ require 'bundler/setup'
28
+
29
+ load Gem.bin_path('rspec-core', 'rspec')
@@ -60,7 +60,7 @@ Rails.application.configure do
60
60
  # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
61
61
 
62
62
  if ENV['RAILS_LOG_TO_STDOUT'].present?
63
- logger = ActiveSupport::Logger.new(STDOUT)
63
+ logger = ActiveSupport::Logger.new($stdout)
64
64
  logger.formatter = config.log_formatter
65
65
  config.logger = ActiveSupport::TaggedLogging.new(logger)
66
66
  end
@@ -34,7 +34,8 @@ RSpec.describe 'people controller create', type: :request do
34
34
 
35
35
  it { should_not be_successful }
36
36
  it { should_not be_server_error }
37
- it { should be_unprocessable }
37
+ it { should be_bad_request }
38
+ it { should have_attributes(status: 400) }
38
39
  end
39
40
 
40
41
  describe 'the act of requesting' do
@@ -46,7 +47,7 @@ RSpec.describe 'people controller create', type: :request do
46
47
  describe 'the response body' do
47
48
  subject { request && response && JSON.parse(response.body) }
48
49
 
49
- it { should have_key('first_name') }
50
+ it { should have_key('$.person.first_name') }
50
51
  end
51
52
  end
52
53
  end
@@ -30,7 +30,7 @@ RSpec.describe 'Index action for people' do
30
30
  end
31
31
 
32
32
  it 'has the right person' do
33
- expect(parsed_body).to include(include('id' => person.id))
33
+ expect(parsed_body).to include(include('id' => person.id.to_s))
34
34
  end
35
35
  end
36
36