sober_swag 0.1.0 → 0.6.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/config/rubocop_linter_action.yml +4 -0
  3. data/.github/workflows/lint.yml +15 -0
  4. data/.github/workflows/ruby.yml +33 -2
  5. data/.gitignore +4 -0
  6. data/.rubocop.yml +75 -1
  7. data/.ruby-version +1 -1
  8. data/README.md +154 -1
  9. data/bin/console +16 -15
  10. data/docs/serializers.md +203 -0
  11. data/example/.rspec +1 -0
  12. data/example/.ruby-version +1 -1
  13. data/example/Gemfile +9 -7
  14. data/example/Gemfile.lock +96 -79
  15. data/example/app/controllers/people_controller.rb +41 -23
  16. data/example/app/controllers/posts_controller.rb +110 -0
  17. data/example/app/models/application_record.rb +3 -0
  18. data/example/app/models/person.rb +6 -0
  19. data/example/app/models/post.rb +9 -0
  20. data/example/app/output_objects/person_errors_output_object.rb +5 -0
  21. data/example/app/output_objects/person_output_object.rb +15 -0
  22. data/example/app/output_objects/post_output_object.rb +10 -0
  23. data/example/bin/bundle +24 -20
  24. data/example/bin/rails +1 -1
  25. data/example/bin/rake +1 -1
  26. data/example/config/application.rb +11 -7
  27. data/example/config/environments/development.rb +0 -1
  28. data/example/config/environments/production.rb +3 -3
  29. data/example/config/puma.rb +5 -5
  30. data/example/config/routes.rb +3 -0
  31. data/example/config/spring.rb +4 -4
  32. data/example/db/migrate/20200311152021_create_people.rb +0 -1
  33. data/example/db/migrate/20200603172347_create_posts.rb +11 -0
  34. data/example/db/schema.rb +16 -7
  35. data/example/spec/rails_helper.rb +64 -0
  36. data/example/spec/requests/people/create_spec.rb +52 -0
  37. data/example/spec/requests/people/get_spec.rb +35 -0
  38. data/example/spec/requests/people/index_spec.rb +69 -0
  39. data/example/spec/spec_helper.rb +94 -0
  40. data/lib/sober_swag.rb +6 -3
  41. data/lib/sober_swag/compiler/error.rb +2 -0
  42. data/lib/sober_swag/compiler/path.rb +2 -5
  43. data/lib/sober_swag/compiler/paths.rb +0 -1
  44. data/lib/sober_swag/compiler/type.rb +86 -56
  45. data/lib/sober_swag/controller.rb +16 -11
  46. data/lib/sober_swag/controller/route.rb +18 -21
  47. data/lib/sober_swag/controller/undefined_body_error.rb +3 -0
  48. data/lib/sober_swag/controller/undefined_path_error.rb +3 -0
  49. data/lib/sober_swag/controller/undefined_query_error.rb +3 -0
  50. data/lib/sober_swag/input_object.rb +28 -0
  51. data/lib/sober_swag/nodes/array.rb +1 -1
  52. data/lib/sober_swag/nodes/base.rb +5 -3
  53. data/lib/sober_swag/nodes/binary.rb +2 -1
  54. data/lib/sober_swag/nodes/enum.rb +4 -2
  55. data/lib/sober_swag/nodes/list.rb +0 -1
  56. data/lib/sober_swag/nodes/primitive.rb +6 -5
  57. data/lib/sober_swag/output_object.rb +102 -0
  58. data/lib/sober_swag/output_object/definition.rb +30 -0
  59. data/lib/sober_swag/{blueprint → output_object}/field.rb +14 -4
  60. data/lib/sober_swag/{blueprint → output_object}/field_syntax.rb +2 -2
  61. data/lib/sober_swag/{blueprint → output_object}/view.rb +15 -6
  62. data/lib/sober_swag/parser.rb +9 -4
  63. data/lib/sober_swag/serializer.rb +5 -2
  64. data/lib/sober_swag/serializer/array.rb +12 -0
  65. data/lib/sober_swag/serializer/base.rb +50 -1
  66. data/lib/sober_swag/serializer/conditional.rb +19 -2
  67. data/lib/sober_swag/serializer/field_list.rb +29 -6
  68. data/lib/sober_swag/serializer/mapped.rb +15 -3
  69. data/lib/sober_swag/serializer/meta.rb +35 -0
  70. data/lib/sober_swag/serializer/optional.rb +17 -2
  71. data/lib/sober_swag/serializer/primitive.rb +4 -1
  72. data/lib/sober_swag/server.rb +83 -0
  73. data/lib/sober_swag/types.rb +3 -0
  74. data/lib/sober_swag/version.rb +1 -1
  75. data/sober_swag.gemspec +8 -4
  76. metadata +79 -47
  77. data/Gemfile.lock +0 -92
  78. data/example/person.json +0 -4
  79. data/example/test/controllers/.keep +0 -0
  80. data/example/test/fixtures/.keep +0 -0
  81. data/example/test/fixtures/files/.keep +0 -0
  82. data/example/test/fixtures/people.yml +0 -11
  83. data/example/test/integration/.keep +0 -0
  84. data/example/test/models/.keep +0 -0
  85. data/example/test/models/person_test.rb +0 -7
  86. data/example/test/test_helper.rb +0 -13
  87. data/lib/sober_swag/blueprint.rb +0 -113
  88. data/lib/sober_swag/path.rb +0 -8
  89. data/lib/sober_swag/path/integer.rb +0 -21
  90. data/lib/sober_swag/path/lit.rb +0 -41
  91. data/lib/sober_swag/path/literal.rb +0 -29
  92. data/lib/sober_swag/path/param.rb +0 -33
