sober_swag 0.18.0 → 0.22.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.
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