lib/fast_serializer/serializer.rb in fast_serializer-1.0.2 vs lib/fast_serializer/serializer.rb in fast_serializer-1.1.0
- old
+ new
@@ -92,13 +92,29 @@
#
# * enumerable: Boolean flag indicating if the field is enumerable (defaults to false). This option is only
# used if the :serializer option has been set. If the field is marked as enumerable, then the value will be
# serialized as an array with each element wrapped in the specified serializer.
#
+ # * condition: Block or method name that will be called at runtime bound to the serializer that will
+ # determine if the attribute will be included or not.
+ #
# Subclasses will inherit all of their parent classes serialized fields. Subclasses can override fields
# defined on the parent class by simply defining them again.
- def serialize(*fields, as: nil, optional: false, delegate: true, serializer: nil, serializer_options: nil, enumerable: false)
+ def serialize(*fields)
+ options = {}
+ if fields.size > 1 && fields.last.is_a?(Hash)
+ options = fields.last
+ fields = fields[0, fields.size - 1]
+ end
+ as = options[:as]
+ optional = options.fetch(:optional, false)
+ delegate = options.fetch(:delegate, true)
+ enumerable = options.fetch(:enumerable, false)
+ serializer = options[:serializer]
+ serializer_options = options[:serializer_options]
+ condition = options[:if]
+
if as && fields.size > 1
raise ArgumentError.new("Cannot specify :as argument with multiple fields to serialize")
end
fields.each do |field|
@@ -107,11 +123,11 @@
name = field.to_s.chomp("?".freeze)
end
field = field.to_sym
attribute = (name || field).to_sym
- add_field(attribute, optional: optional, serializer: serializer, serializer_options: serializer_options, enumerable: enumerable)
+ add_field(attribute, optional: optional, serializer: serializer, serializer_options: serializer_options, enumerable: enumerable, condition: condition)
if delegate && !method_defined?(attribute)
define_delegate(attribute, field)
end
end
@@ -207,13 +223,20 @@
end
private
# Add a field to be serialized.
- def add_field(name, optional:, serializer:, serializer_options:, enumerable:)
+ def add_field(name, optional:, serializer:, serializer_options:, enumerable:, condition:)
name = name.to_sym
- field = SerializedField.new(name, optional: optional, serializer: serializer, serializer_options: serializer_options, enumerable: enumerable)
+ if condition.is_a?(Proc)
+ include_method_name = "__include_#{name}?".to_sym
+ define_method(include_method_name, condition)
+ private include_method_name
+ condition = include_method_name
+ end
+
+ field = SerializedField.new(name, optional: optional, serializer: serializer, serializer_options: serializer_options, enumerable: enumerable, condition: condition)
# Add the field to the frozen list of fields.
field_list = []
added = false
serializable_fields.each do |existing_field|
@@ -276,10 +299,14 @@
# Fetch the specified option from the options hash.
def option(name)
@options[name] if @options
end
+ def scope
+ option(:scope)
+ end
+
# Return true if this serializer is cacheable.
def cacheable?
option(:cacheable) || self.class.cacheable?
end
@@ -295,11 +322,12 @@
# Returns a array of the elements that make this serializer unique. The
# key is an array made up of the serializer class name, wrapped object, and
# serialization options hash.
def cache_key
- [self.class.name, object, options]
+ object_cache_key = (object.respond_to?(:cache_key) ? object.cache_key : object)
+ [self.class.name, object_cache_key, options_cache_key(options)]
end
# :nodoc:
def ==(other)
other.instance_of?(self.class) && @object == other.object && @options == other.options
@@ -314,21 +342,44 @@
include_fields = included_optional_fields
excluded_fields = excluded_regular_fields
SerializationContext.use do
self.class.serializable_fields.each do |field|
name = field.name
+
if field.optional?
next unless include_fields && include_fields.include?(name)
end
- next if excluded_fields && excluded_fields.include?(name)
- value = field.serialize(send(name))
+ next if excluded_fields && excluded_fields[name] == true
+ condition = field.condition
+ next if condition && !send(condition)
+
+ value = field.serialize(send(name), serializer_options(name))
hash[name] = value
end
end
hash
end
+ def serializer_options(name)
+ opts = options
+ return nil unless opts
+ if opts && (opts.include?(:include) || opts.include?(:exclude))
+ opts = opts.dup
+ include_options = opts[:include]
+ if include_options.is_a?(Hash)
+ include_options = include_options[name.to_sym]
+ opts[:include] = include_options if include_options
+ end
+ exclude_options = options[:exclude]
+ if exclude_options.is_a?(Hash)
+ exclude_options = exclude_options[name.to_sym]
+ opts[:exclude] = exclude_options if exclude_options
+ end
+ end
+ opts
+ end
+
# Load the hash that will represent the wrapped object as a serialized object from a cache.
def load_from_cache
if cache
cache.fetch(self, cache_ttl) do
load_hash
@@ -338,26 +389,54 @@
end
end
private
- # Return a list of optional fields to be included in the output from the :include option.
- def included_optional_fields
- included_fields = option(:include)
- if included_fields
- Array(included_fields).collect(&:to_sym)
+ def options_cache_key(options)
+ return nil if options.nil?
+ if options.respond_to?(:cache_key)
+ options.cache_key
+ elsif options.is_a?(Hash)
+ hash_key = {}
+ options.each do |key, value|
+ hash_key[key] = options_cache_key(value)
+ end
+ hash_key
+ elsif options.is_a?(Enumerable)
+ options.collect{|option| options_cache_key(option)}
else
- nil
+ options
end
end
+ # Return a list of optional fields to be included in the output from the :include option.
+ def included_optional_fields
+ normalize_field_list(option(:include))
+ end
+
# Return a list of fields to be excluded from the output from the :exclude option.
def excluded_regular_fields
- excluded_fields = option(:exclude)
- if excluded_fields
- Array(excluded_fields).collect(&:to_sym)
+ normalize_field_list(option(:exclude))
+ end
+
+ def normalize_field_list(vals)
+ return nil if vals.nil?
+ if vals.is_a?(Hash)
+ hash = nil
+ vals.each do |key, values|
+ if hash || !key.is_a?(Symbol)
+ hash ||= {}
+ hash[key.to_sym] = values
+ end
+ end
+ vals = hash if hash
else
- nil
+ hash = {}
+ Array(vals).each do |key|
+ hash[key.to_sym] = true
+ end
+ vals = hash
end
+ vals
end
end
end