activeobject 0.0.3

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 (80) hide show
  1. data/CHANGE +10 -0
  2. data/Interface_desc +21 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README +72 -0
  5. data/Rakefile.rb +9 -0
  6. data/active-object.gemspec +50 -0
  7. data/examples/account.rb +69 -0
  8. data/examples/data.tch +0 -0
  9. data/examples/light_cloud.yml +18 -0
  10. data/examples/test.rb +3 -0
  11. data/examples/user.rb +112 -0
  12. data/init.rb +4 -0
  13. data/lib/active-object.rb +23 -0
  14. data/lib/active_object/adapters/light_cloud.rb +40 -0
  15. data/lib/active_object/adapters/tokyo_cabinet.rb +48 -0
  16. data/lib/active_object/adapters/tokyo_tyrant.rb +14 -0
  17. data/lib/active_object/associations.rb +200 -0
  18. data/lib/active_object/base.rb +415 -0
  19. data/lib/active_object/callbacks.rb +180 -0
  20. data/lib/active_object/observer.rb +180 -0
  21. data/lib/active_object/serialization.rb +99 -0
  22. data/lib/active_object/serializers/json_serializer.rb +75 -0
  23. data/lib/active_object/serializers/xml_serializer.rb +325 -0
  24. data/lib/active_object/validations.rb +687 -0
  25. data/lib/active_support/callbacks.rb +303 -0
  26. data/lib/active_support/core_ext/array/access.rb +53 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +183 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +20 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +106 -0
  30. data/lib/active_support/core_ext/array/random_access.rb +12 -0
  31. data/lib/active_support/core_ext/array.rb +13 -0
  32. data/lib/active_support/core_ext/blank.rb +58 -0
  33. data/lib/active_support/core_ext/class/attribute_accessors.rb +54 -0
  34. data/lib/active_support/core_ext/class/inheritable_attributes.rb +140 -0
  35. data/lib/active_support/core_ext/class/removal.rb +50 -0
  36. data/lib/active_support/core_ext/class.rb +3 -0
  37. data/lib/active_support/core_ext/duplicable.rb +43 -0
  38. data/lib/active_support/core_ext/enumerable.rb +72 -0
  39. data/lib/active_support/core_ext/hash/conversions.rb +259 -0
  40. data/lib/active_support/core_ext/hash/keys.rb +52 -0
  41. data/lib/active_support/core_ext/hash.rb +8 -0
  42. data/lib/active_support/core_ext/module/aliasing.rb +74 -0
  43. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
  44. data/lib/active_support/core_ext/module/attribute_accessors.rb +58 -0
  45. data/lib/active_support/core_ext/module.rb +16 -0
  46. data/lib/active_support/core_ext/object/conversions.rb +14 -0
  47. data/lib/active_support/core_ext/object/extending.rb +80 -0
  48. data/lib/active_support/core_ext/object/instance_variables.rb +74 -0
  49. data/lib/active_support/core_ext/object/metaclass.rb +13 -0
  50. data/lib/active_support/core_ext/object/misc.rb +43 -0
  51. data/lib/active_support/core_ext/object.rb +5 -0
  52. data/lib/active_support/core_ext/string/inflections.rb +167 -0
  53. data/lib/active_support/core_ext/string.rb +7 -0
  54. data/lib/active_support/core_ext.rb +4 -0
  55. data/lib/active_support/inflections.rb +55 -0
  56. data/lib/active_support/inflector.rb +348 -0
  57. data/lib/active_support/vendor/builder-2.1.2/blankslate.rb +113 -0
  58. data/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +20 -0
  59. data/lib/active_support/vendor/builder-2.1.2/builder/css.rb +250 -0
  60. data/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +115 -0
  61. data/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +139 -0
  62. data/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +63 -0
  63. data/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +328 -0
  64. data/lib/active_support/vendor/builder-2.1.2/builder.rb +13 -0
  65. data/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +1021 -0
  66. data/lib/active_support/vendor.rb +14 -0
  67. data/lib/active_support.rb +6 -0
  68. data/spec/case/association_test.rb +97 -0
  69. data/spec/case/base_test.rb +74 -0
  70. data/spec/case/callbacks_observers_test.rb +38 -0
  71. data/spec/case/callbacks_test.rb +424 -0
  72. data/spec/case/serialization_test.rb +87 -0
  73. data/spec/case/validations_test.rb +1482 -0
  74. data/spec/data.tch +0 -0
  75. data/spec/helper.rb +15 -0
  76. data/spec/light_cloud.yml +18 -0
  77. data/spec/model/account.rb +4 -0
  78. data/spec/model/topic.rb +26 -0
  79. data/spec/model/user.rb +8 -0
  80. metadata +173 -0
