activemodel 3.0.0.beta4 → 3.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. data/CHANGELOG +1 -39
  2. data/MIT-LICENSE +1 -1
  3. data/README +16 -200
  4. data/lib/active_model.rb +19 -28
  5. data/lib/active_model/attribute_methods.rb +27 -142
  6. data/lib/active_model/conversion.rb +1 -37
  7. data/lib/active_model/dirty.rb +12 -51
  8. data/lib/active_model/errors.rb +22 -146
  9. data/lib/active_model/lint.rb +14 -48
  10. data/lib/active_model/locale/en.yml +23 -26
  11. data/lib/active_model/naming.rb +5 -41
  12. data/lib/active_model/observing.rb +16 -35
  13. data/lib/active_model/serialization.rb +0 -57
  14. data/lib/active_model/serializers/json.rb +8 -13
  15. data/lib/active_model/serializers/xml.rb +123 -63
  16. data/lib/active_model/state_machine.rb +70 -0
  17. data/lib/active_model/state_machine/event.rb +62 -0
  18. data/lib/active_model/state_machine/machine.rb +75 -0
  19. data/lib/active_model/state_machine/state.rb +47 -0
  20. data/lib/active_model/state_machine/state_transition.rb +40 -0
  21. data/lib/active_model/test_case.rb +2 -0
  22. data/lib/active_model/validations.rb +62 -125
  23. data/lib/active_model/validations/acceptance.rb +18 -23
  24. data/lib/active_model/validations/confirmation.rb +10 -14
  25. data/lib/active_model/validations/exclusion.rb +13 -15
  26. data/lib/active_model/validations/format.rb +24 -26
  27. data/lib/active_model/validations/inclusion.rb +13 -15
  28. data/lib/active_model/validations/length.rb +65 -61
  29. data/lib/active_model/validations/numericality.rb +58 -76
  30. data/lib/active_model/validations/presence.rb +8 -8
  31. data/lib/active_model/validations/with.rb +22 -90
  32. data/lib/active_model/validations_repair_helper.rb +35 -0
  33. data/lib/active_model/version.rb +2 -3
  34. metadata +19 -63
  35. data/lib/active_model/callbacks.rb +0 -134
  36. data/lib/active_model/railtie.rb +0 -2
  37. data/lib/active_model/translation.rb +0 -60
  38. data/lib/active_model/validations/validates.rb +0 -108
  39. data/lib/active_model/validator.rb +0 -183
@@ -1,27 +1,24 @@
1
1
  en:
2
- errors:
3
- # The default format use in full error messages.
4
- format: "%{attribute} %{message}"
5
-
6
- # The values :model, :attribute and :value are always available for interpolation
7
- # The value :count is available when applicable. Can be used for pluralization.
8
- messages:
9
- inclusion: "is not included in the list"
10
- exclusion: "is reserved"
11
- invalid: "is invalid"
12
- confirmation: "doesn't match confirmation"
13
- accepted: "must be accepted"
14
- empty: "can't be empty"
15
- blank: "can't be blank"
16
- too_long: "is too long (maximum is %{count} characters)"
17
- too_short: "is too short (minimum is %{count} characters)"
18
- wrong_length: "is the wrong length (should be %{count} characters)"
19
- not_a_number: "is not a number"
20
- not_an_integer: "must be an integer"
21
- greater_than: "must be greater than %{count}"
22
- greater_than_or_equal_to: "must be greater than or equal to %{count}"
23
- equal_to: "must be equal to %{count}"
24
- less_than: "must be less than %{count}"
25
- less_than_or_equal_to: "must be less than or equal to %{count}"
26
- odd: "must be odd"
27
- even: "must be even"
2
+ activemodel:
3
+ errors:
4
+ # The values :model, :attribute and :value are always available for interpolation
5
+ # The value :count is available when applicable. Can be used for pluralization.
6
+ messages:
7
+ inclusion: "is not included in the list"
8
+ exclusion: "is reserved"
9
+ invalid: "is invalid"
10
+ confirmation: "doesn't match confirmation"
11
+ accepted: "must be accepted"
12
+ empty: "can't be empty"
13
+ blank: "can't be blank"
14
+ too_long: "is too long (maximum is {{count}} characters)"
15
+ too_short: "is too short (minimum is {{count}} characters)"
16
+ wrong_length: "is the wrong length (should be {{count}} characters)"
17
+ not_a_number: "is not a number"
18
+ greater_than: "must be greater than {{count}}"
19
+ greater_than_or_equal_to: "must be greater than or equal to {{count}}"
20
+ equal_to: "must be equal to {{count}}"
21
+ less_than: "must be less than {{count}}"
22
+ less_than_or_equal_to: "must be less than or equal to {{count}}"
23
+ odd: "must be odd"
24
+ even: "must be even"
@@ -1,62 +1,26 @@
1
1
  require 'active_support/inflector'
