active_model_serializers/lib/active_model/serializer/include_tree.rb
Lucas Hosseini 35473cf983 Merge pull request #1186 from bf4/empty_else
Enforce case requires else; allow else nil
2015-09-21 17:48:27 +02:00

112 lines
3.6 KiB
Ruby

module ActiveModel
class Serializer
# TODO: description of this class, and overview of how it's used
class IncludeTree
module Parsing
module_function
# Translates a comma separated list of dot separated paths (JSON API format) into a Hash.
#
# @example
# `'posts.author, posts.comments.upvotes, posts.comments.author'`
#
# would become
#
# `{ posts: { author: {}, comments: { author: {}, upvotes: {} } } }`.
#
# @param [String] included
# @return [Hash] a Hash representing the same tree structure
def include_string_to_hash(included)
# TODO: Needs comment walking through the process of what all this is doing.
included.delete(' ').split(',').reduce({}) do |hash, path|
include_tree = path.split('.').reverse_each.reduce({}) { |a, e| { e.to_sym => a } }
hash.deep_merge!(include_tree)
end
end
# Translates the arguments passed to the include option into a Hash. The format can be either
# a String (see #include_string_to_hash), an Array of Symbols and Hashes, or a mix of both.
#
# @example
# `posts: [:author, comments: [:author, :upvotes]]`
#
# would become
#
# `{ posts: { author: {}, comments: { author: {}, upvotes: {} } } }`.
#
# @example
# `[:author, :comments => [:author]]`
#
# would become
#
# `{:author => {}, :comments => { author: {} } }`
#
# @param [Symbol, Hash, Array, String] included
# @return [Hash] a Hash representing the same tree structure
def include_args_to_hash(included)
case included
when Symbol
{ included => {} }
when Hash
included.each_with_object({}) do |(key, value), hash|
hash[key] = include_args_to_hash(value)
end
when Array
included.reduce({}) { |a, e| a.merge!(include_args_to_hash(e)) }
when String
include_string_to_hash(included)
else
{}
end
end
end
# Builds an IncludeTree from a comma separated list of dot separated paths (JSON API format).
# @example `'posts.author, posts.comments.upvotes, posts.comments.author'`
#
# @param [String] included
# @return [IncludeTree]
#
def self.from_string(included)
new(Parsing.include_string_to_hash(included))
end
# Translates the arguments passed to the include option into an IncludeTree.
# The format can be either a String (see #from_string), an Array of Symbols and Hashes, or a mix of both.
# @example `posts: [:author, comments: [:author, :upvotes]]`
#
# @param [Symbol, Hash, Array, String] included
# @return [IncludeTree]
#
def self.from_include_args(included)
return included if included.is_a?(IncludeTree)
new(Parsing.include_args_to_hash(included))
end
# @param [Hash] hash
def initialize(hash = {})
@hash = hash
end
def key?(key)
@hash.key?(key) || @hash.key?(:*) || @hash.key?(:**)
end
def [](key)
# TODO(beauby): Adopt a lazy caching strategy for generating subtrees.
case
when @hash.key?(key)
self.class.new(@hash[key])
when @hash.key?(:*)
self.class.new(@hash[:*])
when @hash.key?(:**)
self.class.new(:** => {})
else
nil
end
end
end
end
end