rubyamf-ouvrages 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +22 -0
- data/README.rdoc +105 -0
- data/Rakefile +21 -0
- data/lib/rubyamf.rb +64 -0
- data/lib/rubyamf/class_mapping.rb +239 -0
- data/lib/rubyamf/configuration.rb +272 -0
- data/lib/rubyamf/envelope.rb +102 -0
- data/lib/rubyamf/fault.rb +31 -0
- data/lib/rubyamf/gateway.png +0 -0
- data/lib/rubyamf/intermediate_object.rb +18 -0
- data/lib/rubyamf/logger.rb +39 -0
- data/lib/rubyamf/model.rb +215 -0
- data/lib/rubyamf/rails/controller.rb +23 -0
- data/lib/rubyamf/rails/model.rb +151 -0
- data/lib/rubyamf/rails/rails2_bootstrap.rb +73 -0
- data/lib/rubyamf/rails/rails3_bootstrap.rb +53 -0
- data/lib/rubyamf/rails/request_processor.rb +90 -0
- data/lib/rubyamf/rails/routing.rb +97 -0
- data/lib/rubyamf/rails/time.rb +6 -0
- data/lib/rubyamf/request_parser.rb +99 -0
- data/lib/rubyamf/test.rb +61 -0
- data/lib/rubyamf/version.rb +3 -0
- data/rubyamf.gemspec +26 -0
- data/spec/class_mapping_spec.rb +147 -0
- data/spec/configuration_spec.rb +90 -0
- data/spec/envelope_spec.rb +106 -0
- data/spec/fixtures/remotingMessage.bin +0 -0
- data/spec/fixtures/requestWithNewCredentials.bin +0 -0
- data/spec/fixtures/requestWithOldCredentials.bin +0 -0
- data/spec/fixtures/rubyamf_config.rb +24 -0
- data/spec/model_spec.rb +281 -0
- data/spec/rails_integration_spec.rb +22 -0
- data/spec/rails_routing_spec.rb +75 -0
- data/spec/request_parser_spec.rb +52 -0
- data/spec/request_processor_spec.rb +119 -0
- data/spec/spec_helper.rb +58 -0
- metadata +103 -0
@@ -0,0 +1,272 @@
|
|
1
|
+
module RubyAMF
|
2
|
+
# RubyAMF configuration container. It can be accessed by calling
|
3
|
+
# <tt>RubyAMF.configuration</tt>, or modified in a block like so:
|
4
|
+
#
|
5
|
+
# RubyAMF.configure do |config|
|
6
|
+
# config.gateway_path = "/amf"
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# === Gateway configuration
|
10
|
+
#
|
11
|
+
# Gateway configuration includes the gateway path and details about parameter
|
12
|
+
# mapping.
|
13
|
+
#
|
14
|
+
# +gateway_path+::
|
15
|
+
# Default: <tt>"/rubyamf/gateway"</tt>. The URL that responds to AMF requests.
|
16
|
+
# The URL should start with a "/" and not end with a "/".
|
17
|
+
#
|
18
|
+
# +populate_params_hash+::
|
19
|
+
# Default: <tt>true</tt>. For Rails users, all amf parameters can be accessed
|
20
|
+
# in the controller by calling <tt>rubyamf_params</tt>. If enabled, the amf
|
21
|
+
# parameters are merged into the <tt>params</tt> hash as well.
|
22
|
+
#
|
23
|
+
# +show_html_gateway+::
|
24
|
+
# Default: <tt>true</tt>. If enabled, non-AMF requests to the gateway url
|
25
|
+
# will result in a simple HTML page being returned.
|
26
|
+
#
|
27
|
+
# +param_mappings+::
|
28
|
+
# A hash that stores parameter mappings. Should only be modified through
|
29
|
+
# calls to <tt>map_params</tt>
|
30
|
+
#
|
31
|
+
# === Serialization options
|
32
|
+
#
|
33
|
+
# RubyAMF provides a wide variety of customization options for serialization
|
34
|
+
# to simplify integration.
|
35
|
+
#
|
36
|
+
# +translate_case+::
|
37
|
+
# Default: <tt>false</tt>. If enabled, properties will be converted to
|
38
|
+
# underscore style on deserialization from actionscript and will be converted
|
39
|
+
# to camelcase on serialization. This allows you to use language appropriate
|
40
|
+
# case style and have RubyAMF automatically care of translation.
|
41
|
+
#
|
42
|
+
# +auto_class_mapping+::
|
43
|
+
# Default: <tt>false</tt>. If a class mapping for a given ruby or actionscript
|
44
|
+
# class has not been defined, automatically maps it during serialization or
|
45
|
+
# deserialization. Nested ruby or actionscript classes will be automatically
|
46
|
+
# mapped to the class name without the namespace. Example:
|
47
|
+
# <tt>com.rubyamf.User => User</tt> or <tt>RubyAMF::User => User</tt>.
|
48
|
+
#
|
49
|
+
# +use_array_collection+::
|
50
|
+
# Default: <tt>false</tt>. If enabled, all arrays will be serialized as
|
51
|
+
# <tt>ArrayCollection</tt> objects. You can override this on a per-array
|
52
|
+
# basis by setting <tt>is_array_collection</tt> on the array to <tt>true</tt>
|
53
|
+
# or <tt>false</tt>. (Implementation in RocketAMF)
|
54
|
+
#
|
55
|
+
# +hash_key_access+::
|
56
|
+
# Default: <tt>:string</tt>. If set to <tt>:symbol</tt>, all deserialized
|
57
|
+
# hashes have the keys as symbols. RocketAMF defaults to strings, so setting
|
58
|
+
# to <tt>:symbol</tt> will reduce performance and possibly open you up to
|
59
|
+
# memory usage attacks.
|
60
|
+
#
|
61
|
+
# +preload_models+::
|
62
|
+
# If you are using in-model mapping and don't have <tt>auto_class_mapping</tt>
|
63
|
+
# enabled, you may need to force classes to be loaded before mapping takes
|
64
|
+
# effect. Simply include all necessary classes as strings to have RubyAMF
|
65
|
+
# force them to be loaded on initialization.
|
66
|
+
# Example: <tt>config.preload_models = ["User", "Course"]</tt>
|
67
|
+
#
|
68
|
+
# +check_for_associations+::
|
69
|
+
# Default: <tt>true</tt>. If enabled, associations that have been pre-loaded,
|
70
|
+
# either through :include or simply by being accessed, will be automatically
|
71
|
+
# included during serialization without any additional configuration.
|
72
|
+
#
|
73
|
+
# +ignore_fields+::
|
74
|
+
# Default: <tt>['created_at', 'created_on', 'updated_at', 'updated_on']</tt>.
|
75
|
+
# A list of all properties that should not be deserialized by default. The
|
76
|
+
# class-level <tt>:ignore_fields</tt> config overrides this.
|
77
|
+
class Configuration
|
78
|
+
# Gateway options
|
79
|
+
attr_accessor :gateway_path, :populate_params_hash, :show_html_gateway
|
80
|
+
attr_reader :param_mappings
|
81
|
+
|
82
|
+
# Serialization options
|
83
|
+
attr_accessor :translate_case, :auto_class_mapping, :use_array_collection,
|
84
|
+
:hash_key_access, :preload_models, :check_for_associations,
|
85
|
+
:ignore_fields
|
86
|
+
|
87
|
+
def initialize
|
88
|
+
@gateway_path = "/rubyamf/gateway"
|
89
|
+
@param_mappings = {}
|
90
|
+
@populate_params_hash = true
|
91
|
+
@show_html_gateway = true
|
92
|
+
|
93
|
+
@translate_case = false
|
94
|
+
@auto_class_mapping = false
|
95
|
+
@use_array_collection = false
|
96
|
+
@hash_key_access = :string
|
97
|
+
@preload_models = []
|
98
|
+
@check_for_associations = true
|
99
|
+
@ignore_fields = ['created_at', 'created_on', 'updated_at', 'updated_on']
|
100
|
+
end
|
101
|
+
|
102
|
+
# Maps the given array of named parameters to the arguments for calls to the
|
103
|
+
# given controller and action. For Rails users, the prefered method of
|
104
|
+
# parameter mapping is through routing (see RubyAMF::Rails::Routing).
|
105
|
+
#
|
106
|
+
# Example:
|
107
|
+
#
|
108
|
+
# config.map_params "UserController", "login", [:session_token, :username, :password]
|
109
|
+
# # params hash => {
|
110
|
+
# # 0 => "asdf", 1 => "user", 2 => "pass",
|
111
|
+
# # :session_token => "asdf", :username => "user", :password => "pass"
|
112
|
+
# # }
|
113
|
+
def map_params controller, action, params
|
114
|
+
@param_mappings[controller.to_s+"#"+action.to_s] = params
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns the class mapper class being used
|
118
|
+
def class_mapper
|
119
|
+
if @class_mapper.nil?
|
120
|
+
@class_mapper = RubyAMF::ClassMapping
|
121
|
+
end
|
122
|
+
@class_mapper
|
123
|
+
end
|
124
|
+
|
125
|
+
# Set to the class of any conforming class mapper to use it instead of
|
126
|
+
# <tt>RubyAMF::ClassMapping</tt>. If you don't need any of the advanced
|
127
|
+
# features offered by the RubyAMF class mapper, you can gain some substantial
|
128
|
+
# performance improvements by settings this to
|
129
|
+
# <tt>RocketAMF::Ext::FastClassMapping</tt> or <tt>RocketAMF::ClassMapping</tt>
|
130
|
+
# for the slower pure-ruby version.
|
131
|
+
def class_mapper= klass
|
132
|
+
@class_mapper = klass
|
133
|
+
end
|
134
|
+
|
135
|
+
# Loads the legacy config file at the given path or tries to locate it by
|
136
|
+
# looking for a <tt>rubyamf_config.rb</tt> file in several possible locations.
|
137
|
+
# Automatically run by RubyAMF if you are using Rails 2, it should be run
|
138
|
+
# before any additional configuration if you are not using Rails 2, as it
|
139
|
+
# overrides all previous configuration.
|
140
|
+
def load_legacy path=nil
|
141
|
+
# Locate legacy config
|
142
|
+
unless path
|
143
|
+
possible = []
|
144
|
+
possible << File.join(RAILS_ROOT, 'config', 'rubyamf_config.rb') if defined?(RAILS_ROOT)
|
145
|
+
possible << File.join('config', 'rubyamf_config.rb')
|
146
|
+
possible << 'rubyamf_config.rb'
|
147
|
+
unless path = possible.find {|p| File.exists?(p)}
|
148
|
+
raise "rubyamf_config.rb not found"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Load legacy config
|
153
|
+
$" << "app/configuration" # prevent legacy code require from doing anything
|
154
|
+
LegacySandbox.module_eval(File.read(path))
|
155
|
+
$".pop
|
156
|
+
cm = LegacySandbox::RubyAMF::ClassMappings
|
157
|
+
pm = LegacySandbox::RubyAMF::ParameterMappings
|
158
|
+
|
159
|
+
# Raise exceptions for disabled settings
|
160
|
+
if cm.force_active_record_ids != nil; raise "CONFIG PARSE ERROR: force_active_record_ids is no longer supported. Use <tt>:except</tt> if you want to prevent the id from being serialized."; end
|
161
|
+
if cm.hash_key_access == :indifferent; raise "CONFIG PARSE ERROR: indifferent hash_key_access is not supported for performance reasons. Use either :string or :symbol, the default."; end
|
162
|
+
if cm.default_mapping_scope != nil; raise "CONFIG PARSE ERROR: default_mapping_scope is not supported globally. Please log a feature request if you need it, or use switch to the new config syntax which supports per-model defaults."; end
|
163
|
+
if cm.use_ruby_date_time == true; raise "CONFIG PARSE ERROR: use_ruby_date_time is not supported by RocketAMF. Please log a feature request if you need it."; end
|
164
|
+
if pm.scaffolding == true; raise "CONFIG PARSE ERROR: scaffolding is not supported. Please log a feature request if you need it."; end
|
165
|
+
|
166
|
+
# Populate ClassMappings configs from legacy config
|
167
|
+
@ignore_fields = cm.ignore_fields unless cm.ignore_fields.nil?
|
168
|
+
@translate_case = cm.translate_case if cm.translate_case == true
|
169
|
+
@hash_key_access = cm.hash_key_access unless cm.hash_key_access.nil?
|
170
|
+
@use_array_collection = cm.use_array_collection if cm.use_array_collection == true
|
171
|
+
@check_for_associations = cm.check_for_associations if cm.check_for_associations == false
|
172
|
+
mapset = class_mapper.mappings
|
173
|
+
(cm.mappings || []).each do |legacy_mapping|
|
174
|
+
mapping = {}
|
175
|
+
if legacy_mapping[:type] == 'active_resource'
|
176
|
+
raise "CONFIG PARSE ERROR: active_resource mapping type is not supported. Please log a feature request or stop using it."
|
177
|
+
end
|
178
|
+
|
179
|
+
# Extract unscoped settings
|
180
|
+
mapping[:as] = legacy_mapping[:actionscript]
|
181
|
+
mapping[:ruby] = legacy_mapping[:ruby]
|
182
|
+
mapping[:methods] = legacy_mapping[:methods] unless legacy_mapping[:methods].nil?
|
183
|
+
mapping[:ignore_fields] = legacy_mapping[:ignore_fields] unless legacy_mapping[:ignore_fields].nil?
|
184
|
+
|
185
|
+
# Process possibly scoped settings
|
186
|
+
attrs = legacy_mapping[:attributes]
|
187
|
+
assoc = legacy_mapping[:associations]
|
188
|
+
if attrs.is_a?(Hash) || assoc.is_a?(Hash)
|
189
|
+
# Extract scopes
|
190
|
+
scopes = []
|
191
|
+
scopes += attrs.keys if attrs.is_a?(Hash)
|
192
|
+
scopes += assoc.keys if assoc.is_a?(Hash)
|
193
|
+
|
194
|
+
# Build settings for scopes
|
195
|
+
scopes.each do |scope|
|
196
|
+
scoped = mapping.dup
|
197
|
+
scoped[:scope] = scope.to_sym
|
198
|
+
scoped[:only] = attrs.is_a?(Hash) ? attrs[scope] : attrs
|
199
|
+
scoped.delete(:only) if scoped[:only].nil?
|
200
|
+
scoped[:include] = assoc.is_a?(Hash) ? assoc[scope] : assoc
|
201
|
+
scoped.delete(:include) if scoped[:include].nil?
|
202
|
+
mapset.map scoped
|
203
|
+
end
|
204
|
+
else
|
205
|
+
# No scoping
|
206
|
+
mapping[:only] = attrs unless attrs.nil?
|
207
|
+
mapping[:include] = assoc unless assoc.nil?
|
208
|
+
mapset.map mapping
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# Populate ParameterMapping configs from legacy config
|
213
|
+
@populate_params_hash = pm.always_add_to_params if pm.always_add_to_params == false
|
214
|
+
(pm.mappings || []).each do |m|
|
215
|
+
params = []
|
216
|
+
m[:params].each do |k, v|
|
217
|
+
unless v =~ /\[(\d+)\]/
|
218
|
+
raise "CONFIG PARSE ERROR: parameter mappings are no longer evalled - '#{v}' must match [DIGITS]. Please log a feature request if you need this."
|
219
|
+
end
|
220
|
+
params[$1.to_i] = k
|
221
|
+
end
|
222
|
+
self.map_params m[:controller], m[:action], params
|
223
|
+
end
|
224
|
+
|
225
|
+
# Reset sandbox
|
226
|
+
cm.reset
|
227
|
+
pm.reset
|
228
|
+
|
229
|
+
self
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
module LegacySandbox #:nodoc:
|
234
|
+
module RubyAMF #:nodoc:
|
235
|
+
module ClassMappings #:nodoc:
|
236
|
+
class << self
|
237
|
+
attr_accessor :ignore_fields, :translate_case, :force_active_record_ids, :hash_key_access,
|
238
|
+
:assume_types, :default_mapping_scope, :use_ruby_date_time, :use_array_collection,
|
239
|
+
:check_for_associations, :mappings
|
240
|
+
|
241
|
+
def register mapping
|
242
|
+
@mappings ||= []
|
243
|
+
@mappings << mapping
|
244
|
+
end
|
245
|
+
|
246
|
+
def reset
|
247
|
+
methods.each do |m|
|
248
|
+
send(m, nil) if m =~ /[\w_]+=/
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
module ParameterMappings #:nodoc:
|
255
|
+
class << self
|
256
|
+
attr_accessor :always_add_to_params, :scaffolding, :mappings
|
257
|
+
|
258
|
+
def register mapping
|
259
|
+
@mappings ||= []
|
260
|
+
@mappings << mapping
|
261
|
+
end
|
262
|
+
|
263
|
+
def reset
|
264
|
+
methods.each do |m|
|
265
|
+
send(m, nil) if m =~ /[\w_]+=/
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module RubyAMF
|
4
|
+
# Adds several important features to RocketAMF::Envelope. None of these features
|
5
|
+
# are dependent on Rails, and as such can be used by any Rack compliant framework.
|
6
|
+
# Features are credentials support, easy parameter mapping based on configured
|
7
|
+
# parameter mappings, mapping scope support for serialization, and error handling
|
8
|
+
# for method dispatch using <tt>each_method_call</tt>.
|
9
|
+
class Envelope < RocketAMF::Envelope
|
10
|
+
attr_accessor :mapping_scope
|
11
|
+
|
12
|
+
# Finds and returns credentials set on the request as a hash with keys
|
13
|
+
# <tt>username</tt> and <tt>password</tt>, with the type dependent on the
|
14
|
+
# <tt>hash_key_access</tt> setting. <tt>setHeader('Credentials')</tt>
|
15
|
+
# credentials are used first, followed by new-style <tt>DSRemoteCredentials</tt>.
|
16
|
+
# If no credentials are found, a hash is returned with a username and password
|
17
|
+
# of <tt>nil</tt>.
|
18
|
+
def credentials
|
19
|
+
ds_cred_key = RubyAMF.configuration.translate_case ? "ds_remote_credentials" : "DSRemoteCredentials"
|
20
|
+
if RubyAMF.configuration.hash_key_access == :symbol
|
21
|
+
userid_key = :userid
|
22
|
+
username_key = :username
|
23
|
+
password_key = :password
|
24
|
+
ds_cred_key = ds_cred_key.to_sym
|
25
|
+
else
|
26
|
+
userid_key = "userid"
|
27
|
+
username_key = "username"
|
28
|
+
password_key = "password"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Old style setHeader('Credentials', CREDENTIALS_HASH)
|
32
|
+
if @headers['Credentials']
|
33
|
+
h = @headers['Credentials']
|
34
|
+
return {username_key => h.data[userid_key], password_key => h.data[password_key]}
|
35
|
+
end
|
36
|
+
|
37
|
+
# New style DSRemoteCredentials
|
38
|
+
messages.each do |m|
|
39
|
+
if m.data.is_a?(RocketAMF::Values::RemotingMessage)
|
40
|
+
if m.data.headers && m.data.headers[ds_cred_key]
|
41
|
+
username,password = Base64.decode64(m.data.headers[ds_cred_key]).split(':')
|
42
|
+
return {username_key => username, password_key => password}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Failure case sends empty credentials, because rubyamf_plugin does it
|
48
|
+
{username_key => nil, password_key => nil}
|
49
|
+
end
|
50
|
+
|
51
|
+
# Given a controller, action, and the flash arguments array, returns a hash
|
52
|
+
# containing the arguments indexed by number as well as named key if a named
|
53
|
+
# mapping has been configured. Returned hash respects <tt>hash_key_access</tt>
|
54
|
+
# setting for named keys.
|
55
|
+
#
|
56
|
+
# Example:
|
57
|
+
#
|
58
|
+
# RubyAMF.configuration.map_params "c", "a", ["param1", "param2"]
|
59
|
+
# params = envelope.params_hash "c", "a", ["asdf", "fdsa"]
|
60
|
+
# params.should == {:param1 => "asdf", :param2 => "fdsa", 0 => "asdf", 1 => "fdsa"}
|
61
|
+
def params_hash controller, action, arguments
|
62
|
+
conf = RubyAMF.configuration
|
63
|
+
mapped = {}
|
64
|
+
mapping = conf.param_mappings[controller+"#"+action]
|
65
|
+
arguments.each_with_index do |arg, i|
|
66
|
+
mapped[i] = arg
|
67
|
+
if mapping && mapping[i]
|
68
|
+
mapping_key = conf.hash_key_access == :symbol ? mapping[i].to_sym : mapping[i].to_s
|
69
|
+
mapped[mapping_key] = arg
|
70
|
+
end
|
71
|
+
end
|
72
|
+
mapped
|
73
|
+
end
|
74
|
+
|
75
|
+
# Extends default RocketAMF implementation to log caught exceptions and
|
76
|
+
# translate them into a RocketAMF::Values::ErrorMessage for return to flash
|
77
|
+
# after removing the backtrace (for safety).
|
78
|
+
def dispatch_call p
|
79
|
+
begin
|
80
|
+
ret = p[:block].call(p[:method], p[:args])
|
81
|
+
raise ret if ret.is_a?(Exception) # If they return FaultObject like you could in rubyamf_plugin
|
82
|
+
ret
|
83
|
+
rescue Exception => e
|
84
|
+
# Log exception
|
85
|
+
RubyAMF.logger.log_error(e)
|
86
|
+
|
87
|
+
# Clear backtrace so that RocketAMF doesn't send back the full backtrace
|
88
|
+
e.set_backtrace([])
|
89
|
+
|
90
|
+
# Create ErrorMessage object using the source message as the base
|
91
|
+
RocketAMF::Values::ErrorMessage.new(p[:source], e)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def serialize class_mapper=nil #:nodoc:
|
96
|
+
# Create a ClassMapper and set the mapping scope to pass to super implementation.
|
97
|
+
cm = class_mapper || RubyAMF::ClassMapper.new
|
98
|
+
cm.mapping_scope = mapping_scope if cm.respond_to?(:mapping_scope=)
|
99
|
+
super cm
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RubyAMF
|
2
|
+
class Fault < ::Exception #:nodoc:
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
# Convenience object carried over from rubyamf_plugin, it can be returned for
|
7
|
+
# AMF instead of raising an exception.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
#
|
11
|
+
# render :amf => FaultObject.new("No users to get")
|
12
|
+
class FaultObject
|
13
|
+
def self.new *args, &block
|
14
|
+
if args.length == 2
|
15
|
+
raise "payload for FaultObject is no longer available - if you need it you will need to create a custom class to contain your payload"
|
16
|
+
end
|
17
|
+
message = args.length > 0 ? args[0] : ''
|
18
|
+
|
19
|
+
begin
|
20
|
+
raise RubyAMF::Fault.new(message)
|
21
|
+
rescue Exception => e
|
22
|
+
# Fix backtrace
|
23
|
+
b = e.backtrace
|
24
|
+
b.shift
|
25
|
+
e.set_backtrace(b)
|
26
|
+
|
27
|
+
# Return new fault object
|
28
|
+
return e
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
Binary file
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RubyAMF
|
2
|
+
# IntermediateObject packages an object with its requested serialization options.
|
3
|
+
# This allows the pre-configured serialization configuration to be overridden
|
4
|
+
# as needed. They are automatically created by <tt>to_amf</tt> and should not
|
5
|
+
# be generated manually.
|
6
|
+
class IntermediateObject
|
7
|
+
attr_accessor :object, :options
|
8
|
+
|
9
|
+
def initialize object, options
|
10
|
+
@object = object
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def rubyamf_hash
|
15
|
+
@object.rubyamf_hash @options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module RubyAMF
|
4
|
+
class Logger #:nodoc:
|
5
|
+
# Log exceptions in rails-style, with cleaned backtrace if available
|
6
|
+
def log_error e
|
7
|
+
msg = "#{e.class} (#{e.message}):\n "
|
8
|
+
msg += clean_backtrace(e).join("\n ")
|
9
|
+
logger.fatal(msg)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Send every other method call to internally wrapped logger
|
13
|
+
def method_missing name, *args
|
14
|
+
logger.send(name, args)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
# Use rails logger if available or create standard ruby logger to STDERR
|
19
|
+
def logger
|
20
|
+
unless @logger
|
21
|
+
if defined?(Rails) && ::Rails.logger
|
22
|
+
@logger = ::Rails.logger
|
23
|
+
else
|
24
|
+
@logger = ::Logger.new(STDERR)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@logger
|
28
|
+
end
|
29
|
+
|
30
|
+
# Use Rails backtrace cleaner if it exists to clean
|
31
|
+
def clean_backtrace e
|
32
|
+
if defined?(Rails) && ::Rails.respond_to?(:backtrace_cleaner)
|
33
|
+
::Rails.backtrace_cleaner.clean(e.backtrace)
|
34
|
+
else
|
35
|
+
e.backtrace
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|