sober_swag 0.17.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) 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 +5 -1
  8. data/.yardopts +7 -0
  9. data/CHANGELOG.md +21 -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/docs/serializers.md +4 -1
  16. data/example/Gemfile +2 -2
  17. data/example/Gemfile.lock +46 -44
  18. data/example/config/environments/production.rb +1 -1
  19. data/lib/sober_swag/compiler/path.rb +42 -3
  20. data/lib/sober_swag/compiler/paths.rb +20 -0
  21. data/lib/sober_swag/compiler/primitive.rb +20 -1
  22. data/lib/sober_swag/compiler/type.rb +105 -22
  23. data/lib/sober_swag/compiler.rb +29 -3
  24. data/lib/sober_swag/controller/route.rb +103 -20
  25. data/lib/sober_swag/controller.rb +39 -12
  26. data/lib/sober_swag/input_object.rb +124 -7
  27. data/lib/sober_swag/nodes/array.rb +19 -0
  28. data/lib/sober_swag/nodes/attribute.rb +45 -4
  29. data/lib/sober_swag/nodes/base.rb +27 -7
  30. data/lib/sober_swag/nodes/binary.rb +30 -13
  31. data/lib/sober_swag/nodes/enum.rb +16 -1
  32. data/lib/sober_swag/nodes/list.rb +20 -0
  33. data/lib/sober_swag/nodes/nullable_primitive.rb +3 -0
  34. data/lib/sober_swag/nodes/object.rb +4 -1
  35. data/lib/sober_swag/nodes/one_of.rb +11 -3
  36. data/lib/sober_swag/nodes/primitive.rb +34 -2
  37. data/lib/sober_swag/nodes/sum.rb +8 -0
  38. data/lib/sober_swag/output_object/definition.rb +57 -1
  39. data/lib/sober_swag/output_object/field.rb +31 -11
  40. data/lib/sober_swag/output_object/field_syntax.rb +19 -3
  41. data/lib/sober_swag/output_object/view.rb +46 -1
  42. data/lib/sober_swag/output_object.rb +40 -19
  43. data/lib/sober_swag/parser.rb +7 -1
  44. data/lib/sober_swag/serializer/array.rb +27 -3
  45. data/lib/sober_swag/serializer/base.rb +75 -25
  46. data/lib/sober_swag/serializer/conditional.rb +33 -1
  47. data/lib/sober_swag/serializer/field_list.rb +23 -5
  48. data/lib/sober_swag/serializer/hash.rb +53 -0
  49. data/lib/sober_swag/serializer/mapped.rb +10 -1
  50. data/lib/sober_swag/serializer/optional.rb +18 -1
  51. data/lib/sober_swag/serializer/primitive.rb +3 -0
  52. data/lib/sober_swag/serializer.rb +1 -0
  53. data/lib/sober_swag/server.rb +27 -11
  54. data/lib/sober_swag/type/named.rb +14 -0
  55. data/lib/sober_swag/types/comma_array.rb +4 -0
  56. data/lib/sober_swag/version.rb +1 -1
  57. data/lib/sober_swag.rb +6 -1
  58. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a0e2ee1acc571a7f6a90db87f4c15b6d7d820f24b75abd3f37cb369d431f271
4
- data.tar.gz: 6384f275b7b1bd21ef35f4972b519be59a19d1a5e24a5c2138e203748a9702bb
3
+ metadata.gz: f9dce6daadaff9f7ddb1530ecf5fa69693454a29f04da849eec9bea8969166bc
4
+ data.tar.gz: a6cd16e93640b2d9c27fab081c3551d8498643044a6ebf9cab8100b51d8d916d
5
5
  SHA512:
6
- metadata.gz: c1d8b82b62dc05656482b0e550bc5edb24cdf76dde9dc9bcd4729381c5439983df7e98704eb9a0d54964f70297c8097b8192a016736db5ffff3126849d5425e9
7
- data.tar.gz: f55485cc2dd04c4dd414b7c2b5668be91d1c8ada7ad51cf20d04bad62925054d27f940caf83c6c83e1763928c3ea5295d9c592b7a83f85e133cdfbaca697652c
6
+ metadata.gz: fb2dcb7bee3b89e643b3e5d2d1e3d5b7034161ae563de59909120a3f4c817a8f14ab88d5d1968efb2b914b068cf0370d41f9094bbec7ae8ef96a87dfe3ad64fd
7
+ data.tar.gz: bfc9bfe3b4e93dca2a774e416496d430dfa63185acc82db780cc4f26d7eec1ff2a6db0f10103fd962243ab46b9799b8e6536dd94cc07758b5f52ea07af71df67
@@ -0,0 +1,15 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "bundler"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "daily"
12
+ - package-ecosystem: "bundler"
13
+ directory: "/example"
14
+ schedule:
15
+ interval: "daily"
@@ -0,0 +1,39 @@
1
+ name: Ruby Benchmark
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ benchmark:
11
+
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ ruby: [ '2.6', '2.7', '3.0' ]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby }}
23
+ - uses: actions/cache@v2
24
+ with:
25
+ path: vendor/bundle
26
+ key: ${{ runner.os }}-${{ matrix.ruby }}-gem-deps-${{ hashFiles('**/Gemfile.lock') }}
27
+ restore-keys: |
28
+ ${{ runner.os }}-${{ matrix.ruby }}-gem-deps-
29
+ - name: Install dependencies
30
+ run: |
31
+ bundle config path vendor/bundle
32
+ bundle install
33
+ - name: Run Benchmark
34
+ run: bundle exec ruby bench/benchmark.rb
35
+ - uses: actions/upload-artifact@v2
36
+ with:
37
+ name: benchmark-result
38
+ path: benchmark_results.yaml
39
+ if-no-files-found: error
@@ -14,13 +14,11 @@ on:
14
14
  branches: [ master ]
15
15
 
16
16
  jobs:
17
- test:
18
-
17
+ lint:
19
18
  runs-on: ubuntu-latest
20
19
  strategy:
21
20
  matrix:
22
- ruby: [ '2.6', '2.7' ]
23
-
21
+ ruby: [ '2.6', '2.7', '3.0' ]
24
22
  steps:
25
23
  - uses: actions/checkout@v2
26
24
  - name: Set up Ruby
@@ -19,7 +19,7 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby: [ '2.6', '2.7' ]
22
+ ruby: [ '2.6', '2.7', '3.0' ]
23
23
  steps:
24
24
  - uses: actions/checkout@v2
25
25
  - name: Set up Ruby
data/.gitignore CHANGED
@@ -15,3 +15,6 @@ Gemfile.lock
15
15
  *.gem
16
16
 
17
17
  /vendor/
18
+
19
+ .yardoc
20
+ benchmark_results.yaml
data/.rubocop.yml CHANGED
@@ -2,6 +2,7 @@ require: rubocop-rspec
2
2
 
3
3
  AllCops:
4
4
  TargetRubyVersion: 2.6.0
5
+ NewCops: enable
5
6
  Exclude:
6
7
  - 'bin/bundle'
7
8
  - 'example/bin/bundle'
@@ -22,6 +23,9 @@ Metrics/BlockLength:
22
23
  - 'sober_swag.gemspec'
23
24
  - 'example/spec/**/*.rb'
24
25
 
26
+ Lint/MissingSuper:
27
+ Enabled: false
28
+
25
29
  RSpec/ImplicitBlockExpectation:
26
30
  Enabled: false
27
31
 
@@ -123,4 +127,4 @@ Style/FrozenStringLiteralComment:
123
127
  Enabled: false
124
128
 
125
129
  Style/BlockDelimiters:
126
- EnforcedStyle: braces_for_chaining
130
+ EnforcedStyle: braces_for_chaining
data/.yardopts ADDED
@@ -0,0 +1,7 @@
1
+ --markup-provider=redcarpet
2
+ --markup=markdown
3
+ --plugin activesupport-concern
4
+ --plugin solargraph
5
+ --private
6
+ --protected
7
+ --files docs/serializers.md
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.21.0] 2021-09-02
4
+
5
+ - Added a new method of serializing views based on hash lookups, improving performance
6
+ - Added a benchmarking suite
7
+ - Added `except` parameter to the `merge` method, which allows a specified field to be excluded from the merge.
8
+ - Add `type_key` to output objects, for easily serializing out type fields with a constant string.
9
+ - Added `type_attribute` to `SoberSwag::InputObject` to add easy constant-value disambiguation.
10
+
11
+ ## [v0.20.0] 2021-05-17
12
+
13
+ - Added YARD documentation to almost every method
14
+
15
+
16
+ ## [v0.19.0] 2021-03-10
17
+
18
+ - Use [redoc](https://github.com/Redocly/redoc) for generated documentation UI
19
+
20
+ ## [v0.18.0] 2021-03-02
21
+
22
+ - Add generic hash type for primitive types
23
+
3
24
  ## [v0.17.0]: 2020-11-30
4
25
 
5
26
  - Allow tagging endpoints via the new `tags` method.
data/Gemfile CHANGED
@@ -4,3 +4,15 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in sober_swag.gemspec
6
6
  gemspec
7
+
8
+ gem 'yard'
9
+
10
+ gem 'redcarpet'
11
+
12
+ gem 'yard-activesupport-concern'
13
+
14
+ gem 'solargraph'
15
+
16
+ gem 'benchmark-ips'
17
+
18
+ gem 'rspec-its'
data/README.md CHANGED
@@ -11,7 +11,7 @@ An introductory presentation is available [here](https://www.icloud.com/keynote/
11
11
 
12
12
  Further documentation on using the gem is available in the `docs/` directory:
13
13
 
14
- - [Serializers](docs/serializers.md)
14
+ - {file:docs/serializers.md Serializers}
15
15
 
16
16
  ## Types for a fully-automated API
17
17
 
@@ -0,0 +1,34 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'sober_swag'
4
+
5
+ require 'yaml'
6
+ require 'benchmark/ips'
7
+
8
+ ##
9
+ # Quick and dirty way to benchmark things.
10
+ class Bench
11
+ class << self
12
+ def report(name, &block)
13
+ puts name
14
+
15
+ data[name] ||= Benchmark.ips(&block).data
16
+ end
17
+
18
+ def data
19
+ @data ||= {}
20
+ end
21
+
22
+ def write!(filename)
23
+ File.open(filename, 'w') do |f|
24
+ f << YAML.dump(data)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ Dir['bench/benchmarks/**/*.rb'].sort.each do |file|
31
+ require_relative file.gsub(%r{^bench/}, '')
32
+ end
33
+
34
+ Bench.write!('benchmark_results.yaml')
@@ -0,0 +1,21 @@
1
+ ##
2
+ # Bench test for serializing multiple fields.
3
+ class BasicFieldSerializer
4
+ Idea = Struct.new(:name, :grade, :cool)
5
+
6
+ Output = SoberSwag::OutputObject.define do
7
+ field :name, primitive(:String)
8
+ field :grade, primitive(:Integer)
9
+ field :cool, primitive(:Bool)
10
+ end
11
+
12
+ OutputSerializer = Output.serializer
13
+
14
+ MyIdea = Idea.new('Bob', 12, false)
15
+
16
+ Bench.report 'Basic Field Serializers' do |bm|
17
+ bm.report('Output Object') { Output.serialize(MyIdea) }
18
+ bm.report('Serializer of Output Object') { OutputSerializer.serialize(MyIdea) }
19
+ bm.compare!
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ ##
2
+ # Benchmark for speed of selecting what view to use.
3
+ class ViewSelection
4
+ Accomplishment = Struct.new(:name, :description)
5
+ Person = Struct.new(:first_name, :last_name, :accomplishments)
6
+
7
+ MyPerson = Person.new(
8
+ 'Joeseph',
9
+ 'Biden',
10
+ [
11
+ Accomplishment.new('Became President', 'Won a Presidential Election'),
12
+ Accomplishment.new('Oldest President', 'Oldest man to be elected president at time of election'),
13
+ Accomplishment.new('Became Senator', 'Got Elected to the Senate'),
14
+ Accomplishment.new('Youngest Senator', 'Youngest person elected Senator at time of election')
15
+ ]
16
+ )
17
+
18
+ AccomplishmentSerializer = SoberSwag::OutputObject.define do
19
+ field :name, primitive(:String)
20
+
21
+ view :detail do
22
+ field :description, primitive(:String)
23
+ end
24
+ end
25
+
26
+ PersonSerializer = SoberSwag::OutputObject.define do
27
+ field :first_name, primitive(:String)
28
+ field :last_name, primitive(:String)
29
+
30
+ # make a bunch of dummy views
31
+ 1.upto(10).each { |n| view(:"view_#{n}") {} }
32
+
33
+ view :detail do
34
+ field :accomplishments, AccomplishmentSerializer.view(:detail)
35
+ end
36
+
37
+ 1.upto(10).each { |n| view(:"view_after_#{n}") {} }
38
+ end
39
+
40
+ Bench.report 'View Selection' do |bm|
41
+ bm.report('With no view') { PersonSerializer.serialize(MyPerson) }
42
+
43
+ bm.report('With a view') { PersonSerializer.serialize(MyPerson, { view: :detail }) }
44
+
45
+ bm.compare!
46
+ end
47
+ end
data/docs/serializers.md CHANGED
@@ -105,7 +105,7 @@ This changes the type properly too.
105
105
 
106
106
  98% of the time, when we're writing web APIs, we want to transform our domain objects into JSON objects.
107
107
  We often want different ways to do this, too.
108
- Consider, for exmaple, and API for a college.
108
+ Consider, for example, an API for a college.
109
109
  We might want to provide one detailed way to serialize a student, which includes their full name, grade, student ID, GPA, and so on.
110
110
  On another page, we might want to display a classroom with a list of students.
111
111
  However, on the classroom page, we don't want to serialize a full student: that's sending too much data.
@@ -241,6 +241,9 @@ end
241
241
  Using `#merge` lets you add in all the fields from one output object into another.
242
242
  You can even use `merge` from within a view.
243
243
 
244
+ Exclude any unneeded fields from the merge by passing a hash:
245
+ `merge GenericBioOutput, { except: [:position] }`
246
+
244
247
  Note that `merge` does *not* copy anything but fields.
245
248
  Identifiers and views will not be copied over.
246
249
 
data/example/Gemfile CHANGED
@@ -8,7 +8,7 @@ gem 'actionpack', '>= 6.0.3.2'
8
8
  # Use sqlite3 as the database for Active Record
9
9
  gem 'sqlite3', '~> 1.4'
10
10
  # Use Puma as the app server
11
- gem 'puma', '~> 4.3'
11
+ gem 'puma', '~> 5.3'
12
12
  # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
13
13
  # gem 'jbuilder', '~> 2.7'
14
14
  # Use Active Model has_secure_password
@@ -34,7 +34,7 @@ group :development, :test do
34
34
  end
35
35
 
36
36
  group :development do
37
- gem 'listen', '>= 3.0.5', '< 3.2'
37
+ gem 'listen', '>= 3.0.5', '< 3.7'
38
38
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
39
39
  gem 'spring'
40
40
  gem 'spring-watcher-listen', '~> 2.0.0'
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.19.0)
5
5
  activesupport
6
6
  dry-struct (~> 1.0)
7
7
  dry-types (~> 1.2)
@@ -64,12 +64,12 @@ GEM
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.7.5)
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.8)
73
73
  crass (1.0.6)