2
2
 
3
3
  module ActiveModel
4
-
5
4
  class Name < String
6
- attr_reader :singular, :plural, :element, :collection, :partial_path
5
+ attr_reader :singular, :plural, :element, :collection, :partial_path, :human
7
6
  alias_method :cache_key, :collection
8
7
 
9
- def initialize(klass)
10
- super(klass.name)
11
- @klass = klass
8
+ def initialize(name)
9
+ super
12
10
  @singular = ActiveSupport::Inflector.underscore(self).tr('/', '_').freeze
13
11
  @plural = ActiveSupport::Inflector.pluralize(@singular).freeze
14
12
  @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze
15
- @human = ActiveSupport::Inflector.humanize(@element).freeze
13
+ @human = @element.gsub(/_/, " ")
16
14
  @collection = ActiveSupport::Inflector.tableize(self).freeze
17
15
  @partial_path = "#{@collection}/#{@element}".freeze
18
16
  end
19
-
20
- # Transform the model name into a more humane format, using I18n. By default,
21
- # it will underscore then humanize the class name (BlogPost.model_name.human #=> "Blog post").
22
- # Specify +options+ with additional translating options.
23
- def human(options={})
24
- return @human unless @klass.respond_to?(:lookup_ancestors) &&
25
- @klass.respond_to?(:i18n_scope)
26
-
27
- defaults = @klass.lookup_ancestors.map do |klass|
28
- klass.model_name.underscore.to_sym
29
- end
30
-
31
- defaults << options.delete(:default) if options[:default]
32
- defaults << @human
33
-
34
- options.reverse_merge! :scope => [@klass.i18n_scope, :models], :count => 1, :default => defaults
35
- I18n.translate(defaults.shift, options)
36
- end
37
17
  end
38
18
 
39
- # ActiveModel::Naming is a module that creates a +model_name+ method on your
40
- # object.
41
- #
42
- # To implement, just extend ActiveModel::Naming in your object:
43
- #
44
- # class BookCover
45
- # extend ActiveModel::Naming
46
- # end
47
- #
48
- # BookCover.model_name #=> "BookCover"
49
- # BookCover.model_name.human #=> "Book cover"
50
- #
51
- # Providing the functionality that ActiveModel::Naming provides in your object
52
- # is required to pass the ActiveModel Lint test. So either extending the provided
53
- # method below, or rolling your own is required..
54
19
  module Naming
55
20
  # Returns an ActiveModel::Name object for module. It can be
56
21
  # used to retrieve all kinds of naming-related information.
57
22
  def model_name
58
- @_model_name ||= ActiveModel::Name.new(self)
23
+ @_model_name ||= ActiveModel::Name.new(name)
59
24
  end
60
25
  end
61
-
62
26
  end
@@ -1,13 +1,17 @@
1
+ require 'observer'
1
2
  require 'singleton'
2
3
  require 'active_support/core_ext/array/wrap'
3
4
  require 'active_support/core_ext/module/aliasing'
4
5
  require 'active_support/core_ext/string/inflections'
5
- require 'active_support/core_ext/string/conversions'
6
6
 
7
7
  module ActiveModel
8
8
  module Observing
9
9
  extend ActiveSupport::Concern
10
10
 
11
+ included do
12
+ extend Observable
13
+ end
14
+
11
15
  module ClassMethods
12
16
  # Activates the observers assigned. Examples:
13
17
  #
@@ -20,9 +24,8 @@ module ActiveModel
20
24
  # # Same as above, just using explicit class references
21
25
  # ActiveRecord::Base.observers = Cacher, GarbageCollector