@@ -1,13 +1,29 @@
1
1
  module SoberSwag
2
2
  module Serializer
3
+ ##
4
+ # Given something that serializes a type 'A',
5
+ # this can be used to make a serializer of type 'A | nil'.
6
+ #
7
+ # Or, put another way, makes serializers not crash on nil values.
3
8
  class Optional < Base
4
-
5
9
  def initialize(inner)
6
10
  @inner = inner
7
11
  end
8
12
 
9
13
  attr_reader :inner
10
14
 
15
+ def lazy_type?
16
+ @inner.lazy_type?
17
+ end
18
+
19
+ def lazy_type
20
+ @inner.lazy_type.optional
21
+ end
22
+
23
+ def finalize_lazy_type!
24
+ @inner.finalize_lazy_type!
25
+ end
26
+
11
27
  def serialize(object, options = {})
12
28
  if object.nil?
13
29
  object
@@ -23,7 +39,6 @@ module SoberSwag
23
39
  def optional(*)
24
40
  raise ArgumentError, 'no nesting optionals please'
25
41
  end
26
-
27
42
  end
28
43
  end
29
44
  end
@@ -1,5 +1,8 @@
1
1
  module SoberSwag
2
2
  module Serializer
3
+ ##
4
+ # A class that does *no* serialization: you give it a type,
5
+ # and it will pass any serialized input on verbatim.
3
6
  class Primitive < Base
4
7
  def initialize(type)
5
8
  @type = type
@@ -7,7 +10,7 @@ module SoberSwag
7
10
 
8
11
  attr_reader :type
9
12
 
10
- def serialize(object, options = {})
13
+ def serialize(object, _options = {})
11
14
  object
12
15
  end
13
16
  end
