google-ads-savon 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e33b82251dab2fe6023fddf342d54c42baae2ad5
4
+ data.tar.gz: d45eadd1cb5bd5c857580018ca16a08f00616356
5
+ SHA512:
6
+ metadata.gz: 7def73594ce63bdb09025dc8bd0d1bd8a1de1dcee582b425b880408cba3022d248659dce4d13c20771a41710057f1b7be578f2b5053184d2e8b6579839877c5c
7
+ data.tar.gz: 3d3ac185715f0f161f11a4cd98d034948576724ece7f6ee749685e5f75f00107eebbdb6f6e1217a47b48c4e95f365c46053b68b42ea05bc4850d96ff72946906
data/BUILD ADDED
@@ -0,0 +1,7 @@
1
+ # Description:
2
+ # GoogleAdsSavon, a soap library forked from Savon v1.2.0.
3
+ package(default_visibility = ["//visibility:public"])
4
+
5
+ licenses(["notice"]) # MIT
6
+
7
+ exports_files(["LICENSE"])
data/CONTRIBUTING ADDED
@@ -0,0 +1,24 @@
1
+ Want to contribute? Great! First, read this page (including the small print at the end).
2
+
3
+ ### Before you contribute
4
+ Before we can use your code, you must sign the
5
+ [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
6
+ (CLA), which you can do online. The CLA is necessary mainly because you own the
7
+ copyright to your changes, even after your contribution becomes part of our
8
+ codebase, so we need your permission to use and distribute your code. We also
9
+ need to be sure of various other things—for instance that you'll tell us if you
10
+ know that your code infringes on other people's patents. You don't have to sign
11
+ the CLA until after you've submitted your code for review and a member has
12
+ approved it, but you must do it before we can put your code into our codebase.
13
+ Before you start working on a larger contribution, you should get in touch with
14
+ us first through the issue tracker with your idea so that we can help out and
15
+ possibly guide you. Coordinating up front makes it much easier to avoid
16
+ frustration later on.
17
+
18
+ ### Code reviews
19
+ All submissions, including submissions by project members, require review. We
20
+ use Github pull requests for this purpose.
21
+
22
+ ### The small print
23
+ Contributions made by corporations are covered by a different agreement than
24
+ the one above, the Software Grant and Corporate Contributor License Agreement.
data/ChangeLog ADDED
@@ -0,0 +1,3 @@
1
+ 1.0.0:
2
+ - Initial release of Google Ads Savon. This is a fork of Savon version 1,
3
+ which can be found here: https://github.com/savonrb/savon/tree/version1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2010 Daniel Harrington
2
+ Copyright (c) 2015 Google, Inc.
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Google Ads Savon
2
+
3
+ Google Ads Savon is a fork of [Savon 1](http://savonrb.com/version1/)
4
+ specific for use with the Google Ads Ruby Client Library.
5
+
6
+ Google Ads Savon is available through [Rubygems](http://rubygems.org/gems/google-ads-savon) and can be installed via:
7
+
8
+ $ gem install google-ads-savon
9
+
10
+ This library is not intended for re-use outside of google-ads-common.
11
+
12
+ This is not an official Google product (experimental or otherwise), it is just code that happens to be owned by Google.
13
+
14
+ Documentation
15
+ -------------
16
+
17
+ Read about the original library at [savonrb.com/version1/](http://savonrb.com/version1/)
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ desc 'Package the Google Ads Savon library into a gem file.'
2
+ task :build do
3
+ result = system('/usr/bin/env gem build google-ads-savon.gemspec')
4
+ raise 'Build failed.' unless result
5
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding : utf-8 -*-
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $:.unshift lib unless $:.include? lib
4
+
5
+ require "ads_savon/version"
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "google-ads-savon"
9
+ s.version = GoogleAdsSavon::VERSION
10
+ s.authors = "Daniel Harrington"
11
+ s.email = "me@rubiii.com"
12
+ s.homepage = "http://savonrb.com"
13
+ s.summary = "Heavy metal SOAP client"
14
+ s.description = "Delicious SOAP for the Ruby community"
15
+
16
+ s.rubyforge_project = s.name
17
+ s.license = 'MIT'
18
+
19
+ s.add_dependency "nori", "~> 2.4"
20
+ s.add_dependency "httpi", "~> 2.3"
21
+ s.add_dependency "wasabi", "~> 3.4"
22
+ s.add_dependency "akami", "~> 1.2"
23
+ s.add_dependency "gyoku", "~> 1.2"
24
+
25
+ s.add_dependency "builder", ">= 2.1.2"
26
+ s.add_dependency "nokogiri", ">= 1.4.0"
27
+
28
+ s.add_development_dependency "rake", "~> 10.1"
29
+ s.add_development_dependency "rspec", "~> 2.14"
30
+ s.add_development_dependency "mocha", "~> 0.14"
31
+ s.add_development_dependency "timecop", "~> 0.3"
32
+
33
+ s.files = Dir["**/*"]
34
+ s.require_path = "lib"
35
+ end
data/lib/ads_savon.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "ads_savon/version"
2
+ require "ads_savon/config"
3
+ require "ads_savon/client"
4
+ require "ads_savon/model"
5
+
6
+ module GoogleAdsSavon
7
+ extend self
8
+
9
+ def client(*args, &block)
10
+ Client.new(*args, &block)
11
+ end
12
+
13
+ def configure
14
+ yield config
15
+ end
16
+
17
+ def config
18
+ @config ||= Config.default
19
+ end
20
+
21
+ attr_writer :config
22
+
23
+ end
@@ -0,0 +1,163 @@
1
+ require "wasabi/document"
2
+ require "httpi/request"
3
+ require "akami"
4
+
5
+ require "ads_savon/soap/xml"
6
+ require "ads_savon/soap/request"
7
+ require "ads_savon/soap/response"
8
+ require "ads_savon/soap/request_builder"
9
+
10
+ module GoogleAdsSavon
11
+
12
+ # = GoogleAdsSavon::Client
13
+ #
14
+ # GoogleAdsSavon::Client is the main object for connecting to a SOAP service.
15
+ class Client
16
+
17
+ # Initializes the GoogleAdsSavon::Client for a SOAP service. Accepts a +block+ which is evaluated in the
18
+ # context of this object to let you access the +wsdl+, +http+, and +wsse+ methods.
19
+ #
20
+ # == Examples
21
+ #
22
+ # # Using a remote WSDL
23
+ # client = GoogleAdsSavon::Client.new("http://example.com/UserService?wsdl")
24
+ #
25
+ # # Using a local WSDL
26
+ # client = GoogleAdsSavon::Client.new File.expand_path("../wsdl/service.xml", __FILE__)
27
+ #
28
+ # # Directly accessing a SOAP endpoint
29
+ # client = GoogleAdsSavon::Client.new do
30
+ # wsdl.endpoint = "http://example.com/UserService"
31
+ # wsdl.namespace = "http://users.example.com"
32
+ # end
33
+ def initialize(wsdl_document = nil, &block)
34
+ self.config = GoogleAdsSavon.config.clone
35
+ wsdl.document = wsdl_document if wsdl_document
36
+
37
+ process 1, &block if block
38
+ wsdl.request = http
39
+ end
40
+
41
+ # Accessor for the <tt>GoogleAdsSavon::Config</tt>.
42
+ attr_accessor :config
43
+
44
+ # Returns the <tt>Wasabi::Document</tt>.
45
+ def wsdl
46
+ @wsdl ||= Wasabi::Document.new
47
+ end
48
+
49
+ # Returns the <tt>HTTPI::Request</tt>.
50
+ def http
51
+ @http ||= HTTPI::Request.new
52
+ end
53
+
54
+ # Returns the <tt>Akami::WSSE</tt> object.
55
+ def wsse
56
+ @wsse ||= Akami.wsse
57
+ end
58
+
59
+ # Executes a SOAP request for a given SOAP action. Accepts a +block+ which is evaluated in the
60
+ # context of the <tt>SOAP::RequestBuilder</tt> object to let you access its +soap+, +wsdl+,
61
+ # +http+ and +wsse+ methods.
62
+ #
63
+ # == Examples
64
+ #
65
+ # # Calls a "getUser" SOAP action with the payload of "<userId>123</userId>"
66
+ # client.request(:get_user) { soap.body = { :user_id => 123 } }
67
+ #
68
+ # # Prefixes the SOAP input tag with a given namespace: "<wsdl:GetUser>...</wsdl:GetUser>"
69
+ # client.request(:wsdl, "GetUser") { soap.body = { :user_id => 123 } }
70
+ #
71
+ # # SOAP input tag with attributes: <getUser xmlns:wsdl="http://example.com">...</getUser>"
72
+ # client.request(:get_user, "xmlns:wsdl" => "http://example.com")
73
+ def request(*args, &block)
74
+ raise ArgumentError, "GoogleAdsSavon::Client#request requires at least one argument" if args.empty?
75
+
76
+ options = extract_options(args)
77
+
78
+ request_builder = SOAP::RequestBuilder.new(options.delete(:input), options)
79
+ request_builder.wsdl = wsdl
80
+ request_builder.http = http.dup
81
+ request_builder.wsse = wsse.dup
82
+ request_builder.config = config.dup
83
+
84
+ post_configuration = lambda { process(0, request_builder, &block) if block }
85
+
86
+ response = request_builder.request(&post_configuration).response
87
+ http.set_cookies(response.http)
88
+
89
+ if wsse.verify_response
90
+ WSSE::VerifySignature.new(response.http.body).verify!
91
+ end
92
+
93
+ response
94
+ end
95
+
96
+ private
97
+
98
+ # Expects an Array of +args+ and returns a Hash containing the SOAP input,
99
+ # the namespace (might be +nil+), the SOAP action (might be +nil+),
100
+ # the SOAP body (might be +nil+), and a Hash of attributes for the input
101
+ # tag (which might be empty).
102
+ def extract_options(args)
103
+ attributes = Hash === args.last ? args.pop : {}
104
+ body = attributes.delete(:body)
105
+ soap_action = attributes.delete(:soap_action)
106
+
107
+ namespace_identifier = args.size > 1 ? args.shift.to_sym : nil
108
+ input = args.first
109
+
110
+ remove_blank_values(
111
+ :namespace_identifier => namespace_identifier,
112
+ :input => input,
113
+ :attributes => attributes,
114
+ :body => body,
115
+ :soap_action => soap_action
116
+ )
117
+ end
118
+
119
+ # Processes a given +block+. Yields objects if the block expects any arguments.
120
+ # Otherwise evaluates the block in the context of +instance+.
121
+ def process(offset = 0, instance = self, &block)
122
+ block.arity > 0 ? yield_objects(offset, instance, &block) : evaluate(instance, &block)
123
+ end
124
+
125
+ # Yields a number of objects to a given +block+ depending on how many arguments
126
+ # the block is expecting.
127
+ def yield_objects(offset, instance, &block)
128
+ to_yield = [:soap, :wsdl, :http, :wsse]
129
+ yield *(to_yield[offset, block.arity].map { |obj_name| instance.send(obj_name) })
130
+ end
131
+
132
+ # Evaluates a given +block+ inside +instance+. Stores the original block binding.
133
+ def evaluate(instance, &block)
134
+ original_self = eval "self", block.binding
135
+
136
+ # A proxy that attemps to make method calls on +instance+. If a NoMethodError is
137
+ # raised, the call will be made on +original_self+.
138
+ proxy = Object.new
139
+ proxy.instance_eval do
140
+ class << self
141
+ attr_accessor :original_self, :instance
142
+ end
143
+
144
+ def method_missing(method, *args, &block)
145
+ instance.send(method, *args, &block)
146
+ rescue NoMethodError
147
+ original_self.send(method, *args, &block)
148
+ end
149
+ end
150
+
151
+ proxy.instance = instance
152
+ proxy.original_self = original_self
153
+
154
+ proxy.instance_eval &block
155
+ end
156
+
157
+ # Removes all blank values from a given +hash+.
158
+ def remove_blank_values(hash)
159
+ hash.delete_if { |_, value| value.respond_to?(:empty?) ? value.empty? : !value }
160
+ end
161
+
162
+ end
163
+ end
@@ -0,0 +1,46 @@
1
+ require "ads_savon/logger"
2
+ require "ads_savon/null_logger"
3
+ require "ads_savon/hooks/group"
4
+ require "ads_savon/soap"
5
+
6
+ module GoogleAdsSavon
7
+ Config = Struct.new(:_logger, :pretty_print_xml, :raise_errors, :soap_version, :env_namespace, :soap_header) do
8
+
9
+ def self.default
10
+ config = new
11
+ config._logger = Logger.new
12
+ config.raise_errors = true
13
+ config.soap_version = SOAP::DEFAULT_VERSION
14
+ config
15
+ end
16
+
17
+ alias_method :logger, :_logger
18
+
19
+ def logger=(logger)
20
+ _logger.subject = logger
21
+ end
22
+
23
+ def log_level=(level)
24
+ _logger.level = level
25
+ end
26
+
27
+ def log=(log)
28
+ if log == true
29
+ self._logger = Logger.new
30
+ else
31
+ self._logger = NullLogger.new
32
+ end
33
+ end
34
+
35
+ def hooks
36
+ @hooks ||= Hooks::Group.new
37
+ end
38
+
39
+ def clone
40
+ config = super
41
+ config._logger = config._logger.clone
42
+ config
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,30 @@
1
+ require "ads_savon/soap"
2
+
3
+ module GoogleAdsSavon
4
+ module CoreExt
5
+ module String
6
+
7
+ def self.included(base)
8
+ unless "savon".respond_to?(:snakecase)
9
+ base.send(:include, Extension)
10
+ end
11
+ end
12
+
13
+ module Extension
14
+ def snakecase
15
+ str = dup
16
+ str.gsub! /::/, '/'
17
+ str.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2'
18
+ str.gsub! /([a-z\d])([A-Z])/, '\1_\2'
19
+ str.tr! ".", "_"
20
+ str.tr! "-", "_"
21
+ str.downcase!
22
+ str
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+
30
+ String.send :include, GoogleAdsSavon::CoreExt::String
@@ -0,0 +1,6 @@
1
+ module GoogleAdsSavon
2
+
3
+ # Base class for GoogleAdsSavon errors.
4
+ class Error < RuntimeError; end
5
+
6
+ end
@@ -0,0 +1,68 @@
1
+ require "ads_savon/hooks/hook"
2
+
3
+ module GoogleAdsSavon
4
+ module Hooks
5
+
6
+ # = GoogleAdsSavon::Hooks::Group
7
+ #
8
+ # Manages a list of hooks.
9
+ class Group
10
+
11
+ # Accepts an Array of +hooks+ to start with.
12
+ def initialize(hooks = [])
13
+ @hooks = hooks
14
+ end
15
+
16
+ # Returns whether this group contains hooks.
17
+ def empty?
18
+ hooks.empty?
19
+ end
20
+
21
+ # Returns the number of hooks in this group.
22
+ def count
23
+ hooks.count
24
+ end
25
+
26
+ # Adds a new hook.
27
+ def define(id, hook, &block)
28
+ hooks << Hook.new(id, hook, &block)
29
+ end
30
+
31
+ # Removes hooks matching the given +ids+.
32
+ def reject(*ids)
33
+ ids = ids.flatten
34
+ hooks.reject! { |hook| ids.include? hook.id }
35
+ end
36
+
37
+ # Fire a given +hook+ with any given +args+.
38
+ def fire(hook, *args, &callback)
39
+ callable = select(hook)
40
+
41
+ if callable.empty?
42
+ callback.call
43
+ else
44
+ args.unshift(callback) if callback
45
+ callable.call(*args)
46
+ end
47
+ end
48
+
49
+ # Calls the hooks with the given +args+ and returns the
50
+ # value of the last hooks.
51
+ def call(*args)
52
+ hooks.inject(nil) { |memo, hook| hook.call(*args) }
53
+ end
54
+
55
+ private
56
+
57
+ def hooks
58
+ @hooks ||= []
59
+ end
60
+
61
+ # Returns a new group for a given +hook+.
62
+ def select(hook)
63
+ Group.new hooks.select { |h| h.hook == hook }
64
+ end
65
+
66
+ end
67
+ end
68
+ end