22
26
  #
23
- # Note: Setting this does not instantiate the observers yet.
24
- # +instantiate_observers+ is called during startup, and before
25
- # each development request.
27
+ # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is
28
+ # called during startup, and before each development request.
26
29
  def observers=(*values)
27
30
  @observers = values.flatten
28
31
  end
@@ -37,26 +40,6 @@ module ActiveModel
37
40
  observers.each { |o| instantiate_observer(o) }
38
41
  end
39
42
 
40
- def add_observer(observer)
41
- unless observer.respond_to? :update
42
- raise ArgumentError, "observer needs to respond to `update'"
43
- end
44
- @observer_instances ||= []
45
- @observer_instances << observer
46
- end
47
-
48
- def notify_observers(*arg)
49
- if defined? @observer_instances
50
- for observer in @observer_instances
51
- observer.update(*arg)
52
- end
53
- end
54
- end
55
-
56
- def count_observers
57
- @observer_instances.size
58
- end
59
-
60
43
  protected
61
44
  def instantiate_observer(observer) #:nodoc:
62
45
  # string/symbol
@@ -72,6 +55,7 @@ module ActiveModel
72
55
  # Notify observers when the observed class is subclassed.
73
56
  def inherited(subclass)
74
57
  super
58
+ changed
75
59
  notify_observers :observed_class_inherited, subclass
76
60
  end
77
61
  end
@@ -85,6 +69,7 @@ module ActiveModel
85
69
  # notify_observers(:after_save)
86
70
  # end
87
71
  def notify_observers(method)
72
+ self.class.changed
88
73
  self.class.notify_observers(method, self)
89
74
  end
90
75
  end
@@ -117,12 +102,10 @@ module ActiveModel
117
102
  #
118
103
  # == Observing a class that can't be inferred
119
104
  #
120
- # Observers will by default be mapped to the class with which they share a
121
- # name. So CommentObserver will be tied to observing Comment, ProductManagerObserver
122
- # to ProductManager, and so on. If you want to name your observer differently than
123
- # the class you're interested in observing, you can use the Observer.observe class
124
- # method which takes either the concrete class (Product) or a symbol for that
125
- # class (:product):
105
+ # Observers will by default be mapped to the class with which they share a name. So CommentObserver will
106
+ # be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer
107
+ # differently than the class you're interested in observing, you can use the Observer.observe class method which takes
108
+ # either the concrete class (Product) or a symbol for that class (:product):
126
109
  #
127
110
  # class AuditObserver < ActiveModel::Observer
128
111
  # observe :account
@@ -132,8 +115,7 @@ module ActiveModel
132
115
  # end
133
116
  # end
134
117
  #
135
- # If the audit observer needs to watch more than one kind of object, this can be
136
- # specified with multiple arguments:
118
+ # If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:
137
119
  #
138
120
  # class AuditObserver < ActiveModel::Observer
139
121
  # observe :account, :balance
@@ -143,8 +125,7 @@ module ActiveModel
143
125
  # end
144
126
  # end
145
127
  #
146
- # The AuditObserver will now act on both updates to Account and Balance by treating
147
- # them both as records.
128
+ # The AuditObserver will now act on both updates to Account and Balance by treating them both as records.
148
129
  #
149
130
  class Observer
150
131
  include Singleton
@@ -163,7 +144,7 @@ module ActiveModel
163
144
  #
164
145
  # class AuditObserver < ActiveModel::Observer
165
146
  # def self.observed_classes
166
- # [Account, Balance]
147
+ # [AccountObserver, BalanceObserver]
167
148
  # end
168
149
  # end
169
150
  def observed_classes
@@ -2,63 +2,6 @@ require 'active_support/core_ext/hash/except'
2
2
  require 'active_support/core_ext/hash/slice'
3
3
 
4
4
  module ActiveModel
