quest_back 0.0.1

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: 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