google-ads-common 0.4.0 → 0.5.0
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/ChangeLog +5 -0
- data/README +1 -4
- data/Rakefile +2 -2
- data/lib/ads_common/api.rb +106 -16
- data/lib/ads_common/api_config.rb +2 -3
- data/lib/ads_common/auth/base_handler.rb +22 -3
- data/lib/ads_common/auth/client_login_handler.rb +27 -32
- data/lib/ads_common/auth/oauth_handler.rb +260 -0
- data/lib/ads_common/build/savon_abstract_generator.rb +12 -11
- data/lib/ads_common/build/savon_generator.rb +31 -27
- data/lib/ads_common/build/savon_registry.rb +46 -23
- data/lib/ads_common/build/savon_registry_generator.rb +23 -10
- data/lib/ads_common/build/savon_service_generator.rb +17 -3
- data/lib/ads_common/config.rb +1 -1
- data/lib/ads_common/credential_handler.rb +3 -7
- data/lib/ads_common/errors.rb +18 -6
- data/lib/ads_common/savon_headers/base_header_handler.rb +80 -0
- data/lib/ads_common/{soap4r_logger.rb → savon_headers/httpi_request_proxy.rb} +27 -20
- data/lib/ads_common/savon_headers/oauth_header_handler.rb +92 -0
- data/lib/ads_common/savon_headers/simple_header_handler.rb +17 -49
- data/lib/ads_common/savon_service.rb +129 -41
- data/test/test_savon_service.rb +9 -4
- metadata +39 -43
- data/lib/ads_common/build/rake_common.rb +0 -343
- data/lib/ads_common/build/soap4r_generator.rb +0 -565
- data/lib/ads_common/savon_headers/client_login_header_handler.rb +0 -60
- data/lib/ads_common/soap4r_headers/nested_header_handler.rb +0 -50
- data/lib/ads_common/soap4r_headers/single_header_handler.rb +0 -44
- data/lib/ads_common/soap4r_patches.rb +0 -210
- data/lib/ads_common/soap4r_response_handler.rb +0 -80
@@ -30,14 +30,11 @@ module AdsCommon
|
|
30
30
|
raise NoMethodError, "Tried to instantiate an abstract class"
|
31
31
|
end
|
32
32
|
@require_path = args[:require_path]
|
33
|
+
@api_name = args[:api_name]
|
34
|
+
@version = args[:version]
|
33
35
|
@service_name = args[:service_name]
|
34
|
-
@module_name = args[:module_name]
|
35
36
|
@namespace = args[:namespace]
|
36
|
-
|
37
|
-
@generator_stamp = "Code generated by AdsCommon library %s on %s." %
|
38
|
-
[AdsCommon::ApiConfig::ADS_COMMON_VERSION,
|
39
|
-
Time.now.strftime("%Y-%m-%d %H:%M:%S")]
|
40
|
-
prepare_modules_string()
|
37
|
+
prepare_template_strings()
|
41
38
|
end
|
42
39
|
|
43
40
|
def generate_code()
|
@@ -49,11 +46,15 @@ module AdsCommon
|
|
49
46
|
raise NotImplementedError
|
50
47
|
end
|
51
48
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
@
|
56
|
-
|
49
|
+
private
|
50
|
+
|
51
|
+
def prepare_template_strings()
|
52
|
+
@generator_stamp = "Code generated by AdsCommon library %s on %s." %
|
53
|
+
[AdsCommon::ApiConfig::ADS_COMMON_VERSION,
|
54
|
+
Time.now.strftime("%Y-%m-%d %H:%M:%S")]
|
55
|
+
@modules_open_string = 'module ' +
|
56
|
+
[@api_name, @version.to_s.upcase, @service_name].join('; module ')
|
57
|
+
@modules_close_string = 'end; end; end'
|
57
58
|
end
|
58
59
|
|
59
60
|
def remove_lines_with_blanks_only(text)
|
@@ -20,7 +20,6 @@
|
|
20
20
|
# Generates the wrappers for API services. Only used during the
|
21
21
|
# 'rake generate' step of library setup.
|
22
22
|
|
23
|
-
gem 'savon', '~>0.9.1'
|
24
23
|
require 'savon'
|
25
24
|
|
26
25
|
require 'ads_common/build/savon_service_generator'
|
@@ -34,25 +33,29 @@ module AdsCommon
|
|
34
33
|
# Contains the methods that handle wrapper code generation.
|
35
34
|
class SavonGenerator
|
36
35
|
|
37
|
-
# Create a new generator for given WSDL
|
36
|
+
# Create a new generator for given WSDL.
|
38
37
|
#
|
39
38
|
# Args:
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
|
39
|
+
# - wsdl_url local or remote URL to pull WSDL data
|
40
|
+
# - code_path local path to store generated files
|
41
|
+
# - api_name an API name to generate for
|
42
|
+
# - version a version of the service
|
43
|
+
# - service_name a service name to generate stubs for
|
44
|
+
# - extensions an optional list of extensions to include
|
45
|
+
#
|
46
|
+
def initialize(wsdl_url, code_path, api_name, version, service_name,
|
47
|
+
extensions = [])
|
45
48
|
@wsdl_url = wsdl_url
|
46
49
|
@code_path = code_path
|
47
|
-
@
|
48
|
-
@logger = Logger.new(STDOUT)
|
49
|
-
@logger.level = Logger::INFO
|
50
|
+
@extensions = extensions
|
50
51
|
@generator_args = {
|
52
|
+
:api_name => api_name,
|
53
|
+
:version => version,
|
51
54
|
:service_name => service_name,
|
52
|
-
:
|
53
|
-
:require_path => @code_path.sub(/^lib\//, ''),
|
54
|
-
:logger => @logger
|
55
|
+
:require_path => @code_path.sub(/^lib\//, '')
|
55
56
|
}
|
57
|
+
@logger = Logger.new(STDOUT)
|
58
|
+
@logger.level = Logger::INFO
|
56
59
|
Savon.configure do |config|
|
57
60
|
config.logger = @logger
|
58
61
|
config.log_level = :debug
|
@@ -61,13 +64,13 @@ module AdsCommon
|
|
61
64
|
end
|
62
65
|
|
63
66
|
#
|
64
|
-
# Pull, parse and generate wrapper for WSDL on given URL
|
67
|
+
# Pull, parse and generate wrapper for WSDL on given URL.
|
65
68
|
#
|
66
69
|
# Args:
|
67
|
-
#
|
70
|
+
# - none, instance variables are used
|
68
71
|
#
|
69
72
|
# Returns:
|
70
|
-
#
|
73
|
+
# - none
|
71
74
|
def process_wsdl()
|
72
75
|
client = Savon::Client.new(@wsdl_url)
|
73
76
|
begin
|
@@ -82,13 +85,12 @@ module AdsCommon
|
|
82
85
|
|
83
86
|
private
|
84
87
|
|
85
|
-
# Generate code for given Savon client
|
88
|
+
# Generate code for given Savon client.
|
86
89
|
def do_process_wsdl_client(client)
|
87
|
-
service_file_name = @service_name.to_s.snakecase
|
88
|
-
|
89
90
|
wsdl = client.wsdl
|
90
91
|
check_service(wsdl)
|
91
92
|
|
93
|
+
service_file_name = @generator_args[:service_name].to_s.snakecase
|
92
94
|
wrapper_file_name = "%s/%s.rb" % [@code_path, service_file_name]
|
93
95
|
write_wrapper(wsdl, wrapper_file_name)
|
94
96
|
|
@@ -104,36 +106,38 @@ module AdsCommon
|
|
104
106
|
end
|
105
107
|
end
|
106
108
|
|
107
|
-
# Generates wrapper file
|
109
|
+
# Generates wrapper file.
|
108
110
|
def write_wrapper(wsdl, file_name)
|
109
111
|
wrapper_file = create_new_file(file_name)
|
110
112
|
generator = SavonServiceGenerator.new(@generator_args)
|
111
113
|
generator.add_actions(wsdl.soap_actions.dup)
|
114
|
+
generator.add_extensions(@extensions)
|
112
115
|
wrapper_file.write(generator.generate_code())
|
113
116
|
wrapper_file.close
|
114
117
|
end
|
115
118
|
|
116
|
-
# Generates registry file
|
119
|
+
# Generates registry file.
|
117
120
|
def write_registry(wsdl, file_name)
|
118
121
|
registry_file = create_new_file(file_name)
|
119
122
|
generator = SavonRegistryGenerator.new(@generator_args)
|
120
|
-
registry = SavonRegistry.new(wsdl)
|
121
|
-
generator.add_exceptions(registry.soap_exceptions
|
122
|
-
generator.add_methods(registry.soap_methods
|
123
|
-
generator.
|
123
|
+
registry = SavonRegistry.new(wsdl, @generator_args)
|
124
|
+
generator.add_exceptions(registry.soap_exceptions)
|
125
|
+
generator.add_methods(registry.soap_methods)
|
126
|
+
generator.add_namespaces(registry.soap_namespaces)
|
127
|
+
generator.add_types(registry.soap_types)
|
124
128
|
registry_file.write(generator.generate_code())
|
125
129
|
registry_file.close
|
126
130
|
end
|
127
131
|
|
128
132
|
# Creates a new file on specified path, overwriting existing one if it
|
129
|
-
# exists
|
133
|
+
# exists.
|
130
134
|
def create_new_file(file_name)
|
131
135
|
@logger.info("Creating %s..." % [file_name])
|
132
136
|
make_dir_for_path(file_name)
|
133
137
|
new_file = File.new(file_name, File::WRONLY|File::TRUNC|File::CREAT)
|
134
138
|
end
|
135
139
|
|
136
|
-
# Creates a directory for the file path specified if not exists
|
140
|
+
# Creates a directory for the file path specified if not exists.
|
137
141
|
def make_dir_for_path(path)
|
138
142
|
dir_name = File.dirname(path)
|
139
143
|
Dir.mkdir(dir_name) if !File.directory?(dir_name)
|
@@ -25,18 +25,22 @@ require 'rexml/document'
|
|
25
25
|
|
26
26
|
module AdsCommon
|
27
27
|
module Build
|
28
|
-
STANDARD_TYPES = ['long', 'boolean', 'int', 'string', 'double']
|
29
|
-
|
30
28
|
# Contains the methods that extracts WSDL data.
|
31
29
|
class SavonRegistry
|
32
30
|
attr_reader :soap_exceptions
|
33
31
|
attr_reader :soap_methods
|
34
32
|
attr_reader :soap_types
|
33
|
+
attr_reader :soap_namespaces
|
35
34
|
|
36
35
|
# Initializes the instance.
|
36
|
+
#
|
37
37
|
# Args:
|
38
|
-
#
|
39
|
-
|
38
|
+
# - wsdl: string containing wsdl to parse
|
39
|
+
# - options: variuos generation options
|
40
|
+
#
|
41
|
+
def initialize(wsdl, options = {})
|
42
|
+
@options = options
|
43
|
+
@default_namespace = options[:namespace]
|
40
44
|
do_process_wsdl(wsdl)
|
41
45
|
end
|
42
46
|
|
@@ -47,8 +51,9 @@ module AdsCommon
|
|
47
51
|
@soap_exceptions = []
|
48
52
|
@soap_types = []
|
49
53
|
@soap_methods = []
|
54
|
+
@soap_namespaces = []
|
50
55
|
|
51
|
-
doc = REXML::Document.new(wsdl.
|
56
|
+
doc = REXML::Document.new(wsdl.xml)
|
52
57
|
process_types(doc)
|
53
58
|
process_methods(doc)
|
54
59
|
sort_exceptions()
|
@@ -56,18 +61,36 @@ module AdsCommon
|
|
56
61
|
|
57
62
|
# Extracts different types from XML.
|
58
63
|
def process_types(doc)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
REXML::XPath.each(doc, '//schema') do |schema|
|
65
|
+
ns_index = process_namespace(schema)
|
66
|
+
get_complex_types(schema).each do |ctype|
|
67
|
+
ctype_name = get_element_name(ctype)
|
68
|
+
if ctype_name.match('.+Exception$')
|
69
|
+
@soap_exceptions << extract_exception(ctype)
|
70
|
+
elsif ctype_name.match('.+Error$')
|
71
|
+
# We don't use it at the moment.
|
72
|
+
else
|
73
|
+
@soap_types << extract_type(ctype, ns_index)
|
74
|
+
end
|
67
75
|
end
|
68
76
|
end
|
69
77
|
end
|
70
78
|
|
79
|
+
# Returns index of namespace for given schema. Adds namespace to internal
|
80
|
+
# array if not yet present. Returns nil for service default namespace.
|
81
|
+
def process_namespace(schema)
|
82
|
+
namespace_url = schema.attribute('targetNamespace').value
|
83
|
+
unless namespace_url == @default_namespace
|
84
|
+
ns_index = @soap_namespaces.index(namespace_url)
|
85
|
+
if ns_index.nil?
|
86
|
+
ns_index = @soap_namespaces.length
|
87
|
+
@soap_namespaces << namespace_url
|
88
|
+
end
|
89
|
+
return ns_index
|
90
|
+
end
|
91
|
+
return nil
|
92
|
+
end
|
93
|
+
|
71
94
|
# Extracts SOAP actions as methods.
|
72
95
|
def process_methods(doc)
|
73
96
|
iface = REXML::XPath.first(doc, 'descendant::wsdl:portType')
|
@@ -76,13 +99,9 @@ module AdsCommon
|
|
76
99
|
end
|
77
100
|
end
|
78
101
|
|
79
|
-
# Extracts ComplexTypes from
|
80
|
-
def get_complex_types(
|
81
|
-
|
82
|
-
REXML::XPath.each(doc, '//schema/complexType') do |ctype|
|
83
|
-
complex_types << ctype
|
84
|
-
end
|
85
|
-
return complex_types
|
102
|
+
# Extracts ComplexTypes from node into an array.
|
103
|
+
def get_complex_types(node)
|
104
|
+
return REXML::XPath.each(node, 'complexType').to_a
|
86
105
|
end
|
87
106
|
|
88
107
|
# Extracts exception parameters from ComplexTypes element.
|
@@ -110,13 +129,14 @@ module AdsCommon
|
|
110
129
|
|
111
130
|
# Extracts definition of all types. If a non standard undefined type is
|
112
131
|
# found it process it recursively.
|
113
|
-
def extract_type(type_element)
|
132
|
+
def extract_type(type_element, ns_index)
|
114
133
|
type = {:name => get_element_name(type_element), :fields => []}
|
115
134
|
if attribute_to_boolean(type_element.attribute('abstract'))
|
116
135
|
type[:abstract] = true
|
117
136
|
end
|
118
137
|
base_type = get_element_base(type_element)
|
119
138
|
type[:base] = base_type if base_type
|
139
|
+
type[:ns] = ns_index if ns_index
|
120
140
|
REXML::XPath.each(type_element,
|
121
141
|
'sequence | complexContent/extension/sequence') do |seq_node|
|
122
142
|
type[:fields] += get_element_fields(seq_node)
|
@@ -177,17 +197,20 @@ module AdsCommon
|
|
177
197
|
def get_element_fields(element)
|
178
198
|
fields = []
|
179
199
|
REXML::XPath.each(element, 'descendant::element') do |item|
|
180
|
-
|
200
|
+
field = {:name => get_element_name(item).snakecase.to_sym,
|
181
201
|
:type => item.attribute('type').to_s.gsub(/^.+:/, ''),
|
182
202
|
:min_occurs => attribute_to_int(item.attribute('minOccurs')),
|
183
203
|
:max_occurs => attribute_to_int(item.attribute('maxOccurs'))}
|
204
|
+
fields << field.reject {|k, v| v.nil?}
|
184
205
|
end
|
185
206
|
return fields
|
186
207
|
end
|
187
208
|
|
188
209
|
# Simple converter for int values.
|
189
210
|
def attribute_to_int(attribute)
|
190
|
-
return
|
211
|
+
return nil if attribute.nil?
|
212
|
+
return attribute.value.eql?('unbounded') ?
|
213
|
+
:unbounded : attribute.value.to_i
|
191
214
|
end
|
192
215
|
|
193
216
|
# Simple converter for boolean values.
|
@@ -39,6 +39,7 @@ module AdsCommon
|
|
39
39
|
class <%= @service_name %>Registry
|
40
40
|
<%= @service_name.upcase %>_METHODS = <%= format_signature(@methods) %>
|
41
41
|
<%= @service_name.upcase %>_TYPES = <%= format_signature(@types) %>
|
42
|
+
<%= @service_name.upcase %>_NAMESPACES = <%= format_array(@namespaces) %>
|
42
43
|
|
43
44
|
def self.get_method_signature(method_name)
|
44
45
|
return <%= @service_name.upcase %>_METHODS[method_name.to_sym]
|
@@ -47,6 +48,10 @@ module AdsCommon
|
|
47
48
|
def self.get_type_signature(type_name)
|
48
49
|
return <%= @service_name.upcase %>_TYPES[type_name.to_sym]
|
49
50
|
end
|
51
|
+
|
52
|
+
def self.get_namespace(index)
|
53
|
+
return <%= @service_name.upcase %>_NAMESPACES[index]
|
54
|
+
end
|
50
55
|
end
|
51
56
|
<% @exceptions.each do |exception| %>
|
52
57
|
<% array_fields = [] %>
|
@@ -59,11 +64,13 @@ module AdsCommon
|
|
59
64
|
class <%= exception[:name] %> < <%= base_text %>
|
60
65
|
<% exception[:fields].each do |field| %>
|
61
66
|
attr_reader :<%= field[:name] %> # <%= field[:type] %>
|
62
|
-
<%
|
67
|
+
<% is_array_field = (field[:max_occurs].nil?) ? false :
|
68
|
+
((field[:max_occurs] == :unbounded) || (field[:max_occurs] > 1)) %>
|
69
|
+
<% array_fields << field[:name] if is_array_field %>
|
63
70
|
<% end %>
|
64
71
|
<% if !(array_fields.empty?) %>
|
65
72
|
def initialize(exception_fault)
|
66
|
-
@array_fields
|
73
|
+
@array_fields ||= []
|
67
74
|
<% array_fields.each do |field| %>
|
68
75
|
@array_fields << '<%= field.to_s %>'
|
69
76
|
<% end %>
|
@@ -81,8 +88,8 @@ module AdsCommon
|
|
81
88
|
@exceptions = []
|
82
89
|
@methods = []
|
83
90
|
@types = []
|
84
|
-
@
|
85
|
-
|
91
|
+
@namespaces = []
|
92
|
+
@default_exception_base = "%s::Errors::ApiException" % @api_name
|
86
93
|
end
|
87
94
|
|
88
95
|
def get_code_template()
|
@@ -101,6 +108,10 @@ module AdsCommon
|
|
101
108
|
@types += types
|
102
109
|
end
|
103
110
|
|
111
|
+
def add_namespaces(namespaces)
|
112
|
+
@namespaces += namespaces
|
113
|
+
end
|
114
|
+
|
104
115
|
private
|
105
116
|
|
106
117
|
# Multi-line documentation formatter. Used to format text extracted from
|
@@ -120,17 +131,19 @@ module AdsCommon
|
|
120
131
|
return PP.singleline_pp(objects_hash, '')
|
121
132
|
end
|
122
133
|
|
134
|
+
# Prepares string representing a simple array.
|
135
|
+
def format_array(objects_array)
|
136
|
+
return (objects_array.nil?) ? '[]' : PP.singleline_pp(objects_array, '')
|
137
|
+
end
|
138
|
+
|
123
139
|
# Converts an array of hashes to a hash based on ":name" fields:
|
124
140
|
# [{:name => 'foo', :data => 'bar'}] => {:foo => {:data => 'bar'}}
|
125
141
|
def get_hash_for_names_array(input)
|
126
|
-
|
127
|
-
input.each do |e|
|
142
|
+
return input.inject({}) do |output, e|
|
128
143
|
key = e[:name].to_sym
|
129
|
-
|
130
|
-
|
131
|
-
output[key] = value
|
144
|
+
output[key] = e.reject {|k, v| k.equal?(:name)}
|
145
|
+
output
|
132
146
|
end
|
133
|
-
return output
|
134
147
|
end
|
135
148
|
end
|
136
149
|
end
|
@@ -35,13 +35,16 @@ module AdsCommon
|
|
35
35
|
|
36
36
|
require 'ads_common/savon_service'
|
37
37
|
require '<%= @require_path %>/<%= @service_name.to_s.snakecase %>_registry'
|
38
|
+
<% unless @extensions.empty? %>
|
39
|
+
require '<%= @api_name.snakecase %>/extensions'
|
40
|
+
<% end %>
|
38
41
|
|
39
42
|
<%= @modules_open_string %>
|
40
43
|
|
41
44
|
class <%= @service_name %> < AdsCommon::SavonService
|
42
|
-
def initialize(endpoint)
|
45
|
+
def initialize(api, endpoint)
|
43
46
|
namespace = '<%= @namespace %>'
|
44
|
-
super(endpoint, namespace)
|
47
|
+
super(api, endpoint, namespace, :<%= @version %>)
|
45
48
|
end
|
46
49
|
<% @actions.each do |action| %>
|
47
50
|
|
@@ -49,6 +52,12 @@ module AdsCommon
|
|
49
52
|
return execute_action('<%= action %>', args)
|
50
53
|
end
|
51
54
|
<% end %>
|
55
|
+
<% @extensions.each do |extention| %>
|
56
|
+
|
57
|
+
def <%= extention %>(*args)
|
58
|
+
return <%= @api_name %>::Extensions.<%= extention %>(self, args)
|
59
|
+
end
|
60
|
+
<% end %>
|
52
61
|
|
53
62
|
private
|
54
63
|
|
@@ -57,7 +66,7 @@ module AdsCommon
|
|
57
66
|
end
|
58
67
|
|
59
68
|
def get_module()
|
60
|
-
return <%= @
|
69
|
+
return <%= [@api_name, @version.to_s.upcase, @service_name].join('::') %>
|
61
70
|
end
|
62
71
|
end
|
63
72
|
<%= @modules_close_string %>
|
@@ -67,12 +76,17 @@ module AdsCommon
|
|
67
76
|
def initialize(args)
|
68
77
|
super(args)
|
69
78
|
@actions = []
|
79
|
+
@extensions = []
|
70
80
|
end
|
71
81
|
|
72
82
|
def add_actions(actions)
|
73
83
|
@actions += actions
|
74
84
|
end
|
75
85
|
|
86
|
+
def add_extensions(extensions)
|
87
|
+
@extensions += extensions
|
88
|
+
end
|
89
|
+
|
76
90
|
def get_code_template()
|
77
91
|
SERVICE_TEMPLATE
|
78
92
|
end
|
data/lib/ads_common/config.rb
CHANGED
@@ -29,7 +29,7 @@ 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 =
|
32
|
+
@config = {}
|
33
33
|
case param
|
34
34
|
when String then load(param)
|
35
35
|
when Hash then set_all(param)
|