5
- # Provides a basic serialization to a serializable_hash for your object.
6
- #
7
- # A minimal implementation could be:
8
- #
9
- # class Person
10
- #
11
- # include ActiveModel::Serialization
12
- #
13
- # attr_accessor :name
14
- #
15
- # def attributes
16
- # @attributes ||= {'name' => 'nil'}
17
- # end
18
- #
19
- # end
20
- #
21
- # Which would provide you with:
22
- #
23
- # person = Person.new
24
- # person.serializable_hash # => {"name"=>nil}
25
- # person.name = "Bob"
26
- # person.serializable_hash # => {"name"=>"Bob"}
27
- #
28
- # You need to declare some sort of attributes hash which contains the attributes
29
- # you want to serialize and their current value.
30
- #
31
- # Most of the time though, you will want to include the JSON or XML
32
- # serializations. Both of these modules automatically include the
33
- # ActiveModel::Serialization module, so there is no need to explicitly
34
- # include it.
35
- #
36
- # So a minimal implementation including XML and JSON would be:
37
- #
38
- # class Person
39
- #
40
- # include ActiveModel::Serializers::JSON
41
- # include ActiveModel::Serializers::Xml
42
- #
43
- # attr_accessor :name
44
- #
45
- # def attributes
46
- # @attributes ||= {'name' => 'nil'}
47
- # end
48
- #
49
- # end
50
- #
51
- # Which would provide you with:
52
- #
53
- # person = Person.new
54
- # person.serializable_hash # => {"name"=>nil}
55
- # person.to_json # => "{\"name\":null}"
56
- # person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
57
- #
58
- # person.name = "Bob"
59
- # person.serializable_hash # => {"name"=>"Bob"}
60
- # person.to_json # => "{\"name\":\"Bob\"}"
61
- # person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
62
5
  module Serialization
63
6
  def serializable_hash(options = nil)
64
7
  options ||= {}
@@ -1,5 +1,5 @@
1
1
  require 'active_support/json'
2
- require 'active_support/core_ext/class/attribute'
2
+ require 'active_support/core_ext/class/attribute_accessors'
3
3
 
4
4
  module ActiveModel
5
5
  module Serializers
@@ -10,18 +10,19 @@ module ActiveModel
10
10
  included do
11
11
  extend ActiveModel::Naming
12
12
 
13
- class_attribute :include_root_in_json
14
- self.include_root_in_json = true
13
+ cattr_accessor :include_root_in_json, :instance_writer => false
15
14
  end
16
15
 
17
16
  # Returns a JSON string representing the model. Some configuration is
18
17
  # available through +options+.
19
18
  #
20
- # The option <tt>ActiveModel::Base.include_root_in_json</tt> controls the
21
- # top-level behavior of to_json. It is true by default. When it is <tt>true</tt>,
19
+ # The option <tt>ActiveRecord::Base.include_root_in_json</tt> controls the
20
+ # top-level behavior of to_json. In a new Rails application, it is set to
21
+ # <tt>true</tt> in initializers/new_rails_defaults.rb. When it is <tt>true</tt>,
22
22
  # to_json will emit a single root node named after the object's type. For example:
23
23
  #
24
24
  # konata = User.find(1)
25
+ # ActiveRecord::Base.include_root_in_json = true
25
26
  # konata.to_json
26
27
  # # => { "user": {"id": 1, "name": "Konata Izumi", "age": 16,
27
28
  # "created_at": "2006/08/01", "awesome": true} }
@@ -80,11 +81,7 @@ module ActiveModel
80
81
  # "title": "So I was thinking"}]}
81
82
  def encode_json(encoder)
82
83
  hash = serializable_hash(encoder.options)
83
- if include_root_in_json
84
- custom_root = encoder.options && encoder.options[:root]
85
- hash = { custom_root || self.class.model_name.element => hash }
86
- end
87
-
84
+ hash = { self.class.model_name.element => hash } if include_root_in_json
88
85
  ActiveSupport::JSON.encode(hash)
89
86
  end
90
87
 
@@ -93,9 +90,7 @@ module ActiveModel
93
90
  end
94
91
 
95
92
  def from_json(json)
96
- hash = ActiveSupport::JSON.decode(json)
97
- hash = hash.values.first if include_root_in_json
98
- self.attributes = hash
93
+ self.attributes = ActiveSupport::JSON.decode(json)
99
94
  self
100
95
  end
101
96
  end
@@ -1,8 +1,5 @@
1
- require 'active_support/core_ext/array/wrap'
2
1
  require 'active_support/core_ext/class/attribute_accessors'
