quest_back 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 71ac294356aae1fe3423d0cba13cb705a1245cfd
4
+ data.tar.gz: 99bf75d03a7984badd0291ba474d27e07b9796fd
5
+ SHA512:
6
+ metadata.gz: 83d3d479391da098c8c62d9bc1d157c0fe14708c1ad320cb76d61605519b3404ce133648a8a38007c00cc9a436882f8f052d269786c05590e8b3ab56ce180d91
7
+ data.tar.gz: f030b1fa5a1f02645e39386cc630cde2c08d5f5e06d2a7dd02938bb941c15905192df38c24bfe467ae3bec4c645cdffb16d5a0fb299977aa8d5c223cfe7d9299
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ bin
19
+ config.yml
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in quest_back.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Thorbjørn Hermansen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # QuestBack
2
+
3
+ Simply Ruby client for QuestBack's SOAP API.
4
+
5
+ ### WARNING
6
+
7
+ This gem is not complete and may lack many functions provided by QuestBack.
8
+ Please feel free to contribute and make pull requests.
9
+
10
+ It is also very simplistic, only using simple hashes for both sending in arguments to the API and returning responses.
11
+ The hash you send as argument to operation methods is more or less sent on to QuestBack.
12
+ Maybe this will change in the future with real objects sent in to the API.
13
+
14
+
15
+
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ gem 'quest_back'
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install quest_back
30
+
31
+ ## Usage
32
+
33
+ ### Get access - test client in console
34
+
35
+ 1. Go to https://response.questback.com/soapdocs/integration/ and request white listing of the IP you will make requests from.
36
+ 2. Sign in to QuestBack. Go to your account's page and fill in "Integration username and password".
37
+ If you have no fields under Integration Information you have to contact QuestBack to get access.
38
+ 3. Copy config.example.yml to config.yml and insert your username and password.
39
+ 4. `QuestBack.conf!` to load config.yml as default config.
40
+ 5. `QuestBack::Client.new.test_connection` to make a test connection API call. On successful connection this returns string with current namespace of integration library.
41
+
42
+
43
+ ### Example of usage
44
+
45
+ ```ruby
46
+ # Read quests
47
+ api = QuestBack::Api.new
48
+ response = api.get_quests
49
+ irb(main):005:0> response.results
50
+ => [
51
+ {
52
+ :quest_id=>"4567668",
53
+ :security_lock=>"m0pI8orKJp",
54
+ :quest_title=>"Skalars spørreundersøkelse",
55
+ ...
56
+ },
57
+ {
58
+ ...
59
+ }
60
+ ]
61
+
62
+
63
+ # Add email invitees
64
+ response = api.add_email_invitees(
65
+ quest_info: {quest_id: 4567668, security_lock: 'm0pI8orKJp'},
66
+ emails: ['inviso@skalar.no', 'th@skalar.no'],
67
+ sendduplicate: true
68
+ )
69
+
70
+ response.result
71
+ => "Added 2 invitations to QuestId:4567668"
72
+
73
+
74
+ # Add respondent data
75
+ response = api.add_respondents_data(
76
+ quest_info: {quest_id: 4567668, security_lock: 'm0pI8orKJp'},
77
+ respondents_data: {
78
+ respondent_data_header: {
79
+ respondent_data_header: [
80
+ {
81
+ title: 'Epost',
82
+ type: QuestBack::Api.respondent_data_header_type_for(:text),
83
+ is_email_field: true,
84
+ is_sms_field: false,
85
+ },
86
+ {
87
+ title: 'Navn',
88
+ type: QuestBack::Api.respondent_data_header_type_for(:text),
89
+ is_email_field: false,
90
+ is_sms_field: false,
91
+ },
92
+ {
93
+ title: 'Alder',
94
+ type: QuestBack::Api.respondent_data_header_type_for(:numeric),
95
+ is_email_field: false,
96
+ is_sms_field: false,
97
+ },
98
+ ]
99
+ },
100
+ respondent_data: ['th@skalar.no;Thorbjorn;32'],
101
+ allow_duplicate: true,
102
+ add_as_invitee: true
103
+ }
104
+ )
105
+
106
+ response.result
107
+ => "Added 1 respondent data to QuestId :4567668"
108
+ ```
109
+
110
+ ### Debug XML without making a request
111
+
112
+ If you ever need to see XML generated without sending the request it can be done by doing:
113
+
114
+ ```ruby
115
+ QuestBack.debug!
116
+ QuestBack::Api.new.test_connection
117
+
118
+ DEBUG -- : HTTPI GET request to integration.questback.com (net_http)
119
+ INFO -- : !!!!!!!!!
120
+ INFO -- : !!! SOAP request hijacked by QuestBack::DebugObserver.
121
+ INFO -- : !!!!!!!!!
122
+ DEBUG -- :
123
+
124
+ <?xml version="1.0" encoding="UTF-8"?>
125
+ <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="https://integration.questback.com/2011/03" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:array="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:enum="http://schemas.microsoft.com/2003/10/Serialization/Enums">
126
+ <env:Body>
127
+ <wsdl:TestConnection>
128
+ <wsdl:userInfo>
129
+ <wsdl:Username>inviso@skalar.no</wsdl:Username>
130
+ <wsdl:Password>xxxxx</wsdl:Password>
131
+ </wsdl:userInfo>
132
+ </wsdl:TestConnection>
133
+ </env:Body>
134
+ </env:Envelope>
135
+
136
+ QuestBack.remove_debug! # Activates real requests again
137
+ ```
138
+
139
+
140
+
141
+ ## Contributing
142
+
143
+ 1. Fork it (https://github.com/Skalar/quest_back/fork)
144
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
145
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
146
+ 4. Push to the branch (`git push origin my-new-feature`)
147
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ username: 'my-username'
2
+ password: 'my-password'
3
+ http_proxy: ~
@@ -0,0 +1,310 @@
1
+ module QuestBack
2
+ class Api
3
+ # This hash contains parts of request we can include in soap operation.
4
+ # For instance call(:some_action, attributes, include_defaults: [:paging_info]) will
5
+ # slice paging_info and include it in the request.
6
+ DEFAULTS = {
7
+ paging_info: {page_no: 0, page_size: 50},
8
+ quest_filter: '',
9
+ sendduplicate: false,
10
+ respondents_data: {
11
+ delimiter: ';',
12
+ order!: [:respondent_data_header, :respondent_data, :delimiter, :allow_duplicate, :add_as_invitee]
13
+ }
14
+ }
15
+
16
+ # The order of the elements in the SOAP body is important for the SOAP API.
17
+ # For operations with multiple arguments this hash gives savon the order of which
18
+ # it should .. well, order the elements.
19
+ ORDER = {
20
+ get_quests: [:user_info, :paging_info, :quest_filter],
21
+ add_email_invitees: [:user_info, :quest_info, :emails, :sendduplicate, :language_id],
22
+ add_respondents_data: [:user_info, :quest_info, :respondents_data, :language_id]
23
+ }
24
+
25
+ # In order to provide a simple response.result and response.results interface
26
+ # where the actual result we care about is returned we have to give knowledge to
27
+ # where this result is found. As it turns out, get_quests returns it's quests within
28
+ # quests/quest array, and at the same time get_quest_questions returns the questions
29
+ # within simply it's root result element. No nestings there.. So, it seems a bit randon
30
+ # and we need to have this configured. I though it would be put under quest_questions/quest_question,
31
+ # but no such luck.
32
+ RESULT_KEY_NESTINGS = {
33
+ test_connection: [],
34
+ get_quests: [:quests, :quest],
35
+ get_language_list: [:language],
36
+ add_email_invitees: [],
37
+ add_respondents_data: []
38
+ }
39
+
40
+ RESPONDENTS_HEADER_TYPE = {
41
+ numeric: 1,
42
+ text: 2
43
+ }
44
+
45
+ NAMESPACES = {
46
+ 'xmlns:array' => 'http://schemas.microsoft.com/2003/10/Serialization/Arrays',
47
+ 'xmlns:enum' => 'http://schemas.microsoft.com/2003/10/Serialization/Enums'
48
+ }
49
+
50
+ def self.respondent_data_header_type_for(type)
51
+ RESPONDENTS_HEADER_TYPE.fetch(type.to_sym) { fail ArgumentError, "#{type.to_s.inspect} is an unkown respondent data header type." }
52
+ end
53
+
54
+ # Public: Creates a new API gateway object.
55
+ #
56
+ # Attributes
57
+ # config - A QuestBack::Configuration object. May be nil if
58
+ # QuestBack.default_configuration has been set.
59
+ def initialize(attributes = {})
60
+ attributes = ActiveSupport::HashWithIndifferentAccess.new attributes
61
+
62
+ @config = attributes[:config]
63
+ end
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+ # Public: Make a test connection call to QuestBack
72
+ #
73
+ # Returns QuestBack::Response
74
+ def test_connection
75
+ call :test_connection
76
+ end
77
+
78
+ # Public: Get quests
79
+ #
80
+ # attributes - Attributes sent to QuestBack
81
+ #
82
+ # Example
83
+ #
84
+ # response = api.get_quests paging_info: {page_size: 2} # Limits result to two
85
+ # response.results
86
+ # => [result, result]
87
+ #
88
+ # Returns QuestBack::Response
89
+ def get_quests(attributes = {})
90
+ call :get_quests, attributes, include_defaults: [:paging_info, :quest_filter]
91
+ end
92
+
93
+ # Public: Returns a list of languages from QuestBack.
94
+ #
95
+ #
96
+ # Returns QuestBack::Response
97
+ def get_language_list
98
+ call :get_language_list
99
+ end
100
+
101
+ # Public: Invites a set of emails to a quest.
102
+ #
103
+ # attributes - Attributes sent to QuestBack
104
+ #
105
+ # Example
106
+ #
107
+ # response = api.add_email_invitees(
108
+ # quest_info: {quest_id: 4567668, security_lock: 'm0pI8orKJp'},
109
+ # emails: ['inviso@skalar.no', 'th@skalar.no'],
110
+ # sendduplicate: true, # or false as default
111
+ # language_id: 123, # optional
112
+ # )
113
+ #
114
+ # Returns QuestBack::Response
115
+ def add_email_invitees(attributes = {})
116
+ call :add_email_invitees, attributes, include_defaults: [:sendduplicate]
117
+ end
118
+
119
+ # Public: Add respondent data to a quest - optionally send as invitee as well.
120
+ #
121
+ # attributes - Attributes sent to QuestBack
122
+ #
123
+ # QuestBack is doing a bit of CSV over XML here? As you need to serialize
124
+ # respondent_data as a string with a delimiter ala CSV. The order of the
125
+ # data must match the order of respondent_data_header. I guess simply using XML
126
+ # and named elements was too easy? :-)
127
+ #
128
+ # Example
129
+ #
130
+ # response = api.add_respondents_data(
131
+ # quest_info: {quest_id: 4567668, security_lock: 'm0pI8orKJp'},
132
+ # respondents_data: {
133
+ # respondent_data_header: {
134
+ # respondent_data_header: [
135
+ # {
136
+ # title: 'Epost',
137
+ # type: QuestBack::Api.respondent_data_header_type_for(:text),
138
+ # is_email_field: true,
139
+ # is_sms_field: false,
140
+ # },
141
+ # {
142
+ # title: 'Navn',
143
+ # type: QuestBack::Api.respondent_data_header_type_for(:text),
144
+ # is_email_field: false,
145
+ # is_sms_field: false,
146
+ # },
147
+ # {
148
+ # title: 'Alder',
149
+ # type: QuestBack::Api.respondent_data_header_type_for(:numeric),
150
+ # is_email_field: false,
151
+ # is_sms_field: false,
152
+ # },
153
+ # ]
154
+ # },
155
+ # respondent_data: ['th@skalar.no;Thorbjorn;32'], # According to QuestBack's doc you can only do one here
156
+ # allow_duplicate: true,
157
+ # add_as_invitee: true
158
+ # }
159
+ # )
160
+ #
161
+ # You may override respondent_data's delimiter in string too.
162
+ #
163
+ # Returns QuestBack::Response
164
+ def add_respondents_data(attributes = {})
165
+ call :add_respondents_data, attributes, include_defaults: [:respondents_data]
166
+ end
167
+
168
+
169
+
170
+
171
+
172
+ # Public: Savon client.
173
+ #
174
+ # Savon client all API method calls will go through.
175
+ def client
176
+ @client ||= begin
177
+ client_config = {
178
+ wsdl: config.wsdl,
179
+ namespace: config.soap_namespace,
180
+ log_level: config.log_level,
181
+ element_form_default: :qualified,
182
+ namespaces: NAMESPACES
183
+ }
184
+
185
+ client_config[:proxy] = config.http_proxy if config.http_proxy.present?
186
+
187
+ Savon::Client.new client_config
188
+ end
189
+ end
190
+
191
+
192
+ # Public: Configuration for the API.
193
+ #
194
+ # Returns a QuestBack::Configuration object
195
+ def config
196
+ @config || QuestBack.default_configuration || fail(QuestBack::Error, 'No configuration given or found on QuestBack.default_configuration.')
197
+ end
198
+
199
+
200
+
201
+
202
+ private
203
+
204
+ def call(operation_name, attributes = {}, options = {})
205
+ options[:operation_name] = operation_name
206
+
207
+ options_to_response = {
208
+ operation_name: options[:operation_name],
209
+ result_key_nestings: RESULT_KEY_NESTINGS.fetch(operation_name) { fail KeyError, "You must configure RESULT_KEY_NESTINGS for #{operation_name}" }
210
+ }
211
+
212
+ savon_response = client.call operation_name, build_hash_for_savon_call(attributes, options)
213
+
214
+ Response.new savon_response, options_to_response
215
+ end
216
+
217
+
218
+ # Private: Builds a hash for savon call - include user info and other defaults you ask it to
219
+ #
220
+ # attributes - A hash representing attributes the client sent to us which it expects us to send to QuestBack
221
+ # options - A hash where we can send in options:
222
+ # :include_defaults - Give an array with key names to slice from DEFAULTS and mix in with
223
+ # the rest of the attributes.
224
+ #
225
+ # Returns a merged hash for Savon client
226
+ def build_hash_for_savon_call(attributes = {}, options = {})
227
+ user_info = {user_info: {username: config.username, password: config.password}}
228
+ message = user_info.merge attributes
229
+
230
+ if default_keys = options[:include_defaults]
231
+ message = DEFAULTS.slice(*Array.wrap(default_keys)).deep_merge message
232
+ end
233
+
234
+ if order = ORDER[options[:operation_name]]
235
+ unkown_keys = attributes.keys - order
236
+
237
+ if unkown_keys.any?
238
+ fail ArgumentError, "Unkown attributes given to #{options[:operation_name]}: #{unkown_keys.join(', ')}. Attributes' order needs to be configured in #{self.class.name}::ORDER."
239
+ end
240
+
241
+ message[:order!] = order & message.keys
242
+ end
243
+
244
+ {
245
+ message: transform_hash_for_quest_back(message)
246
+ }
247
+ end
248
+
249
+
250
+ # Private: Transforms given hash as how Savon needs it to build the correct SOAP body.
251
+ #
252
+ # Since QuestBack's API needs to have elements like this:
253
+ #
254
+ # <wsdl:TestConnection>
255
+ # <wsdl:userInfo>
256
+ # <wsdl:Username>
257
+ # ...
258
+ #
259
+ # We cannot simply use Savon's convert_request_keys_to config, as it translate all keys.
260
+ # We need some keys camelcased (keys within nested hashes) and some lower_camelcased (keys in the outer most hash).
261
+ #
262
+ # Thus we map our inner attributes, for instance for userInfo to camelcase and keeps them
263
+ # as strings so Savon will not manipulate them.
264
+ #
265
+ # I guess this helper method here is kinda not optimal, and we may have a simple class / struct
266
+ # which can do this job for us, so the api class does not have multiple responsibilites. Oh well,
267
+ # works for now.
268
+ def transform_hash_for_quest_back(hash, transform_keys = false)
269
+ Hash[
270
+ hash.map do |key, value|
271
+ if key == :order!
272
+ # Key was :order! - it has special meaning: The symbols within it's array are used to
273
+ # dictate order of elements. If transform_keys is false we are on "root keys". These are
274
+ # keept as symbols and Savon does it's magic and we'll do nothing. If it is true it means that keys
275
+ # on this level is put to camelcase and the values in the :order! array must match this.
276
+ if transform_keys
277
+ value = value.map { |v| v.to_s.camelcase }
278
+ end
279
+ else
280
+ key = transform_keys ? key.to_s.camelcase : key
281
+
282
+ # Oh my god this is quick, dirty and mega hackish!
283
+ # Type element in the RespondentDataHeader must be in namespace enum.
284
+ key = "enum:Type" if key == "Type"
285
+
286
+ # In some cases we would like to transform values as well as the key
287
+ value = case value
288
+ when Hash
289
+ # Keep on transforming recursively..
290
+ transform_hash_for_quest_back value, true
291
+ when Array
292
+ if value.all? { |v| v.is_a? String }
293
+ # Put it in a structure QuestBack likes..
294
+ {'array:string' => value}
295
+ elsif value.all? { |v| v.is_a? Hash }
296
+ # Keep on transforming recursively..
297
+ value.map { |hash| transform_hash_for_quest_back(hash, true) }
298
+ end
299
+ else
300
+ # We don't know anything better - just let value fall through
301
+ value
302
+ end
303
+ end
304
+
305
+ [key, value]
306
+ end
307
+ ]
308
+ end
309
+ end
310
+ end
@@ -0,0 +1,34 @@
1
+ module QuestBack
2
+ class Configuration
3
+ API_DEFAULTS = {
4
+ wsdl: 'https://integration.questback.com/integration.svc?wsdl',
5
+ soap_namespace: 'https://integration.questback.com/2011/03',
6
+ log_level: :debug
7
+ }
8
+
9
+ attr_accessor :http_proxy, :wsdl, :soap_namespace, :log_level, :username, :password
10
+
11
+ def initialize(attributes = {})
12
+ assign API_DEFAULTS
13
+ assign attributes
14
+ end
15
+
16
+ def []=(name, value)
17
+ public_send "#{name}=", value
18
+ end
19
+
20
+ def [](name)
21
+ public_send name
22
+ end
23
+
24
+
25
+
26
+ private
27
+
28
+ def assign(attributes)
29
+ attributes.each_pair do |name, value|
30
+ self[name] = value
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+ module QuestBack
2
+ # Public: Simple debug observer.
3
+ #
4
+ # Hijacks operations and pretty prints XML which could have been sent.
5
+ class DebugObserver
6
+ def notify(operation_name, builder, globals, locals)
7
+ logger = globals[:logger]
8
+
9
+ logger.info "!!!!!!!!!"
10
+ logger.info "!!! SOAP request hijacked by #{self.class.name}."
11
+ logger.info "!!!!!!!!!"
12
+
13
+ logger.debug "\n\n" + Nokogiri.XML(builder.to_s).to_xml + "\n"
14
+
15
+ HTTPI::Response.new(200, {}, '')
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module QuestBack
2
+ class Error < StandardError
3
+ # Public: Raised when you ask response object for a single result when response contained multiple
4
+ class MultipleResultsFound < self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,45 @@
1
+ module QuestBack
2
+ # Public: Simple proxy object decorating Savon's response.
3
+ #
4
+ # Main motication for class is to have #result and #results as a common
5
+ # interface to get to respons' result(s), with all outer response nesting
6
+ # removed.
7
+ #
8
+ # At the moment you are still getting back simple hashes from both methods.
9
+ class Response
10
+ attr_reader :savon_response, :operation_name, :result_key_nestings
11
+
12
+ delegate *Savon::Response.instance_methods(false), to: :savon_response
13
+
14
+ def initialize(savon_response, options = {})
15
+ @savon_response = savon_response
16
+ @operation_name = options[:operation_name] or fail ArgumentError.new('Missing operation_name')
17
+ @result_key_nestings = options[:result_key_nestings] or fail ArgumentError.new('Missing result key nestings')
18
+ end
19
+
20
+ def result
21
+ extract_result.tap do |result|
22
+ fail QuestBack::Error::MultipleResultsFound if result.is_a? Array
23
+ end
24
+ end
25
+
26
+ def results
27
+ Array.wrap extract_result
28
+ end
29
+
30
+
31
+
32
+
33
+ private
34
+
35
+ def extract_result
36
+ result_container = savon_response.body["#{operation_name}_response".to_sym]["#{operation_name}_result".to_sym]
37
+
38
+ result = result_key_nestings.inject(result_container) do |result, key|
39
+ result.fetch key do
40
+ fail KeyError, "Expected #{result.inspect} to contain #{key_in_body}. Respons' result_key_nestings is wrong, or unexpected result from QuestBack."
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module QuestBack
2
+ VERSION = "0.0.1"
3
+ end
data/lib/quest_back.rb ADDED
@@ -0,0 +1,57 @@
1
+ require "quest_back/version"
2
+
3
+ require "pathname"
4
+ require "active_support/all"
5
+ require "savon"
6
+
7
+
8
+ module QuestBack
9
+ extend ActiveSupport::Autoload
10
+
11
+ autoload :Configuration
12
+ autoload :Error
13
+ autoload :Response
14
+ autoload :Api
15
+ autoload :DebugObserver
16
+
17
+
18
+ # Public: Default configuration is read from here.
19
+ #
20
+ # Returns a Configuration object
21
+ mattr_accessor :default_configuration
22
+
23
+
24
+
25
+
26
+
27
+ # :nodoc:
28
+ #
29
+ # Read config from file, just makes it easy for me to spin up
30
+ # a console, read API credentials and get going
31
+ def self.conf!
32
+ read_default_configuration_from_file 'config.yml'
33
+ end
34
+
35
+ # :nodoc:
36
+ #
37
+ # Injects a debug observer which hijacks requests so we don't send anything.
38
+ # We'll pretty print the SOAP body for inspection.
39
+ def self.debug!
40
+ remove_debug!
41
+ Savon.observers << DebugObserver.new
42
+ end
43
+
44
+ # :nodoc:
45
+ #
46
+ # Removes any debug observers.
47
+ def self.remove_debug!
48
+ Savon.observers.delete_if { |observer| observer.is_a? DebugObserver }
49
+ end
50
+
51
+ # :nodoc:
52
+ def self.read_default_configuration_from_file(pathname)
53
+ path = Pathname.new pathname
54
+ path = Pathname.new [Dir.pwd, pathname].join('/') unless path.absolute?
55
+ self.default_configuration = Configuration.new YAML.load_file(path)
56
+ end
57
+ end