serega 0.33.2 → 0.35.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5ecb4ac9c23db4ed45c7118bcd62b8a07f20710bac2ea8fd57aea0f66e136af
4
- data.tar.gz: b5af4351059c516658d6031f68fbf5dfa0e9e5a5e03e9c70d904848e7a5a8a4d
3
+ metadata.gz: a32fcd6506959b5498ef6357c27110bd7623d0bf16e28d0485703016704e6cf4
4
+ data.tar.gz: 4e2bf60aba2c1db746587b1135a3d852e34858606ac30c6947c960d4e2dba726
5
5
  SHA512:
6
- metadata.gz: 33267e2460b8b48da8b2b0886ac1fa2dc4c47fad82f594e277195c092d3100891b98901824c802bf5d23b3ee045ef00e6c9c904ab059faa52f403cb91ccc88fc
7
- data.tar.gz: d89903f46ee168ab027bad60e253170c50c67fc029e4357db5947aef48066c94edc581fb156323f9f6eb5a822ad21da5909fb5591f473fda936fc22c5bb74b91
6
+ metadata.gz: 8cb7d76c325320e144dd7de3dcfc376a03386a7742f7eea68cae1bbb421b0cbe969e2c858fbae253114bbb3ed86e63d4c689395976ac94463813a8229ae66f9e
7
+ data.tar.gz: e4595313b09bb2fcb7f37c6e26ebe9376a5caf86c66ed2ab4a19091aae854f1c51fafd0adea54cae0ac97eeb69e770e74f7e66d1aee44a8714d50ae225b8683a
data/README.md CHANGED
@@ -319,7 +319,7 @@ Serega includes built-in batch loading functionality to efficiently load data on
319
319
 
320
320
  #### Defining Named Batch Loaders
321
321
 
322
- Named loaders can be defined using the `batch_loader` class method and reused across attributes:
322
+ Named loaders can be defined using the `batch` class method and reused across attributes:
323
323
 
324
324
  ```ruby
325
325
  class UserSerializer < Serega
@@ -385,10 +385,14 @@ class AppSerializer < Serega
385
385
  # It helps to preload associations automatically, omitting N+1 requests.
386
386
  config.auto_preload = false
387
387
 
388
- # Automatically marks as hidden attributes with `:preload` or `:batch` options.
389
- # By default is false. Useful option to not make extra DB requests if attribute
390
- # was not requested
391
- config.auto_hide = false
388
+ # Hides attributes by default. Accepts:
389
+ # false - nothing hidden (default)
390
+ # true - all attributes hidden
391
+ # [:preload] - attributes with :preload option hidden
392
+ # [:batch] - attributes with :batch option hidden
393
+ # [:preload, :batch] - either option triggers hiding
394
+ # Useful to avoid extra DB requests for attributes that were not requested.
395
+ config.hide_by_default = false
392
396
 
393
397
  # Default method used on serialized object to resolve batch value
394
398
  # For example:
@@ -418,9 +422,8 @@ into a single associations hash.
418
422
 
419
423
  Configuration options:
420
424
 
421
- - `config.auto_preload_attributes_with_delegate` - default `false`
422
- - `config.auto_preload_attributes_with_serializer` - default `false`
423
- - `config.auto_hide_attributes_with_preload` - default `false`
425
+ - `config.auto_preload` - default `false` (use `true` or `{ has_delegate_option: true, has_serializer_option: true }`)
426
+ - `config.hide_by_default` - default `false` (use `[:preload]` to hide attributes with preloads)
424
427
 
425
428
  These options are extremely useful if you want to forget about finding
426
429
  preloads manually.
@@ -433,9 +436,8 @@ For some examples, **please read the comments in the code below**
433
436
 
434
437
  ```ruby
435
438
  class AppSerializer < Serega
436
- config.auto_preload_attributes_with_delegate = true
437
- config.auto_preload_attributes_with_serializer = true
438
- config.auto_hide_attributes_with_preload = true
439
+ config.auto_preload = true
440
+ config.hide_by_default = [:preload]
439
441
  end