3
- require 'active_support/core_ext/array/conversions'
4
2
  require 'active_support/core_ext/hash/conversions'
5
- require 'active_support/core_ext/hash/slice'
6
3
 
7
4
  module ActiveModel
8
5
  module Serializers
@@ -14,31 +11,68 @@ module ActiveModel
14
11
  class Attribute #:nodoc:
15
12
  attr_reader :name, :value, :type
16
13
 
17
- def initialize(name, serializable, raw_value=nil)
14
+ def initialize(name, serializable)
18
15
  @name, @serializable = name, serializable
19
- @value = value || @serializable.send(name)
20
16
  @type = compute_type
17
+ @value = compute_value
21
18
  end
22
19
 
23
- def decorations
20
+ # There is a significant speed improvement if the value
21
+ # does not need to be escaped, as <tt>tag!</tt> escapes all values
22
+ # to ensure that valid XML is generated. For known binary
23
+ # values, it is at least an order of magnitude faster to
24
+ # Base64 encode binary values and directly put them in the
25
+ # output XML than to pass the original value or the Base64
26
+ # encoded value to the <tt>tag!</tt> method. It definitely makes
27
+ # no sense to Base64 encode the value and then give it to
28
+ # <tt>tag!</tt>, since that just adds additional overhead.
29
+ def needs_encoding?
30
+ ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type)
31
+ end
32
+
33
+ def decorations(include_types = true)
24
34
  decorations = {}
25
- decorations[:encoding] = 'base64' if type == :binary
26
- decorations[:type] = type unless type == :string
27
- decorations[:nil] = true if value.nil?
35
+
36
+ if type == :binary
37
+ decorations[:encoding] = 'base64'
38
+ end
39
+
40
+ if include_types && type != :string
41
+ decorations[:type] = type
42
+ end
43
+
44
+ if value.nil?
45
+ decorations[:nil] = true
46
+ end
47
+
28
48
  decorations
29
49
  end
30
50
 
31
- protected
51
+ protected
52
+ def compute_type
53
+ value = @serializable.send(name)
54
+ type = Hash::XML_TYPE_NAMES[value.class.name]
55
+ type ||= :string if value.respond_to?(:to_str)
56
+ type ||= :yaml
57
+ type
58
+ end
32
59
 
33
- def compute_type
34
- type = ActiveSupport::XmlMini::TYPE_NAMES[value.class.name]
35
- type ||= :string if value.respond_to?(:to_str)
36
- type ||= :yaml
37
- type
38
- end
60
+ def compute_value
61
+ value = @serializable.send(name)
62
+
63
+ if formatter = Hash::XML_FORMATTING[type.to_s]
64
+ value ? formatter.call(value) : nil
65
+ else
66
+ value
67
+ end
68
+ end
39
69
  end
40
70
 
41
71
  class MethodAttribute < Attribute #:nodoc:
72
+ protected
73
+ def compute_type
74
+ Hash::XML_TYPE_NAMES[@serializable.send(name).class.name] || :string
75
+ end
42
76
  end
43
77
 
44
78
  attr_reader :options
@@ -51,84 +85,110 @@ module ActiveModel
51
85
  @options[:except] = Array.wrap(@options[:except]).map { |n| n.to_s }
52
86
  end
53
87
 
54
- # To replicate the behavior in ActiveRecord#attributes, <tt>:except</tt>
55
- # takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
88
+ # To replicate the behavior in ActiveRecord#attributes,
89
+ # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
56
90
  # for a N level model but is set for the N+1 level models,
57
91
  # then because <tt>:except</tt> is set to a default value, the second
58
92
  # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
59
93
  # <tt>:only</tt> is set, always delete <tt>:except</tt>.
60
- def attributes_hash
61
- attributes = @serializable.attributes
94
+ def serializable_attribute_names
95
+ attribute_names = @serializable.attributes.keys.sort
96
+
62
97
  if options[:only].any?
63
- attributes.slice(*options[:only])
98
+ attribute_names &= options[:only]
64
99
  elsif options[:except].any?
65
- attributes.except(*options[:except])
66
- else
67
- attributes
100
+ attribute_names -= options[:except]
68
101
  end
102
+
103
+ attribute_names
69
104
  end
