google-ads-common 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|