alba 0.12.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee2f8d482fedb98083c2acab37b425c7ecedb429ab7bae7698b4eea7949635d9
4
- data.tar.gz: 1a44f23d425072253ba6743e18c6da9d8fa81de448b58720848c4e9667b12bfb
3
+ metadata.gz: 36890dfa4b9b73b60f1d6a09cf674de7ff7a6dd495ff4b74bbb3d048f9cf5a85
4
+ data.tar.gz: 3e3d49619f646be866262e14e21e5fba11e2caafbc24064d57eb9c549cb64e4d
5
5
  SHA512:
6
- metadata.gz: 9bf421fcd99f06cb56499ee31c88dda019e004c58a1880c03326f2a1ce395f7dc4b64be7cee012169c7039530194e85a312b3c53d964b1aaf5288cdf8cb78ae4
7
- data.tar.gz: 02f20dd839f72f9d2c1859b48470595fff263939f41421e240d74452677edae2dc0569078823984144f630cbc2e6000b6ac3bd0d4161a9ef65bd95dbf311294f
6
+ metadata.gz: fc7e025a035b41dadaab5300096cf920eb3557a4be900d31b514dfc66e8ae803b0fb63d77ec06174d72d70ad2e07da81c491502c8462ad306f2379720222fc65
7
+ data.tar.gz: 741f5c1c69b2809aec51d2a2a139d4d8e00060c9aa174bf5fb68d5dbcec7996096aced5fb377d77fa147d7b6086a65191c8c764802c65bbd88d3806751ec0eb4
@@ -0,0 +1,34 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ os: [ubuntu-latest, windows-latest, macos-latest]
11
+ ruby: [2.5, 2.6, 2.7, 3.0, head, jruby, truffleruby]
12
+ gemfile: [all, without_active_support, without_oj]
13
+ exclude:
14
+ - os: windows-latest
15
+ ruby: jruby
16
+ - os: windows-latest
17
+ ruby: truffleruby
18
+ runs-on: ${{ matrix.os }}
19
+ env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
20
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ - name: Set up Ruby
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby }}
27
+ bundler-cache: true
28
+ - name: Run the default task
29
+ run: |
30
+ bundle exec rake
31
+ - name: CodeCov
32
+ uses: codecov/codecov-action@v1
33
+ with:
34
+ files: ./coverage/coverage.xml
data/.gitignore CHANGED
@@ -6,3 +6,6 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+
10
+ Gemfile.lock
11
+ /gemfiles/*.lock
data/.rubocop.yml CHANGED
@@ -12,8 +12,10 @@ AllCops:
12
12
  Exclude:
13
13
  - 'Rakefile'
14
14
  - 'alba.gemspec'
15
+ - 'benchmark/**/*.rb'
15
16
  NewCops: enable
16
17
  EnabledByDefault: true
18
+ TargetRubyVersion: 2.5
17
19
 
18
20
  # Oneline comment is not valid so until it gets valid, we disable it
19
21
  Bundler/GemComment:
@@ -28,13 +30,29 @@ Layout/MultilineAssignmentLayout:
28
30
  Lint/ConstantResolution:
29
31
  Enabled: false
30
32
 
31
- Metrics/ClassLength:
33
+ # In test code we don't care about the metrics!
34
+ Metrics:
32
35
  Exclude:
33
- - 'test/alba_test.rb'
36
+ - 'test/**/*.rb'
34
37
 
35
38
  Metrics/MethodLength:
36
39
  Max: 15
37
40
 
41
+ # `Resource` module is a core module and its length tends to be long...
42
+ Metrics/ModuleLength:
43
+ Max: 150
44
+
45
+ # Resource class includes DSLs, which tend to accept long list of parameters
46
+ Metrics/ParameterLists:
47
+ Exclude:
48
+ - 'lib/alba/resource.rb'
49
+ - 'test/**/*.rb'
50
+
51
+ # We need to eval resource code to test errors on resource classes
52
+ Security/Eval:
53
+ Exclude:
54
+ - 'test/**/*.rb'
55
+
38
56
  Style/ConstantVisibility:
39
57
  Exclude:
