google-ads-common 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +201 -0
- data/ChangeLog +14 -0
- data/README +4 -3
- data/Rakefile +9 -9
- data/lib/ads_common/api_config.rb +2 -2
- data/lib/ads_common/build/savon_abstract_generator.rb +5 -1
- data/lib/ads_common/build/savon_generator.rb +2 -2
- data/lib/ads_common/build/savon_registry.rb +87 -101
- data/lib/ads_common/build/savon_registry_generator.rb +1 -3
- data/lib/ads_common/build/savon_service_generator.rb +12 -61
- data/lib/ads_common/build/soap4r_generator.rb +2 -2
- data/lib/ads_common/config.rb +37 -52
- data/lib/ads_common/savon_headers/simple_header_handler.rb +7 -58
- data/lib/ads_common/savon_service.rb +266 -0
- metadata +40 -32
@@ -34,8 +34,6 @@ module AdsCommon
|
|
34
34
|
#
|
35
35
|
# <%= @generator_stamp %>
|
36
36
|
|
37
|
-
require 'savon'
|
38
|
-
|
39
37
|
<%= @modules_open_string %>
|
40
38
|
|
41
39
|
class <%= @service_name %>Registry
|
@@ -73,7 +71,7 @@ module AdsCommon
|
|
73
71
|
end
|
74
72
|
<% end %>
|
75
73
|
end
|
76
|
-
|
74
|
+
<% end %>
|
77
75
|
<%= @modules_close_string %>
|
78
76
|
|
79
77
|
}.gsub(/^ /, '')
|
@@ -33,80 +33,31 @@ module AdsCommon
|
|
33
33
|
#
|
34
34
|
# <%= @generator_stamp %>
|
35
35
|
|
36
|
-
require '
|
36
|
+
require 'ads_common/savon_service'
|
37
37
|
require '<%= @require_path %>/<%= @service_name.to_s.snakecase %>_registry'
|
38
38
|
|
39
39
|
<%= @modules_open_string %>
|
40
40
|
|
41
|
-
class <%= @service_name %>
|
42
|
-
attr_accessor :headerhandler, :wiredump_dev, :options
|
41
|
+
class <%= @service_name %> < AdsCommon::SavonService
|
43
42
|
def initialize(endpoint)
|
44
|
-
|
45
|
-
|
46
|
-
@options = {}
|
47
|
-
@client = Savon::Client.new do |wsdl|
|
48
|
-
wsdl.namespace = '<%= @namespace %>'
|
49
|
-
wsdl.endpoint = endpoint
|
50
|
-
end
|
43
|
+
namespace = '<%= @namespace %>'
|
44
|
+
super(endpoint, namespace)
|
51
45
|
end
|
52
|
-
|
53
46
|
<% @actions.each do |action| %>
|
54
|
-
def <%= action %>(args = nil)
|
55
|
-
validate_args(:<%= action %>, args)
|
56
|
-
response = @client.request(:<%= action %>) {|soap|
|
57
|
-
set_headers(soap, args)
|
58
|
-
}
|
59
|
-
handle_errors(response)
|
60
|
-
return extract_result(response, '<%= action %>')
|
61
|
-
end
|
62
|
-
<% end %>
|
63
|
-
private
|
64
|
-
|
65
|
-
def validate_args(action_symbol, args = nil)
|
66
|
-
true
|
67
|
-
end
|
68
|
-
|
69
|
-
def set_headers(soap, args)
|
70
|
-
@headerhandler.each { |handler| handler.prepare_soap(soap, args) }
|
71
|
-
end
|
72
47
|
|
73
|
-
|
74
|
-
|
75
|
-
def extract_result(response, action_name)
|
76
|
-
method = <%= @service_name %>Registry::get_method_signature(action_name)
|
77
|
-
action = method[:output][:name].to_sym
|
78
|
-
result = response.to_hash
|
79
|
-
result = result[action] if result.include?(action)
|
80
|
-
result = result[:rval] if result.include?(:rval)
|
81
|
-
return result
|
48
|
+
def <%= action %>(*args)
|
49
|
+
return execute_action('<%= action %>', args)
|
82
50
|
end
|
51
|
+
<% end %>
|
83
52
|
|
84
|
-
|
85
|
-
def handle_errors(response)
|
86
|
-
if response.soap_fault?
|
87
|
-
exception = exception_for_soap_fault(response)
|
88
|
-
raise exception
|
89
|
-
end
|
53
|
+
private
|
90
54
|
|
91
|
-
|
92
|
-
|
93
|
-
"HTTP Error occurred: %s" % response.http_error
|
94
|
-
end
|
55
|
+
def get_service_registry()
|
56
|
+
return <%= @service_name %>Registry
|
95
57
|
end
|
96
58
|
|
97
|
-
|
98
|
-
|
99
|
-
begin
|
100
|
-
exception_fault =
|
101
|
-
response.to_hash[:fault][:detail][:api_exception_fault]
|
102
|
-
exception_name = exception_fault[:application_exception_type]
|
103
|
-
exception_class = <%= @module_name %>::const_get(exception_name)
|
104
|
-
return exception_class.new(exception_fault)
|
105
|
-
rescue Exception => e
|
106
|
-
return AdsCommon::Errors::ApiException.new(
|
107
|
-
"Failed to resolve exception (%s)\n SOAP fault: %s" %
|
108
|
-
[e.message, response.soap_fault])
|
109
|
-
end
|
59
|
+
def get_module()
|
60
|
+
return <%= @module_name %>
|
110
61
|
end
|
111
62
|
end
|
112
63
|
<%= @modules_close_string %>
|
@@ -268,7 +268,7 @@ module AdsCommon
|
|
268
268
|
object.each do |entry, value|
|
269
269
|
entry = entry.to_s
|
270
270
|
unless entry == 'xsi_type'
|
271
|
-
if @api.config.read('service.use_ruby_names')
|
271
|
+
if @api.config.read('service.use_ruby_names', true)
|
272
272
|
entry = camel_case(entry)
|
273
273
|
end
|
274
274
|
if value.is_a? Hash
|
@@ -319,7 +319,7 @@ module AdsCommon
|
|
319
319
|
if object.respond_to? property and !property.include?('_Type')
|
320
320
|
value = object.send(property)
|
321
321
|
property_name = nil
|
322
|
-
if @api.config.read('service.use_ruby_names')
|
322
|
+
if @api.config.read('service.use_ruby_names', true)
|
323
323
|
property_name = underscore(property).to_sym
|
324
324
|
else
|
325
325
|
property_name = property.to_sym
|
data/lib/ads_common/config.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
#
|
3
|
-
# Authors:: api.
|
3
|
+
# Authors:: api.dklimkin@gmail.com (Danial Klimkin)
|
4
4
|
#
|
5
5
|
# Copyright:: Copyright 2010, Google Inc. All Rights Reserved.
|
6
6
|
#
|
@@ -29,26 +29,21 @@ module AdsCommon
|
|
29
29
|
# Initialized the Config object with either the contents of a provided file
|
30
30
|
# or a provided hash.
|
31
31
|
def initialize(param = nil)
|
32
|
-
@config =
|
33
|
-
|
34
|
-
load(param)
|
35
|
-
|
36
|
-
set_all(param)
|
32
|
+
@config = Hash.new
|
33
|
+
case param
|
34
|
+
when String: load(param)
|
35
|
+
when Hash: set_all(param)
|
37
36
|
end
|
38
37
|
end
|
39
38
|
|
40
39
|
# Reads a property or category from the loaded configuration.
|
41
40
|
# They can be indexed using a dot-based notation (e.g. "category.property"
|
42
41
|
# to access "property" under "category").
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
current_level = current_level[item.to_sym]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
return current_level
|
42
|
+
#
|
43
|
+
# Returns the specified default if no value found.
|
44
|
+
def read(property_path, default_value = nil)
|
45
|
+
result = find_value(@config, property_path)
|
46
|
+
return (result.nil?) ? default_value : result
|
52
47
|
end
|
53
48
|
|
54
49
|
# Writes a new value to a property or category in memory (creating it if
|
@@ -56,18 +51,13 @@ module AdsCommon
|
|
56
51
|
# They can be indexed using a dot-based notation (e.g. "category.property"
|
57
52
|
# to access "property" under "category").
|
58
53
|
def set(property_path, value)
|
59
|
-
@config = {} if !@config
|
60
|
-
current_level = @config
|
61
54
|
if property_path
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
if current_level and current_level.is_a?(Hash)
|
68
|
-
current_level[segments.last] = value
|
69
|
-
return value
|
55
|
+
last_node = @config
|
56
|
+
last_name = property_path.split('.').inject(nil) do |last_name, section|
|
57
|
+
last_node = last_node[last_name.to_sym] ||= {} unless last_name.nil?
|
58
|
+
section
|
70
59
|
end
|
60
|
+
last_node[last_name.to_sym] = value
|
71
61
|
end
|
72
62
|
return nil
|
73
63
|
end
|
@@ -77,46 +67,41 @@ module AdsCommon
|
|
77
67
|
@config = process_hash_keys(properties)
|
78
68
|
end
|
79
69
|
|
70
|
+
private
|
71
|
+
|
80
72
|
# Auxiliary method to recurse through a hash and convert all the keys to
|
81
73
|
# symbols.
|
82
74
|
def process_hash_keys(hash)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
new_hash[key.to_sym] = value
|
89
|
-
end
|
75
|
+
return hash.inject({}) do |result, pair|
|
76
|
+
key, value = pair
|
77
|
+
result[key.to_sym] = value.is_a?(Hash) ?
|
78
|
+
process_hash_keys(value) : value
|
79
|
+
result
|
90
80
|
end
|
91
|
-
return new_hash
|
92
81
|
end
|
93
82
|
|
94
|
-
#
|
95
|
-
|
96
|
-
|
83
|
+
# Finds a value for string of format 'level1.level2.name' in a given hash.
|
84
|
+
def find_value(data, path)
|
85
|
+
return (path.nil? or data.nil?) ? nil :
|
86
|
+
path.split('.').inject(data) do |node, section|
|
87
|
+
break if node.nil?
|
88
|
+
key = section.to_sym
|
89
|
+
(node.is_a?(Hash) and node.include?(key)) ? node[key] : nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Reads a configuration file into instance variable as a Ruby structure with
|
94
|
+
# the complete set of keys and values.
|
97
95
|
#
|
98
96
|
# Args:
|
99
97
|
# - filename: config file to be read (*String*)
|
100
98
|
#
|
101
|
-
# Returns:
|
102
|
-
# - Ruby objects for the stored YAML
|
103
|
-
#
|
104
99
|
# Raises:
|
105
|
-
# - <b>Errno::
|
100
|
+
# - <b>Errno::ENOENT</b> if the file does not exist.
|
106
101
|
#
|
107
102
|
def load(filename)
|
108
|
-
|
109
|
-
|
110
|
-
end
|
111
|
-
file = nil
|
112
|
-
begin
|
113
|
-
file = File.open(filename)
|
114
|
-
@config = YAML::load(file)
|
115
|
-
ensure
|
116
|
-
file.close if file
|
117
|
-
end
|
118
|
-
return @config
|
103
|
+
@config = YAML::load_file(filename)
|
104
|
+
return nil
|
119
105
|
end
|
120
106
|
end
|
121
|
-
|
122
107
|
end
|
@@ -45,7 +45,8 @@ module AdsCommon
|
|
45
45
|
end
|
46
46
|
|
47
47
|
# Enriches soap object with API-specific headers like namespaces, login
|
48
|
-
# credentials etc.
|
48
|
+
# credentials etc. Sets the default namespace for the body to the one
|
49
|
+
# specified in initializer.
|
49
50
|
#
|
50
51
|
# Args:
|
51
52
|
# - soap: a Savon soap object to fill fields in.
|
@@ -57,9 +58,8 @@ module AdsCommon
|
|
57
58
|
soap.header[prepend_namespace(@element_name)] =
|
58
59
|
generate_request_header()
|
59
60
|
soap.namespace = @namespace
|
60
|
-
if
|
61
|
-
|
62
|
-
end
|
61
|
+
soap.body = args if args
|
62
|
+
soap.input[1] = {:xmlns => @namespace}
|
63
63
|
end
|
64
64
|
|
65
65
|
private
|
@@ -82,66 +82,15 @@ module AdsCommon
|
|
82
82
|
return request_header
|
83
83
|
end
|
84
84
|
|
85
|
-
#
|
86
|
-
# and Array data types dives deeper into structure.
|
87
|
-
#
|
88
|
-
# Args:
|
89
|
-
# - args: subtree of request parameters.
|
90
|
-
#
|
91
|
-
# Returns:
|
92
|
-
# - subtree with modified parameters including namespaces.
|
93
|
-
def prepare_args(args)
|
94
|
-
res = case args
|
95
|
-
when Hash
|
96
|
-
prepare_hash_args(args)
|
97
|
-
when Array
|
98
|
-
prepare_array_args(args)
|
99
|
-
else
|
100
|
-
args
|
101
|
-
end
|
102
|
-
return res
|
103
|
-
end
|
104
|
-
|
105
|
-
# Crawls hash for all the request parameters and adds namespace
|
106
|
-
# reference for the keys.
|
107
|
-
#
|
108
|
-
# Args:
|
109
|
-
# - args: Hash element of subtree of request parameters.
|
110
|
-
#
|
111
|
-
# Returns:
|
112
|
-
# - Modified Hash with all keys updated and all values crawled.
|
113
|
-
def prepare_hash_args(args)
|
114
|
-
res = {}
|
115
|
-
args.each do |key, value|
|
116
|
-
res[prepend_namespace(key)] = prepare_args(value)
|
117
|
-
end
|
118
|
-
return res
|
119
|
-
end
|
120
|
-
|
121
|
-
# Crawls array and process each of its elements to include namespace.
|
122
|
-
#
|
123
|
-
# Args:
|
124
|
-
# - args: Array element of subtree of request parameters.
|
125
|
-
#
|
126
|
-
# Returns:
|
127
|
-
# - Modified Array with every element crawled.
|
128
|
-
def prepare_array_args(args)
|
129
|
-
res = []
|
130
|
-
args.each do |item|
|
131
|
-
res << prepare_args(item)
|
132
|
-
end
|
133
|
-
return res
|
134
|
-
end
|
135
|
-
|
136
|
-
# Adds namespace to the request parameter name.
|
85
|
+
# Adds namespace to the given string.
|
137
86
|
#
|
138
87
|
# Args:
|
139
|
-
# - str: String to prepend with a namespace
|
88
|
+
# - str: String to prepend with a namespace.
|
140
89
|
#
|
141
90
|
# Returns:
|
142
91
|
# - String with a namespace.
|
143
92
|
def prepend_namespace(str)
|
144
|
-
return "%s:%s" % [DEFAULT_NAMESPACE, str
|
93
|
+
return "%s:%s" % [DEFAULT_NAMESPACE, str]
|
145
94
|
end
|
146
95
|
end
|
147
96
|
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# Author:: api.dklimkin@gmail.com (Danial Klimkin)
|
4
|
+
#
|
5
|
+
# Copyright:: Copyright 2011, Google Inc. All Rights Reserved.
|
6
|
+
#
|
7
|
+
# License:: Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
16
|
+
# implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
#
|
20
|
+
# Base class for all generated API services based on Savon backend.
|
21
|
+
|
22
|
+
gem 'savon', '~>0.9.1'
|
23
|
+
require 'savon'
|
24
|
+
|
25
|
+
module AdsCommon
|
26
|
+
class SavonService
|
27
|
+
attr_accessor :headerhandler, :wiredump_dev, :options
|
28
|
+
|
29
|
+
# Creates a new service.
|
30
|
+
def initialize(endpoint, namespace)
|
31
|
+
if self.class() == AdsCommon::SavonService
|
32
|
+
raise NoMethodError, "Tried to instantiate an abstract class"
|
33
|
+
end
|
34
|
+
@headerhandler = []
|
35
|
+
@wiredump_dev = nil
|
36
|
+
@options = {}
|
37
|
+
@client = Savon::Client.new do |wsdl|
|
38
|
+
wsdl.namespace = namespace
|
39
|
+
wsdl.endpoint = endpoint
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
# Returns ServiceRegistry for the current service. Has to be overriden.
|
46
|
+
def get_service_registry()
|
47
|
+
raise NoMethodError, "This methods needs to be overriden"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns Module for the current service. Has to be overriden.
|
51
|
+
def get_module()
|
52
|
+
raise NoMethodError, "This methods needs to be overriden"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Executes SOAP action specified as a string with given arguments.
|
56
|
+
def execute_action(action_name, args)
|
57
|
+
args = validate_args(action_name, args)
|
58
|
+
response = @client.request(action_name.to_sym) do |soap|
|
59
|
+
set_headers(soap, args)
|
60
|
+
end
|
61
|
+
handle_errors(response)
|
62
|
+
return extract_result(response, action_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Validates input parameters to:
|
66
|
+
# - add parameter names;
|
67
|
+
# - resolve xsi:type where required;
|
68
|
+
# - convert some native types to xml.
|
69
|
+
def validate_args(action_name, *args)
|
70
|
+
validated_args = Hash.new
|
71
|
+
in_params = get_service_registry.get_method_signature(action_name)[:input]
|
72
|
+
in_params.each_with_index do |in_param, index|
|
73
|
+
key = in_param[:name]
|
74
|
+
value = args[index]
|
75
|
+
validated_args[key] = (value.nil?) ? nil :
|
76
|
+
validate_arg(value, validated_args, key)
|
77
|
+
end
|
78
|
+
return validated_args
|
79
|
+
end
|
80
|
+
|
81
|
+
# Validates method argument. Runs recursively if hash or array encountered.
|
82
|
+
# Also handles some types that need special conversions.
|
83
|
+
def validate_arg(arg, parent = nil, key = nil)
|
84
|
+
result = case arg
|
85
|
+
when Hash: validate_hash_arg(arg, parent, key)
|
86
|
+
when Array: arg.map {|item| validate_arg(item, parent, key)}
|
87
|
+
when Time: time_to_xml_hash(arg)
|
88
|
+
else arg
|
89
|
+
end
|
90
|
+
return result
|
91
|
+
end
|
92
|
+
|
93
|
+
# Validates hash argument recursively. Keeps tracking of correct place
|
94
|
+
# for xsi:type and adds is when required.
|
95
|
+
def validate_hash_arg(arg, parent = nil, key = nil)
|
96
|
+
xsi_type = arg.delete('xsi:type') || arg.delete(:xsi_type)
|
97
|
+
if xsi_type
|
98
|
+
if parent and key
|
99
|
+
add_xsi_type(parent, key, xsi_type)
|
100
|
+
else
|
101
|
+
raise AdsCommon::Errors::ApiException.new(
|
102
|
+
"Can't find correct position for xsi:type (%s) [%s], [%s]" %
|
103
|
+
[xsi_type, parent, key])
|
104
|
+
end
|
105
|
+
end
|
106
|
+
return arg.inject({}) do |result, (key, value)|
|
107
|
+
result[key] = (key == :attributes!) ? value :
|
108
|
+
validate_arg(value, result, key)
|
109
|
+
result
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Adds ":attributes!" record for Savon to specify xsi:type.
|
114
|
+
def add_xsi_type(parent, key, xsi_type)
|
115
|
+
parent[:attributes!] ||= {}
|
116
|
+
parent[:attributes!][key] ||= {}
|
117
|
+
parent[:attributes!][key]["xsi:type"] ||= []
|
118
|
+
parent[:attributes!][key]["xsi:type"] << xsi_type
|
119
|
+
end
|
120
|
+
|
121
|
+
# Executes each handler to generate SOAP headers.
|
122
|
+
def set_headers(soap, args)
|
123
|
+
@headerhandler.each {|handler| handler.prepare_soap(soap, args)}
|
124
|
+
end
|
125
|
+
|
126
|
+
# Checks for errors in response and raises appropriate exception.
|
127
|
+
def handle_errors(response)
|
128
|
+
if response.soap_fault?
|
129
|
+
exception = exception_for_soap_fault(response)
|
130
|
+
raise exception
|
131
|
+
end
|
132
|
+
if response.http_error?
|
133
|
+
raise AdsCommon::Errors::HttpError,
|
134
|
+
"HTTP Error occurred: %s" % response.http_error
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Finds an exception object for a given response.
|
139
|
+
def exception_for_soap_fault(response)
|
140
|
+
begin
|
141
|
+
fault = response[:fault]
|
142
|
+
if fault[:detail] and fault[:detail][:api_exception_fault]
|
143
|
+
exception_fault = fault[:detail][:api_exception_fault]
|
144
|
+
exception_name = exception_fault[:application_exception_type]
|
145
|
+
exception_class = get_module().const_get(exception_name)
|
146
|
+
return exception_class.new(exception_fault)
|
147
|
+
elsif fault[:faultstring]
|
148
|
+
fault_message = fault[:faultstring]
|
149
|
+
return AdsCommon::Errors::ApiException.new(
|
150
|
+
"Unknown exception with error: %s" % fault_message)
|
151
|
+
else
|
152
|
+
raise ArgumentError.new(fault.to_s)
|
153
|
+
end
|
154
|
+
rescue Exception => e
|
155
|
+
return AdsCommon::Errors::ApiException.new(
|
156
|
+
"Failed to resolve exception (%s), SOAP fault: %s" %
|
157
|
+
[e.message, response.soap_fault])
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Extracts the finest results possible for the given result. Returns the
|
162
|
+
# response itself in worst case (contents unknown).
|
163
|
+
def extract_result(response, action_name)
|
164
|
+
method = get_service_registry.get_method_signature(action_name)
|
165
|
+
action = method[:output][:name].to_sym
|
166
|
+
result = response.to_hash
|
167
|
+
result = result[action] if result.include?(action)
|
168
|
+
return normalize_output(result, method)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Normalizes output starting with root node "rval".
|
172
|
+
def normalize_output(output_data, method_definition)
|
173
|
+
fields_list = method_definition[:output][:fields]
|
174
|
+
result = normalize_output_field(output_data, fields_list, :rval)
|
175
|
+
return result[:rval]
|
176
|
+
end
|
177
|
+
|
178
|
+
# Normalizes one field of a given data recursively.
|
179
|
+
# Args:
|
180
|
+
# - output_data: XML data to normalize
|
181
|
+
# - fields_list: expected list of fields from signature
|
182
|
+
# - field_name: specifies field name to normalize
|
183
|
+
def normalize_output_field(output_data, fields_list, field_name)
|
184
|
+
return nil if output_data.nil?
|
185
|
+
field_definition = get_field_by_name(fields_list, field_name)
|
186
|
+
field_sym = field_name.to_sym
|
187
|
+
output_data[field_sym] = normalize_type(output_data[field_sym],
|
188
|
+
field_definition)
|
189
|
+
|
190
|
+
sub_type = get_service_registry.get_type_signature(
|
191
|
+
field_definition[:type])
|
192
|
+
if sub_type
|
193
|
+
sub_type[:fields] += implode_parent(sub_type)
|
194
|
+
if sub_type[:fields]
|
195
|
+
# go recursive
|
196
|
+
sub_type[:fields].each do |sub_type_field|
|
197
|
+
if output_data[field_sym].is_a?(Array)
|
198
|
+
items_list = output_data[field_sym]
|
199
|
+
output_data[field_sym] = Array.new
|
200
|
+
items_list.each do |item|
|
201
|
+
output_data[field_sym] <<
|
202
|
+
normalize_output_field(item, sub_type_field,
|
203
|
+
sub_type_field[:name])
|
204
|
+
end
|
205
|
+
else
|
206
|
+
output_data[field_sym] =
|
207
|
+
normalize_output_field(output_data[field_sym], sub_type_field,
|
208
|
+
sub_type_field[:name])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
return output_data
|
214
|
+
end
|
215
|
+
|
216
|
+
# Converts XML input string into a native format.
|
217
|
+
def normalize_type(data, field)
|
218
|
+
type_name = field[:type]
|
219
|
+
result = case type_name
|
220
|
+
when 'long', 'int': Integer(data)
|
221
|
+
when 'double': Float(data)
|
222
|
+
when 'boolean': data.kind_of?(String) ? data.casecmp('true') == 0 : data
|
223
|
+
else data
|
224
|
+
end
|
225
|
+
# If field signature allows an array, forcing array structure even for one
|
226
|
+
# item.
|
227
|
+
if !field[:min_occurs].nil? and
|
228
|
+
(field[:max_occurs].nil? or field[:max_occurs] > 1)
|
229
|
+
result = arrayize(result)
|
230
|
+
end
|
231
|
+
return result
|
232
|
+
end
|
233
|
+
|
234
|
+
# Finds a field in a list by its name.
|
235
|
+
def get_field_by_name(fields_list, name)
|
236
|
+
fields_array = arrayize(fields_list)
|
237
|
+
index = fields_array.find_index {|field| field[:name].eql?(name)}
|
238
|
+
return (index.nil?) ? nil : fields_array.at(index)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Makes sure object is an array.
|
242
|
+
def arrayize(object)
|
243
|
+
return Array.new if object.nil?
|
244
|
+
return object.is_a?(Array) ? object : [object]
|
245
|
+
end
|
246
|
+
|
247
|
+
# Converts Time to a hash for XML marshalling.
|
248
|
+
def time_to_xml_hash(time)
|
249
|
+
return {
|
250
|
+
:hour => time.hour, :minute => time.min, :second => time.sec,
|
251
|
+
:date => {:year => time.year, :month => time.month, :day => time.day}
|
252
|
+
}
|
253
|
+
end
|
254
|
+
|
255
|
+
# Returns all inherited fields of superclasses for given type.
|
256
|
+
def implode_parent(data_type)
|
257
|
+
result = Array.new
|
258
|
+
if data_type and data_type[:base]
|
259
|
+
parent_type = get_service_registry.get_type_signature(data_type[:base])
|
260
|
+
result += parent_type[:fields] if parent_type[:fields]
|
261
|
+
result += implode_parent(parent_type) if parent_type[:base]
|
262
|
+
end
|
263
|
+
return result
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|