sober_swag 0.20.0 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/benchmark.yml +39 -0
- data/.github/workflows/lint.yml +1 -3
- data/.gitignore +1 -0
- data/CHANGELOG.md +9 -1
- data/Gemfile +4 -0
- data/bench/benchmark.rb +34 -0
- data/bench/benchmarks/basic_field_serializer.rb +21 -0
- data/bench/benchmarks/view_selection.rb +47 -0
- data/docs/serializers.md +1 -1
- data/example/Gemfile +2 -2
- data/example/Gemfile.lock +10 -10
- data/lib/sober_swag/input_object.rb +34 -0
- data/lib/sober_swag/output_object/definition.rb +26 -0
- data/lib/sober_swag/output_object.rb +5 -15
- data/lib/sober_swag/serializer/field_list.rb +5 -3
- data/lib/sober_swag/serializer/hash.rb +53 -0
- data/lib/sober_swag/serializer.rb +1 -0
- data/lib/sober_swag/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9dce6daadaff9f7ddb1530ecf5fa69693454a29f04da849eec9bea8969166bc
|
4
|
+
data.tar.gz: a6cd16e93640b2d9c27fab081c3551d8498643044a6ebf9cab8100b51d8d916d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb2dcb7bee3b89e643b3e5d2d1e3d5b7034161ae563de59909120a3f4c817a8f14ab88d5d1968efb2b914b068cf0370d41f9094bbec7ae8ef96a87dfe3ad64fd
|
7
|
+
data.tar.gz: bfc9bfe3b4e93dca2a774e416496d430dfa63185acc82db780cc4f26d7eec1ff2a6db0f10103fd962243ab46b9799b8e6536dd94cc07758b5f52ea07af71df67
|
@@ -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
|
data/.github/workflows/lint.yml
CHANGED
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,17 @@
|
|
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
|
+
|
3
11
|
## [v0.20.0] 2021-05-17
|
4
12
|
|
5
13
|
- Added YARD documentation to almost every method
|
6
|
-
|
14
|
+
|
7
15
|
|
8
16
|
## [v0.19.0] 2021-03-10
|
9
17
|
|
data/Gemfile
CHANGED
data/bench/benchmark.rb
ADDED
@@ -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
|
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.
|
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', '~> 5.
|
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.
|
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
@@ -64,7 +64,7 @@ GEM
|
|
64
64
|
minitest (~> 5.1)
|
65
65
|
tzinfo (~> 1.1)
|
66
66
|
zeitwerk (~> 2.2, >= 2.2.2)
|
67
|
-
bootsnap (1.7.
|
67
|
+
bootsnap (1.7.5)
|
68
68
|
msgpack (~> 1.0)
|
69
69
|
builder (3.2.4)
|
70
70
|
byebug (11.1.3)
|
@@ -103,13 +103,13 @@ GEM
|
|
103
103
|
dry-types (>= 0.8.1)
|
104
104
|
rails (>= 3)
|
105
105
|
erubi (1.10.0)
|
106
|
-
ffi (1.15.
|
106
|
+
ffi (1.15.3)
|
107
107
|
globalid (0.4.2)
|
108
108
|
activesupport (>= 4.2.0)
|
109
109
|
i18n (1.8.9)
|
110
110
|
concurrent-ruby (~> 1.0)
|
111
111
|
ice_nine (0.11.2)
|
112
|
-
listen (3.
|
112
|
+
listen (3.6.0)
|
113
113
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
114
114
|
rb-inotify (~> 0.9, >= 0.9.10)
|
115
115
|
loofah (2.9.0)
|
@@ -124,17 +124,17 @@ GEM
|
|
124
124
|
nokogiri (~> 1)
|
125
125
|
rake
|
126
126
|
mini_mime (1.0.2)
|
127
|
-
mini_portile2 (2.5.
|
127
|
+
mini_portile2 (2.5.1)
|
128
128
|
minitest (5.14.4)
|
129
129
|
msgpack (1.4.2)
|
130
130
|
nio4r (2.5.7)
|
131
|
-
nokogiri (1.11.
|
131
|
+
nokogiri (1.11.5)
|
132
132
|
mini_portile2 (~> 2.5.0)
|
133
133
|
racc (~> 1.4)
|
134
|
-
pry (0.14.
|
134
|
+
pry (0.14.1)
|
135
135
|
coderay (~> 1.1)
|
136
136
|
method_source (~> 1.0)
|
137
|
-
puma (5.
|
137
|
+
puma (5.3.2)
|
138
138
|
nio4r (~> 2.0)
|
139
139
|
racc (1.5.2)
|
140
140
|
rack (2.2.3)
|
@@ -167,7 +167,7 @@ GEM
|
|
167
167
|
rake (>= 0.8.7)
|
168
168
|
thor (>= 0.20.3, < 2.0)
|
169
169
|
rake (13.0.3)
|
170
|
-
rb-fsevent (0.
|
170
|
+
rb-fsevent (0.11.0)
|
171
171
|
rb-inotify (0.10.1)
|
172
172
|
ffi (~> 1.0)
|
173
173
|
rspec-core (3.10.1)
|
@@ -216,9 +216,9 @@ DEPENDENCIES
|
|
216
216
|
bootsnap (>= 1.4.2)
|
217
217
|
byebug
|
218
218
|
dry-types-rails
|
219
|
-
listen (>= 3.0.5, < 3.
|
219
|
+
listen (>= 3.0.5, < 3.7)
|
220
220
|
pry
|
221
|
-
puma (~> 5.
|
221
|
+
puma (~> 5.3)
|
222
222
|
rails (~> 6.0.2, >= 6.0.2.2)
|
223
223
|
rspec-rails
|
224
224
|
sober_swag!
|
@@ -46,6 +46,40 @@ module SoberSwag
|
|
46
46
|
super(key, parent, &block)
|
47
47
|
end
|
48
48
|
|
49
|
+
##
|
50
|
+
# Add on an attribute which only ever parses from a constant value.
|
51
|
+
# By default, this attribute will be called `type`, but you can override it with the kwarg.
|
52
|
+
# This is useful in situations where you want to emulate a sum type.
|
53
|
+
# For example, if you want to make an API endpoint that can either accept or reject proposals
|
54
|
+
#
|
55
|
+
# ```ruby
|
56
|
+
#
|
57
|
+
# ApiInputType = SoberSwag.input_object {
|
58
|
+
# identifier 'AcceptProposal'
|
59
|
+
# type_attribute 'accept'
|
60
|
+
# attribute(:message, primitive(:String))
|
61
|
+
# } | SoberSwag.input_object {
|
62
|
+
# identifier 'RejectProposal'
|
63
|
+
# type_attribute 'reject'
|
64
|
+
# attribute(:message, primitive(:String))
|
65
|
+
# }
|
66
|
+
# ```
|
67
|
+
#
|
68
|
+
# Under the hood, this basically looks like:
|
69
|
+
#
|
70
|
+
# ```ruby
|
71
|
+
# type_attribute 'archive'
|
72
|
+
# # is equivalent to
|
73
|
+
#
|
74
|
+
# attribute(:type, SoberSwag::Types::String.enum('archive'))
|
75
|
+
# ```
|
76
|
+
#
|
77
|
+
# @param value [String,Symbol] the value to parse
|
78
|
+
# @param attribute_key [Symbol] what key to use
|
79
|
+
def type_attribute(value, attribute_key: :type)
|
80
|
+
attribute(attribute_key, SoberSwag::Types::String.enum(value.to_s))
|
81
|
+
end
|
82
|
+
|
49
83
|
##
|
50
84
|
# @overload attribute(key, parent = SoberSwag::InputObject, &block)
|
51
85
|
# Defines an optional attribute by defining a sub-object inline.
|
@@ -19,6 +19,32 @@ module SoberSwag
|
|
19
19
|
|
20
20
|
include FieldSyntax
|
21
21
|
|
22
|
+
##
|
23
|
+
# Adds a "type key", which is basically a field that will be
|
24
|
+
# serialized out to a constant value.
|
25
|
+
#
|
26
|
+
# This is useful if you have multiple types you may want to serialize out, and want consumers of your API to distinguish between them.
|
27
|
+
#
|
28
|
+
# By default this will have the key "type" but you can set it with the keyword arg.
|
29
|
+
# ```ruby
|
30
|
+
# type_key('MyObject')
|
31
|
+
# # is equivalent to
|
32
|
+
# field :type, SoberSwag::Serializer::Primitive.new(SoberSwag::Types::String.enum('MyObject')) do |_, _|
|
33
|
+
# 'MyObject'
|
34
|
+
# end
|
35
|
+
# ```
|
36
|
+
# @param str [String, Symbol] the value to serialize (will be converted to a string)
|
37
|
+
# @param
|
38
|
+
def type_key(str, field_name: :type)
|
39
|
+
str = str.to_s
|
40
|
+
field(
|
41
|
+
field_name,
|
42
|
+
SoberSwag::Serializer::Primitive.new(
|
43
|
+
SoberSwag::Types::String.enum(str)
|
44
|
+
)
|
45
|
+
) { |_, _| str }
|
46
|
+
end
|
47
|
+
|
22
48
|
##
|
23
49
|
# Adds a new field to the fields array
|
24
50
|
# @param field [SoberSwag::OutputObject::Field]
|
@@ -37,6 +37,7 @@ module SoberSwag
|
|
37
37
|
# the correct thing, with the name you give it. This works for now, though.
|
38
38
|
#
|
39
39
|
# @return [Class] the serializer generated.
|
40
|
+
# @yieldself [SoberSwag::OutputObject::Definition]
|
40
41
|
def self.define(&block)
|
41
42
|
d = Definition.new.tap do |o|
|
42
43
|
o.instance_eval(&block)
|
@@ -99,23 +100,12 @@ module SoberSwag
|
|
99
100
|
# and {SoberSwag::Serializer::FieldList} to do the actual serialization.
|
100
101
|
#
|
101
102
|
# @todo: optimize view selection to use binary instead of linear search
|
102
|
-
def serializer
|
103
|
+
def serializer
|
103
104
|
@serializer ||=
|
104
105
|
begin
|
105
|
-
views.
|
106
|
-
|
107
|
-
|
108
|
-
proc do |object, options|
|
109
|
-
if options[:view].to_s == view.name.to_s
|
110
|
-
[:left, object]
|
111
|
-
else
|
112
|
-
[:right, object]
|
113
|
-
end
|
114
|
-
end,
|
115
|
-
view_serializer,
|
116
|
-
base
|
117
|
-
)
|
118
|
-
end
|
106
|
+
view_choices = views.map { |view| [view.name.to_s, view.serializer] }.to_h
|
107
|
+
view_choices['base'] = base_serializer
|
108
|
+
SoberSwag::Serializer::Hash.new(view_choices, base, proc { |_, options| options[:view]&.to_s })
|
119
109
|
end
|
120
110
|
end
|
121
111
|
|
@@ -27,9 +27,11 @@ module SoberSwag
|
|
27
27
|
# @param options [Hash] arbitrary options
|
28
28
|
# @return [Hash] serialized object.
|
29
29
|
def serialize(object, options = {})
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
{}.tap do |hash|
|
31
|
+
field_list.each do |field|
|
32
|
+
hash[field.name] = field.serializer.serialize(object, options)
|
33
|
+
end
|
34
|
+
end
|
33
35
|
end
|
34
36
|
|
35
37
|
##
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module SoberSwag
|
4
|
+
module Serializer
|
5
|
+
##
|
6
|
+
# Serialize via hash lookup.
|
7
|
+
# This is used to speed up serialization of views, but it may be useful elsewhere.
|
8
|
+
#
|
9
|
+
class Hash < Base
|
10
|
+
##
|
11
|
+
# @param choices [Hash<Object => SoberSwag::Serializer::Base>] hash of serializers
|
12
|
+
# that we might use.
|
13
|
+
# @param default [SoberSwag::Serializer::Base] default to use if key not found.
|
14
|
+
# @param key_proc [Proc<Object, Hash>] extract the key we are interested in from the proc.
|
15
|
+
# Will be called with the object to serialize and the options hash.
|
16
|
+
def initialize(choices, default, key_proc)
|
17
|
+
@choices = choices
|
18
|
+
@default = default
|
19
|
+
@key_proc = key_proc
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :choices, :default, :key_proc
|
23
|
+
|
24
|
+
def serialize(object, options = {})
|
25
|
+
key = key_proc.call(object, options)
|
26
|
+
|
27
|
+
choices.fetch(key) { default }.serialize(object, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# @return [Set<SoberSwag::Serializer::Base>]
|
32
|
+
def possible_serializers
|
33
|
+
@possible_serializers ||= (choices.values + [default]).to_set
|
34
|
+
end
|
35
|
+
|
36
|
+
def lazy_type?
|
37
|
+
possible_serializers.any?(&:lazy_type?)
|
38
|
+
end
|
39
|
+
|
40
|
+
def finalize_lazy_type!
|
41
|
+
possible_serializers.each(&:finalize_lazy_type!)
|
42
|
+
end
|
43
|
+
|
44
|
+
def lazy_type
|
45
|
+
@lazy_type ||= possible_serializers.map(&:lazy_type).reduce(:|)
|
46
|
+
end
|
47
|
+
|
48
|
+
def type
|
49
|
+
@type ||= possible_serializers.map(&:type).reduce(:|)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -10,6 +10,7 @@ module SoberSwag
|
|
10
10
|
autoload(:Mapped, 'sober_swag/serializer/mapped')
|
11
11
|
autoload(:Optional, 'sober_swag/serializer/optional')
|
12
12
|
autoload(:FieldList, 'sober_swag/serializer/field_list')
|
13
|
+
autoload(:Hash, 'sober_swag/serializer/hash')
|
13
14
|
autoload(:Meta, 'sober_swag/serializer/meta')
|
14
15
|
|
15
16
|
class << self
|
data/lib/sober_swag/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sober_swag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.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: 2021-
|
11
|
+
date: 2021-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -173,6 +173,7 @@ extra_rdoc_files: []
|
|
173
173
|
files:
|
174
174
|
- ".github/config/rubocop_linter_action.yml"
|
175
175
|
- ".github/dependabot.yml"
|
176
|
+
- ".github/workflows/benchmark.yml"
|
176
177
|
- ".github/workflows/lint.yml"
|
177
178
|
- ".github/workflows/ruby.yml"
|
178
179
|
- ".gitignore"
|
@@ -186,6 +187,9 @@ files:
|
|
186
187
|
- LICENSE.txt
|
187
188
|
- README.md
|
188
189
|
- Rakefile
|
190
|
+
- bench/benchmark.rb
|
191
|
+
- bench/benchmarks/basic_field_serializer.rb
|
192
|
+
- bench/benchmarks/view_selection.rb
|
189
193
|
- bin/console
|
190
194
|
- bin/rspec
|
191
195
|
- bin/setup
|
@@ -284,6 +288,7 @@ files:
|
|
284
288
|
- lib/sober_swag/serializer/base.rb
|
285
289
|
- lib/sober_swag/serializer/conditional.rb
|
286
290
|
- lib/sober_swag/serializer/field_list.rb
|
291
|
+
- lib/sober_swag/serializer/hash.rb
|
287
292
|
- lib/sober_swag/serializer/mapped.rb
|
288
293
|
- lib/sober_swag/serializer/meta.rb
|
289
294
|
- lib/sober_swag/serializer/optional.rb
|