@@ -0,0 +1,180 @@
1
+ require 'observer'
2
+
3
+ module ActiveObject
4
+ # Callbacks是一个Ant Mapper对象生命周期内的钩子函数,允许你在对象状态改变的之前或之后触发相关规则.
5
+
6
+ # 当一个新对象的 <tt>Base#save</tt> 方法被调用时:
7
+ #
8
+ # * (-) <tt>save</tt>
9
+ # * (-) <tt>valid</tt>
10
+ # * (1) <tt>before_validation</tt>
11
+ # * (2) <tt>before_validation_on_create</tt>
12
+ # * (-) <tt>validate</tt>
13
+ # * (-) <tt>validate_on_create</tt>
14
+ # * (3) <tt>after_validation</tt>
15
+ # * (4) <tt>after_validation_on_create</tt>
16
+ # * (5) <tt>before_save</tt>
17
+ # * (6) <tt>before_create</tt>
18
+ # * (-) <tt>create</tt>
19
+ # * (7) <tt>after_create</tt>
20
+ # * (8) <tt>after_save</tt>
21
+ #
22
+ # 这里总共有8个回调.已经存在的记录调用<tt>Base#save</tt>时,除了<tt>_on_create</tt> 回调被<tt>_on_update</tt>取代外,其它都一样.
23
+ #
24
+ # 示例:
25
+ # class CreditCard < ActiveObject::Base
26
+ # # Strip everything but digits, so the user can specify "555 234 34" or
27
+ # # "5552-3434" or both will mean "55523434"
28
+ # def before_validation_on_create
29
+ # self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
30
+ # end
31
+ # end
32
+ #
33
+ # class Subscription < ActiveObject::Base
34
+ # before_create :record_signup
35
+ #
36
+ # private
37
+ # def record_signup
38
+ # self.signed_up_on = Date.today
39
+ # end
40
+ # end
41
+ #
42
+ #
43
+ # == 继承回调序列
44
+ #
45
+ # 除了重写回调方法外,它也可以通过使用回调宏注册回调.宏能添加行为到回调序列,这样在多级继承时,能保留回调序列的完整。
46
+ # 示例:
47
+ #
48
+ # class Topic < ActiveObject::Base
49
+ # before_destroy :destroy_author
50
+ # end
51
+ #
52
+ # class Reply < Topic
53
+ # before_destroy :destroy_readers
54
+ # end
55
+ #
56
+ # 现在, 当 <tt>Topic#destroy</tt> 运行时只调用 +destroy_author+.当<tt>Reply#destroy</tt>运行时,将调用+destroy_author+ 和 # +destroy_readers+ 。
57
+ #
58
+ #
59
+ module Callbacks
60
+ CALLBACKS = %w(
61
+ after_find after_initialize before_save after_save before_create after_create before_update after_update before_validation
62
+ after_validation before_validation_on_create after_validation_on_create before_validation_on_update
63
+ after_validation_on_update before_destroy after_destroy
64
+ )
65
+
66
+ def self.included(base) #:nodoc:
67
+ base.extend Observable
68
+
69
+ [:initialize,:create_or_update, :valid?, :create, :update, :destroy].each do |method|
70
+ base.send :alias_method_chain, method, :callbacks
71
+ end
72
+
73
+ base.send :include, ActiveSupport::Callbacks
74
+ base.define_callbacks *CALLBACKS
75
+ end
76
+
77
+ # 在调用<tt>Base.new</tt>时,对象被初始化之后执行。
78
+ def after_initialize() end
79
+
80
+ def initialize_with_callbacks(*args)
81
+ result = initialize_without_callbacks(*args)
82
+ callback(:after_initialize)
83
+ result
84
+ end
85
+
86
+ # 在执行<tt>Base.save</tt>之前被调用 (不管是创建还是更新).
87
+ def before_save() end
88
+
89
+ # 在执行<tt>Base.save</tt>被调用(不管是创建还是更新).
90
+ #
91
+ # class Contact < ActiveObject::Base
92
+ # after_save { logger.info( 'New contact saved!' ) }
93
+ # end
94
+ def after_save() end
95
+ def create_or_update_with_callbacks #:nodoc:
96
+ return false if callback(:before_save) == false
97
+ result = create_or_update_without_callbacks
98
+ callback(:after_save)
99
+ result
100
+ end
101
+ private :create_or_update_with_callbacks
102
+
103
+
104
+ def before_create() end
105
+
106
+ def after_create() end
107
+ def create_with_callbacks #:nodoc:
108
+ return false if callback(:before_create) == false
109
+ result = create_without_callbacks
110
+ callback(:after_create)
111
+ result
112
+ end
113
+ private :create_with_callbacks
114
+
115
+ def before_update() end
116
+
117
+ def after_update() end
118
+
119
+ def update_with_callbacks(*args) #:nodoc:
120
+ return false if callback(:before_update) == false
121
+ result = update_without_callbacks(*args)
122
+ callback(:after_update)
123
+ result
124
+ end
125
+ private :update_with_callbacks
126
+
127
+ def before_validation() end
128
+
129
+ def after_validation() end
130
+
131
+ def before_validation_on_create() end
132
+
133
+ def after_validation_on_create() end
134
+
135
+ def before_validation_on_update() end
136
+
137
+ def after_validation_on_update() end
138
+
139
+ def valid_with_callbacks? #:nodoc:
140
+ return false if callback(:before_validation) == false
141
+ if new_record? then result = callback(:before_validation_on_create) else result = callback(:before_validation_on_update) end
142
+ return false if false == result
143
+
144
+ result = valid_without_callbacks?
145
+
146
+ callback(:after_validation)
147
+ if new_record? then callback(:after_validation_on_create) else callback(:after_validation_on_update) end
148
+
149
+ return result
150
+ end
151
+
152
+ def before_destroy() end
153
+
154
+ def after_destroy() end
155
+ def destroy_with_callbacks #:nodoc:
156
+ return false if callback(:before_destroy) == false
157
+ result = destroy_without_callbacks
158
+ callback(:after_destroy)
159
+ result
160
+ end
161
+
162
+ private
163
+ def callback(method)
164
+ result = run_callbacks(method) { |result, object| false == result }
165
+
166
+ if result != false #&& respond_to_without_attributes?(method)
167
+ result = send(method)
168
+ end
169
+
170
+ notify(method)
171
+
172
+ return result
173
+ end
174
+
175
+ def notify(method) #:nodoc:
176
+ self.class.changed
177
+ self.class.notify_observers(method, self)
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,180 @@
1
+ require 'singleton'
2
+ require 'set'
3
+
4
+ module ActiveObject
5
+ module Observing # :nodoc:
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ # 激活观察器. 示例:
12
+ #
13
+ # # 调用PersonObserver.instance
14
+ # ActiveObject::Base.observers = :person_observer
15
+ #
16
+ # # 调用Cacher.instance 和 GarbageCollector.instance
17
+ # ActiveObject::Base.observers = :cacher, :garbage_collector
18
+ #
19
+ # # 同上
20
+ # ActiveObject::Base.observers = Cacher, GarbageCollector
21
+ #
22
+ # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is
23
+ # called during startup, and before each development request.
24
+ def observers=(*observers)
25
+ @observers = observers.flatten
26
+ end
27
+
28
+ # 获得当前observers.
29
+ def observers
30
+ @observers ||= []
31
+ end
32
+
33
+ # 实例化全部Ant Mapper观察器.
34
+ def instantiate_observers
35
+ return if @observers.blank?
36
+ @observers.each do |observer|
37
+ if observer.respond_to?(:to_sym) # Symbol or String
38
+ observer.to_s.camelize.constantize.instance
39
+ elsif observer.respond_to?(:instance)
40
+ observer.instance
41
+ else
42
+ raise ArgumentError, "#{observer} must be a lowercase, underscored class name (or an instance of the class itself) responding to the instance method. Example: Person.observers = :big_brother # calls BigBrother.instance"
43
+ end
44
+ end
45
+ end
46
+
47
+ protected
48
+ # Notify observers when the observed class is subclassed.
49
+ def inherited(subclass)
50
+ super
51
+ changed
52
+ notify_observers :observed_class_inherited, subclass
53
+ end
54
+ end
55
+ end
56
+
57
+ # Observer classes respond to lifecycle callbacks to implement trigger-like
58
+ # behavior outside the original class. This is a great way to reduce the
59
+ # clutter that normally comes when the model class is burdened with
60
+ # functionality that doesn't pertain to the core responsibility of the
61
+ # class. Example:
62
+ #
63
+ # class CommentObserver < ActiveObject::Observer
64
+ # def after_save(comment)
65
+ # Notifications.deliver_comment("admin@do.com", "New comment was posted", comment)
66
+ # end
67
+ # end
68
+ #
69
+ # This Observer sends an email when a Comment#save is finished.
70
+ #
71
+ # class ContactObserver < ActiveObject::Observer
72
+ # def after_create(contact)
73
+ # contact.logger.info('New contact added!')
74
+ # end
75
+ #
76
+ # def after_destroy(contact)
77
+ # contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
78
+ # end
79
+ # end
80
+ #
81
+ # This Observer uses logger to log when specific callbacks are triggered.
82
+ #
83
+ # == Observing a class that can't be inferred
84
+ #
85
+ # Observers will by default be mapped to the class with which they share a name. So CommentObserver will
86
+ # be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer
87
+ # differently than the class you're interested in observing, you can use the Observer.observe class method which takes
88
+ # either the concrete class (Product) or a symbol for that class (:product):
89
+ #
90
+ # class AuditObserver < ActiveObject::Observer
91
+ # observe :account
92
+ #
93
+ # def after_update(account)
94
+ # AuditTrail.new(account, "UPDATED")
95
+ # end
96
+ # end
97
+ #
98
+ # If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:
99
+ #
100
+ # class AuditObserver < ActiveObject::Observer
101
+ # observe :account, :balance
102
+ #
103
+ # def after_update(record)
104
+ # AuditTrail.new(record, "UPDATED")
105
+ # end
106
+ # end
107
+ #
108
+ # The AuditObserver will now act on both updates to Account and Balance by treating them both as records.
109
+ #
110
+ # == Available callback methods
111
+ #
112
+ # The observer can implement callback methods for each of the methods described in the Callbacks module.
113
+ #
114
+ #
115
+ # == Loading
116
+ #
117
+ # Observers register themselves in the model class they observe, since it is the class that
118
+ # notifies them of events when they occur. As a side-effect, when an observer is loaded its
119
+ # corresponding model class is loaded.
120
+ #
121
+ # If by any chance you are using observed models in the initialization you can still
122
+ # load their observers by calling <tt>ModelObserver.instance</tt> before. Observers are
123
+ # singletons and that call instantiates and registers them.
124
+ #
125
+ class Observer
126
+ include Singleton
127
+
128
+ class << self
129
+ # Attaches the observer to the supplied model classes.
130
+ def observe(*models)
131
+ models.flatten!
132
+ models.collect! { |model| model.is_a?(Symbol) ? model.to_s.camelize.constantize : model }
133
+ define_method(:observed_classes) { Set.new(models) }
134
+ end
135
+
136
+ # The class observed by default is inferred from the observer's class name:
137
+ # assert_equal Person, PersonObserver.observed_class
138
+ def observed_class
139
+ if observed_class_name = name[/(.*)Observer/, 1]
140
+ observed_class_name.constantize
141
+ else
142
+ nil
143
+ end
144
+ end
145
+ end
146
+
147
+ # Start observing the declared classes and their subclasses.
148
+ def initialize
149
+ Set.new(observed_classes + observed_subclasses).each { |klass| add_observer! klass }
150
+ end
151
+
152
+ # Send observed_method(object) if the method exists.
153
+ def update(observed_method, object) #:nodoc:
154
+ send(observed_method, object) if respond_to?(observed_method)
155
+ end
156
+
157
+ # Special method sent by the observed class when it is inherited.
158
+ # Passes the new subclass.
159
+ def observed_class_inherited(subclass) #:nodoc:
160
+ self.class.observe(observed_classes + [subclass])
161
+ add_observer!(subclass)
162
+ end
163
+
164
+ protected
165
+ def observed_classes
166
+ Set.new([self.class.observed_class].compact.flatten)
167
+ end
168
+
169
+ def observed_subclasses
170
+ observed_classes.sum([]) { |klass| klass.send(:subclasses) }
171
+ end
172
+
173
+ def add_observer!(klass)
174
+ klass.add_observer(self)
175
+ if respond_to?(:after_find) && !klass.method_defined?(:after_find)
176
+ klass.class_eval 'def after_find() end'
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,99 @@
1
+ module ActiveObject #:nodoc:
2
+ module Serialization
3
+ class Serializer #:nodoc:
4
+ attr_reader :options
5
+
6
+ def initialize(object, options = {})
7
+ @object, @options = object, options.dup
8
+ end
9
+
10
+ # To replicate the behavior in ActiveObject#attributes,
11
+ # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
12
+ # for a N level model but is set for the N+1 level models,
13
+ # then because <tt>:except</tt> is set to a default value, the second
14
+ # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
15
+ # <tt>:only</tt> is set, always delete <tt>:except</tt>.
16
+ def serializable_attribute_names
17
+ attribute_names = @object.attributes
18
+
19
+ if options[:only]
20
+ options.delete(:except)
21
+ attribute_names = attribute_names & Array(options[:only]).collect { |n| n.to_s }
22
+ else
23
+ options[:except] = Array(options[:except])
24
+ attribute_names = attribute_names - options[:except].collect { |n| n.to_s }
25
+ end
26
+
27
+ attribute_names
28
+ end
29
+
30
+ def serializable_method_names
31
+ Array(options[:methods]).inject([]) do |method_attributes, name|
32
+ method_attributes << name if @object.respond_to?(name.to_s)
33
+ method_attributes
34
+ end
35
+ end
36
+
37
+ def serializable_names
38
+ serializable_attribute_names + serializable_method_names
39
+ end
40
+
41
+ # Add associations specified via the <tt>:includes</tt> option.
42
+ # Expects a block that takes as arguments:
43
+ # +association+ - name of the association
44
+ # +objects+ - the association object(s) to be serialized
45
+ # +opts+ - options for the association objects
46
+ def add_includes(&block)
47
+ if include_associations = options.delete(:include)
48
+ base_only_or_except = { :except => options[:except],
49
+ :only => options[:only] }
50
+
51
+ include_has_options = include_associations.is_a?(Hash)
52
+ associations = include_has_options ? include_associations.keys : Array(include_associations)
53
+
54
+ for association in associations
55
+ objects = @object.send association
56
+
57
+ objects = objects.objects if objects.is_a?(ActiveObject::Associations::HasManyAssociation::Collection)
58
+
59
+ unless objects.nil?
60
+ association_options = include_has_options ? include_associations[association] : base_only_or_except
61
+ opts = options.merge(association_options)
62
+ yield(association, objects, opts)
63
+ end
64
+ end
65
+
66
+ options[:include] = include_associations
67
+ end
68
+ end
69
+
70
+ def serializable_object
71
+ returning(serializable_object = {}) do
72
+ serializable_names.each { |name| serializable_object[name] = @object.send(name) }
73
+
74
+ add_includes do |association, objects, opts|
75
+ if objects.is_a?(Enumerable)
76
+ serializable_object[association] = objects.collect { |r| self.class.new(r, opts).serializable_object }
77
+ serializable_object.delete("#{association}_ids")
78
+ else
79
+ serializable_object[association] = self.class.new(objects, opts).serializable_object
80
+ serializable_object.delete("#{association}_id")
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+
87
+ def serialize
88
+ # overwrite to implement
89
+ end
90
+
91
+ def to_s(&block)
92
+ serialize(&block)
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ require 'active_object/serializers/xml_serializer'
99
+ require 'active_object/serializers/json_serializer'
@@ -0,0 +1,75 @@
1
+ module ActiveObject #:nodoc:
2
+ module Serialization
3
+ def self.included(base)
4
+ base.cattr_accessor :include_root_in_json, :instance_writer => false
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ # Returns a JSON string representing the model. Some configuration is
9
+ # available through +options+.
10
+ #
11
+ # Without any +options+, the returned JSON string will include all
12
+ # the model's attributes. For example:
13
+ #
14
+ # konata = User.find(1)
15
+ # konata.to_json
16
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
17
+ # "created_at": "2006/08/01", "awesome": true}
18
+ #
19
+ # The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the attributes
20
+ # included, and work similar to the +attributes+ method. For example:
21
+ #
22
+ # konata.to_json(:only => [ :id, :name ])
23
+ # # => {"id": 1, "name": "Konata Izumi"}
24
+ #
25
+ # konata.to_json(:except => [ :id, :created_at, :age ])
26
+ # # => {"name": "Konata Izumi", "awesome": true}
27
+ #
28
+ # To include any methods on the model, use <tt>:methods</tt>.
29
+ #
30
+ # konata.to_json(:methods => :permalink)
31
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
32
+ # "created_at": "2006/08/01", "awesome": true,
33
+ # "permalink": "1-konata-izumi"}
34
+ #
35
+ # To include associations, use <tt>:include</tt>.
36
+ #
37
+ # konata.to_json(:include => :posts)
38
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
39
+ # "created_at": "2006/08/01", "awesome": true,
40
+ # "posts": [{"id": 1, "author_id": 1, "title": "Welcome to the weblog"},
41
+ # {"id": 2, author_id: 1, "title": "So I was thinking"}]}
42
+ #
43
+ # 2nd level and higher order associations work as well:
44
+ #
45
+ # konata.to_json(:include => { :posts => {
46
+ # :include => { :comments => {
47
+ # :only => :body } },
48
+ # :only => :title } })
49
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
50
+ # "created_at": "2006/08/01", "awesome": true,
51
+ # "posts": [{"comments": [{"body": "1st post!"}, {"body": "Second!"}],
52
+ # "title": "Welcome to the weblog"},
53
+ # {"comments": [{"body": "Don't think too hard"}],
54
+ # "title": "So I was thinking"}]}
55
+ def to_json(options = {})
56
+ if include_root_in_json
57
+ "{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}"
58
+ else
59
+ JsonSerializer.new(self, options).to_s
60
+ end
61
+ end
62
+
63
+ class JsonSerializer < ActiveObject::Serialization::Serializer #:nodoc:
64
+ def serialize
65
+ serializable_object.to_json
66
+ end
67
+ end
68
+
69
+ module ClassMethods
70
+ def json_class_name
71
+ @json_class_name ||= name.demodulize.underscore.inspect
72
+ end
73
+ end
74
+ end
75
+ end