transmutation 0.2.2 → 0.3.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +152 -10
- data/lib/transmutation/serialization/lookup.rb +3 -9
- data/lib/transmutation/serialization/rendering.rb +3 -3
- data/lib/transmutation/serialization.rb +11 -3
- data/lib/transmutation/serializer.rb +83 -30
- data/lib/transmutation/version.rb +1 -1
- data/transmutation.gemspec +1 -0
- metadata +3 -3
- data/lib/transmutation/collection_serializer.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1184809d63cb5abaad091e433a5e150579f5ca634a5522c57b7dd49c3465a3c
|
4
|
+
data.tar.gz: a0e2bddde883737a82369d14cd4bc75235ea1dee366c7a0234a262e29930a74c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee23262517dba8436c182542b02bd3e1b15df0225b84eae7dedb106c4d155cf6dd78db791e9a98d44c57654dcf87d9aa8110e87cde6bface0943952199f8e2a5
|
7
|
+
data.tar.gz: 8b23bfbd305587fde6d6fef4a714840a73e4415d27902c3169dd06561f141b127944d64f13029a37f9aaf10d88bdab5b1059554ae132fc4584c899f6ecb3148e
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,19 +2,29 @@
|
|
2
2
|
|
3
3
|
Transmutation is a Ruby gem that provides a simple way to serialize Ruby objects into JSON.
|
4
4
|
|
5
|
-
It takes inspiration from the [Active Model Serializers](https://github.com/rails-api/active_model_serializers) gem, but strips away adapters.
|
5
|
+
It also adds an opinionated way to automatically find and use serializer classes based on the object's class name and the caller's namespace - it takes inspiration from the [Active Model Serializers](https://github.com/rails-api/active_model_serializers) gem, but strips away adapters.
|
6
6
|
|
7
7
|
It aims to be a performant and elegant solution for serializing Ruby objects into JSON, with a touch of opinionated "magic" :sparkles:.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
-
Install the gem and add to
|
11
|
+
Install the gem and add to your application's Gemfile by executing:
|
12
12
|
|
13
|
-
|
13
|
+
```bash
|
14
|
+
bundle add transmutation
|
15
|
+
```
|
16
|
+
|
17
|
+
or manually add the following to your Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem "transmutation"
|
21
|
+
```
|
14
22
|
|
15
23
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
16
24
|
|
17
|
-
|
25
|
+
```bash
|
26
|
+
gem install transmutation
|
27
|
+
```
|
18
28
|
|
19
29
|
## Usage
|
20
30
|
|
@@ -48,13 +58,16 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
48
58
|
|
49
59
|
As long as your object responds to the attributes defined in the serializer, it can be serialized.
|
50
60
|
|
51
|
-
|
61
|
+
<details>
|
62
|
+
<summary>Struct</summary>
|
52
63
|
|
53
64
|
```ruby
|
54
65
|
User = Struct.new(:id, :name, :email)
|
55
66
|
```
|
67
|
+
</details>
|
56
68
|
|
57
|
-
|
69
|
+
<details>
|
70
|
+
<summary>Class</summary>
|
58
71
|
|
59
72
|
```ruby
|
60
73
|
class User
|
@@ -67,8 +80,10 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
67
80
|
end
|
68
81
|
end
|
69
82
|
```
|
83
|
+
</details>
|
70
84
|
|
71
|
-
|
85
|
+
<details>
|
86
|
+
<summary>ActiveRecord</summary>
|
72
87
|
|
73
88
|
```ruby
|
74
89
|
# == Schema Information
|
@@ -81,15 +96,142 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
81
96
|
class User < ApplicationRecord
|
82
97
|
end
|
83
98
|
```
|
99
|
+
</details>
|
100
|
+
|
101
|
+
### The `#serialize` method
|
102
|
+
|
103
|
+
When you include the `Transmutation::Serialization` module in your class, you can use the `#serialize` method to serialize an object.
|
104
|
+
|
105
|
+
It will attempt to find a serializer class based on the object's class name along with the caller's namespace.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
include Transmutation::Serialization
|
109
|
+
|
110
|
+
serialize(User.new) # => UserSerializer.new(User.new)
|
111
|
+
```
|
112
|
+
|
113
|
+
If no serializer class is found, it will return the object as is.
|
114
|
+
|
115
|
+
### With Ruby on Rails
|
116
|
+
|
117
|
+
When then `Transmutation::Serialization` module is included in a Rails controller, it also extends your `render` calls.
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
class Api::V1::UsersController < ApplicationController
|
121
|
+
include Transmutation::Serialization
|
122
|
+
|
123
|
+
def show
|
124
|
+
user = User.find(params[:id])
|
84
125
|
|
85
|
-
|
126
|
+
render json: user
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
This will attempt to bubble up the controller namespaces to find a defined serializer class:
|
132
|
+
|
133
|
+
- `Api::V1::UserSerializer`
|
134
|
+
- `Api::UserSerializer`
|
135
|
+
- `UserSerializer`
|
136
|
+
|
137
|
+
This calls the `#serialize` method under the hood.
|
138
|
+
|
139
|
+
If no serializer class is found, it will fall back to the default behavior of rendering the object as JSON.
|
140
|
+
|
141
|
+
You can disable this behaviour by passing `serialize: false` to the `render` method.
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
render json: user, serialize: false # => user.to_json
|
145
|
+
```
|
146
|
+
|
147
|
+
## Configuration
|
148
|
+
|
149
|
+
You can override the serialization lookup by passing the following options:
|
150
|
+
|
151
|
+
- `namespace`: The namespace to use when looking up the serializer class.
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
render json: user, namespace: "V1" # => Api::V1::V1::UserSerializer
|
155
|
+
```
|
156
|
+
|
157
|
+
To prevent caller namespaces from being appended to the provided namespace, prefix the namespace with `::`.
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
render json: user, namespace: "::V1" # => V1::UserSerializer
|
161
|
+
```
|
162
|
+
|
163
|
+
The `namespace` key is forwarded to the `#serialize` method.
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
render json: user, namespace: "V1" # => serialize(user, namespace: "V1")
|
167
|
+
```
|
168
|
+
|
169
|
+
- `serializer`: The serializer class to use.
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
render json: user, serializer: "SuperUserSerializer" # => Api::V1::SuperUserSerializer
|
173
|
+
```
|
174
|
+
|
175
|
+
To prevent all namespaces from being appended to the serializer class, prefix the serializer class with `::`.
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
render json: user, serializer: "::SuperUserSerializer" # => SuperUserSerializer
|
179
|
+
```
|
180
|
+
|
181
|
+
The `serializer` key is forwarded to the `#serialize` method.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
render json: user, serializer: "SuperUserSerializer" # => serialize(user, serializer: "SuperUserSerializer")
|
185
|
+
```
|
186
|
+
|
187
|
+
## Opinionated Architecture
|
188
|
+
|
189
|
+
If you follow the pattern outlined below, you can take full advantage of the automatic serializer lookup.
|
190
|
+
|
191
|
+
### File Structure
|
192
|
+
|
193
|
+
```
|
194
|
+
.
|
195
|
+
└── app/
|
196
|
+
├── controllers/
|
197
|
+
│ └── api/
|
198
|
+
│ ├── v1/
|
199
|
+
│ │ └── users_controller.rb
|
200
|
+
│ └── v2
|
201
|
+
│ └── users_controller.rb
|
202
|
+
├── models/
|
203
|
+
│ └── user.rb
|
204
|
+
└── serializers/
|
205
|
+
└── api/
|
206
|
+
├── v1/
|
207
|
+
│ └── user_serializer.rb
|
208
|
+
├── v2/
|
209
|
+
│ └── user_serializer.rb
|
210
|
+
└── user_serializer.rb
|
211
|
+
```
|
212
|
+
|
213
|
+
### Serializers
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
class Api::UserSerializer < Transmutation::Serializer
|
217
|
+
attributes :id, :name, :email
|
218
|
+
end
|
219
|
+
|
220
|
+
class Api::V1::UserSerializer < Api::UserSerializer
|
221
|
+
attributes :phone # Added in V1
|
222
|
+
end
|
223
|
+
|
224
|
+
class Api::V2::UserSerializer < Api::UserSerializer
|
225
|
+
attributes :avatar # Added in V2
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
To remove attributes, it is recommended to redefine all attributes and start anew. This acts as a reset and makes serializer inheritance much easier to follow.
|
86
230
|
|
87
231
|
## Development
|
88
232
|
|
89
233
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
90
234
|
|
91
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
92
|
-
|
93
235
|
## Contributing
|
94
236
|
|
95
237
|
Bug reports and pull requests are welcome on GitHub at https://github.com/spellbook-technology/transmutation. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/spellbook-technology/transmutation/blob/main/CODE_OF_CONDUCT.md).
|
@@ -12,9 +12,9 @@ module Transmutation
|
|
12
12
|
# Bubbles up the namespace until we find a matching serializer.
|
13
13
|
#
|
14
14
|
# @see Transmutation::Serialization#lookup_serializer
|
15
|
+
# @note This never bubbles up the object's namespace, only the caller's namespace.
|
15
16
|
#
|
16
|
-
#
|
17
|
-
#
|
17
|
+
# @example
|
18
18
|
# namespace: Api::V1::Admin::Detailed
|
19
19
|
# serializer: Chat::User
|
20
20
|
#
|
@@ -25,11 +25,7 @@ module Transmutation
|
|
25
25
|
# - Api::V1::Chat::UserSerializer
|
26
26
|
# - Api::Chat::UserSerializer
|
27
27
|
# - Chat::UserSerializer
|
28
|
-
#
|
29
|
-
# Note: This never bubbles up the object's namespace, only the caller's namespace.
|
30
28
|
def serializer_for(object, serializer: nil)
|
31
|
-
return Transmutation::CollectionSerializer if object.respond_to?(:map)
|
32
|
-
|
33
29
|
serializer_name = serializer_name_for(object, serializer: serializer)
|
34
30
|
|
35
31
|
return constantize_serializer!(Object, serializer_name, object: object) if serializer_name.start_with?("::")
|
@@ -38,7 +34,7 @@ module Transmutation
|
|
38
34
|
return potential_namespace.const_get(serializer_name) if potential_namespace.const_defined?(serializer_name)
|
39
35
|
end
|
40
36
|
|
41
|
-
raise SerializerNotFound.new(
|
37
|
+
raise SerializerNotFound.new(object, namespace: serializer_namespace, name: serializer_name)
|
42
38
|
end
|
43
39
|
|
44
40
|
# Returns the highest specificity serializer name for the given object.
|
@@ -47,8 +43,6 @@ module Transmutation
|
|
47
43
|
#
|
48
44
|
# @return [String] The serializer name.
|
49
45
|
def serializer_name_for(object, serializer: nil)
|
50
|
-
return "::Transmutation::CollectionSerializer" if object.respond_to?(:map)
|
51
|
-
|
52
46
|
"#{serializer&.delete_suffix("Serializer") || object.class.name}Serializer"
|
53
47
|
end
|
54
48
|
|
@@ -3,11 +3,11 @@
|
|
3
3
|
module Transmutation
|
4
4
|
module Serialization
|
5
5
|
module Rendering
|
6
|
-
def render(json: nil, serialize: true, **args)
|
6
|
+
def render(json: nil, serialize: true, namespace: nil, serializer: nil, max_depth: 1, **args)
|
7
7
|
return super(**args) unless json
|
8
|
-
return super(json: json
|
8
|
+
return super(**args, json: json) unless serialize
|
9
9
|
|
10
|
-
super(**args, json: serialize(json))
|
10
|
+
super(**args, json: serialize(json, namespace: namespace, serializer: serializer, max_depth: max_depth))
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -8,10 +8,18 @@ module Transmutation
|
|
8
8
|
# @param object [Object] The object to serialize.
|
9
9
|
# @param namespace [String, Symbol, Module] The namespace to lookup the serializer in.
|
10
10
|
# @param serializer [String, Symbol, Class] The serializer to use.
|
11
|
+
# @param max_depth [Integer] The maximum depth of nested associations to serialize.
|
11
12
|
#
|
12
13
|
# @return [Transmutation::Serializer] The serialized object. This will respond to `#as_json` and `#to_json`.
|
13
|
-
def serialize(object, namespace: nil, serializer: nil)
|
14
|
-
|
14
|
+
def serialize(object, namespace: nil, serializer: nil, depth: 0, max_depth: 1)
|
15
|
+
if object.respond_to?(:map)
|
16
|
+
return object.map do |item|
|
17
|
+
serialize(item, namespace: namespace, serializer: serializer, depth: depth, max_depth: max_depth)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
lookup_serializer(object, namespace: namespace, serializer: serializer)
|
22
|
+
.new(object, depth: depth, max_depth: max_depth)
|
15
23
|
end
|
16
24
|
|
17
25
|
# Lookup the serializer for the given object.
|
@@ -29,7 +37,7 @@ module Transmutation
|
|
29
37
|
end
|
30
38
|
|
31
39
|
private_class_method def self.included(base)
|
32
|
-
base.include(Rendering) if base.
|
40
|
+
base.include(Rendering) if base.method_defined?(:render)
|
33
41
|
end
|
34
42
|
end
|
35
43
|
end
|
@@ -10,12 +10,20 @@ module Transmutation
|
|
10
10
|
# attribute :full_name do
|
11
11
|
# "#{object.first_name} #{object.last_name}".strip
|
12
12
|
# end
|
13
|
+
#
|
14
|
+
# belongs_to :organization
|
15
|
+
#
|
16
|
+
# has_many :posts
|
13
17
|
# end
|
14
18
|
class Serializer
|
15
19
|
extend ClassAttributes
|
16
20
|
|
17
|
-
|
21
|
+
include Transmutation::Serialization
|
22
|
+
|
23
|
+
def initialize(object, depth: 0, max_depth: 1)
|
18
24
|
@object = object
|
25
|
+
@depth = depth
|
26
|
+
@max_depth = max_depth
|
19
27
|
end
|
20
28
|
|
21
29
|
def to_json(options = {})
|
@@ -24,39 +32,84 @@ module Transmutation
|
|
24
32
|
|
25
33
|
def as_json(_options = {})
|
26
34
|
attributes_config.each_with_object({}) do |(attr_name, attr_options), hash|
|
27
|
-
|
35
|
+
if attr_options[:association]
|
36
|
+
hash[attr_name.to_s] = instance_exec(&attr_options[:block]) if @depth + 1 <= @max_depth
|
37
|
+
else
|
38
|
+
hash[attr_name.to_s] = attr_options[:block] ? instance_exec(&attr_options[:block]) : object.send(attr_name)
|
39
|
+
end
|
28
40
|
end
|
29
41
|
end
|
30
42
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
class << self
|
44
|
+
# Define an attribute to be serialized
|
45
|
+
#
|
46
|
+
# @param attribute_name [Symbol] The name of the attribute to serialize
|
47
|
+
# @param block [Proc] The block to call to get the value of the attribute
|
48
|
+
# - The block is called in the context of the serializer instance
|
49
|
+
#
|
50
|
+
# @example
|
51
|
+
# class UserSerializer < Transmutation::Serializer
|
52
|
+
# attribute :first_name
|
53
|
+
#
|
54
|
+
# attribute :full_name do
|
55
|
+
# "#{object.first_name} #{object.last_name}".strip
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
def attribute(attribute_name, &block)
|
59
|
+
attributes_config[attribute_name] = { block: block }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Define an association to be serialized
|
63
|
+
#
|
64
|
+
# @note By default, the serializer for the association is looked up in the same namespace as the serializer
|
65
|
+
#
|
66
|
+
# @param association_name [Symbol] The name of the association to serialize
|
67
|
+
# @param namespace [String, Symbol, Module] The namespace to lookup the association's serializer in
|
68
|
+
# @param serializer [String, Symbol, Class] The serializer to use for the association's serialization
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# class UserSerializer < Transmutation::Serializer
|
72
|
+
# association :posts
|
73
|
+
# association :comments, namespace: "Nested", serializer: "User::CommentSerializer"
|
74
|
+
# end
|
75
|
+
def association(association_name, namespace: nil, serializer: nil)
|
76
|
+
block = lambda do
|
77
|
+
serialize(object.send(association_name), namespace: namespace, serializer: serializer, depth: @depth + 1)
|
78
|
+
end
|
79
|
+
|
80
|
+
attributes_config[association_name] = { block: block, association: true }
|
81
|
+
end
|
82
|
+
|
83
|
+
alias belongs_to association
|
84
|
+
alias has_one association
|
85
|
+
alias has_many association
|
86
|
+
|
87
|
+
# Shorthand for defining multiple attributes
|
88
|
+
#
|
89
|
+
# @param attribute_names [Array<Symbol>] The names of the attributes to serialize
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# class UserSerializer < Transmutation::Serializer
|
93
|
+
# attributes :first_name, :last_name
|
94
|
+
# end
|
95
|
+
def attributes(*attribute_names)
|
96
|
+
attribute_names.each do |attribute_name|
|
97
|
+
attribute(attribute_name)
|
98
|
+
end
|
99
|
+
end
|
48
100
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
101
|
+
# Shorthand for defining multiple associations
|
102
|
+
#
|
103
|
+
# @param association_names [Array<Symbol>] The names of the associations to serialize
|
104
|
+
#
|
105
|
+
# @example
|
106
|
+
# class UserSerializer < Transmutation::Serializer
|
107
|
+
# associations :posts, :comments
|
108
|
+
# end
|
109
|
+
def associations(*association_names)
|
110
|
+
association_names.each do |association_name|
|
111
|
+
association(association_name)
|
112
|
+
end
|
60
113
|
end
|
61
114
|
end
|
62
115
|
|
data/transmutation.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.metadata["homepage_uri"] = spec.homepage
|
17
17
|
spec.metadata["source_code_uri"] = "https://github.com/spellbook-technology/transmutation"
|
18
18
|
spec.metadata["changelog_uri"] = "https://github.com/spellbook-technology/transmutation/CHANGELOG.md"
|
19
|
+
spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/transmutation"
|
19
20
|
|
20
21
|
# Specify which files should be added to the gem when it is released.
|
21
22
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: transmutation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nitemaeric
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-06-
|
12
|
+
date: 2024-06-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: zeitwerk
|
@@ -46,7 +46,6 @@ files:
|
|
46
46
|
- Rakefile
|
47
47
|
- lib/transmutation.rb
|
48
48
|
- lib/transmutation/class_attributes.rb
|
49
|
-
- lib/transmutation/collection_serializer.rb
|
50
49
|
- lib/transmutation/serialization.rb
|
51
50
|
- lib/transmutation/serialization/lookup.rb
|
52
51
|
- lib/transmutation/serialization/lookup/serializer_not_found.rb
|
@@ -62,6 +61,7 @@ metadata:
|
|
62
61
|
homepage_uri: https://github.com/spellbook-technology/transmutation
|
63
62
|
source_code_uri: https://github.com/spellbook-technology/transmutation
|
64
63
|
changelog_uri: https://github.com/spellbook-technology/transmutation/CHANGELOG.md
|
64
|
+
documentation_uri: https://rubydoc.info/gems/transmutation
|
65
65
|
post_install_message:
|
66
66
|
rdoc_options: []
|
67
67
|
require_paths:
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Transmutation
|
4
|
-
# Out-of-the-box collection serializer.
|
5
|
-
#
|
6
|
-
# This serializer will be used to serialize all collections of objects.
|
7
|
-
#
|
8
|
-
# @example Basic usage
|
9
|
-
# Transmutation::CollectionSerializer.new([object, object]).to_json
|
10
|
-
class CollectionSerializer
|
11
|
-
include Transmutation::Serialization
|
12
|
-
|
13
|
-
def initialize(objects, namespace: nil, serializer: nil)
|
14
|
-
@objects = objects
|
15
|
-
@namespace = namespace
|
16
|
-
@serializer = serializer
|
17
|
-
end
|
18
|
-
|
19
|
-
def as_json(options = {})
|
20
|
-
objects.map { |item| serialize(item, namespace: namespace, serializer: serializer).as_json(options) }
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_json(options = {})
|
24
|
-
as_json(options).to_json
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
attr_reader :objects, :namespace, :serializer
|
30
|
-
end
|
31
|
-
end
|