Module: Serega::ClassMethods

Included in:
Serega
Defined in:
lib/serega.rb

Overview

Serializers class methods

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#configSeregaConfig (readonly)

Returns current config

Returns:



105
106
107
# File 'lib/serega.rb', line 105

def config
  @config
end

Instance Method Details

#attribute(name, **opts, &block) ⇒ Serega::SeregaAttribute

Adds attribute

Patched in:

  • plugin :presenter (additionally adds method in Presenter class)

Examples:

attribute :statistics, method: :itself do
  attribute :likes_count
  attribute :comments_count
end

Parameters:

  • name (Symbol)

    Attribute name. Attribute value will be found by executing object.<name>

  • opts (Hash)

    Options to serialize attribute

  • block (Proc)

    Defines attributes of a nested anonymous serializer. The block is executed in the context of that serializer, so everything available in a serializer class body can be used inside. The attribute value (found by name/:method/:value/:delegate/:const/:batch as usual) is serialized with this nested serializer. The nested serializer inherits from the :base_serializer attribute option or config.base_serializer (one of them is required).

Returns:



196
197
198
199
# File 'lib/serega.rb', line 196

def attribute(name, **opts, &block)
  attribute = self::SeregaAttribute.new(name: name, opts: opts, block: block)
  attributes[attribute.name] = attribute
end

#attributesHash

Lists attributes

Returns:

  • (Hash)

    attributes list



158
159
160
# File 'lib/serega.rb', line 158

def attributes
  @attributes ||= {}
end

#batch(name, value = nil, &block) ⇒ #call

Defines a batch loader

Examples:

batch :tags, PostTagsLoader

with block

batch_loader(:tags) do |posts|
  Tags.where(post: posts).group(:post_id).pluck(:post_id, Arel.sql('ARRAY_AGG(tags.tag ORDER BY tag)')).to_h
end

attribute :tags, batch: :tags, value: { |post, batch:| batch[:tags][post.id] }

with context

batch_loader(:tags) do |posts, ctx:|
  next {} if ctx[:bot]

  Tags.where(post: posts).group(:post_id).pluck(:post_id, Arel.sql('ARRAY_AGG(tags.tag ORDER BY tag)')).to_h
end

attribute :tags, batch: :tags, value: { |post, batch:| batch[:tags][post.id] }