70
105
 
71
106
  def serializable_attributes
72
- attributes_hash.map do |name, value|
73
- self.class::Attribute.new(name, @serializable, value)
74
- end
107
+ serializable_attribute_names.collect { |name| Attribute.new(name, @serializable) }
75
108
  end
76
109
 
77
- def serializable_methods
78
- Array.wrap(options[:methods]).inject([]) do |methods, name|
79
- methods << self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
110
+ def serializable_method_attributes
111
+ Array(options[:methods]).inject([]) do |methods, name|
112
+ methods << MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
80
113
  methods
81
114
  end
82
115
  end
83
116
 
84
117
  def serialize
85
- require 'builder' unless defined? ::Builder
86
-
87
- options[:indent] ||= 2
88
- options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
89
-
90
- @builder = options[:builder]
91
- @builder.instruct! unless options[:skip_instruct]
118
+ args = [root]
92
119
 
93
- root = (options[:root] || @serializable.class.model_name.element).to_s
94
- root = ActiveSupport::XmlMini.rename_key(root, options)
120
+ if options[:namespace]
121
+ args << {:xmlns => options[:namespace]}
122
+ end
95
123
 
96
- args = [root]
97
- args << {:xmlns => options[:namespace]} if options[:namespace]
98
- args << {:type => options[:type]} if options[:type] && !options[:skip_types]
124
+ if options[:type]
125
+ args << {:type => options[:type]}
126
+ end
99
127
 
100
- @builder.tag!(*args) do
101
- add_attributes_and_methods
102
- add_extra_behavior
128
+ builder.tag!(*args) do
129
+ add_attributes
130
+ procs = options.delete(:procs)
131
+ options[:procs] = procs
103
132
  add_procs
104
- yield @builder if block_given?
133
+ yield builder if block_given?
105
134
  end
106
135
  end
107
136
 
108
- private
137
+ private
138
+ def builder
139
+ @builder ||= begin
140
+ require 'builder' unless defined? ::Builder
141
+ options[:indent] ||= 2
142
+ builder = options[:builder] ||= ::Builder::XmlMarkup.new(:indent => options[:indent])
109
143
 
110
- def add_extra_behavior
111
- end
144
+ unless options[:skip_instruct]
145
+ builder.instruct!
146
+ options[:skip_instruct] = true
147
+ end
112
148
 
113
- def add_attributes_and_methods
114
- (serializable_attributes + serializable_methods).each do |attribute|
115
- key = ActiveSupport::XmlMini.rename_key(attribute.name, options)
116
- ActiveSupport::XmlMini.to_tag(key, attribute.value,
117
- options.merge(attribute.decorations))
149
+ builder
150
+ end
118
151
  end
119
- end
120
152
 
121
- def add_procs
122
- if procs = options.delete(:procs)
123
- Array.wrap(procs).each do |proc|
124
- if proc.arity == 1
125
- proc.call(options)
126
- else
127
- proc.call(options, @serializable)
153
+ def root
154
+ root = (options[:root] || @serializable.class.model_name.singular).to_s
155
+ reformat_name(root)
156
+ end
157
+
158
+ def dasherize?
159
+ !options.has_key?(:dasherize) || options[:dasherize]
160
+ end
161
+
162
+ def camelize?
163
+ options.has_key?(:camelize) && options[:camelize]
164
+ end
165
+
166
+ def reformat_name(name)
167
+ name = name.camelize if camelize?
168
+ dasherize? ? name.dasherize : name
169
+ end
170
+
171
+ def add_attributes
172
+ (serializable_attributes + serializable_method_attributes).each do |attribute|
173
+ builder.tag!(
174
+ reformat_name(attribute.name),
175
+ attribute.value.to_s,
176
+ attribute.decorations(!options[:skip_types])
177
+ )
178
+ end
179
+ end
180
+
181
+ def add_procs
182
+ if procs = options.delete(:procs)
183
+ [ *procs ].each do |proc|
184
+ if proc.arity > 1
185
+ proc.call(options, @serializable)
186
+ else
187
+ proc.call(options)
188
+ end
128
189
  end
129
190
  end
130
191
  end
131
- end
132
192
  end
133
193
 
134
194
  def to_xml(options = {}, &block)