74
74
  diff-lcs (1.4.4)
75
75
  dry-configurable (0.11.6)
@@ -102,18 +102,17 @@ GEM
102
102
  dry-types-rails (0.3.4)
103
103
  dry-types (>= 0.8.1)
104
104
  rails (>= 3)
105
- erubi (1.9.0)
106
- ffi (1.13.1)
105
+ erubi (1.10.0)
106
+ ffi (1.15.3)
107
107
  globalid (0.4.2)
108
108
  activesupport (>= 4.2.0)
109
- i18n (1.8.3)
109
+ i18n (1.8.9)
110
110
  concurrent-ruby (~> 1.0)
111
111
  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)
112
+ listen (3.6.0)
113
+ rb-fsevent (~> 0.10, >= 0.10.3)
114
+ rb-inotify (~> 0.9, >= 0.9.10)
115
+ loofah (2.9.0)
117
116
  crass (~> 1.0.2)
118
117
  nokogiri (>= 1.5.9)
119
118
  mail (2.7.1)
@@ -121,19 +120,23 @@ GEM
121
120
  marcel (0.3.3)
122
121
  mimemagic (~> 0.3.2)
123
122
  method_source (1.0.0)
124
- mimemagic (0.3.5)
123
+ mimemagic (0.3.10)
124
+ nokogiri (~> 1)
125
+ rake
125
126
  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)