Parameters:

  • name (Symbol)

    A batch loader name

  • value (#call) (defaults to: nil)

    Batch loader

  • block (Proc)

    Batch loader

Returns:

  • (#call)

    Batch loader

Raises:



229
230
231
232
233
234
# File 'lib/serega.rb', line 229

def batch(name, value = nil, &block)
  raise SeregaError, "Batch loader must be defined with a callable value or block" if (value && block) || (!value && !block)

  batch_loader = self::SeregaEngineLoader.new(name: name, block: value || block)
  batch_loaders[batch_loader.name] = batch_loader
end

#batch_loadersHash

Lists defined batch loaders

Returns:

  • (Hash)

    batch loaders list



168
169
170
# File 'lib/serega.rb', line 168

def batch_loaders
  @batch_loaders ||= {}
end

#call(object, opts = nil) ⇒ Hash Also known as: to_h

Serializes provided object to Hash

Parameters:

  • object (Object)

    Serialized object

  • opts (Hash, nil) (defaults to: nil)

    Serializer modifiers and other instantiating options

Options Hash (opts):

  • :only (Array, Hash, String, Symbol)

    The only attributes to serialize

  • :except (Array, Hash, String, Symbol)

    Attributes to hide

  • :with (Array, Hash, String, Symbol)

    Attributes (usually hidden) to serialize additionally

  • :validate (Boolean)

    Validates provided modifiers (Default is true)

  • :context (Hash)

    Serialization context

  • :many (Boolean)

    Set true if provided multiple objects (Default object.is_a?(Enumerable) && !object.is_a?(Hash) && !object.is_a?(Struct))

Returns:

  • (Hash)

    Serialization result



282
283
284
285
286
287
# File 'lib/serega.rb', line 282

def call(object, opts = nil)
  opts = opts&.transform_keys(&:to_sym)
  modifiers_opts = init_modifier_opts(opts)
  serialize_opts = init_serialize_opts(opts)
  new(modifiers_opts).to_h(object, serialize_opts)
end

#plugin(name, **opts) ⇒ class<Module>

Enables plugin for current serializer

Parameters:

  • name (Symbol, Class<Module>)

    Plugin name or plugin module itself

  • opts (Hash)

    ] Plugin options

Returns:

  • (class<Module>)

    Loaded plugin module

Raises:



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/serega.rb', line 114

def plugin(name, **opts)
  raise SeregaError, "This plugin is already loaded" if plugin_used?(name)

  plugin = SeregaPlugins.find_plugin(name)

  # We split loading of plugin to three parts - before_load, load, after_load:
  #
  # - **before_load_plugin** usually used to check requirements and to load additional plugins
  # - **load_plugin** usually used to include plugin modules
  # - **after_load_plugin** usually used to add config options
  plugin.before_load_plugin(self, **opts) if plugin.respond_to?(:before_load_plugin)
  plugin.load_plugin(self, **opts) if plugin.respond_to?(:load_plugin)
  plugin.after_load_plugin(self, **opts) if plugin.respond_to?(:after_load_plugin)

  # Store attached plugins, so we can check it is loaded later
  config.plugins << (plugin.respond_to?(:plugin_name) ? plugin.plugin_name : plugin)

  plugin
end

#plugin_used?(name) ⇒ Boolean

Checks plugin is used

Parameters:

  • name (Symbol, Class<Module>)

    Plugin name or plugin module itself

Returns:

  • (Boolean)

    Is plugin used



142
143
144
145
146
147
148
149
150
# File 'lib/serega.rb', line 142

def plugin_used?(name)
  plugin_name =
    case name
    when Module then name.respond_to?(:plugin_name) ? name.plugin_name : name
    else name
    end

  config.plugins.include?(plugin_name)
end

#preload_with(value = nil, &block) ⇒ #call?

Registers (or returns) the handler used to preload an attribute's associations onto the records gathered during serialization.

The handler is called once per preloaded attribute with the gathered objects and that attribute's preloads. ORM plugins register a handler that performs the actual eager loading.

Examples:

with a block

preload_with { |objects, preloads| MyORM.eager_load(objects, preloads) }

with a callable value

preload_with MyPreloader

Parameters:

  • value (#call, nil) (defaults to: nil)

    Preload handler accepting two positional arguments

  • block (Proc)

    Preload handler accepting two positional arguments

Returns:

  • (#call, nil)

    The registered preload handler

Raises:



255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/serega.rb', line 255

def preload_with(value = nil, &block)
  return @preload_with if value.nil? && block.nil?
  raise SeregaError, "preload_with accepts a single callable or a block, not both" if value && block

  handler = value || block
  raise SeregaError, "preload_with value must be a Proc or respond to #call" if !handler.is_a?(Proc) && !handler.respond_to?(:call)

  signature = SeregaUtils::MethodSignature.call(handler, pos_limit: 2)
  raise SeregaError, "preload_with handler must accept two positional arguments: (objects, preloads)" unless signature == "2"

  @preload_with = handler
end

#to_data(object, opts = nil) ⇒ Data, ...

Serializes provided object to a tree of Ruby Data objects

Parameters:

  • object (Object)

    Serialized object

  • opts (Hash, nil) (defaults to: nil)

    Serializer modifiers and other instantiating options

Options Hash (opts):

  • :only (Array, Hash, String, Symbol)

    The only attributes to serialize

  • :except (Array, Hash, String, Symbol)

    Attributes to hide

  • :with (Array, Hash, String, Symbol)

    Attributes (usually hidden) to serialize additionally

  • :validate (Boolean)

    Validates provided modifiers (Default is true)

  • :context (Hash)

    Serialization context

  • :many (Boolean)

    Set true if provided multiple objects (Default object.is_a?(Enumerable) && !object.is_a?(Hash) && !object.is_a?(Struct))

Returns:

  • (Data, Array<Data>, nil)

    Serialization result as Data object(s)



303
304
305
306
307
308
# File 'lib/serega.rb', line 303

def to_data(object, opts = nil)
  opts = opts&.transform_keys(&:to_sym)
  modifiers_opts = init_modifier_opts(opts)
  serialize_opts = init_serialize_opts(opts)
  new(modifiers_opts).to_data(object, serialize_opts)
end