right_cloud_api_base 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|