surrealist 0.4.0 → 1.0.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: 936bf35d7c1f0511db6d2f9458ade02330ec2246d444f9c0c7f9069ed7f24d73
4
- data.tar.gz: 1b91381b04081fb2e4cd6af4167cd41907f982c9a1f713077e76d78ec51a82c4
3
+ metadata.gz: 18d601273dc48757785a2356db0353254bf692deb46ed7df9e128aa329eef928
4
+ data.tar.gz: 20bdde30e93d282483c88beb6de145fb198e332a3cf73379fa0f96d176a99895
5
5
  SHA512:
6
- metadata.gz: d058ddf6a4314ee51c09fc2bd7866302971d9a8f9171430189d95df37871331883237519579c9044a4e720435bdf99702e134e9af992cddb4b5a241db528a92e
7
- data.tar.gz: ccee664c6cadf85ec84e5584a8ac1c9490f43a5dfb7308ecf7d8d883daa5f4bbc6c6f1a2836c58f30677bb1ca6a5cfb1c5111f03db9ca6e0b9fade5420a11998
6
+ metadata.gz: bec9aaebea9985002b24625c3d99316137344794cbab43a2e04d8fa685eda6c46a10f7dc072b37cbfef2428e6a3a0abbb5a7223823feb0ca546fd31128aab7a2
7
+ data.tar.gz: 9c47eb33373325982ab09eeba0aae2dacf963bdf27f0291d79301ea3f5cf1495369d9c7d9f808288cc6dcf596e4dcab409481255909e6dcc266acdf4e43b6c2b
data/.rubocop.yml CHANGED
@@ -2,6 +2,12 @@ AllCops:
2
2
  TargetRubyVersion: 2.2
3
3
  Exclude:
4
4
  - './gemfiles/*gemfile'
5
+ - './tmp/*'
6
+
7
+ Documentation:
8
+ Exclude:
9
+ - benchmarks/*rb
10
+ - spec/**/*rb
5
11
 
6
12
  # Layout
7
13
 
@@ -51,6 +57,7 @@ Lint/RescueType:
51
57
  Metrics/BlockLength:
52
58
  Exclude:
53
59
  - spec/**/*rb
60
+ - benchmarks
54
61
 
55
62
  Metrics/CyclomaticComplexity:
56
63
  Enabled: false
@@ -59,6 +66,7 @@ Metrics/MethodLength:
59
66
  Max: 15
60
67
 
61
68
  Metrics/LineLength:
