Checkout of Instiki Trunk 1/21/2007.
This commit is contained in:
commit
69b62b6f33
1138 changed files with 139586 additions and 0 deletions
201
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
vendored
Normal file
201
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
require 'benchmark'
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module Dispatcher # :nodoc:
|
||||
class DispatcherError < ActionWebService::ActionWebServiceError # :nodoc:
|
||||
end
|
||||
|
||||
def self.append_features(base) # :nodoc:
|
||||
super
|
||||
base.class_inheritable_option(:web_service_dispatching_mode, :direct)
|
||||
base.class_inheritable_option(:web_service_exception_reporting, true)
|
||||
base.send(:include, ActionWebService::Dispatcher::InstanceMethods)
|
||||
end
|
||||
|
||||
module InstanceMethods # :nodoc:
|
||||
private
|
||||
def invoke_web_service_request(protocol_request)
|
||||
invocation = web_service_invocation(protocol_request)
|
||||
if invocation.is_a?(Array) && protocol_request.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol)
|
||||
xmlrpc_multicall_invoke(invocation)
|
||||
else
|
||||
web_service_invoke(invocation)
|
||||
end
|
||||
end
|
||||
|
||||
def web_service_direct_invoke(invocation)
|
||||
@method_params = invocation.method_ordered_params
|
||||
arity = method(invocation.api_method.name).arity rescue 0
|
||||
if arity < 0 || arity > 0
|
||||
params = @method_params
|
||||
else
|
||||
params = []
|
||||
end
|
||||
web_service_filtered_invoke(invocation, params)
|
||||
end
|
||||
|
||||
def web_service_delegated_invoke(invocation)
|
||||
web_service_filtered_invoke(invocation, invocation.method_ordered_params)
|
||||
end
|
||||
|
||||
def web_service_filtered_invoke(invocation, params)
|
||||
cancellation_reason = nil
|
||||
return_value = invocation.service.perform_invocation(invocation.api_method.name, params) do |x|
|
||||
cancellation_reason = x
|
||||
end
|
||||
if cancellation_reason
|
||||
raise(DispatcherError, "request canceled: #{cancellation_reason}")
|
||||
end
|
||||
return_value
|
||||
end
|
||||
|
||||
def web_service_invoke(invocation)
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
return_value = web_service_direct_invoke(invocation)
|
||||
when :delegated, :layered
|
||||
return_value = web_service_delegated_invoke(invocation)
|
||||
end
|
||||
web_service_create_response(invocation.protocol, invocation.protocol_options, invocation.api, invocation.api_method, return_value)
|
||||
end
|
||||
|
||||
def xmlrpc_multicall_invoke(invocations)
|
||||
responses = []
|
||||
invocations.each do |invocation|
|
||||
if invocation.is_a?(Hash)
|
||||
responses << invocation
|
||||
next
|
||||
end
|
||||
begin
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
return_value = web_service_direct_invoke(invocation)
|
||||
when :delegated, :layered
|
||||
return_value = web_service_delegated_invoke(invocation)
|
||||
end
|
||||
api_method = invocation.api_method
|
||||
if invocation.api.has_api_method?(api_method.name)
|
||||
return_value = api_method.cast_returns(return_value)
|
||||
end
|
||||
responses << [return_value]
|
||||
rescue Exception => e
|
||||
responses << { 'faultCode' => 3, 'faultString' => e.message }
|
||||
end
|
||||
end
|
||||
invocation = invocations[0]
|
||||
invocation.protocol.encode_response('system.multicall', responses, nil, invocation.protocol_options)
|
||||
end
|
||||
|
||||
def web_service_invocation(request, level = 0)
|
||||
public_method_name = request.method_name
|
||||
invocation = Invocation.new
|
||||
invocation.protocol = request.protocol
|
||||
invocation.protocol_options = request.protocol_options
|
||||
invocation.service_name = request.service_name
|
||||
if web_service_dispatching_mode == :layered
|
||||
case invocation.protocol
|
||||
when Protocol::Soap::SoapProtocol
|
||||
soap_action = request.protocol_options[:soap_action]
|
||||
if soap_action && soap_action =~ /^\/\w+\/(\w+)\//
|
||||
invocation.service_name = $1
|
||||
end
|
||||
when Protocol::XmlRpc::XmlRpcProtocol
|
||||
if request.method_name =~ /^([^\.]+)\.(.*)$/
|
||||
public_method_name = $2
|
||||
invocation.service_name = $1
|
||||
end
|
||||
end
|
||||
end
|
||||
if invocation.protocol.is_a? Protocol::XmlRpc::XmlRpcProtocol
|
||||
if public_method_name == 'multicall' && invocation.service_name == 'system'
|
||||
if level > 0
|
||||
raise(DispatcherError, "Recursive system.multicall invocations not allowed")
|
||||
end
|
||||
multicall = request.method_params.dup
|
||||
unless multicall.is_a?(Array) && multicall[0].is_a?(Array)
|
||||
raise(DispatcherError, "Malformed multicall (expected array of Hash elements)")
|
||||
end
|
||||
multicall = multicall[0]
|
||||
return multicall.map do |item|
|
||||
raise(DispatcherError, "Multicall elements must be Hash") unless item.is_a?(Hash)
|
||||
raise(DispatcherError, "Multicall elements must contain a 'methodName' key") unless item.has_key?('methodName')
|
||||
method_name = item['methodName']
|
||||
params = item.has_key?('params') ? item['params'] : []
|
||||
multicall_request = request.dup
|
||||
multicall_request.method_name = method_name
|
||||
multicall_request.method_params = params
|
||||
begin
|
||||
web_service_invocation(multicall_request, level + 1)
|
||||
rescue Exception => e
|
||||
{'faultCode' => 4, 'faultMessage' => e.message}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
invocation.api = self.class.web_service_api
|
||||
invocation.service = self
|
||||
when :delegated, :layered
|
||||
invocation.service = web_service_object(invocation.service_name)
|
||||
invocation.api = invocation.service.class.web_service_api
|
||||
end
|
||||
if invocation.api.nil?
|
||||
raise(DispatcherError, "no API attached to #{invocation.service.class}")
|
||||
end
|
||||
invocation.protocol.register_api(invocation.api)
|
||||
request.api = invocation.api
|
||||
if invocation.api.has_public_api_method?(public_method_name)
|
||||
invocation.api_method = invocation.api.public_api_method_instance(public_method_name)
|
||||
else
|
||||
if invocation.api.default_api_method.nil?
|
||||
raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api}")
|
||||
else
|
||||
invocation.api_method = invocation.api.default_api_method_instance
|
||||
end
|
||||
end
|
||||
if invocation.service.nil?
|
||||
raise(DispatcherError, "no service available for service name #{invocation.service_name}")
|
||||
end
|
||||
unless invocation.service.respond_to?(invocation.api_method.name)
|
||||
raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api} (#{invocation.api_method.name})")
|
||||
end
|
||||
request.api_method = invocation.api_method
|
||||
begin
|
||||
invocation.method_ordered_params = invocation.api_method.cast_expects(request.method_params.dup)
|
||||
rescue
|
||||
logger.warn "Casting of method parameters failed" unless logger.nil?
|
||||
invocation.method_ordered_params = request.method_params
|
||||
end
|
||||
request.method_params = invocation.method_ordered_params
|
||||
invocation.method_named_params = {}
|
||||
invocation.api_method.param_names.inject(0) do |m, n|
|
||||
invocation.method_named_params[n] = invocation.method_ordered_params[m]
|
||||
m + 1
|
||||
end
|
||||
invocation
|
||||
end
|
||||
|
||||
def web_service_create_response(protocol, protocol_options, api, api_method, return_value)
|
||||
if api.has_api_method?(api_method.name)
|
||||
return_type = api_method.returns ? api_method.returns[0] : nil
|
||||
return_value = api_method.cast_returns(return_value)
|
||||
else
|
||||
return_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0)
|
||||
end
|
||||
protocol.encode_response(api_method.public_name + 'Response', return_value, return_type, protocol_options)
|
||||
end
|
||||
|
||||
class Invocation # :nodoc:
|
||||
attr_accessor :protocol
|
||||
attr_accessor :protocol_options
|
||||
attr_accessor :service_name
|
||||
attr_accessor :api
|
||||
attr_accessor :api_method
|
||||
attr_accessor :method_ordered_params
|
||||
attr_accessor :method_named_params
|
||||
attr_accessor :service
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
380
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
vendored
Normal file
380
vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
vendored
Normal file
|
@ -0,0 +1,380 @@
|
|||
require 'benchmark'
|
||||
require 'builder/xmlmarkup'
|
||||
|
||||
module ActionWebService # :nodoc:
|
||||
module Dispatcher # :nodoc:
|
||||
module ActionController # :nodoc:
|
||||
def self.append_features(base) # :nodoc:
|
||||
super
|
||||
class << base
|
||||
include ClassMethods
|
||||
alias_method :inherited_without_action_controller, :inherited
|
||||
alias_method :inherited, :inherited_with_action_controller
|
||||
end
|
||||
base.class_eval do
|
||||
alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke
|
||||
end
|
||||
base.add_web_service_api_callback do |klass, api|
|
||||
if klass.web_service_dispatching_mode == :direct
|
||||
klass.class_eval 'def api; dispatch_web_service_request; end'
|
||||
end
|
||||
end
|
||||
base.add_web_service_definition_callback do |klass, name, info|
|
||||
if klass.web_service_dispatching_mode == :delegated
|
||||
klass.class_eval "def #{name}; dispatch_web_service_request; end"
|
||||
elsif klass.web_service_dispatching_mode == :layered
|
||||
klass.class_eval 'def api; dispatch_web_service_request; end'
|
||||
end
|
||||
end
|
||||
base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods)
|
||||
end
|
||||
|
||||
module ClassMethods # :nodoc:
|
||||
def inherited_with_action_controller(child)
|
||||
inherited_without_action_controller(child)
|
||||
child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction)
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods # :nodoc:
|
||||
private
|
||||
def dispatch_web_service_request
|
||||
exception = nil
|
||||
begin
|
||||
ws_request = discover_web_service_request(request)
|
||||
rescue Exception => e
|
||||
exception = e
|
||||
end
|
||||
if ws_request
|
||||
ws_response = nil
|
||||
exception = nil
|
||||
bm = Benchmark.measure do
|
||||
begin
|
||||
ws_response = invoke_web_service_request(ws_request)
|
||||
rescue Exception => e
|
||||
exception = e
|
||||
end
|
||||
end
|
||||
log_request(ws_request, request.raw_post)
|
||||
if exception
|
||||
log_error(exception) unless logger.nil?
|
||||
send_web_service_error_response(ws_request, exception)
|
||||
else
|
||||
send_web_service_response(ws_response, bm.real)
|
||||
end
|
||||
else
|
||||
exception ||= DispatcherError.new("Malformed SOAP or XML-RPC protocol message")
|
||||
log_error(exception) unless logger.nil?
|
||||
send_web_service_error_response(ws_request, exception)
|
||||
end
|
||||
rescue Exception => e
|
||||
log_error(e) unless logger.nil?
|
||||
send_web_service_error_response(ws_request, e)
|
||||
end
|
||||
|
||||
def send_web_service_response(ws_response, elapsed=nil)
|
||||
log_response(ws_response, elapsed)
|
||||
options = { :type => ws_response.content_type, :disposition => 'inline' }
|
||||
send_data(ws_response.body, options)
|
||||
end
|
||||
|
||||
def send_web_service_error_response(ws_request, exception)
|
||||
if ws_request
|
||||
unless self.class.web_service_exception_reporting
|
||||
exception = DispatcherError.new("Internal server error (exception raised)")
|
||||
end
|
||||
api_method = ws_request.api_method
|
||||
public_method_name = api_method ? api_method.public_name : ws_request.method_name
|
||||
return_type = ActionWebService::SignatureTypes.canonical_signature_entry(Exception, 0)
|
||||
ws_response = ws_request.protocol.encode_response(public_method_name + 'Response', exception, return_type, ws_request.protocol_options)
|
||||
send_web_service_response(ws_response)
|
||||
else
|
||||
if self.class.web_service_exception_reporting
|
||||
message = exception.message
|
||||
backtrace = "\nBacktrace:\n#{exception.backtrace.join("\n")}"
|
||||
else
|
||||
message = "Exception raised"
|
||||
backtrace = ""
|
||||
end
|
||||
render_text("Internal protocol error: #{message}#{backtrace}", "500 Internal Protocol Error")
|
||||
end
|
||||
end
|
||||
|
||||
def web_service_direct_invoke(invocation)
|
||||
invocation.method_named_params.each do |name, value|
|
||||
params[name] = value
|
||||
end
|
||||
params['action'] = invocation.api_method.name.to_s
|
||||
if before_action == false
|
||||
raise(DispatcherError, "Method filtered")
|
||||
end
|
||||
return_value = web_service_direct_invoke_without_controller(invocation)
|
||||
after_action
|
||||
return_value
|
||||
end
|
||||
|
||||
def log_request(ws_request, body)
|
||||
unless logger.nil?
|
||||
name = ws_request.method_name
|
||||
api_method = ws_request.api_method
|
||||
params = ws_request.method_params
|
||||
if api_method && api_method.expects
|
||||
params = api_method.expects.zip(params).map{ |type, param| "#{type.name}=>#{param.inspect}" }
|
||||
else
|
||||
params = params.map{ |param| param.inspect }
|
||||
end
|
||||
service = ws_request.service_name
|
||||
logger.debug("\nWeb Service Request: #{name}(#{params.join(", ")}) Entrypoint: #{service}")
|
||||
logger.debug(indent(body))
|
||||
end
|
||||
end
|
||||
|
||||
def log_response(ws_response, elapsed=nil)
|
||||
unless logger.nil?
|
||||
elapsed = (elapsed ? " (%f):" % elapsed : ":")
|
||||
logger.debug("\nWeb Service Response" + elapsed + " => #{ws_response.return_value.inspect}")
|
||||
logger.debug(indent(ws_response.body))
|
||||
end
|
||||
end
|
||||
|
||||
def indent(body)
|
||||
body.split(/\n/).map{|x| " #{x}"}.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
module WsdlAction # :nodoc:
|
||||
XsdNs = 'http://www.w3.org/2001/XMLSchema'
|
||||
WsdlNs = 'http://schemas.xmlsoap.org/wsdl/'
|
||||
SoapNs = 'http://schemas.xmlsoap.org/wsdl/soap/'
|
||||
SoapEncodingNs = 'http://schemas.xmlsoap.org/soap/encoding/'
|
||||
SoapHttpTransport = 'http://schemas.xmlsoap.org/soap/http'
|
||||
|
||||
def wsdl
|
||||
case request.method
|
||||
when :get
|
||||
begin
|
||||
options = { :type => 'text/xml', :disposition => 'inline' }
|
||||
send_data(to_wsdl, options)
|
||||
rescue Exception => e
|
||||
log_error(e) unless logger.nil?
|
||||
end
|
||||
when :post
|
||||
render_text('POST not supported', '500 POST not supported')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def base_uri
|
||||
host = request.env['HTTP_HOST'] || request.env['SERVER_NAME'] || 'localhost'
|
||||
relative_url_root = request.relative_url_root
|
||||
scheme = request.ssl? ? 'https' : 'http'
|
||||
'%s://%s%s/%s/' % [scheme, host, relative_url_root, self.class.controller_path]
|
||||
end
|
||||
|
||||
def to_wsdl
|
||||
xml = ''
|
||||
dispatching_mode = web_service_dispatching_mode
|
||||
global_service_name = wsdl_service_name
|
||||
namespace = wsdl_namespace || 'urn:ActionWebService'
|
||||
soap_action_base = "/#{controller_name}"
|
||||
|
||||
marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace)
|
||||
apis = {}
|
||||
case dispatching_mode
|
||||
when :direct
|
||||
api = self.class.web_service_api
|
||||
web_service_name = controller_class_name.sub(/Controller$/, '').underscore
|
||||
apis[web_service_name] = [api, register_api(api, marshaler)]
|
||||
when :delegated, :layered
|
||||
self.class.web_services.each do |web_service_name, info|
|
||||
service = web_service_object(web_service_name)
|
||||
api = service.class.web_service_api
|
||||
apis[web_service_name] = [api, register_api(api, marshaler)]
|
||||
end
|
||||
end
|
||||
custom_types = []
|
||||
apis.values.each do |api, bindings|
|
||||
bindings.each do |b|
|
||||
custom_types << b unless custom_types.include?(b)
|
||||
end
|
||||
end
|
||||
|
||||
xm = Builder::XmlMarkup.new(:target => xml, :indent => 2)
|
||||
xm.instruct!
|
||||
xm.definitions('name' => wsdl_service_name,
|
||||
'targetNamespace' => namespace,
|
||||
'xmlns:typens' => namespace,
|
||||
'xmlns:xsd' => XsdNs,
|
||||
'xmlns:soap' => SoapNs,
|
||||
'xmlns:soapenc' => SoapEncodingNs,
|
||||
'xmlns:wsdl' => WsdlNs,
|
||||
'xmlns' => WsdlNs) do
|
||||
# Generate XSD
|
||||
if custom_types.size > 0
|
||||
xm.types do
|
||||
xm.xsd(:schema, 'xmlns' => XsdNs, 'targetNamespace' => namespace) do
|
||||
custom_types.each do |binding|
|
||||
case
|
||||
when binding.type.array?
|
||||
xm.xsd(:complexType, 'name' => binding.type_name) do
|
||||
xm.xsd(:complexContent) do
|
||||
xm.xsd(:restriction, 'base' => 'soapenc:Array') do
|
||||
xm.xsd(:attribute, 'ref' => 'soapenc:arrayType',
|
||||
'wsdl:arrayType' => binding.element_binding.qualified_type_name('typens') + '[]')
|
||||
end
|
||||
end
|
||||
end
|
||||
when binding.type.structured?
|
||||
xm.xsd(:complexType, 'name' => binding.type_name) do
|
||||
xm.xsd(:all) do
|
||||
binding.type.each_member do |name, type|
|
||||
b = marshaler.register_type(type)
|
||||
xm.xsd(:element, 'name' => name, 'type' => b.qualified_type_name('typens'))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# APIs
|
||||
apis.each do |api_name, values|
|
||||
api = values[0]
|
||||
api.api_methods.each do |name, method|
|
||||
gen = lambda do |msg_name, direction|
|
||||
xm.message('name' => message_name_for(api_name, msg_name)) do
|
||||
sym = nil
|
||||
if direction == :out
|
||||
returns = method.returns
|
||||
if returns
|
||||
binding = marshaler.register_type(returns[0])
|
||||
xm.part('name' => 'return', 'type' => binding.qualified_type_name('typens'))
|
||||
end
|
||||
else
|
||||
expects = method.expects
|
||||
expects.each do |type|
|
||||
binding = marshaler.register_type(type)
|
||||
xm.part('name' => type.name, 'type' => binding.qualified_type_name('typens'))
|
||||
end if expects
|
||||
end
|
||||
end
|
||||
end
|
||||
public_name = method.public_name
|
||||
gen.call(public_name, :in)
|
||||
gen.call("#{public_name}Response", :out)
|
||||
end
|
||||
|
||||
# Port
|
||||
port_name = port_name_for(global_service_name, api_name)
|
||||
xm.portType('name' => port_name) do
|
||||
api.api_methods.each do |name, method|
|
||||
xm.operation('name' => method.public_name) do
|
||||
xm.input('message' => "typens:" + message_name_for(api_name, method.public_name))
|
||||
xm.output('message' => "typens:" + message_name_for(api_name, "#{method.public_name}Response"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Bind it
|
||||
binding_name = binding_name_for(global_service_name, api_name)
|
||||
xm.binding('name' => binding_name, 'type' => "typens:#{port_name}") do
|
||||
xm.soap(:binding, 'style' => 'rpc', 'transport' => SoapHttpTransport)
|
||||
api.api_methods.each do |name, method|
|
||||
xm.operation('name' => method.public_name) do
|
||||
case web_service_dispatching_mode
|
||||
when :direct
|
||||
soap_action = soap_action_base + "/api/" + method.public_name
|
||||
when :delegated, :layered
|
||||
soap_action = soap_action_base \
|
||||
+ "/" + api_name.to_s \
|
||||
+ "/" + method.public_name
|
||||
end
|
||||
xm.soap(:operation, 'soapAction' => soap_action)
|
||||
xm.input do
|
||||
xm.soap(:body,
|
||||
'use' => 'encoded',
|
||||
'namespace' => namespace,
|
||||
'encodingStyle' => SoapEncodingNs)
|
||||
end
|
||||
xm.output do
|
||||
xm.soap(:body,
|
||||
'use' => 'encoded',
|
||||
'namespace' => namespace,
|
||||
'encodingStyle' => SoapEncodingNs)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Define it
|
||||
xm.service('name' => "#{global_service_name}Service") do
|
||||
apis.each do |api_name, values|
|
||||
port_name = port_name_for(global_service_name, api_name)
|
||||
binding_name = binding_name_for(global_service_name, api_name)
|
||||
case web_service_dispatching_mode
|
||||
when :direct, :layered
|
||||
binding_target = 'api'
|
||||
when :delegated
|
||||
binding_target = api_name.to_s
|
||||
end
|
||||
xm.port('name' => port_name, 'binding' => "typens:#{binding_name}") do
|
||||
xm.soap(:address, 'location' => "#{base_uri}#{binding_target}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def port_name_for(global_service, service)
|
||||
"#{global_service}#{service.to_s.camelize}Port"
|
||||
end
|
||||
|
||||
def binding_name_for(global_service, service)
|
||||
"#{global_service}#{service.to_s.camelize}Binding"
|
||||
end
|
||||
|
||||
def message_name_for(api_name, message_name)
|
||||
mode = web_service_dispatching_mode
|
||||
if mode == :layered || mode == :delegated
|
||||
api_name.to_s + '-' + message_name
|
||||
else
|
||||
message_name
|
||||
end
|
||||
end
|
||||
|
||||
def register_api(api, marshaler)
|
||||
bindings = {}
|
||||
traverse_custom_types(api, marshaler, bindings) do |binding|
|
||||
bindings[binding] = nil unless bindings.has_key?(binding)
|
||||
element_binding = binding.element_binding
|
||||
bindings[element_binding] = nil if element_binding && !bindings.has_key?(element_binding)
|
||||
end
|
||||
bindings.keys
|
||||
end
|
||||
|
||||
def traverse_custom_types(api, marshaler, bindings, &block)
|
||||
api.api_methods.each do |name, method|
|
||||
expects, returns = method.expects, method.returns
|
||||
expects.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if expects
|
||||
returns.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if returns
|
||||
end
|
||||
end
|
||||
|
||||
def traverse_type(marshaler, type, bindings, &block)
|
||||
binding = marshaler.register_type(type)
|
||||
return if bindings.has_key?(binding)
|
||||
bindings[binding] = nil
|
||||
yield binding
|
||||
if type.array?
|
||||
yield marshaler.register_type(type.element_type)
|
||||
type = type.element_type
|
||||
end
|
||||
type.each_member{ |name, type| traverse_type(marshaler, type, bindings, &block) } if type.structured?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue