Permalink
Browse files

Break up concerns for choosing what attributes should be serialized a…

…nd the actual serializer
  • Loading branch information...
1 parent 7a26c21 commit c6bc8e662614be711f45a8d4b231d5f993b024a7 @josh josh committed Aug 14, 2009
@@ -35,7 +35,7 @@ module ActiveModel
autoload :Naming, 'active_model/naming'
autoload :Observer, 'active_model/observing'
autoload :Observing, 'active_model/observing'
- autoload :Serializer, 'active_model/serializer'
+ autoload :Serialization, 'active_model/serialization'
autoload :StateMachine, 'active_model/state_machine'
autoload :TestCase, 'active_model/test_case'
autoload :Validations, 'active_model/validations'
@@ -0,0 +1,30 @@
+require 'active_support/core_ext/hash/except'
+require 'active_support/core_ext/hash/slice'
+
+module ActiveModel
+ module Serialization
+ def serializable_hash(options = nil)
+ options ||= {}
+
+ options[:only] = Array.wrap(options[:only]).map { |n| n.to_s }
+ options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
+
+ attribute_names = attributes.keys.sort
+ if options[:only].any?
+ attribute_names &= options[:only]
+ elsif options[:except].any?
+ attribute_names -= options[:except]
+ end
+
+ method_names = Array.wrap(options[:methods]).inject([]) do |methods, name|
+ methods << name if respond_to?(name.to_s)
+ methods
+ end
+
+ (attribute_names + method_names).inject({}) { |hash, name|
+ hash[name] = send(name)
+ hash
+ }
+ end
+ end
+end
@@ -1,60 +0,0 @@
-require 'active_support/core_ext/hash/except'
-require 'active_support/core_ext/hash/slice'
-
-module ActiveModel
- class Serializer
- attr_reader :options
-
- def initialize(serializable, options = nil)
- @serializable = serializable
- @options = options ? options.dup : {}
-
- @options[:only] = Array.wrap(@options[:only]).map { |n| n.to_s }
- @options[:except] = Array.wrap(@options[:except]).map { |n| n.to_s }
- end
-
- def serialize
- raise NotImplemented
- end
-
- def to_s(&block)
- serialize(&block)
- end
-
- # To replicate the behavior in ActiveRecord#attributes,
- # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
- # for a N level model but is set for the N+1 level models,
- # then because <tt>:except</tt> is set to a default value, the second
- # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
- # <tt>:only</tt> is set, always delete <tt>:except</tt>.
- def serializable_attribute_names
- attribute_names = @serializable.attributes.keys.sort
-
- if options[:only].any?
- attribute_names &= options[:only]
- elsif options[:except].any?
- attribute_names -= options[:except]
- end
-
- attribute_names
- end
-
- def serializable_method_names
- Array.wrap(options[:methods]).inject([]) do |methods, name|
- methods << name if @serializable.respond_to?(name.to_s)
- methods
- end
- end
-
- def serializable_names
- serializable_attribute_names + serializable_method_names
- end
-
- def serializable_hash
- serializable_names.inject({}) { |hash, name|
- hash[name] = @serializable.send(name)
- hash
- }
- end
- end
-end
@@ -5,26 +5,14 @@ module ActiveModel
module Serializers
module JSON
extend ActiveSupport::Concern
+ include ActiveModel::Serialization
included do
extend ActiveModel::Naming
cattr_accessor :include_root_in_json, :instance_writer => false
end
- class Serializer < ActiveModel::Serializer
- def serializable_hash
- model = super
- @serializable.include_root_in_json ?
- { @serializable.class.model_name.element => model } :
- model
- end
-
- def serialize
- ActiveSupport::JSON.encode(serializable_hash)
- end
- end
-
# Returns a JSON string representing the model. Some configuration is
# available through +options+.
#
@@ -92,7 +80,9 @@ def serialize
# {"comments": [{"body": "Don't think too hard"}],
# "title": "So I was thinking"}]}
def encode_json(encoder)
- Serializer.new(self, encoder.options).to_s
+ hash = serializable_hash(encoder.options)
+ hash = { self.class.model_name.element => hash } if include_root_in_json
+ ActiveSupport::JSON.encode(hash)
end
def as_json(options = nil)
@@ -5,8 +5,9 @@ module ActiveModel
module Serializers
module Xml
extend ActiveSupport::Concern
+ include ActiveModel::Serialization
- class Serializer < ActiveModel::Serializer #:nodoc:
+ class Serializer #:nodoc:
class Attribute #:nodoc:
attr_reader :name, :value, :type
@@ -74,32 +75,32 @@ def compute_type
end
end
- def builder
- @builder ||= begin
- require 'builder' unless defined? ::Builder
- options[:indent] ||= 2
- builder = options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
+ attr_reader :options
- unless options[:skip_instruct]
- builder.instruct!
- options[:skip_instruct] = true
- end
+ def initialize(serializable, options = nil)
+ @serializable = serializable
+ @options = options ? options.dup : {}
- builder
- end
+ @options[:only] = Array.wrap(@options[:only]).map { |n| n.to_s }
+ @options[:except] = Array.wrap(@options[:except]).map { |n| n.to_s }
end
- def root
- root = (options[:root] || @serializable.class.model_name.singular).to_s
- reformat_name(root)
- end
-
- def dasherize?
- !options.has_key?(:dasherize) || options[:dasherize]
- end
+ # To replicate the behavior in ActiveRecord#attributes,
+ # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
+ # for a N level model but is set for the N+1 level models,
+ # then because <tt>:except</tt> is set to a default value, the second
+ # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
+ # <tt>:only</tt> is set, always delete <tt>:except</tt>.
+ def serializable_attribute_names
+ attribute_names = @serializable.attributes.keys.sort
+
+ if options[:only].any?
+ attribute_names &= options[:only]
+ elsif options[:except].any?
+ attribute_names -= options[:except]
+ end
- def camelize?
- options.has_key?(:camelize) && options[:camelize]
+ attribute_names
end
def serializable_attributes
@@ -134,6 +135,34 @@ def serialize
end
private
+ def builder
+ @builder ||= begin
+ require 'builder' unless defined? ::Builder
+ options[:indent] ||= 2
+ builder = options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
+
+ unless options[:skip_instruct]
+ builder.instruct!
+ options[:skip_instruct] = true
+ end
+
+ builder
+ end
+ end
+
+ def root
+ root = (options[:root] || @serializable.class.model_name.singular).to_s
+ reformat_name(root)
+ end
+
+ def dasherize?
+ !options.has_key?(:dasherize) || options[:dasherize]
+ end
+
+ def camelize?
+ options.has_key?(:camelize) && options[:camelize]
+ end
+
def reformat_name(name)
name = name.camelize if camelize?
dasherize? ? name.dasherize : name
@@ -163,8 +192,7 @@ def add_procs
end
def to_xml(options = {}, &block)
- serializer = Serializer.new(self, options)
- block_given? ? serializer.to_s(&block) : serializer.to_s
+ Serializer.new(self, options).serialize(&block)
end
def from_xml(xml)
@@ -1,60 +1,58 @@
module ActiveRecord #:nodoc:
module Serialization
- module RecordSerializer #:nodoc:
- def initialize(*args)
- super
- options[:except] |= Array.wrap(@serializable.class.inheritance_column)
+ extend ActiveSupport::Concern
+ include ActiveModel::Serializers::JSON
+
+ def serializable_hash(options = nil)
+ options ||= {}
+
+ options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
+ options[:except] |= Array.wrap(self.class.inheritance_column)
+
+ hash = super(options)
+
+ serializable_add_includes(options) do |association, records, opts|
+ hash[association] = records.is_a?(Enumerable) ?
+ records.map { |r| r.serializable_hash(opts) } :
+ records.serializable_hash(opts)
end
+ hash
+ end
+
+ private
# Add associations specified via the <tt>:includes</tt> option.
# Expects a block that takes as arguments:
# +association+ - name of the association
# +records+ - the association record(s) to be serialized
# +opts+ - options for the association records
- def add_includes(&block)
- if include_associations = options.delete(:include)
- base_only_or_except = { :except => options[:except],
- :only => options[:only] }
-
- include_has_options = include_associations.is_a?(Hash)
- associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
-
- for association in associations
- records = case @serializable.class.reflect_on_association(association).macro
- when :has_many, :has_and_belongs_to_many
- @serializable.send(association).to_a
- when :has_one, :belongs_to
- @serializable.send(association)
- end
-
- unless records.nil?
- association_options = include_has_options ? include_associations[association] : base_only_or_except
- opts = options.merge(association_options)
- yield(association, records, opts)
- end
- end
+ def serializable_add_includes(options = {})
+ return unless include_associations = options.delete(:include)
- options[:include] = include_associations
- end
- end
+ base_only_or_except = { :except => options[:except],
+ :only => options[:only] }
+
+ include_has_options = include_associations.is_a?(Hash)
+ associations = include_has_options ? include_associations.keys : Array.wrap(include_associations)
- def serializable_hash
- hash = super
+ for association in associations
+ records = case self.class.reflect_on_association(association).macro
+ when :has_many, :has_and_belongs_to_many
+ send(association).to_a
+ when :has_one, :belongs_to
+ send(association)
+ end
- add_includes do |association, records, opts|
- hash[association] =
- if records.is_a?(Enumerable)
- records.collect { |r| self.class.new(r, opts).serializable_hash }
- else
- self.class.new(records, opts).serializable_hash
- end
+ unless records.nil?
+ association_options = include_has_options ? include_associations[association] : base_only_or_except
+ opts = options.merge(association_options)
+ yield(association, records, opts)
+ end
end
- hash
+ options[:include] = include_associations
end
- end
end
end
require 'active_record/serializers/xml_serializer'
-require 'active_record/serializers/json_serializer'
@@ -1,14 +0,0 @@
-module ActiveRecord #:nodoc:
- module Serialization
- extend ActiveSupport::Concern
- include ActiveModel::Serializers::JSON
-
- class JSONSerializer < ActiveModel::Serializers::JSON::Serializer
- include Serialization::RecordSerializer
- end
-
- def encode_json(encoder)
- JSONSerializer.new(self, encoder.options).to_s
- end
- end
-end
Oops, something went wrong.

0 comments on commit c6bc8e6

Please sign in to comment.