google-ads-common 0.2.0 → 0.2.1
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.
- 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
|