@@ -0,0 +1,83 @@
1
+ require 'set'
2
+
3
+ module SoberSwag
4
+ ##
5
+ # A basic, rack-only server to serve up swagger definitions.
6
+ # By default it is configured to work with rails, but you can pass stuff to initialize.
7
+ class Server
8
+ RAILS_CONTROLLER_PROC = proc do
9
+ Rails.application.routes.routes.map { |route|
10
+ route.defaults[:controller]
11
+ }.to_set.reject(&:nil?).map { |controller|
12
+ "#{controller}_controller".classify.constantize
13
+ }.filter { |controller| controller.ancestors.include?(SoberSwag::Controller) }
14
+ end
15
+
16
+ ##
17
+ # Start up.
18
+ #
19
+ # @param controller_proc [Proc] a proc that, when called, gives a list of {SoberSwag::Controller}s to document
20
+ # @param cache [Bool | Proc] if we should cache our defintions (default false)
21
+ def initialize(
22
+ controller_proc: RAILS_CONTROLLER_PROC,
23
+ cache: false
24
+ )
25
+ @controller_proc = controller_proc
26
+ @cache = cache
27
+ end
28
+
29
+ EFFECT_HTML = <<~HTML.freeze
30
+ <!DOCTYPE html>
31
+ <html>
32
+ <head>
33
+ <title>Swagger-UI</title>
34
+ <script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
35
+ <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@3.23.4/swagger-ui.css"></link>
36
+ </head>
37
+ <body>
38
+ <div id="swagger">
39
+ </div>
40
+ <script>
41
+ SwaggerUIBundle({url: 'SCRIPT_NAME', dom_id: '#swagger'})
42
+ </script>
43
+ </body>
44
+ </html>
45
+ HTML
46
+
47
+ def call(env)
48
+ req = Rack::Request.new(env)
49
+ if req.path_info&.match?(/json/si) || req.get_header('Accept')&.match?(/json/si)
50
+ [200, { 'Content-Type' => 'application/json' }, [generate_json_string]]
51
+ else
52
+ [200, { 'Content-Type' => 'text/html' }, [EFFECT_HTML.gsub(/SCRIPT_NAME/, env['SCRIPT_NAME'] + '.json')]]
53
+ end
54
+ end
55
+
56
+ def generate_json_string
57
+ if cache?
58
+ @json_string ||= JSON.dump(generate_swagger)
59
+ else
60
+ JSON.dump(generate_swagger)
61
+ end
62
+ end
63
+
64
+ def cache?
65
+ @cache.respond_to?(:call) ? @cache.call : @cache
66
+ end
67
+
68
+ def generate_swagger
69
+ routes = sober_controllers.flat_map(&:defined_routes).reduce(SoberSwag::Compiler.new) { |c, r| c.add_route(r) }
70
+ {
71
+ openapi: '3.0.0',
72
+ info: {
73
+ version: '1',
74
+ title: 'SoberSwag Swagger'
75
+ }
76
+ }.merge(routes.to_swagger)
77
+ end
78
+
79
+ def sober_controllers
80
+ @controller_proc.call
81
+ end
82
+ end
83
+ end
@@ -1,4 +1,7 @@
1
1
  module SoberSwag
2
+ ##
3
+ # Container for types.
4
+ # You can use constants like SoberSwag::Types::Integer and things as a result of this module existing.
2
5
  class Types
3
6
  include ::Dry::Types()
4
7
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SoberSwag
4
- VERSION = '0.1.0'
4
+ VERSION = '0.6.0'
5
5
  end
@@ -15,10 +15,12 @@ Gem::Specification.new do |spec|
15
15
  spec.homepage = 'https://github.com/SonderMindOrg/sober_swag'
16
16
  spec.license = 'MIT'
17
17
 
18
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
19
 
20
20
  spec.metadata['homepage_uri'] = spec.homepage
21
21
 
22
+ spec.required_ruby_version = '>= 2.6.0'
23
+
22
24
  # Specify which files should be added to the gem when it is released.
23
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
26
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
@@ -28,13 +30,15 @@ Gem::Specification.new do |spec|
28
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
31
  spec.require_paths = ['lib']
30
32
 
33
+ spec.add_dependency 'activesupport'
31
34
  spec.add_dependency 'dry-struct', '~> 1.0'
32
35
  spec.add_dependency 'dry-types', '~> 1.2'
33
- spec.add_dependency 'activesupport'
34
36
 
35
- spec.add_development_dependency 'pry'
36
- spec.add_development_dependency 'simplecov'
37
37
  spec.add_development_dependency 'bundler', '~> 2.0'
38
+ spec.add_development_dependency 'pry'
38
39
  spec.add_development_dependency 'rake', '~> 13.0'