440
442
 
441
443
  class UserSerializer < AppSerializer
@@ -447,11 +449,11 @@ class UserSerializer < AppSerializer
447
449
  value: proc { |user| user.user_stats.followers_count }
448
450
 
449
451
  # `preload: :user_stats` added automatically, as
450
- # `auto_preload_attributes_with_delegate` option is true
452
+ # `auto_preload` includes `has_delegate_option: true`
451
453
  attribute :comments_count, delegate: { to: :user_stats }
452
454
 
453
455
  # `preload: :albums` added automatically as
454
- # `auto_preload_attributes_with_serializer` option is true
456
+ # `auto_preload` includes `has_serializer_option: true`
455
457
  attribute :albums, serializer: 'AlbumSerializer'
456
458
  end
457
459
 
@@ -459,7 +461,7 @@ class AlbumSerializer < AppSerializer
459
461
  attribute :images_count, delegate: { to: :album_stats }
460
462
  end
461
463
 
462
- # By default, preloads are empty, as we specify `auto_hide_attributes_with_preload`
464
+ # By default, preloads are empty, as we specify `hide_by_default = [:preload]`
463
465
  # so attributes with preloads will be skipped and nothing will be preloaded
464
466
  UserSerializer.new.preloads
465
467
  # => {}
@@ -487,10 +489,8 @@ other user associations. You should specify `preload: nil` to preload
487
489
 
488
490
  ```ruby
489
491
  class AppSerializer < Serega
490
- plugin :preloads,
491
- auto_preload_attributes_with_delegate: true,
492
- auto_preload_attributes_with_serializer: true,
493
- auto_hide_attributes_with_preload: true
492
+ config.auto_preload = true
493
+ config.hide_by_default = [:preload]
494
494
  end
495
495
 
496
496
  class UserSerializer < AppSerializer
@@ -511,9 +511,7 @@ achieve this:
511
511
 
512
512
  ```ruby
513
513
  class AppSerializer < Serega
514
- plugin :preloads,
515
- auto_preload_attributes_with_delegate: true,
516
- auto_preload_attributes_with_serializer: true
514
+ config.auto_preload = true
517
515
  end
518
516
 
519
517
  class UserSerializer < AppSerializer
@@ -570,9 +568,8 @@ uses ActiveRecord::Associations::Preloader to preload associations to objects.
570
568
 
571
569
  ```ruby
572
570
  class AppSerializer < Serega
573
- config.auto_preload_attributes_with_delegate = true
574
- config.auto_preload_attributes_with_serializer = true
575
- config.auto_hide_attributes_with_preload = false
571
+ config.auto_preload = true
572
+ config.hide_by_default = false
576
573
 
577
574
  plugin :activerecord_preloads
578
575
  end
@@ -764,27 +761,50 @@ end
764
761
 
765
762
  ### Plugin :presenter
766
763
 
767
- Helps to write clean code by using a Presenter class.
764
+ Moves computed attribute logic out of blocks and into a dedicated `Presenter` class,
765
+ keeping serializers readable as schemas rather than bags of lambdas.
766
+
767
+ Without the plugin, computed attributes live as inline blocks:
768
+
769
+ ```ruby
770
+ class UserSerializer < Serega
771
+ attribute :name, value: proc { |u| [u.first_name, u.last_name].compact.join(' ') }
772
+ attribute :role, value: proc { |u, ctx| u == ctx[:current_user] ? :self : :other }
773
+ end
774
+ ```
775
+
776
+ With the plugin, they move into a clean class:
768
777
 
769
778
  ```ruby
770
779
  class UserSerializer < Serega
771
780
  plugin :presenter
772
781
 
773
782
  attribute :name
774
- attribute :address
783
+ attribute :role
775
784
 
776
785
  class Presenter
777
786
  def name
