right_cloud_api_base 0.1.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.
- checksums.yaml +7 -0
- data/HISTORY +2 -0
- data/LICENSE +19 -0
- data/README.md +14 -0
- data/Rakefile +37 -0
- data/lib/base/api_manager.rb +707 -0
- data/lib/base/helpers/cloud_api_logger.rb +214 -0
- data/lib/base/helpers/http_headers.rb +239 -0
- data/lib/base/helpers/http_parent.rb +103 -0
- data/lib/base/helpers/http_request.rb +173 -0
- data/lib/base/helpers/http_response.rb +122 -0
- data/lib/base/helpers/net_http_patch.rb +31 -0
- data/lib/base/helpers/query_api_patterns.rb +862 -0
- data/lib/base/helpers/support.rb +270 -0
- data/lib/base/helpers/support.xml.rb +306 -0
- data/lib/base/helpers/utils.rb +380 -0
- data/lib/base/manager.rb +122 -0
- data/lib/base/parsers/json.rb +38 -0
- data/lib/base/parsers/plain.rb +36 -0
- data/lib/base/parsers/rexml.rb +83 -0
- data/lib/base/parsers/sax.rb +200 -0
- data/lib/base/routines/cache_validator.rb +184 -0
- data/lib/base/routines/connection_proxies/net_http_persistent_proxy.rb +194 -0
- data/lib/base/routines/connection_proxies/right_http_connection_proxy.rb +224 -0
- data/lib/base/routines/connection_proxy.rb +66 -0
- data/lib/base/routines/request_analyzer.rb +122 -0
- data/lib/base/routines/request_generator.rb +48 -0
- data/lib/base/routines/request_initializer.rb +52 -0
- data/lib/base/routines/response_analyzer.rb +152 -0
- data/lib/base/routines/response_parser.rb +79 -0
- data/lib/base/routines/result_wrapper.rb +75 -0
- data/lib/base/routines/retry_manager.rb +106 -0
- data/lib/base/routines/routine.rb +98 -0
- data/lib/right_cloud_api_base.rb +72 -0
- data/lib/right_cloud_api_base_version.rb +37 -0
- data/right_cloud_api_base.gemspec +63 -0
- data/spec/helpers/query_api_pattern_spec.rb +312 -0
- data/spec/helpers/support_spec.rb +211 -0
- data/spec/helpers/support_xml_spec.rb +207 -0
- data/spec/helpers/utils_spec.rb +179 -0
- data/spec/routines/connection_proxies/test_net_http_persistent_proxy_spec.rb +143 -0
- data/spec/routines/test_cache_validator_spec.rb +152 -0
- data/spec/routines/test_connection_proxy_spec.rb +44 -0
- data/spec/routines/test_request_analyzer_spec.rb +106 -0
- data/spec/routines/test_response_analyzer_spec.rb +132 -0
- data/spec/routines/test_response_parser_spec.rb +228 -0
- data/spec/routines/test_result_wrapper_spec.rb +63 -0
- data/spec/routines/test_retry_manager_spec.rb +84 -0
- data/spec/spec_helper.rb +15 -0
- metadata +215 -0
@@ -0,0 +1,312 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2013 RightScale, 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 NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
require File.expand_path(File.dirname(__FILE__)) + "/../spec_helper"
|
25
|
+
require "base/helpers/query_api_patterns"
|
26
|
+
|
27
|
+
module RightScale
|
28
|
+
module CloudApi
|
29
|
+
module Test
|
30
|
+
|
31
|
+
class FakeRoutine < Routine
|
32
|
+
def process
|
33
|
+
@data[:result] = @data.dup
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class ApiManager < RightScale::CloudApi::ApiManager
|
38
|
+
include RightScale::CloudApi::Mixin::QueryApiPatterns
|
39
|
+
|
40
|
+
set_routine FakeRoutine
|
41
|
+
|
42
|
+
query_api_pattern :GetService, :get
|
43
|
+
|
44
|
+
query_api_pattern :GetResource, :get, 'resource/1'
|
45
|
+
|
46
|
+
query_api_pattern :GetResourceWithHardcodedData, :get, 'resource/1',
|
47
|
+
:params => { 'p1' => 1, 'p2' => 2 },
|
48
|
+
:headers => { 'x-text-header' => 'my-test-value' },
|
49
|
+
:body => 'MyTestStringBody'
|
50
|
+
|
51
|
+
query_api_pattern :GetResourceWithVars, :get, 'resource/{:ResourceId}',
|
52
|
+
:params => { 'p1' => :Param1, 'p2' => :Param2 },
|
53
|
+
:headers => { 'x-text-header' => :MyHeader },
|
54
|
+
:body => :MyBody
|
55
|
+
|
56
|
+
query_api_pattern :GetResourceWithFlexibleVars, :get,'resource/{:ResourceId}/subresource/{:SubresourceId}',
|
57
|
+
:headers => { 'x-text-header' => "{:MyHeaderSource}/{:MyHeaderKey}" },
|
58
|
+
:body => "text-{:BodyParam1}-text-again-{:BodyParam2}"
|
59
|
+
|
60
|
+
query_api_pattern :GetResourceWithFlexibleVarsAndDefaults, :get,'resource/{:ResourceId}/subresource/{:SubresourceId}',
|
61
|
+
:headers => { 'x-text-header' => "{:MyHeaderSource}/{:MyHeaderKey}" },
|
62
|
+
:body => "text-{:BodyParam1}-text-again-{:BodyParam2}",
|
63
|
+
:defaults => {
|
64
|
+
:BodyParam2 => Utils::NONE,
|
65
|
+
:SubresourceId => 2,
|
66
|
+
:MyHeaderSource => 'something'
|
67
|
+
}
|
68
|
+
|
69
|
+
query_api_pattern :GetResourceWithFlexibleVarsAndDefaultsV2, :get, '',
|
70
|
+
:body => {
|
71
|
+
'Key1' => 'Value1',
|
72
|
+
'Key2' => :Value2,
|
73
|
+
'Key3' => {
|
74
|
+
'Key4' => :Value4
|
75
|
+
}
|
76
|
+
},
|
77
|
+
:defaults => {
|
78
|
+
:Value4 => Utils::NONE,
|
79
|
+
}
|
80
|
+
|
81
|
+
query_api_pattern :GetResourceWithFlexibleVarsAndCollection, :get, '',
|
82
|
+
:body => {
|
83
|
+
'Key1' => :Value1,
|
84
|
+
'Collection[{:Items}]' => {
|
85
|
+
'Name' => :Name,
|
86
|
+
'Value' => :Value
|
87
|
+
},
|
88
|
+
'Collection2[]' => {
|
89
|
+
'Name2' => :Name2,
|
90
|
+
'Value2' => :Value2
|
91
|
+
}
|
92
|
+
},
|
93
|
+
:defaults => {
|
94
|
+
:Value => 13,
|
95
|
+
}
|
96
|
+
|
97
|
+
query_api_pattern :GetResourceWithSubCollectionReplacement, :get, '',
|
98
|
+
:body => {
|
99
|
+
'Key1' => :Value1,
|
100
|
+
'Collections{:Collections}' => {
|
101
|
+
'Collection[{:Items}]' => {
|
102
|
+
'Name' => :Name,
|
103
|
+
'Value' => :Value
|
104
|
+
}
|
105
|
+
}
|
106
|
+
},
|
107
|
+
:defaults => {
|
108
|
+
:Value => 13
|
109
|
+
}
|
110
|
+
|
111
|
+
query_api_pattern :GetResourceWithSubCollectionReplacementAndDefaults, :get, '',
|
112
|
+
:body => {
|
113
|
+
'Key1' => :Value1,
|
114
|
+
'Collections{:Collections}' => {
|
115
|
+
'Collection[{:Items}]' => {
|
116
|
+
'Name' => :Name,
|
117
|
+
'Value' => :Value
|
118
|
+
}
|
119
|
+
}
|
120
|
+
},
|
121
|
+
:defaults => {
|
122
|
+
:Value => 13,
|
123
|
+
:Collections => Utils::NONE
|
124
|
+
}
|
125
|
+
|
126
|
+
query_api_pattern(:GetResourceWithBlock, :get, 'resource/1') do |result|
|
127
|
+
result[:path] = 'my-new-path'
|
128
|
+
result[:verb] = :post
|
129
|
+
result[:params] = {'p1' => 'v1'}
|
130
|
+
result[:headers] = {'x-my-header' => 'value'}
|
131
|
+
result[:body] = 'MyBody'
|
132
|
+
end
|
133
|
+
|
134
|
+
query_api_pattern :GetResourceWithProc, :get, 'resource/1',
|
135
|
+
:after => Proc.new { |result| result[:path] = 'my-new-path'
|
136
|
+
result[:verb] = :post
|
137
|
+
result[:params] = {'p1' => 'v1'}
|
138
|
+
result[:headers] = {'x-my-header' => 'value'}
|
139
|
+
result[:body] = 'MyBody' }
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "QueryApiPattern" do
|
147
|
+
before(:each) do
|
148
|
+
unless @initialized
|
149
|
+
logger = Logger.new(STDOUT)
|
150
|
+
logger.level = Logger::INFO
|
151
|
+
@api_manager = RightScale::CloudApi::Test::ApiManager.new({'x' => 'y'},'endpoint', {:logger => logger})
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "query_api_pattern" do
|
156
|
+
it "fails when there is an unexpected parameter" do
|
157
|
+
expect {
|
158
|
+
@api_manager.class.query_api_pattern(:GetService, :get, '', :unknown_something => 'blah-blah')
|
159
|
+
}.to raise_error(RightScale::CloudApi::Error)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it "works when there are no issues and generates request data properly" do
|
164
|
+
data = @api_manager.GetService
|
165
|
+
request = data[:request]
|
166
|
+
expect(request[:verb]).to eq(:get)
|
167
|
+
expect(request[:relative_path]._blank?).to be(true)
|
168
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
169
|
+
expect(request[:params]._blank?).to be(true)
|
170
|
+
expect(request[:body].nil?).to be(true)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "moves all unused variables into URL params" do
|
174
|
+
data = @api_manager.GetService('Param1' => 'value1', 'Param2' => 'value2')
|
175
|
+
request = data[:request]
|
176
|
+
expect(request[:verb]).to eq(:get)
|
177
|
+
expect(request[:relative_path]._blank?).to be(true)
|
178
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
179
|
+
expect(request[:params]).to eq('Param1' => 'value1', 'Param2' => 'value2')
|
180
|
+
expect(request[:body]).to be(nil)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "works for GetResource Query API definition" do
|
184
|
+
data = @api_manager.GetResource
|
185
|
+
request = data[:request]
|
186
|
+
expect(request[:verb]).to eq :get
|
187
|
+
expect(request[:relative_path]).to eq 'resource/1'
|
188
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
189
|
+
expect(request[:params]._blank?).to be(true)
|
190
|
+
expect(request[:body]).to be(nil)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "works for GetResourceWithHardcodedData Query API definition" do
|
194
|
+
data = @api_manager.GetResourceWithHardcodedData
|
195
|
+
request = data[:request]
|
196
|
+
expect(request[:verb]).to eq :get
|
197
|
+
expect(request[:relative_path]).to eq 'resource/1'
|
198
|
+
expect(request[:headers].to_hash).to eq('x-text-header' => ['my-test-value'])
|
199
|
+
expect(request[:params]).to eq('p1' => 1, 'p2' => 2 )
|
200
|
+
expect(request[:body]).to eq 'MyTestStringBody'
|
201
|
+
end
|
202
|
+
|
203
|
+
it "works for GetResourceWithVars Query API definition" do
|
204
|
+
data = @api_manager.GetResourceWithVars( 'ResourceId' => 123, 'Param1' => 11, 'Param2' => 12, 'MyHeader' => 'x-test-something', 'MyBody' => 'MyTestStringBody')
|
205
|
+
request = data[:request]
|
206
|
+
expect(request[:verb]).to eq :get
|
207
|
+
expect(request[:relative_path]).to eq 'resource/123'
|
208
|
+
expect(request[:headers].to_hash).to eq('x-text-header' => ['x-test-something'])
|
209
|
+
expect(request[:params]).to eq( 'p1' => 11, 'p2' => 12 )
|
210
|
+
expect(request[:body]).to eq 'MyTestStringBody'
|
211
|
+
end
|
212
|
+
|
213
|
+
it "fails when a mandatory variable is missing" do
|
214
|
+
expect{ @api_manager.GetResourceWithVars }.to raise_error(RightScale::CloudApi::Error)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "works for GetResourceWithFlexibleVars Query API definition" do
|
218
|
+
data = @api_manager.GetResourceWithFlexibleVars( 'ResourceId' => 1, 'SubresourceId' => 2, 'MyHeaderSource' => 3, 'MyHeaderKey' => 4, 'BodyParam1' => 5, 'BodyParam2' => 6)
|
219
|
+
request = data[:request]
|
220
|
+
expect(request[:verb]).to eq :get
|
221
|
+
expect(request[:relative_path]).to eq 'resource/1/subresource/2'
|
222
|
+
expect(request[:headers].to_hash).to eq('x-text-header' => ['3/4'])
|
223
|
+
expect(request[:body]).to eq 'text-5-text-again-6'
|
224
|
+
end
|
225
|
+
|
226
|
+
it "works for GetResourceWithFlexibleVarsAndDefaults Query API definition" do
|
227
|
+
data = @api_manager.GetResourceWithFlexibleVarsAndDefaults('ResourceId' => 1, 'MyHeaderKey' => 3, 'BodyParam1' => 5)
|
228
|
+
request = data[:request]
|
229
|
+
expect(request[:verb]).to eq :get
|
230
|
+
expect(request[:relative_path]).to eq 'resource/1/subresource/2'
|
231
|
+
expect(request[:headers].to_hash).to eq('x-text-header' => ['something/3'])
|
232
|
+
expect(request[:body]).to eq 'text-5-text-again-'
|
233
|
+
end
|
234
|
+
|
235
|
+
it "works for GetResourceWithFlexibleVarsAndDefaultsV2 Query API definition" do
|
236
|
+
data = @api_manager.GetResourceWithFlexibleVarsAndDefaultsV2('Value2' => 1)
|
237
|
+
request = data[:request]
|
238
|
+
expect(request[:verb]).to eq :get
|
239
|
+
expect(request[:relative_path]._blank?).to be(true)
|
240
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
241
|
+
expect(request[:params]._blank?).to be(true)
|
242
|
+
expect(request[:body]).to eq('Key1' => 'Value1', 'Key2' => 1, 'Key3' => {})
|
243
|
+
end
|
244
|
+
|
245
|
+
it "works for GetResourceWithFlexibleVarsAndCollection Query API definition" do
|
246
|
+
data = @api_manager.GetResourceWithFlexibleVarsAndCollection('Value1' => 1,
|
247
|
+
'Items' => [{'Name' => 'x1', 'Value' => 'xv1'}, {'Name' => 'x2'}],
|
248
|
+
'Collection2' => [{'Name2' => 'x21', 'Value2' => 'xv21'}, {'Name2' => 'x22', 'Value2' => 'v22'}]
|
249
|
+
)
|
250
|
+
request = data[:request]
|
251
|
+
expect(request[:verb]).to eq :get
|
252
|
+
expect(request[:relative_path]._blank?).to be(true)
|
253
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
254
|
+
expect(request[:params]._blank?).to be(true)
|
255
|
+
expect(request[:body]).to eq('Key1' => 1,
|
256
|
+
'Collection' => [{'Name' => 'x1', 'Value' => 'xv1'}, {'Name' => 'x2', 'Value' => 13}],
|
257
|
+
'Collection2' => [{'Name2' => 'x21', 'Value2' => 'xv21'}, {'Name2' => 'x22', 'Value2' => 'v22'}])
|
258
|
+
end
|
259
|
+
|
260
|
+
it "works for GetResourceWithSubCollectionReplacement Query API definition" do
|
261
|
+
# Nothing is pased - should complain
|
262
|
+
expect {
|
263
|
+
@api_manager.GetResourceWithSubCollectionReplacement('Value1' => 1)
|
264
|
+
}.to raise_error(RightScale::CloudApi::Error)
|
265
|
+
# A replacement is passed - must replace
|
266
|
+
data = @api_manager.GetResourceWithSubCollectionReplacement('Value1' => 1, 'Collections' => 'blah-blah')
|
267
|
+
request = data[:request]
|
268
|
+
expect(request[:verb]).to eq :get
|
269
|
+
expect(request[:relative_path]._blank?).to be(true)
|
270
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
271
|
+
expect(request[:params]._blank?).to be(true)
|
272
|
+
expect(request[:body]).to eq('Key1' => 1, 'Collections' => 'blah-blah')
|
273
|
+
|
274
|
+
data = @api_manager.GetResourceWithSubCollectionReplacement('Value1' => 1, 'Items' => [{'Name' => 'x1', 'Value' => 'xv1'}, {'Name' => 'x2'}])
|
275
|
+
request = data[:request]
|
276
|
+
expect(request[:verb]).to eq :get
|
277
|
+
expect(request[:relative_path]._blank?).to be(true)
|
278
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
279
|
+
expect(request[:params]._blank?).to be(true)
|
280
|
+
expect(request[:body]).to eq('Key1' => 1, 'Collections' => {'Collection' => [{'Name' => 'x1', 'Value' => 'xv1'}, {'Name' => 'x2', 'Value' => 13}]})
|
281
|
+
end
|
282
|
+
|
283
|
+
it "works for GetResourceWithSubCollectionReplacementAndDefaults Query API definition" do
|
284
|
+
data = @api_manager.GetResourceWithSubCollectionReplacementAndDefaults('Value1' => 1)
|
285
|
+
request = data[:request]
|
286
|
+
expect(request[:verb]).to eq :get
|
287
|
+
expect(request[:relative_path]._blank?).to be(true)
|
288
|
+
expect(request[:headers].to_hash._blank?).to be(true)
|
289
|
+
expect(request[:params]._blank?).to be(true)
|
290
|
+
expect(request[:body]).to eq('Key1' => 1 )
|
291
|
+
end
|
292
|
+
|
293
|
+
it "works for GetResourceWithBlock Query API definition" do
|
294
|
+
data = @api_manager.GetResourceWithBlock
|
295
|
+
request = data[:request]
|
296
|
+
expect(request[:verb]).to eq :post
|
297
|
+
expect(request[:relative_path]).to eq 'my-new-path'
|
298
|
+
expect(request[:headers].to_hash).to eq('x-my-header' => ['value'])
|
299
|
+
expect(request[:params]).to eq( 'p1' => 'v1')
|
300
|
+
expect(request[:body]).to eq 'MyBody'
|
301
|
+
end
|
302
|
+
|
303
|
+
it "works for GetResourceWithProc Query API definition" do
|
304
|
+
data = @api_manager.GetResourceWithProc
|
305
|
+
request = data[:request]
|
306
|
+
expect(request[:verb]).to eq :post
|
307
|
+
expect(request[:relative_path]).to eq 'my-new-path'
|
308
|
+
expect(request[:headers].to_hash).to eq('x-my-header' => ['value'])
|
309
|
+
expect(request[:params]).to eq( 'p1' => 'v1')
|
310
|
+
expect(request[:body]).to eq 'MyBody'
|
311
|
+
end
|
312
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2013 RightScale, 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 NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
require File.expand_path(File.dirname(__FILE__)) + "/../spec_helper"
|
25
|
+
|
26
|
+
describe "support.rb" do
|
27
|
+
|
28
|
+
# --- String ---
|
29
|
+
|
30
|
+
context "String#_constantize" do
|
31
|
+
it "constantizes when a string points to an existing class/module name" do
|
32
|
+
class MyCoolTestConstantizeClass; end
|
33
|
+
expect('MyCoolTestConstantizeClass'._constantize).to be MyCoolTestConstantizeClass
|
34
|
+
end
|
35
|
+
it "fails when a string points to a non-existing class/module name" do
|
36
|
+
expect {
|
37
|
+
'MyBadTestConstantizeClass'._constantize
|
38
|
+
}.to raise_error(::NameError)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "String#_camelize" do
|
43
|
+
it "camelizes a string" do
|
44
|
+
expect('my_test_string'._camelize).to eq'MyTestString'
|
45
|
+
expect('MyTestString'._camelize).to eq 'MyTestString'
|
46
|
+
expect('my_test_string'._camelize(:lower_case)).to eq 'myTestString'
|
47
|
+
expect('MyTestString'._camelize(:lower_case)).to eq 'myTestString'
|
48
|
+
expect('Privet, how are you_doing, los_Amigos?'._camelize).to eq 'Privet, How Are YouDoing, LosAmigos?'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "String#_snake_case" do
|
53
|
+
it "underscorizes a string" do
|
54
|
+
expect('MyTestString'._snake_case).to eq 'my_test_string'
|
55
|
+
expect('my_test_string'._snake_case).to eq 'my_test_string'
|
56
|
+
expect('Privet, How Are YouDoing, LosAmigos?'._snake_case).to eq 'privet, how are you_doing, los_amigos?'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "String#_arrayify" do
|
61
|
+
it "arrayifies into array" do
|
62
|
+
expect(''._arrayify).to eq ['']
|
63
|
+
expect('something'._arrayify).to eq ['something']
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "String#_blank?" do
|
68
|
+
it "returns true when it has zero size" do
|
69
|
+
expect(''._blank?).to be true
|
70
|
+
end
|
71
|
+
it "returns true when it contains spaces only" do
|
72
|
+
expect(" \n\n\n "._blank?).to be true
|
73
|
+
end
|
74
|
+
it "returns false when it has anything valueble" do
|
75
|
+
expect("something"._blank?).to be false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# --- Object ---
|
80
|
+
|
81
|
+
context "Object#_blank?" do
|
82
|
+
it "checks if an object responds blank?" do
|
83
|
+
object = Object.new
|
84
|
+
expect(object).to receive(:blank?).once.and_return(true)
|
85
|
+
expect(object).to receive(:respond_to?).with(:blank?).once.and_return(true)
|
86
|
+
expect(object._blank?).to be true
|
87
|
+
end
|
88
|
+
it "checks if an object responds empty? unles it responds to blank?" do
|
89
|
+
object = Object.new
|
90
|
+
expect(object).to receive(:empty?).once.and_return(true)
|
91
|
+
expect(object).to receive(:respond_to?).with(:blank?).once.and_return(false)
|
92
|
+
expect(object).to receive(:respond_to?).with(:empty?).once.and_return(true)
|
93
|
+
expect(object._blank?).to be true
|
94
|
+
end
|
95
|
+
it "returns !self unless it responds to blank? and empty?" do
|
96
|
+
object = Object.new
|
97
|
+
expect(object).to receive(:respond_to?).with(:blank?).once.and_return(false)
|
98
|
+
expect(object).to receive(:respond_to?).with(:empty?).once.and_return(false)
|
99
|
+
expect(object._blank?).to eq !object
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "Object#_arrayify" do
|
104
|
+
it "feeds self to Array()" do
|
105
|
+
[nil, 1, :symbol].each do |object|
|
106
|
+
expect(object._arrayify).to eq Array(object)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# --- NilClass ---
|
112
|
+
|
113
|
+
context "NilClass" do
|
114
|
+
it "always return true" do
|
115
|
+
expect(nil._blank?).to be true
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# --- FalseClass ---
|
120
|
+
|
121
|
+
context "FalseClass" do
|
122
|
+
it "always return true" do
|
123
|
+
expect(false._blank?).to be true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# --- TrueClass ---
|
128
|
+
|
129
|
+
context "FalseClass" do
|
130
|
+
it "always return false" do
|
131
|
+
expect(true._blank?).to be false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# --- Array ---
|
136
|
+
|
137
|
+
context "Array#_blank?" do
|
138
|
+
it "behaves accordingly to array's emptyness status" do
|
139
|
+
expect([]._blank?).to be true
|
140
|
+
expect([1]._blank?).to be false
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "Array#_stringify_keys" do
|
145
|
+
it "stringifies all the keys for all its hash items" do
|
146
|
+
expect([[{:x=>{:y=>[:z => 13]}}]]._stringify_keys).to eq [[{"x"=>{"y"=>[{"z"=>13}]}}]]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context "Array#_stringify_keys" do
|
151
|
+
it "symbolizes all the keys for all its hash items" do
|
152
|
+
expect([[{"x"=>{"y"=>[{"z"=>13}]}}]]._symbolize_keys).to eq [[{:x=>{:y=>[:z => 13]}}]]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# --- Hash ---
|
157
|
+
|
158
|
+
context "Hash#_blank?" do
|
159
|
+
it "behaves accordingly to hash's emptyness status" do
|
160
|
+
expect({}._blank?).to be true
|
161
|
+
expect({:foo => :bar}._blank?).to be false
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context "Hash#_stringify_keys" do
|
166
|
+
it "stringifies all the keys" do
|
167
|
+
expect({"1"=>2, :x=>[[{:y=>{:z=>13}}], 2]}._stringify_keys).to eq("1"=>2, "x"=>[[{"y"=>{"z"=>13}}], 2])
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "Hash#_symbolize_keys" do
|
172
|
+
it "symbolizes all keys" do
|
173
|
+
expect({"1"=>2, "x"=>[[{"y"=>{"z"=>13}}], 2]}._symbolize_keys).to eq(:"1"=>2, :x=>[[{:y=>{:z=>13}}], 2])
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context "Hash#_at" do
|
178
|
+
it "fails if the given path does not not exist" do
|
179
|
+
expect { {}._at('x','y') }.to raise_error(StandardError)
|
180
|
+
end
|
181
|
+
it "does not fail if the given path does not exist but a default value is provided" do
|
182
|
+
expect({}._at('x', :default => 'defval')).to eq 'defval'
|
183
|
+
end
|
184
|
+
it "calls a block if the given path does not exist and a default value is not provided" do
|
185
|
+
expect({}._at('x'){ 'defval' }).to eq 'defval'
|
186
|
+
expect{ {}._at('x'){ fail "NotFound.MyCoolError" }}.to raise_error(RuntimeError, "NotFound.MyCoolError")
|
187
|
+
end
|
188
|
+
it "returns the requested value by the given path when the path exists" do
|
189
|
+
expect({'x' => nil}._at('x')).to be nil
|
190
|
+
expect({'x' => 4}._at('x')).to eq 4
|
191
|
+
expect({'x' => { 'y' => { 'z' => 'value'} }}._at('x', 'y', 'z')).to eq 'value'
|
192
|
+
end
|
193
|
+
it "arrayifies the result when :arrayify => true option is set" do
|
194
|
+
expect({'x' => { 'y' => { 'z' => 'value'} }}._at('x', 'y', 'z', :arrayify => true)).to eq ['value']
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context "Hash#_arrayify_at" do
|
199
|
+
it "extracts a value by the given path and arrayifies it" do
|
200
|
+
expect({'x' => { 'y' => 'z' }}._arrayify_at('x', 'y')).to eq ['z']
|
201
|
+
expect({'x' => { 'y' => ['z'] }}._arrayify_at('x', 'y')).to eq ['z']
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "Hash#_arrayify" do
|
206
|
+
it "wraps self into array" do
|
207
|
+
hash = { 1 => 2}
|
208
|
+
expect(hash._arrayify).to eq [hash]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|