39
40
  spec.add_development_dependency 'rspec', '~> 3.0'
41
+ spec.add_development_dependency 'rubocop'
42
+ spec.add_development_dependency 'rubocop-rspec'
43
+ spec.add_development_dependency 'simplecov'
40
44
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sober_swag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Super
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-21 00:00:00.000000000 Z
11
+ date: 2020-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: dry-struct
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,19 +53,19 @@ dependencies:
39
53
  - !ruby/object:Gem::Version
40
54
  version: '1.2'
41
55
  - !ruby/object:Gem::Dependency
42
- name: activesupport
56
+ name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - ">="
59
+ - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
61
+ version: '2.0'
62
+ type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ">="
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '0'
68
+ version: '2.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: pry
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -67,61 +81,75 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: simplecov
84
+ name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ">="
87
+ - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '0'
89
+ version: '13.0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - ">="
94
+ - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '0'
96
+ version: '13.0'
83
97
  - !ruby/object:Gem::Dependency
84
- name: bundler
98
+ name: rspec
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
101
  - - "~>"
88
102
  - !ruby/object:Gem::Version
89
- version: '2.0'
103
+ version: '3.0'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
- version: '2.0'
110
+ version: '3.0'
97
111
  - !ruby/object:Gem::Dependency
98
- name: rake
112
+ name: rubocop
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
- - - "~>"
115
+ - - ">="
102
116
  - !ruby/object:Gem::Version
103
- version: '13.0'
117
+ version: '0'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - "~>"
122
+ - - ">="
109
123
  - !ruby/object:Gem::Version
110
- version: '13.0'
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
- name: rspec
126
+ name: rubocop-rspec
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - "~>"
129
+ - - ">="
116
130
  - !ruby/object:Gem::Version
117
- version: '3.0'
131
+ version: '0'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - "~>"
136
+ - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: '3.0'
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
125
153
  description: Parse data, don't write docs
126
154
  email:
127
155
  - asuper@sondermind.com
@@ -129,6 +157,8 @@ executables: []
129
157
  extensions: []
130
158
  extra_rdoc_files: []
131
159
  files:
160
+ - ".github/config/rubocop_linter_action.yml"
161
+ - ".github/workflows/lint.yml"
132
162
  - ".github/workflows/ruby.yml"
133
163
  - ".gitignore"
134
164
  - ".rspec"
@@ -136,13 +166,14 @@ files:
136
166
  - ".ruby-version"
137
167
  - ".travis.yml"
138
168
  - Gemfile
139
- - Gemfile.lock
140
169
  - LICENSE.txt
141
170
  - README.md
142
171
  - Rakefile
143
172
  - bin/console
144
173
  - bin/setup
174
+ - docs/serializers.md
145
175
  - example/.gitignore
176
+ - example/.rspec
146
177
  - example/.ruby-version
147
178
  - example/Gemfile
148
179
  - example/Gemfile.lock
@@ -151,10 +182,15 @@ files:
151
182
  - example/app/controllers/application_controller.rb
152
183
  - example/app/controllers/concerns/.keep
153
184
  - example/app/controllers/people_controller.rb
185
+ - example/app/controllers/posts_controller.rb
154
186
  - example/app/jobs/application_job.rb
155
187
  - example/app/models/application_record.rb
156
188
  - example/app/models/concerns/.keep
157
189
  - example/app/models/person.rb
190
+ - example/app/models/post.rb
191
+ - example/app/output_objects/person_errors_output_object.rb
192
+ - example/app/output_objects/person_output_object.rb
193
+ - example/app/output_objects/post_output_object.rb
158
194
  - example/bin/bundle
159
195
  - example/bin/rails
160
196
  - example/bin/rake
@@ -181,27 +217,20 @@ files:
181
217
  - example/config/routes.rb
182
218
  - example/config/spring.rb
183
219
  - example/db/migrate/20200311152021_create_people.rb
220
+ - example/db/migrate/20200603172347_create_posts.rb
184
221
  - example/db/schema.rb