778
- [first_name, last_name].compact_blank.join(' ')
787
+ [first_name, last_name].compact.join(' ')
779
788
  end
780
789
 
781
- def address
782
- [country, city, address].join("\n")
790
+ def role
791
+ id == __ctx__[:current_user_id] ? :self : :other
783
792
  end
784
793
  end
785
794
  end
786
795
  ```
787
796
 
797
+ `Presenter` inherits from `SimpleDelegator`, so every method of the serialized
798
+ object is available directly inside presenter methods. Any method not explicitly
799
+ defined on `Presenter` is resolved via `method_missing` on the first call, which
800
+ also defines a real delegator method — so all subsequent serializations call it
801
+ directly, without going through `method_missing` again.
802
+
803
+ The original wrapped object is accessible via `__getobj__` (standard
804
+ `SimpleDelegator` API) when you need an unambiguous reference to it.
805
+
806
+ The serialization context is accessible via the private method `__ctx__`.
807
+
788
808
  ### Plugin :string_modifiers
789
809
 
790
810
  Allows to specify modifiers as strings.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.33.2
1
+ 0.35.0
@@ -153,18 +153,18 @@ class Serega
153
153
  end
154
154
 
155
155
  def prepare_hide
156
- # Return provided durectly value
156
+ # Return provided directly value
157
157
  hide = init_opts[:hide]
158
158
  return hide if (hide == true) || (hide == false)
159
159
 
160
- # Auto hide when `:preload` option provided
161
- if config.auto_hide.fetch(:has_preload_option)
162
- return true if preloads
163
- end
160
+ hide_setting = config.hide_by_default
164
161
 
165
- # Auto hide when `:batch` option provided
166
- if config.auto_hide.fetch(:has_batch_option)
167
- return true if batch_loaders.any?
162
+ case hide_setting
163
+ when true
164
+ return true
165
+ when Array
166
+ return true if hide_setting.include?(:preload) && preloads # hide when attribute has `:preload` option
167
+ return true if hide_setting.include?(:batch) && batch_loaders.any? # hide when attribute has `:batch` option
168
168
  end
169
169
 
170
170
  # Return nil for undefined value which means "not hide" but allows
data/lib/serega/config.rb CHANGED
@@ -32,7 +32,7 @@ class Serega
32
32
  delegate_default_allow_nil: false,
33
33
  max_cached_plans_per_serializer_count: 0,
34
34
  auto_preload: {has_delegate_option: false, has_serializer_option: false},
35
- auto_hide: {has_preload_option: false, has_batch_option: false},
35
+ hide_by_default: false,
36
36
  batch_id_option: :id
37
37
  }.freeze
38
38
  # :nocov:
@@ -115,23 +115,28 @@ class Serega
115
115
  opts[:delegate_default_allow_nil] = value
116
116
  end
117
117
 
118
- # @return [Hash] auto_hide option
119
- def auto_hide
120
- opts.fetch(:auto_hide)
118
+ # Returns :hide_by_default config option
119
+ # @return [Boolean, Array<Symbol>] Current :hide_by_default config option
120
+ def hide_by_default
121
+ opts.fetch(:hide_by_default)
121
122
  end
122
123
 
123
- # Validates and sets auto_hide option
124
- # @return [Hash] New auto_hide option with attributes that trigger auto hide
125
- def auto_hide=(value)
126
- opts[:auto_hide] =
124
+ # Sets :hide_by_default config option
125
+ #
126
+ # @param value [Boolean, Array<Symbol>] false, true, or array of :preload/:batch symbols
127
+ #
128
+ # @return [Boolean, Array<Symbol>] New :hide_by_default config option
129
+ def hide_by_default=(value)
130
+ opts[:hide_by_default] =
127
131
  case value
128
- when true then {has_preload_option: true, has_batch_option: true}
129
- when false then {has_preload_option: false, has_batch_option: false}
130
- when Hash
131
- SeregaValidations::Utils::CheckAllowedKeys.call(value, %i[has_preload_option has_batch_option], "auto_hide")
132
- {has_preload_option: !!value[:has_preload_option], has_batch_option: !!value[:has_batch_option]}
132
+ when true, false
133
+ value
134
+ when Array
135
+ invalid = value - %i[preload batch]
136
+ raise SeregaError, "Must have true, false, or an Array of [:preload, :batch], #{value.inspect} provided" if invalid.any?
137
+ value
133
138
  else
134
- raise SeregaError, "Must have boolean value or Hash, #{value.inspect} provided"
139
+ raise SeregaError, "Must have true, false, or an Array of [:preload, :batch], #{value.inspect} provided"
135
140
  end
136
141
  end
137
142
 
@@ -15,7 +15,7 @@ class Serega
15
15
  # class AppSerializer < Serega
16
16
  # config.auto_preload_attributes_with_delegate = true
17
17
  # config.auto_preload_attributes_with_serializer = true
18
- # config.auto_hide_attributes_with_preload = true
18
+ # config.hide_by_default = [:preload]
19
19
  #
20
20
  # plugin :activerecord_preloads
21
21
  # end
@@ -6,16 +6,28 @@ require "forwardable"
6
6
  class Serega
7
7
  module SeregaPlugins
8
8
  #
9
- # Plugin Presenter adds possibility to use declare Presenter for your objects inside serializer
9
+ # Plugin :presenter moves computed attribute logic into a dedicated Presenter class.
10
10
  #
11
- # class User < Serega
11
+ # Presenter inherits from SimpleDelegator:
12
+ # - All methods of the serialized object are available directly inside presenter methods.
13
+ # - Methods not defined on Presenter are resolved via method_missing on the first call
14
+ # and then defined as real delegators, so subsequent calls skip method_missing entirely.
15
+ # - The original object is accessible via __getobj__ (standard SimpleDelegator API).
16
+ # - The serialization context is accessible via the private method __ctx__.
17
+ #
18
+ # class UserSerializer < Serega
12
19
  # plugin :presenter
13
20
  #
14
21
  # attribute :name
22
+ # attribute :role
15
23
  #
16
24
  # class Presenter
17
25
  # def name
18
- # [first_name, last_name].compact_blank.join(' ')
26
+ # [first_name, last_name].compact.join(' ') # first_name/last_name delegated to object
27
+ # end
28
+ #
29
+ # def role
30
+ # id == __ctx__[:current_user_id] ? :self : :other
19
31
  # end
20
32
  # end
21
33
  # end
@@ -56,6 +68,19 @@ class Serega
56
68
  class Presenter < SimpleDelegator
57
69
  # Presenter instance methods
58
70
  module InstanceMethods
71
+ #
72
+ # @param object [Object] Serialized object to wrap
73
+ # @param ctx [Hash, nil] Serialization context
74
+ #
75
+ def initialize(object, ctx = nil)
76
+ super(object)
77
+ @__ctx__ = ctx
78
+ end
79
+
80
+ private
81
+
82
+ attr_reader :__ctx__
83
+
59
84
  #
60
85
  # Delegates all missing methods to serialized object.
61
86
  #
@@ -100,10 +125,10 @@ class Serega
100
125
  private
101
126
 
102
127
  #
103
- # Replaces serialized object with Presenter.new(object)
128
+ # Replaces serialized object with Presenter.new(object, ctx)
104
129
  #
105
130
  def serialize_object(object)
106
- object = self.class.serializer_class::Presenter.new(object)
131
+ object = self.class.serializer_class::Presenter.new(object, context)
107
132
  super
108
133
  end
109
134
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serega
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.33.2
4
+ version: 0.35.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Glushkov
@@ -121,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
123
  requirements: []
124
- rubygems_version: 3.6.7
124
+ rubygems_version: 4.0.11
125
125
  specification_version: 4
126
126
  summary: JSON Serializer
127
127
  test_files: []