sober_swag 0.17.0 → 0.21.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 (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!