69
+ Exclude: [benchmarks/*rb]
62
70
  Max: 110
63
71
 
64
72
  Metrics/PerceivedComplexity:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # 1.0.0
2
+
3
+ ## Added
4
+ * `#build_schema` for collections from `Surrealist::Serializer` (@nesaulov) #74
5
+ * Oj dependency
6
+ * Multiple serializers API (@nulldef) #66
7
+
8
+ ## Miscellaneous
9
+ * Benchmarks for Surrealist vs AMS
10
+ * A lot of memory & performance optimizations (@nesaulov) #64
11
+
1
12
  # 0.4.0
2
13
 
3
14
  ## Added
data/Gemfile CHANGED
@@ -4,7 +4,9 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :development, :test do
7
+ gem 'active_model_serializers', '~> 0.10.0'
7
8
  gem 'activerecord'
9
+ gem 'benchmark-ips'
8
10
  gem 'coveralls', require: false
9
11
  gem 'dry-struct'
10
12
  gem 'dry-types'
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Coverage Status](https://coveralls.io/repos/github/nesaulov/surrealist/badge.svg?branch=master)](https://coveralls.io/github/nesaulov/surrealist?branch=master)
4
4
  [![Inline docs](http://inch-ci.org/github/nesaulov/surrealist.svg?branch=master)](http://inch-ci.org/github/nesaulov/surrealist)
5
5
  [![Gem Version](https://badge.fury.io/rb/surrealist.svg)](https://rubygems.org/gems/surrealist)
6
+ [![Open Source Helpers](https://www.codetriage.com/nesaulov/surrealist/badges/users.svg)](https://www.codetriage.com/nesaulov/surrealist)
6
7
 
7
8
  ![Surrealist](surrealist-icon.png)
8
9
 
@@ -22,15 +23,21 @@ to serialize nested objects and structures. [Introductory blogpost.](https://med
22
23
  * [Simple example](#simple-example)
23
24
  * [Nested structures](#nested-structures)
24
25
  * [Nested objects](#nested-objects)
25
- * [Delegating Surrealization](#delegating-surrealization)
26
- * [Usage with Dry::Types](#usage-with-drytypes)
26
+ * [Collection Surrealization](#collection-surrealization)
27
27
  * [Defining custom serializers](#defining-custom-serializers)
28
+ * [Multiple serializers](#multiple-serializers)
28
29
  * [Build schema](#build-schema)
29
- * [Camelization](#camelization)
30
- * [Include root](#include-root)
31
- * [Include namespaces](#include-namespaces)
32
- * [Collection Surrealization](#collection-surrealization)
33
- * [Root](#root)
30
+ * [Working with ORMs](#working-with-orms)
31
+ * [ActiveRecord](#activerecord)
32
+ * [ROM](#rom)
33
+ * [Sequel](#sequel)
34
+ * [Usage with Dry::Types](#usage-with-drytypes)
35
+ * [Delegating Surrealization](#delegating-surrealization)
36
+ * [Optional arguments](#optional-arguments)
37
+ * [Camelization](#camelization)
38
+ * [Include root](#include-root)
39
+ * [Root](#root)
40
+ * [Include namespaces](#include-namespaces)
34
41
  * [Bool and Any](#bool-and-any)
35
42
  * [Type errors](#type-errors)
36
43
  * [Undefined methods in schema](#undefined-methods-in-schema)
@@ -38,6 +45,7 @@ to serialize nested objects and structures. [Introductory blogpost.](https://med
38
45
  * [Roadmap](#roadmap)
39
46
  * [Contributing](#contributing)
40
47
  * [Credits](#credits)
48
+ * [Authors](#authors)
41
49
  * [License](#license)
42
50
 
43
51
 
@@ -59,7 +67,7 @@ Or install it yourself as:
59
67
 
60
68
  ## Usage
61
69
  Schema should be defined with a block that contains a hash. Every key of the schema should be
62
- either a name of a method of the surrealizable object (or it's parents/mixins),
70
+ either a name of a method of the surrealizable object (or it's ancestors/mixins),
63
71
  or - in case you want to build json structure independently from object's structure - a symbol.
64
72
  Every value of the hash should be a constant that represents a Ruby class,
65
73
  that will be used for type-checks.
@@ -151,101 +159,33 @@ User.new.surrealize
151
159
 
152
160
  ```
153
161
 
154
- ### Delegating surrealization
155
- You can share the `json_schema` between classes:
162
+ ### Collection Surrealization
163
+ Since 0.2.0 Surrealist has API for collection serialization. Example for ActiveRecord:
156
164
  ``` ruby
157
- class Host
165
+ class User < ActiveRecord::Base
158
166
  include Surrealist
159
167
 
160
168
  json_schema do
161
- { name: String }
162
- end
163
-
164
- def name
165
- 'Host'
169
+ { name: String, age: Integer }
166
170
  end
167
171
  end
168
-
169
- class Guest
170
- delegate_surrealization_to Host
171
172
 
172
- def name
173
- 'Guest'
174
- end
175
- end
176
-
177
- Host.new.surrealize
178
- # => '{ "name": "Host" }'
179
- Guest.new.surrealize
180
- # => '{ "name": "Guest" }'
181
- ```
182
- Schema delegation works without inheritance as well, so if you wish you can
183
- delegate surrealization not only to parent classes, but to any class. Please note that
184
- in this case you have to `include Surrealist` in class that delegates schema as well.
185
- ``` ruby
186
- class Potato
187
- include Surrealist
188
- delegate_surrealization_to Host
173
+ users = User.all
174
+ # => [#<User:0x007fa1485de878 id: 1, name: "Nikita", age: 23>, #<User:0x007fa1485de5f8 id: 2, name: "Alessandro", age: 24>]
189
175
 
190
- def name
191
- 'Potato'
192
- end
193
- end
194
-
195
- Potato.new.surrealize
196
- # => '{ "name": "Potato" }'
176
+ Surrealist.surrealize_collection(users)
177
+ # => '[{ "name": "Nikita", "age": 23 }, { "name": "Alessandro", "age": 24 }]'
197
178
  ```
179
+ You can find motivation behind introducing new API versus monkey-patching [here](https://alessandrominali.github.io/monkey_patching_real_example).
180
+ `#surrealize_collection` works for all data structures that respond to `#each`. All ActiveRecord
181
+ features (like associations, inheritance etc) are supported and covered. Further reading: [working with ORMs](#working-with-orms).
182
+ All optional arguments (`camelize`, `include_root` etc) are also supported.
198
183
 
199
-
200
- ### Usage with Dry::Types
201
- You can use `Dry::Types` for type checking. Note that Surrealist does not ship
202
- with dry-types by default, so you should do the [installation and configuration](http://dry-rb.org/gems/dry-types/)
203
- by yourself. All built-in features of dry-types work, so if you use, say, `Types::Coercible::String`,
204
- your data will be coerced if it is able to, otherwise you will get a TypeError.
205
- Assuming that you have defined module called `Types`:
206
-
207
- ``` ruby
208
- require 'dry-types'
209
-
210
- class Car
211
- include Surrealist
212
-
213
- json_schema do
214
- {
215
- age: Types::Coercible::Int,
216
- brand: Types::Coercible::String,
217
- doors: Types::Int.optional,
218
- horsepower: Types::Strict::Int.constrained(gteq: 20),
219
- fuel_system: Types::Any,
220
- previous_owner: Types::String,
221
- }
222
- end
223
-
224
- def age;
225
- '7'
226
- end
227
-
228
- def previous_owner;
229
- 'John Doe'
230
- end
231
-
232
- def horsepower;
233
- 140
234
- end
235
-
236
- def brand;
237
- 'Toyota'
238
- end
239
-
240
- def doors; end
241
-
242
- def fuel_system;
243
- 'Direct injection'
244
- end
245
- end
246
-
247
- Car.new.surrealize
248
- # => '{ "age": 7, "brand": "Toyota", "doors": null, "horsepower": 140, "fuel_system": "Direct injection", "previous_owner": "John Doe" }'
184
+ An additional and unique argument for `#surrealize_collection` is `raw` which is evaluated as a Boolean.
185
+ If this option is 'truthy' then the results will be an array of surrealized hashes (i.e. NOT a JSON string).
186
+ ```
187
+ Surrealist.surrealize_collection(users, raw: true)
188
+ # => [{ "name": "Nikita", "age": 23 }, { "name": "Alessandro", "age": 24 }]
249
189
  ```
250
190
 
251
191
  ### Defining custom serializers
@@ -314,6 +254,43 @@ IncomeSerializer.new(income, current_user: User.find(3)).surrealize
314
254
  # => '{ "amount": 200 }'
315
255
  ```
316
256
 
257
+ ### Multiple serializers
258
+
259
+ You can define several custom serializers for one object and use it in different cases. Just mark it with a tag:
260
+
261
+ ``` ruby
262
+ class PostSerializer < Surrealist::Serializer
263
+ json_schema { { id: Integer, title: String, author: { name: String } } }
264
+ end
265
+
266
+ class PreviewSerializer < Surrealist::Serializer
267
+ json_schema { { id: Integer, title: String } }
268
+ end
269
+
270
+ class Post
271
+ include Surrealist
272
+
273
+ surrealize_with PostSerializer
274
+ surrealize_with PreviewSerializer, tag: :preview
275
+
276
+ attr_reader :id, :title, :author
277
+ end
278
+ ```
279
+
280
+ And then specify serializer's tag with `for` argument:
281
+ ``` ruby
282
+ author = Struct.new(:name).new("John")
283
+ post = Post.new(1, "Ruby is awesome", author)
284
+ post.surrealize # => '{ "id": 1, "title": "Ruby is awesome", author: { name: "John" } }'
285
+
286
+ post.surrealize(for: :preview) # => '{ "id": 1, "title": "Ruby is awesome" }'
287
+ ```
288
+ Or specify serializer explicitly with `serializer` argument:
289
+
290
+ ``` ruby
291
+ post.surrealize(serializer: PreviewSerializer) # => '{ "id": 1, "title": "Ruby is awesome" }'
292
+ ```
293
+
317
294
  ### Build schema
318
295
  If you don't need to dump the hash to json, you can use `#build_schema`
319
296
  method on the instance. It calculates values and checks types, but returns
@@ -324,7 +301,256 @@ Car.new.build_schema
324
301
  # => { age: 7, brand: "Toyota", doors: nil, horsepower: 140, fuel_system: "Direct injection", previous_owner: "John Doe" }
325
302
  ```
326
303
 
327
- ### Camelization
304
+ ### Working with ORMs
305
+
306
+ There are two kinds of return values of ORM methods: some return collections of objects, while others return instances.
307
+ For the first ones one should use `instance#surrealize`, whereas for the second ones `Surrealist.surrealize_collection(collection)`
308
+ Please keep in mind that if your serialization logic is [kept in a separate class](#defining-custom-serializers) which is inherited from
309
+ `Surrealist::Serializer`, than usage boils down to `YourSerializer.new(instance || collection).surrealize`.
310
+
311
+ #### ActiveRecord
312
+ All associations work as expected: `.has_many`, `.has_and_belongs_to_many` return collections,
313
+ `.has_one`, `.belongs_to` return instances.
314
+
315
+ Methods that return instances:
316
+ ``` ruby
317
+ .find
318
+ .find_by
319
+ .find_by!
320
+ .take!
321
+ .first
322
+ .first!
323
+ .second
324
+ .second!
325
+ .third
326
+ .third!
327
+ .fourth
328
+ .fourth!
329
+ .fifth
330
+ .fifth!
331
+ .forty_two
332
+ .forty_two!
333
+ .last
334
+ .last!
335
+ .third_to_last
336
+ .third_to_last!
337
+ .second_to_last
338
+ .second_to_last!
339
+ ```
340
+ Methods that return collections:
341
+ ``` ruby
342
+ .all
343
+ .where
344
+ .where_not
345
+ .order
346
+ .take
347
+ .limit
348
+ .offset
349
+ .lock
350
+ .readonly
351
+ .reorder
352
+ .distinct
353
+ .find_each
354
+ .select
355
+ .group
356
+ .order
357
+ .except
358
+ .extending
359
+ .having
360
+ .references
361
+ .includes
362
+ .joins
363
+ ```
364
+
365
+ #### ROM
366
+
367
+ For detailed usage example (covering ROM 3.x and ROM 4.x) please see `spec/orms/rom/`.
368
+ Under the hood ROM uses Sequel, and Sequel returns instances only on `.first`, `.last`, `.[]` and `.with_pk!`.
369
+ Collections are returned for all other methods.
370
+ ``` ruby
371
+ container = ROM.container(:sql, ['sqlite::memory']) do |conf|
372
+ conf.default.create_table(:users) do
373
+ primary_key :id
374
+ column :name, String, null: false
375
+ column :email, String, null: false
376
+ end
377
+ # ...
378
+ end
379
+
380
+ users = UserRepo.new(container).users
381
+ # => #<ROM::Relation[Users] name=ROM::Relation::Name(users) dataset=#<Sequel::SQLite::Dataset: "SELECT `users`.`id`, `users`.`name`, `users`.`email` FROM `users` ORDER BY `users`.`id`">>
382
+ ```
383
+ Basically, there are several ways to fetch/represent data in ROM:
384
+ ``` ruby
385
+ # With json_schema defined in ROM::Struct::User
386
+ class ROM::Struct::User < ROM::Struct
387
+ include Surrealist
388
+
389
+ json_schema { { name: String } }
390
+ end
391
+
392
+ users.to_a.first # => #<ROM::Struct::User id=1 name="Jane Struct" email="jane@struct.rom">
393
+ users.to_a.first.surrealize # => "{\"name\":\"Jane Struct\"}"
394
+
395
+ users.where(id: 1).first # => #<ROM::Struct::User id=1 name="Jane Struct" email="jane@struct.rom">
396
+ users.where(id: 1).first.surrealize # => "{\"name\":\"Jane Struct\"}"
397
+
398
+ Surrealist.surrealize_collection(users.to_a) # => "[{\"name\":\"Jane Struct\"},{\"name\":\"Dane As\"},{\"name\":\"Jack Mapper\"}]"
399
+
400
+ # using ROM::Struct::Model#as(Representative) with json_schema defined in representative
401
+ class RomUser < Dry::Struct
402
+ include Surrealist
403
+
404
+ attribute :name, String
405
+ attribute :email, String
406
+
407
+ json_schema { { email: String } }
408
+ end
409
+
410
+ # ROM 3.x
411
+ rom_users = users.as(RomUser).to_a
412
+
413
+ # ROM 4.x
414
+ rom_users = users.map_to(RomUser).to_a
415
+
416
+ rom_users[1].surrealize # => "{\"email\":\"dane@as.rom\"}"
417
+ Surrealist.surrealize_collection(rom_users) # => "[{\"email\":\"jane@struct.rom\"},{\"email\":\"dane@as.rom\"},{\"email\":\"jack@mapper.rom\"}]"
418
+
419
+ # using Mappers
420
+ class UserModel
421
+ include Surrealist
422
+
423
+ json_schema { { id: Integer, email: String } }
424
+
425
+ attr_reader :id, :name, :email
426
+
427
+ def initialize(attributes)
428
+ @id, @name, @email = attributes.values_at(:id, :name, :email)
429
+ end
430
+ end
431
+
432
+ class UsersMapper < ROM::Mapper
433
+ register_as :user_obj
434
+ relation :users
435
+ model UserModel
436
+ end
437
+
438
+ # ROM 3.x
439
+ mapped = users.as(:user_obj)
440
+ # ROM 4.x
441
+ mapped = users.map_with(:user_obj)
442
+
443
+ mapped.to_a[2] # => #<UserModel:0x00007f8ec19fb3c8 @email="jack@mapper.rom", @id=3, @name="Jack Mapper">
444
+ mapped.where(id: 3).first # => #<UserModel:0x00007f8ec19fb3c8 @email="jack@mapper.rom", @id=3, @name="Jack Mapper">
445
+ mapped.to_a[2].surrealize # => "{\"id\":3,\"email\":\"jack@mapper.rom\"}"
446
+ Surrealist.surrealize_collection(mapped.to_a) # => "[{\"email\":\"jane@struct.rom\"},{\"email\":\"dane@as.rom\"},{\"email\":\"jack@mapper.rom\"}]"
447
+ Surrealist.surrealize_collection(mapped.where { id < 4 }.to_a) # => "[{\"email\":\"jane@struct.rom\"},{\"email\":\"dane@as.rom\"},{\"email\":\"jack@mapper.rom\"}]"
448
+ ```
449
+
450
+ #### Sequel
451
+ Basically, Sequel returns instances only on `.first`, `.last`, `.[]` and `.with_pk!`. Collections are returned for all other methods.
452
+ Most of them are covered in `spec/orms/sequel` specs, please refer to them for code examples.
453
+ Associations serialization works the same way as it does with ActiveRecord.
454
+
455
+ ### Usage with Dry::Types
456
+ You can use `Dry::Types` for type checking. Note that Surrealist does not ship
457
+ with dry-types by default, so you should do the [installation and configuration](http://dry-rb.org/gems/dry-types/)
458
+ by yourself. All built-in features of dry-types work, so if you use, say, `Types::Coercible::String`,
459
+ your data will be coerced if it is able to, otherwise you will get a TypeError.
460
+ Assuming that you have defined module called `Types`:
461
+
462
+ ``` ruby
463
+ require 'dry-types'
464
+
465
+ class Car
466
+ include Surrealist
467
+
468
+ json_schema do
469
+ {
470
+ age: Types::Coercible::Int,
471
+ brand: Types::Coercible::String,
472
+ doors: Types::Int.optional,
473
+ horsepower: Types::Strict::Int.constrained(gteq: 20),
474
+ fuel_system: Types::Any,
475
+ previous_owner: Types::String,
476
+ }
477
+ end
478
+
479
+ def age;
480
+ '7'
481
+ end
482
+
483
+ def previous_owner;
484
+ 'John Doe'
485
+ end
486
+
487
+ def horsepower;
488
+ 140
489
+ end
490
+
491
+ def brand;
492
+ 'Toyota'
493
+ end
494
+
495
+ def doors; end
496
+
497
+ def fuel_system;
498
+ 'Direct injection'
499
+ end
500
+ end
501
+
502
+ Car.new.surrealize
503
+ # => '{ "age": 7, "brand": "Toyota", "doors": null, "horsepower": 140, "fuel_system": "Direct injection", "previous_owner": "John Doe" }'
504
+ ```
505
+
506
+ ### Delegating surrealization
507
+ You can share the `json_schema` between classes:
508
+ ``` ruby
509
+ class Host
510
+ include Surrealist
511
+
512
+ json_schema do
513
+ { name: String }
514
+ end
515
+
516
+ def name
517
+ 'Host'
518
+ end
519
+ end
520
+
521
+ class Guest
522
+ delegate_surrealization_to Host
523
+
524
+ def name
525
+ 'Guest'
526
+ end
527
+ end
528
+
529
+ Host.new.surrealize
530
+ # => '{ "name": "Host" }'
531
+ Guest.new.surrealize
532
+ # => '{ "name": "Guest" }'
533
+ ```
534
+ Schema delegation works without inheritance as well, so if you wish you can
535
+ delegate surrealization not only to parent classes, but to any class. Please note that
536
+ in this case you have to `include Surrealist` in class that delegates schema as well.
537
+ ``` ruby
538
+ class Potato
539
+ include Surrealist
540
+ delegate_surrealization_to Host
541
+
542
+ def name
543
+ 'Potato'
544
+ end
545
+ end
546
+
547
+ Potato.new.surrealize
548
+ # => '{ "name": "Potato" }'
549
+ ```
550
+
551
+ ### Optional arguments
552
+
553
+ #### Camelization
328
554
  If you need to have keys in camelBack, you can pass optional `camelize` argument
329
555
  to `#surrealize or #build_schema`. From the previous example:
330
556
 
@@ -333,7 +559,7 @@ Car.new.surrealize(camelize: true)
333
559
  # => '{ "age": 7, "brand": "Toyota", "doors": null, "horsepower": 140, "fuelSystem": "Direct injection", "previousOwner": "John Doe" }'
334
560
  ```
335
561
 
336
- ### Include root
562
+ #### Include root
337
563
  If you want to wrap the resulting JSON into a root key, you can pass optional `include_root` argument
338
564
  to `#surrealize` or `#build_schema`. The root key in this case will be taken from the class name of the
339
565
  surrealizable object.
@@ -373,62 +599,7 @@ Animal::Dog.new.surrealize(include_root: true)
373
599
  # => '{ "dog": { "breed": "Collie" } }'
374
600
  ```
375
601
 
376
- ### Include namespaces
377
- You can build wrap schema into a nested hash from namespaces of the object's class.
378
- ``` ruby
379
- class BusinessSystem::Cashout::ReportSystem::Withdraws
380
- include Surrealist
381
-
382
- json_schema do
383
- { withdraws_amount: Integer }
384
- end
385
-
386
- def withdraws_amount
387
- 34
388
- end
389
- end
390
-
391
- withdraws = BusinessSystem::Cashout::ReportSystem::Withdraws.new
392
-
393
- withdraws.surrealize(include_namespaces: true)
394
- # => '{ "business_system": { "cashout": { "report_system": { "withdraws": { "withdraws_amount": 34 } } } } }'
395
- ```
396
- By default all namespaces will be taken. If you want you can explicitly specify the level of nesting:
397
- ``` ruby
398
- withdraws.surrealize(include_namespaces: true, namespaces_nesting_level: 2)
399
- # => '{ "report_system": { "withdraws": { "withdraws_amount": 34 } } }'
400
- ```
401
-
402
- ### Collection Surrealization
403
- Since 0.2.0 Surrealist has API for collection serialization. Example for ActiveRecord:
404
- ``` ruby
405
- class User < ActiveRecord::Base
406
- include Surrealist
407
-
408
- json_schema do
409
- { name: String, age: Integer }
410
- end
411
- end
412
-
413
- users = User.all
414
- # => [#<User:0x007fa1485de878 id: 1, name: "Nikita", age: 23>, #<User:0x007fa1485de5f8 id: 2, name: "Alessandro", age: 24>]
415
-
416
- Surrealist.surrealize_collection(users)
417
- # => '[{ "name": "Nikita", "age": 23 }, { "name": "Alessandro", "age": 24 }]'
418
- ```
419
- You can find motivation behind introducing new API versus monkey-patching [here](https://alessandrominali.github.io/monkey_patching_real_example).
420
- `#surrealize_collection` works for all data structures that respond to `#each`. All ActiveRecord
421
- features (like associations, inheritance etc) are supported and covered. Other ORMs should work without
422
- issues as well, tests are in progress. All optional arguments (`camelize`, `include_root` etc) are also supported.
423
-
424
- An additional and unique arguement for `#surrealize_collection` is `raw` which is evalauted as a Boolean. If this option is 'truthy' then the results will be an array of surrealized hashes (ie. NOT a JSON string).
425
- ```
426
- Surrealist.surrealize_collection(users, raw: true)
427
- # => [{ "name": "Nikita", "age": 23 }, { "name": "Alessandro", "age": 24 }]
428
- ```
429
- Guides on where to use `#surrealize_collection` vs `#surrealize` for all ORMs are coming.
430
-
431
- ### Root
602
+ #### Root
432
603
  If you want to wrap the resulting JSON into a specified root key, you can pass optional `root` argument
433
604
  to `#surrealize` or `#build_schema`. The `root` argument will be stripped of whitespaces.
434
605
  ``` ruby
@@ -457,6 +628,32 @@ Animal::Cat.new.surrealize(include_namespaces: true, root: 'kitten')
457
628
  # => '{ "kitten": { "weight": "3 kilos" } }'
458
629
  ```
459
630
 
631
+ #### Include namespaces
632
+ You can build wrap schema into a nested hash from namespaces of the object's class.
633
+ ``` ruby
634
+ class BusinessSystem::Cashout::ReportSystem::Withdraws
635
+ include Surrealist
636
+
637
+ json_schema do
638
+ { withdraws_amount: Integer }
639
+ end
640
+
641
+ def withdraws_amount
642
+ 34
643
+ end
644
+ end
645
+
646
+ withdraws = BusinessSystem::Cashout::ReportSystem::Withdraws.new
647
+
648
+ withdraws.surrealize(include_namespaces: true)
649
+ # => '{ "business_system": { "cashout": { "report_system": { "withdraws": { "withdraws_amount": 34 } } } } }'
650
+ ```
651
+ By default all namespaces will be taken. If you want you can explicitly specify the level of nesting:
652
+ ``` ruby
653
+ withdraws.surrealize(include_namespaces: true, namespaces_nesting_level: 2)
654
+ # => '{ "report_system": { "withdraws": { "withdraws_amount": 34 } } }'
655
+ ```
656
+
460
657
  ### Bool and Any
461
658
  If you have a parameter that is of boolean type, or if you don't care about the type, you
462
659
  can use `Bool` and `Any` respectively.
@@ -518,7 +715,9 @@ type check will be passed. If you want to be strict about `nil`s consider using
518
715
 
519
716
  ## Roadmap
520
717
  Here is a list of features that are not implemented yet (contributions are welcome):
521
- * [Benchmarks](https://github.com/nesaulov/surrealist/issues/40)
718
+ * [Having a config that would keep serialization parameters](https://github.com/nesaulov/surrealist/issues/76)
719
+ * [DSL for serializer contexts](https://github.com/nesaulov/surrealist/issues/67)
720
+ * Memoization/caching
522
721
 
523
722
  ## Contributing
524
723
  Bug reports and pull requests are welcome on GitHub at https://github.com/nesaulov/surrealist.
@@ -528,5 +727,12 @@ to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of
528
727
  ## Credits
529
728
  The icon was created by [Simon Child from Noun Project](https://thenounproject.com/term/salvador-dali/124566/) and is published under [Creative Commons License](https://creativecommons.org/licenses/by/3.0/us/)
530
729
 
730
+ ## Authors
731
+ Created by [Nikita Esaulov](https://github.com/nesaulov) with help from [Alessandro Minali](https://github.com/AlessandroMinali) and [Alexey Bespalov](https://github.com/nulldef).
732
+
733
+ <a href="https://github.com/umbrellio/">
734
+ <img style="float: left;" src="https://umbrellio.github.io/Umbrellio/supported_by_umbrellio.svg" alt="Supported by Umbrellio" width="439" height="72">
735
+ </a>
736
+
531
737
  ## License
532
738
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).