Class: OjSerializers::Serializer
- Inherits:
-
Object
- Object
- OjSerializers::Serializer
- Defined in:
- lib/oj_serializers/serializer.rb
Overview
Public: Implementation of an “ActiveModelSerializer”-like DSL, but with a design that allows replacing the internal object, which greatly reduces object allocation.
Unlike ActiveModelSerializer, which builds a Hash which then gets encoded to JSON, this implementation allows to use Oj::StringWriter to write directly to JSON, greatly reducing the overhead of allocating and garbage collecting the hashes.
Constant Summary collapse
- ALLOWED_INSTANCE_VARIABLES =
Public: Used to validate incorrect memoization during development. Users of this library might add additional options as needed.
%w[ memo object options _routes ]
- KNOWN_ATTRIBUTE_OPTIONS =
%i[ attribute association identifier if optional type serializer ].to_set
- CACHE =
(Rails) && Rails.cache) || (defined?(ActiveSupport::Cache::MemoryStore) ? ActiveSupport::Cache::MemoryStore.new : OjSerializers::Memo.new)
- DEV_MODE =
Internal: Used to display warnings or detect misusage during development.
%w[test development].include?(environment) && !ENV['BENCHMARK']
- DEFAULT_OPTIONS =
{}.freeze
Class Method Summary collapse
-
._attributes ⇒ Object
Internal: List of attributes to be serialized.
-
.default_format(format) ⇒ Object
Public: Allows the user to specify ‘default_format :json`, as a simple way to ensure that `.one` and `.many` work as in Version 1.
-
.inherited(subclass) ⇒ Object
Internal: Will alias the object according to the name of the wrapper class.
-
.many_as_hash(items, options = nil) ⇒ Object
Public: Renders an array of items using this serializer, without serializing to JSON.
-
.many_as_json(items, options = nil) ⇒ Object
Public: Serializes an array of items using this serializer.
-
.object_as(name) ⇒ Object
Public: Creates an alias for the internal object.
-
.one_as_hash(item, options = nil) ⇒ Object
Public: Renders the configured attributes for the specified object, without serializing to JSON.
-
.one_as_json(item, options = nil) ⇒ Object
Public: Serializes the configured attributes for the specified object.
-
.one_if(item, options = nil) ⇒ Object
Helper: Serializes the item unless it’s nil.
-
.render(item, options = nil) ⇒ Object
Helper: Serializes one or more items.
-
.render_as_hash(item, options = nil) ⇒ Object
Helper: Serializes one or more items.
-
.sort_attributes_by(strategy) ⇒ Object
Public: Allows to sort fields by name instead of by definition order, or pass a Proc to apply a custom order.
-
.transform_keys(strategy = nil, &block) ⇒ Object
Public: Allows to transform the JSON keys to camelCase, or pass a Proc to apply a custom transformation.
Instance Method Summary collapse
- #_check_instance_variables ⇒ Object
-
#options ⇒ Object
Backwards Compatibility: Allows to access options passed through ‘render json`, in the same way than ActiveModel::Serializers.
-
#write_many(writer, items, options = nil) ⇒ Object
Internal: Used internally to write an array of objects to JSON.
-
#write_one(writer, item, options = nil) ⇒ Object
Internal: Used internally to write a single object to JSON.
Class Method Details
._attributes ⇒ Object
Internal: List of attributes to be serialized.
Any attributes defined in parent classes are inherited.
234 235 236 |
# File 'lib/oj_serializers/serializer.rb', line 234 def _attributes @_attributes ||= superclass.try(:_attributes)&.dup || {} end |
.default_format(format) ⇒ Object
Public: Allows the user to specify ‘default_format :json`, as a simple way to ensure that `.one` and `.many` work as in Version 1.
This setting is inherited from parent classes.
105 106 107 108 |
# File 'lib/oj_serializers/serializer.rb', line 105 def default_format(format) define_singleton_method(:_default_format) { format } define_serialization_shortcuts end |
.inherited(subclass) ⇒ Object
Internal: Will alias the object according to the name of the wrapper class.
225 226 227 228 229 |
# File 'lib/oj_serializers/serializer.rb', line 225 def inherited(subclass) object_alias = subclass.name.demodulize.chomp('Serializer').underscore subclass.object_as(object_alias) unless method_defined?(object_alias) || object_alias == 'base' super end |
.many_as_hash(items, options = nil) ⇒ Object
Public: Renders an array of items using this serializer, without serializing to JSON.
items - Must respond to ‘each`. options - list of external options to pass to the sub class (available in `item.options`)
Returns an Array of Hash, each with the attributes specified in the serializer.
219 220 221 222 |
# File 'lib/oj_serializers/serializer.rb', line 219 def many_as_hash(items, = nil) serializer = instance items.map { |item| serializer.render_as_hash(item, ) } end |
.many_as_json(items, options = nil) ⇒ Object
Public: Serializes an array of items using this serializer.
items - Must respond to ‘each`. options - list of external options to pass to the sub class (available in `item.options`)
Returns an Oj::StringWriter instance, which is encoded as raw json.
195 196 197 198 199 |
# File 'lib/oj_serializers/serializer.rb', line 195 def many_as_json(items, = nil) writer = new_json_writer write_many(writer, items, ) writer end |
.object_as(name) ⇒ Object
Public: Creates an alias for the internal object.
140 141 142 |
# File 'lib/oj_serializers/serializer.rb', line 140 def object_as(name, **) define_method(name) { @object } end |
.one_as_hash(item, options = nil) ⇒ Object
Public: Renders the configured attributes for the specified object, without serializing to JSON.
item - the item to serialize options - list of external options to pass to the sub class (available in ‘item.options`)
Returns a Hash, with the attributes specified in the serializer.
208 209 210 |
# File 'lib/oj_serializers/serializer.rb', line 208 def one_as_hash(item, = nil) instance.render_as_hash(item, ) end |
.one_as_json(item, options = nil) ⇒ Object
Public: Serializes the configured attributes for the specified object.
item - the item to serialize options - list of external options to pass to the sub class (available in ‘item.options`)
Returns an Oj::StringWriter instance, which is encoded as raw json.
183 184 185 186 187 |
# File 'lib/oj_serializers/serializer.rb', line 183 def one_as_json(item, = nil) writer = new_json_writer write_one(writer, item, ) writer end |
.one_if(item, options = nil) ⇒ Object
Helper: Serializes the item unless it’s nil.
173 174 175 |
# File 'lib/oj_serializers/serializer.rb', line 173 def one_if(item, = nil) one(item, ) if item end |
.render(item, options = nil) ⇒ Object
Helper: Serializes one or more items.
163 164 165 |
# File 'lib/oj_serializers/serializer.rb', line 163 def render(item, = nil) many?(item) ? many(item, ) : one(item, ) end |
.render_as_hash(item, options = nil) ⇒ Object
Helper: Serializes one or more items.
168 169 170 |
# File 'lib/oj_serializers/serializer.rb', line 168 def render_as_hash(item, = nil) many?(item) ? many_as_hash(item, ) : one_as_hash(item, ) end |
.sort_attributes_by(strategy) ⇒ Object
Public: Allows to sort fields by name instead of by definition order, or pass a Proc to apply a custom order.
This setting is inherited from parent classes.
114 115 116 117 118 119 120 121 |
# File 'lib/oj_serializers/serializer.rb', line 114 def sort_attributes_by(strategy) case strategy when :name, :definition, Proc define_singleton_method(:_sort_attributes_by) { strategy } else raise ArgumentError, "Unknown sorting option: #{strategy.inspect}" end end |
.transform_keys(strategy = nil, &block) ⇒ Object
Public: Allows to transform the JSON keys to camelCase, or pass a Proc to apply a custom transformation.
This setting is inherited from parent classes.
127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/oj_serializers/serializer.rb', line 127 def transform_keys(strategy = nil, &block) transformer = case (strategy ||= block) when :camelize, :camel_case then ->(key) { key.camelize(:lower).chomp('?') } when :none then nil when Symbol then strategy.to_proc when Proc then strategy else raise(ArgumentError, "Expected transform_keys to be callable, got: #{strategy.inspect}") end define_singleton_method(:_transform_keys) { transformer } end |
Instance Method Details
#_check_instance_variables ⇒ Object
58 59 60 61 62 63 |
# File 'lib/oj_serializers/serializer.rb', line 58 def _check_instance_variables if instance_values.keys.any? { |key| !ALLOWED_INSTANCE_VARIABLES.include?(key) } bad_keys = instance_values.keys.reject { |key| ALLOWED_INSTANCE_VARIABLES.include?(key) } raise ArgumentError, "Serializer instances are reused so they must be stateless. Use `memo.fetch` for memoization purposes instead. Bad keys: #{bad_keys.join(',')} in #{self.class}" end end |
#options ⇒ Object
Backwards Compatibility: Allows to access options passed through ‘render json`, in the same way than ActiveModel::Serializers.
52 53 54 |
# File 'lib/oj_serializers/serializer.rb', line 52 def @options || DEFAULT_OPTIONS end |
#write_many(writer, items, options = nil) ⇒ Object
Internal: Used internally to write an array of objects to JSON.
writer - writer used to serialize results items - items to serialize results for options - list of external options to pass to the serializer (available as ‘options`)
85 86 87 88 89 90 91 |
# File 'lib/oj_serializers/serializer.rb', line 85 def write_many(writer, items, = nil) writer.push_array items.each do |item| write_one(writer, item, ) end writer.pop end |
#write_one(writer, item, options = nil) ⇒ Object
Internal: Used internally to write a single object to JSON.
writer - writer used to serialize results item - item to serialize results for options - list of external options to pass to the serializer (available as ‘options`)
NOTE: Binds this instance to the specified object and options and writes to json using the provided writer.
74 75 76 77 78 |
# File 'lib/oj_serializers/serializer.rb', line 74 def write_one(writer, item, = nil) writer.push_object write_to_json(writer, item, ) writer.pop end |