40
58
  - 'lib/alba/version.rb'
@@ -42,6 +60,10 @@ Style/ConstantVisibility:
42
60
  Style/Copyright:
43
61
  Enabled: false
44
62
 
63
+ # I know what I do :)
64
+ Style/DisableCopsWithinSourceCodeDirective:
65
+ Enabled: false
66
+
45
67
  Style/FrozenStringLiteralComment:
46
68
  Enabled: false
47
69
 
@@ -50,3 +72,7 @@ Style/InlineComment:
50
72
 
51
73
  Style/MethodCallWithArgsParentheses:
52
74
  Enabled: false
75
+
76
+ # There are so many cases we just want `if` expression!
77
+ Style/MissingElse:
78
+ EnforcedStyle: case
data/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.1.0] - 2021-04-23
10
+
11
+ - [Feat] Implement circular associations control [71e1543]
12
+ - [Feat] Support :oj_rails backend [76e519e]
13
+
14
+ ## [1.0.1] - 2021-04-15
15
+
16
+ - [Fix] Don't cache resource class for `Alba.serialize` [9ed5253]
17
+ - [Improve] Warn when `ActiveSupport` or `Oj` are absent [d3ab3eb]
18
+ - [Fix] Delete unreachable `to_hash` method on Association [1ba1f90]
19
+ - [Fix] Stringify key before transforming [b4eb79e]
20
+ - [Misc] Support Ruby 2.5.0 and above, not 2.5.7 and above [43f1d17]
21
+ - [Fix] Remove accidentally added `p` debug [5d0324b]
22
+
23
+ ## [1.0.0] - 2021-04-07
24
+
25
+ This is the first major release of Alba and it includes so many features. To see all the features you can have a look at [README](https://github.com/okuramasafumi/alba/blob/master/README.md#features).
data/Gemfile CHANGED
@@ -4,13 +4,19 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'activesupport', require: false # For backend
7
- gem 'coveralls', require: false # For test coverage
7
+ gem 'ffaker', require: false # For testing
8
8
  gem 'minitest', '~> 5.14' # For test
9
- gem 'oj', '~> 3.11', platform: :ruby, require: false # For backend
10
9
  gem 'rake', '~> 13.0' # For test and automation
11
10
  gem 'rubocop', '>= 0.79.0', require: false # For lint
12
- gem 'rubocop-minitest', '~> 0.10.3', require: false # For lint
13
- gem 'rubocop-performance', '~> 1.9.2', require: false # For lint
11
+ gem 'rubocop-minitest', '~> 0.11.0', require: false # For lint
12
+ gem 'rubocop-performance', '~> 1.11.0', require: false # For lint
14
13
  gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
15
14
  gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
15
+ gem 'simplecov', '~> 0.21.0', require: false # For test coverage
16
+ gem 'simplecov-cobertura', require: false # For test coverage
16
17
  gem 'yard', require: false
18
+
19
+ platforms :ruby do
20
+ gem 'oj', '~> 3.11', require: false # For backend
21
+ gem 'ruby-prof', require: false # For performance profiling
22
+ end
data/README.md CHANGED
@@ -1,29 +1,37 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/alba.svg)](https://badge.fury.io/rb/alba)
2
- [![Build Status](https://travis-ci.com/okuramasafumi/alba.svg?branch=master)](https://travis-ci.com/okuramasafumi/alba)
3
- [![Coverage Status](https://coveralls.io/repos/github/okuramasafumi/alba/badge.svg?branch=master)](https://coveralls.io/github/okuramasafumi/alba?branch=master)
2
+ [![CI](https://github.com/okuramasafumi/alba/actions/workflows/main.yml/badge.svg)](https://github.com/okuramasafumi/alba/actions/workflows/main.yml)
3
+ [![codecov](https://codecov.io/gh/okuramasafumi/alba/branch/master/graph/badge.svg?token=3D3HEZ5OXT)](https://codecov.io/gh/okuramasafumi/alba)
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/fdab4cc0de0b9addcfe8/maintainability)](https://codeclimate.com/github/okuramasafumi/alba/maintainability)
5
5
  ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/okuramasafumi/alba)
6
6
  ![GitHub](https://img.shields.io/github/license/okuramasafumi/alba)
7
7
 
8
8
  # Alba
9
9
 
10
- `Alba` is the fastest JSON serializer for Ruby.
10
+ Alba is the fastest JSON serializer for Ruby, JRuby, and TruffleRuby.
11
11
 
12
- ## Why yet another JSON serializer?
12
+ ## Discussions
13
13
 
14
- We know that there are several other JSON serializers for Ruby around, but none of them made us satisfied.
14
+ Alba uses [GitHub Discussions](https://github.com/okuramasafumi/alba/discussions) to openly discuss the project.
15
15
 
16
- Alba has some advantages over other JSON serializers which we've wanted to have.
16
+ If you've already used Alba, please consider posting your thoughts and feelings on [Feedback](https://github.com/okuramasafumi/alba/discussions/categories/feedback). The fact that you enjoy using Alba gives me energy to keep developing Alba!
17
17
 
18
- ### Easy to understand
18
+ If you have feature requests or interesting ideas, join us with [Ideas](https://github.com/okuramasafumi/alba/discussions/categories/ideas). Let's make Alba even better, together!
19
19
 
20
- DSL is great. It makes the coding experience natural and intuitive. However, remembering lots of DSL requires us a lot of effort. Unfortunately, most of the existing libraries have implemented their features via DSL and it's not easy to understand how they behave entirely. Alba's core DSL are only four (`attributes`, `attribute`, `one` and `many`) so it's easy to understand how to use.
20
+ ## Why Alba?
21
21
 
22
- Alba is also understandable internally. The codebase is much smaller than the alternatives. In fact, it's less than 300 lines of code. Look at the code on [GitHub](https://github.com/okuramasafumi/alba/tree/master/lib) and you'll be surprised how simple it is!
22
+ Because it's fast, flexible and well-maintained!
23
23
 
24
- ### Performance
24
+ ### Fast
25
25
 
26
- Alba is faster than most of the alternatives. We have a [benchmark](https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829).
26
+ Alba is faster than most of the alternatives. We have a [benchmark](https://github.com/okuramasafumi/alba/tree/master/benchmark).
27
+
28
+ ### Flexible
29
+
30
+ Alba provides a small set of DSL to define your serialization logic. It also provides methods you can override to alter and filter serialized hash so that you have full control over the result.
31
+
32
+ ### Maintained
33
+
34
+ Alba is well-maintained and adds features quickly. [Coverage Status](https://coveralls.io/github/okuramasafumi/alba?branch=master) and [CodeClimate Maintainability](https://codeclimate.com/github/okuramasafumi/alba/maintainability) show the code base is quite healthy.
27
35
 
28
36
  ## Installation
29
37
 
@@ -43,11 +51,11 @@ Or install it yourself as:
43
51
 
44
52
  ## Supported Ruby versions
45
53
 
46
- Alba supports CRuby 2.5.7 and higher and latest TruffleRuby.
54
+ Alba supports CRuby 2.5 and higher and latest JRuby and TruffleRuby.
47
55
 
48
56
  ## Documentation
49
57
 
50
- You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
58
+ You can find the documentation on [RubyDoc](https://rubydoc.info/github/okuramasafumi/alba).
51
59
 
52
60
  ## Features
53
61
 
@@ -56,9 +64,13 @@ You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
56
64
  * One and many association with the ability to define them inline
57
65
  * Adding condition and filter to association
58
66
  * Parameters can be injected and used in attributes and associations
59
- * Setting root key separately in Serializer
60
- * Adding metadata
67
+ * Conditional attributes and associations
61
68
  * Selectable backend
69
+ * Key transformation
70
+ * Root key inference
71
+ * Error handling
72
+ * Resource name inflection based on association name
73
+ * Circular associations control
62
74
  * No runtime dependencies
63
75
 
64
76
  ## Anti features
@@ -68,7 +80,6 @@ You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
68
80
  * Supporting all existing JSON encoder/decoder
69
81
  * Cache
70
82
  * [JSON:API](https://jsonapi.org) support
71
- * Association name inflection
72
83
  * And many others
73
84
 
74
85
  ## Usage
@@ -77,7 +88,7 @@ You can find the documentation on [RubyDoc](https://rubydoc.info/gems/alba).
77
88
 
78
89
  Alba's configuration is fairly simple.
79
90
 
80
- #### Backend
91
+ #### Backend configuration
81
92
 
82
93
  Backend is the actual part serializing an object into JSON. Alba supports these backends.
83
94
 
@@ -91,6 +102,26 @@ You can set a backend like this:
91
102
  Alba.backend = :oj
92
103
  ```
93
104
 
105
+ #### Inference configuration
106
+
107
+ You can enable inference feature using `enable_inference!` method.
108
+
109
+ ```ruby
110
+ Alba.enable_inference!
111
+ ```
112
+
113
+ You must install `ActiveSupport` to enable inference.
114
+
115
+ #### Error handling configuration
116
+
117
+ You can configure error handling with `on_error` method.
118
+
119
+ ```ruby
120
+ Alba.on_error :ignore
121
+ ```
122
+
123
+ For the details, see [Error handling section](#error-handling)
124
+
94
125
  ### Simple serialization with key
95
126
 
96
127
  ```ruby
@@ -108,6 +139,8 @@ end
108
139
  class UserResource
109
140
  include Alba::Resource
110
141
 
142
+ key :user
143
+
111
144
  attributes :id, :name
112
145
 
113
146
  attribute :name_with_email do |resource|
@@ -115,12 +148,6 @@ class UserResource
115
148
  end
116
149
  end
117
150
 
118
- class SerializerWithKey
119
- include Alba::Serializer
120
-
121
- set key: :user
122
- end
123
-
124
151
  user = User.new(1, 'Masafumi OKURA', 'masafumi@example.com')
125
152
  UserResource.new(user).serialize
126
153
  # => "{\"id\":1,\"name\":\"Masafumi OKURA\",\"name_with_email\":\"Masafumi OKURA: masafumi@example.com\"}"
@@ -180,7 +207,7 @@ UserResource.new(user).serialize
180
207
  `Alba.serialize` method is a shortcut to define everything inline.
181
208
 
182
209
  ```ruby
183
- Alba.serialize(user, with: proc { set key: :foo }) do
210
+ Alba.serialize(user, key: :foo) do
184
211
  attributes :id
185
212
  many :articles do
186
213
  attributes :title, :body
@@ -189,7 +216,7 @@ end
189
216
  # => '{"foo":{"id":1,"articles":[{"title":"Hello World!","body":"Hello World!!!"},{"title":"Super nice","body":"Really nice!"}]}}'
190
217
  ```
191
218
 
192
- Although this might be useful sometimes, it's generally recommended to define a class for both Resource and Serializer.
219
+ Although this might be useful sometimes, it's generally recommended to define a class for Resource.
193
220
 
194
221
  ### Inheritance and Ignorance
195
222
 
@@ -221,10 +248,218 @@ RestrictedFooResouce.new(foo).serialize
221
248
  end
222
249
  ```
223
250
 
224
- ## Comparison
251
+ ### Attribute key transformation
252
+
253
+ ** Note: You need to install `active_support` gem to use `transform_keys` DSL.
254
+
255
+ With `active_support` installed, you can transform attribute keys.
256
+
257
+ ```ruby
258
+ class User
259
+ attr_reader :id, :first_name, :last_name
260
+
261
+ def initialize(id, first_name, last_name)
262
+ @id = id
263
+ @first_name = first_name
264
+ @last_name = last_name
265
+ end
266
+ end
267
+
268
+ class UserResource
269
+ include Alba::Resource
270
+
271
+ attributes :id, :first_name, :last_name
272
+
273
+ transform_keys :lower_camel
274
+ end
275
+
276
+ user = User.new(1, 'Masafumi', 'Okura')
277
+ UserResourceCamel.new(user).serialize
278
+ # => '{"id":1,"firstName":"Masafumi","lastName":"Okura"}'
279
+ ```
280
+
281
+ Supported transformation types are :camel, :lower_camel and :dash.
282
+
283
+ ### Filtering attributes
284
+
285
+ You can filter attributes by overriding `Alba::Resource#converter` method, but it's a bit tricky.
286
+
287
+ ```ruby
288
+ class User
289
+ attr_accessor :id, :name, :email, :created_at, :updated_at
290
+
291
+ def initialize(id, name, email)
292
+ @id = id
293
+ @name = name
294
+ @email = email
295
+ end
296
+ end
297
+
298
+ class UserResource
299
+ include Alba::Resource
300
+
301
+ attributes :id, :name, :email
302
+
303
+ private
304
+
305
+ # Here using `Proc#>>` method to compose a proc from `super`
306
+ def converter
307
+ super >> proc { |hash| hash.compact }
308
+ end
309
+ end
310
+
311
+ user = User.new(1, nil, nil)
312
+ UserResource.new(user).serialize # => '{"id":1}'
313
+ ```
314
+
315
+ The key part is the use of `Proc#>>` since `Alba::Resource#converter` returns a `Proc` which contains the basic logic and it's impossible to change its behavior by just overriding the method.
225
316
 
226
- Alba is faster than alternatives.
227
- For a performance benchmark, see https://gist.github.com/okuramasafumi/4e375525bd3a28e4ca812d2a3b3e5829.
317
+ It's not recommended to swap the whole conversion logic. It's recommended to always call `super` when you override `converter`.
318
+
319
+ ### Conditional attributes
320
+
321
+ Filtering attributes with overriding `convert` works well for simple cases. However, It's cumbersome when we want to filter various attributes based on different conditions for keys.
322
+
323
+ In these cases, conditional attributes works well. We can pass `if` option to `attributes`, `attribute`, `one` and `many`. Below is an example for the same effect as [filtering attributes section](#filtering-attributes).
324
+
325
+ ```ruby
326
+ class User
327
+ attr_accessor :id, :name, :email, :created_at, :updated_at
328
+
329
+ def initialize(id, name, email)
330
+ @id = id
331
+ @name = name
332
+ @email = email
333
+ end
334
+ end
335
+
336
+ class UserResource
337
+ include Alba::Resource
338
+
339
+ attributes :id, :name, :email, if: proc { |user, attribute| !attribute.nil? }
340
+ end
341
+
342
+ user = User.new(1, nil, nil)
343
+ UserResource.new(user).serialize # => '{"id":1}'
344
+ ```
345
+
346
+ ### Inference
347
+
348
+ After `Alba.enable_inference!` called, Alba tries to infer root key and association resource name.
349
+
350
+ ```ruby
351
+ Alba.enable_inference!
352
+
353
+ class User
354
+ attr_reader :id
355
+ attr_accessor :articles
356
+
357
+ def initialize(id)
358
+ @id = id
359
+ @articles = []
360
+ end
361
+ end
362
+
363
+ class Article
364
+ attr_accessor :id, :title
365
+
366
+ def initialize(id, title)
367
+ @id = id
368
+ @title = title
369
+ end
370
+ end
371
+
372
+ class ArticleResource
373
+ include Alba::Resource
374
+
375
+ attributes :title
376
+ end
377
+
378
+ class UserResource
379
+ include Alba::Resource
380
+
381
+ key!
382
+
383
+ attributes :id
384
+
385
+ many :articles
386
+ end
387
+
388
+ user = User.new(1)
389
+ user.articles << Article.new(1, 'The title')
390
+
391
+ UserResource.new(user).serialize # => '{"user":{"id":1,"articles":[{"title":"The title"}]}}'
392
+ UserResource.new([user]).serialize # => '{"users":[{"id":1,"articles":[{"title":"The title"}]}]}'
393
+ ```
394
+
395
+ This resource automatically sets its root key to either "users" or "user", depending on the given object is collection or not.
396
+
397
+ Also, you don't have to specify which resource class to use with `many`. Alba infers it from association name.
398
+
399
+ Note that to enable this feature you must install `ActiveSupport` gem.
400
+
401
+ ### Error handling
402
+
403
+ You can set error handler globally or per resource using `on_error`.
404
+
405
+ ```ruby
406
+ class User
407
+ attr_accessor :id, :name
408
+
409
+ def initialize(id, name, email)
410
+ @id = id
411
+ @name = name
412
+ @email = email
413
+ end
414
+
415
+ def email
416
+ raise RuntimeError, 'Error!'
417
+ end
418
+ end
419
+
420
+ class UserResource
421
+ include Alba::Resource
422
+
423
+ attributes :id, :name, :email
424
+
425
+ on_error :ignore
426
+ end
427
+
428
+ user = User.new(1, 'Test', 'email@example.com')
429
+ UserResource.new(user).serialize # => '{"id":1,"name":"Test"}'
430
+ ```
431
+
432
+ This way you can exclude an entry when fetching an attribute gives an exception.
433
+
434
+ There are four possible arguments `on_error` method accepts.
435
+
436
+ * `:raise` re-raises an error. This is the default behavior.
437
+ * `:ignore` ignores the entry with the error.
438
+ * `:nullify` sets the attribute with the error to `nil`.
439
+ * Block gives you more control over what to be returned.
440
+
441
+ The block receives five arguments, `error`, `object`, `key`, `attribute` and `resource class` and must return a two-element array. Below is an example.
442
+
443
+ ```ruby
444
+ # Global error handling
445
+ Alba.on_error do |error, object, key, attribute, resource_class|
446
+ if resource_class == MyResource
447
+ ['error_fallback', object.error_fallback]
448
+ else
449
+ [key, error.message]
450
+ end
451
+ end
452
+ ```
453
+
454
+ ### Circular associations control
455
+
456
+ You can control circular associations with `within` option. `within` option is a nested Hash such as `{book: {authors: books}}`. In this example, Alba serializes a book's authors' books. This means you can reference `BookResource` from `AuthorResource` and vice versa. This is really powerful when you have a complex data structure and serialize certain parts of it.
457
+
458
+ For more details, please refer to [test code](https://github.com/okuramasafumi/alba/blob/master/test/usecases/circular_association_test.rb)
459
+
460
+ ### Caching
461
+
462
+ Currently, Alba doesn't support caching, primarily due to the behavior of `ActiveRecord::Relation`'s cache. See [the issue](https://github.com/rails/rails/issues/41784).
228
463
 
229
464
  ## Rails
230
465
 
@@ -232,23 +467,20 @@ When you use Alba in Rails, you can create an initializer file with the line bel
232
467
 
233
468
  ```ruby
234
469
  Alba.backend = :active_support
470
+ # or
471
+ Alba.backend = :oj_rails
235
472
  ```
236
473
 
237
474
  ## Why named "Alba"?
238
475
 
239
476
  The name "Alba" comes from "albatross", a kind of birds. In Japanese, this bird is called "Aho-dori", which means "stupid bird". I find it funny because in fact albatrosses fly really fast. I hope Alba looks stupid but in fact it does its job quick.
240
477
 
241
- ## Alba internals
242
-
243
- Alba has three component, `Serializer`, `Resource` and `Value` (`Value` is conceptual and not implemented directly).
244
-
245
- `Serializer` is a component responsible for rendering JSON output with `Resource`. `Serializer` can add more data to `Resource` such as `metadata`. Users can define one single `Serializer` and reuse it for all `Resource`s. The main interface is `#serialize`.
246
-
247
- `Resource` is a component responsible for defining how an object (or a collection of objects) is converted into JSON. The difference between `Serializer` and `Resource` is that while `Serializer` can add arbitrary data into JSON, `Resource` can get data only from the object under it. The main interface is `#serializable_hash`.
478
+ ## Pioneers
248
479
 
249
- `One` and `Many` are the special object fetching other resources and converting them into Hash.
480
+ There are great pioneers in Ruby's ecosystem which does basically the same thing as Alba does. To name a few:
250
481
 
251
- The main `Alba` module holds config values and one convenience method, `.serialize`.
482
+ * [ActiveModelSerializers](https://github.com/rails-api/active_model_serializers) a.k.a AMS, the most famous implementation of JSON serializer for Ruby
483
+ * [Blueprinter](https://github.com/procore/blueprinter) shares some concepts with Alba
252
484
 
253
485
  ## Development
254
486