185
222
  - example/db/seeds.rb
186
223
  - example/lib/tasks/.keep
187
224
  - example/log/.keep
188
- - example/person.json
189
225
  - example/public/robots.txt
190
- - example/test/controllers/.keep
191
- - example/test/fixtures/.keep
192
- - example/test/fixtures/files/.keep
193
- - example/test/fixtures/people.yml
194
- - example/test/integration/.keep
195
- - example/test/models/.keep
196
- - example/test/models/person_test.rb
197
- - example/test/test_helper.rb
226
+ - example/spec/rails_helper.rb
227
+ - example/spec/requests/people/create_spec.rb
228
+ - example/spec/requests/people/get_spec.rb
229
+ - example/spec/requests/people/index_spec.rb
230
+ - example/spec/spec_helper.rb
198
231
  - example/tmp/.keep
199
232
  - example/vendor/.keep
200
233
  - lib/sober_swag.rb
201
- - lib/sober_swag/blueprint.rb
202
- - lib/sober_swag/blueprint/field.rb
203
- - lib/sober_swag/blueprint/field_syntax.rb
204
- - lib/sober_swag/blueprint/view.rb
205
234
  - lib/sober_swag/compiler.rb
206
235
  - lib/sober_swag/compiler/error.rb
207
236
  - lib/sober_swag/compiler/path.rb
@@ -212,6 +241,7 @@ files:
212
241
  - lib/sober_swag/controller/undefined_body_error.rb
213
242
  - lib/sober_swag/controller/undefined_path_error.rb
214
243
  - lib/sober_swag/controller/undefined_query_error.rb
244
+ - lib/sober_swag/input_object.rb
215
245
  - lib/sober_swag/nodes.rb
216
246
  - lib/sober_swag/nodes/array.rb
217
247
  - lib/sober_swag/nodes/attribute.rb
@@ -224,20 +254,22 @@ files:
224
254
  - lib/sober_swag/nodes/one_of.rb
225
255
  - lib/sober_swag/nodes/primitive.rb
226
256
  - lib/sober_swag/nodes/sum.rb
257
+ - lib/sober_swag/output_object.rb
258
+ - lib/sober_swag/output_object/definition.rb
259
+ - lib/sober_swag/output_object/field.rb
260
+ - lib/sober_swag/output_object/field_syntax.rb
261
+ - lib/sober_swag/output_object/view.rb
227
262
  - lib/sober_swag/parser.rb
228
- - lib/sober_swag/path.rb
229
- - lib/sober_swag/path/integer.rb
230
- - lib/sober_swag/path/lit.rb
231
- - lib/sober_swag/path/literal.rb
232
- - lib/sober_swag/path/param.rb
233
263
  - lib/sober_swag/serializer.rb
234
264
  - lib/sober_swag/serializer/array.rb
235
265
  - lib/sober_swag/serializer/base.rb
236
266
  - lib/sober_swag/serializer/conditional.rb
237
267
  - lib/sober_swag/serializer/field_list.rb
238
268
  - lib/sober_swag/serializer/mapped.rb
269
+ - lib/sober_swag/serializer/meta.rb
239
270
  - lib/sober_swag/serializer/optional.rb
240
271
  - lib/sober_swag/serializer/primitive.rb
272
+ - lib/sober_swag/server.rb
241
273
  - lib/sober_swag/types.rb
242
274
  - lib/sober_swag/version.rb
243
275
  - sober_swag.gemspec
@@ -255,14 +287,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
255
287
  requirements:
256
288
  - - ">="
257
289
  - !ruby/object:Gem::Version
258
- version: '0'
290
+ version: 2.6.0
259
291
  required_rubygems_version: !ruby/object:Gem::Requirement
260
292
  requirements:
261
293
  - - ">="
262
294
  - !ruby/object:Gem::Version
263
295
  version: '0'
264
296
  requirements: []
265
- rubygems_version: 3.1.2
297
+ rubygems_version: 3.0.3
266
298
  signing_key:
267
299
  specification_version: 4
268
300
  summary: Generate swagger types from dry-types