127
+ mini_portile2 (2.5.1)
128
+ minitest (5.14.4)
129
+ msgpack (1.4.2)
130
+ nio4r (2.5.7)
131
+ nokogiri (1.11.5)
132
+ mini_portile2 (~> 2.5.0)
133
+ racc (~> 1.4)
134
+ pry (0.14.1)
133
135
  coderay (~> 1.1)
134
136
  method_source (~> 1.0)
135
- puma (4.3.5)
137
+ puma (5.3.2)
136
138
  nio4r (~> 2.0)
139
+ racc (1.5.2)
137
140
  rack (2.2.3)
138
141
  rack-test (1.1.0)
139
142
  rack (>= 1.0, < 3)
@@ -163,29 +166,28 @@ GEM
163
166
  method_source
164
167
  rake (>= 0.8.7)
165
168
  thor (>= 0.20.3, < 2.0)
166
- rake (13.0.1)
167
- rb-fsevent (0.10.4)
169
+ rake (13.0.3)
170
+ rb-fsevent (0.11.0)
168
171
  rb-inotify (0.10.1)
169
172
  ffi (~> 1.0)
170
- rspec-core (3.9.2)
171
- rspec-support (~> 3.9.3)
172
- rspec-expectations (3.9.2)
173
+ rspec-core (3.10.1)
174
+ rspec-support (~> 3.10.0)
175
+ rspec-expectations (3.10.1)
173
176
  diff-lcs (>= 1.2.0, < 2.0)
174
- rspec-support (~> 3.9.0)
175
- rspec-mocks (3.9.1)
177
+ rspec-support (~> 3.10.0)
178
+ rspec-mocks (3.10.2)
176
179
  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)
180
+ rspec-support (~> 3.10.0)
181
+ rspec-rails (5.0.1)
182
+ actionpack (>= 5.2)
183
+ activesupport (>= 5.2)
184
+ railties (>= 5.2)
185
+ rspec-core (~> 3.10)
186
+ rspec-expectations (~> 3.10)
187
+ rspec-mocks (~> 3.10)
188
+ rspec-support (~> 3.10)
189
+ rspec-support (3.10.2)
190
+ spring (2.1.1)
189
191
  spring-watcher-listen (2.0.1)
190
192
  listen (>= 2.7, < 4.0)
191
193
  spring (>= 1.2, < 3.0)
@@ -197,14 +199,14 @@ GEM
197
199
  activesupport (>= 4.0)
198
200
  sprockets (>= 3.0.0)
199
201
  sqlite3 (1.4.2)
200
- thor (1.0.1)
202
+ thor (1.1.0)
201
203
  thread_safe (0.3.6)
202
- tzinfo (1.2.7)
204
+ tzinfo (1.2.9)
203
205
  thread_safe (~> 0.1)
204
206
  websocket-driver (0.7.3)
205
207
  websocket-extensions (>= 0.1.0)
206
208
  websocket-extensions (0.1.5)
207
- zeitwerk (2.4.0)
209
+ zeitwerk (2.4.2)
208
210
 
209
211
  PLATFORMS
210
212
  ruby
@@ -214,9 +216,9 @@ DEPENDENCIES
214
216
  bootsnap (>= 1.4.2)
215
217
  byebug
216
218
  dry-types-rails
217
- listen (>= 3.0.5, < 3.2)
219
+ listen (>= 3.0.5, < 3.7)
218
220
  pry
219
- puma (~> 4.3)
221
+ puma (~> 5.3)
220
222
  rails (~> 6.0.2, >= 6.0.2.2)
221
223
  rspec-rails
222
224
  sober_swag!