right_support 2.6.17 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +4 -0
- data/CHANGELOG.rdoc +37 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +111 -0
- data/README.rdoc +2 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/features/balancer_error_handling.feature +34 -0
- data/features/balancer_health_check.feature +33 -0
- data/features/continuous_integration.feature +51 -0
- data/features/continuous_integration_cucumber.feature +28 -0
- data/features/continuous_integration_rspec1.feature +28 -0
- data/features/continuous_integration_rspec2.feature +28 -0
- data/features/http_client_timeout.feature +19 -0
- data/features/serialization.feature +95 -0
- data/features/step_definitions/http_client_steps.rb +27 -0
- data/features/step_definitions/request_balancer_steps.rb +93 -0
- data/features/step_definitions/ruby_steps.rb +176 -0
- data/features/step_definitions/serialization_steps.rb +96 -0
- data/features/step_definitions/server_steps.rb +134 -0
- data/features/support/env.rb +138 -0
- data/features/support/file_utils_bundler_mixin.rb +45 -0
- data/lib/right_support/ci/java_cucumber_formatter.rb +22 -8
- data/lib/right_support/ci/java_spec_formatter.rb +26 -8
- data/lib/right_support/ci/rake_task.rb +3 -0
- data/lib/right_support/ci.rb +24 -0
- data/lib/right_support/crypto/signed_hash.rb +22 -0
- data/lib/right_support/data/serializer.rb +24 -2
- data/lib/right_support/net/address_helper.rb +20 -8
- data/lib/right_support/net/dns.rb +20 -8
- data/lib/right_support/net/http_client.rb +22 -0
- data/lib/right_support/net/request_balancer.rb +27 -21
- data/lib/right_support/net/s3_helper.rb +20 -8
- data/lib/right_support/net/ssl/open_ssl_patch.rb +22 -0
- data/lib/right_support/net/ssl.rb +20 -8
- data/lib/right_support/ruby/easy_singleton.rb +22 -0
- data/lib/right_support/ruby/object_extensions.rb +22 -0
- data/lib/right_support/ruby/string_extensions.rb +1 -1
- data/lib/right_support.rb +13 -10
- data/right_support.gemspec +180 -18
- data/right_support.rconf +8 -0
- data/spec/config/feature_set_spec.rb +83 -0
- data/spec/crypto/signed_hash_spec.rb +60 -0
- data/spec/data/hash_tools_spec.rb +471 -0
- data/spec/data/uuid_spec.rb +45 -0
- data/spec/db/cassandra_model_part1_spec.rb +84 -0
- data/spec/db/cassandra_model_part2_spec.rb +73 -0
- data/spec/db/cassandra_model_spec.rb +359 -0
- data/spec/fixtures/encrypted_priv_rsa.pem +30 -0
- data/spec/fixtures/good_priv_dsa.pem +12 -0
- data/spec/fixtures/good_priv_rsa.pem +15 -0
- data/spec/fixtures/good_pub_dsa.ssh +1 -0
- data/spec/fixtures/good_pub_rsa.pem +5 -0
- data/spec/fixtures/good_pub_rsa.ssh +1 -0
- data/spec/log/exception_logger_spec.rb +76 -0
- data/spec/log/filter_logger_spec.rb +8 -0
- data/spec/log/mixin_spec.rb +62 -0
- data/spec/log/multiplexer_spec.rb +54 -0
- data/spec/log/null_logger_spec.rb +36 -0
- data/spec/log/system_logger_spec.rb +92 -0
- data/spec/net/address_helper_spec.rb +57 -0
- data/spec/net/balancing/health_check_spec.rb +382 -0
- data/spec/net/balancing/round_robin_spec.rb +15 -0
- data/spec/net/balancing/sticky_policy_spec.rb +92 -0
- data/spec/net/dns_spec.rb +152 -0
- data/spec/net/http_client_spec.rb +171 -0
- data/spec/net/request_balancer_spec.rb +579 -0
- data/spec/net/s3_helper_spec.rb +160 -0
- data/spec/net/ssl_spec.rb +42 -0
- data/spec/net/string_encoder_spec.rb +58 -0
- data/spec/rack/log_setter_spec.rb +5 -0
- data/spec/rack/request_logger_spec.rb +68 -0
- data/spec/rack/request_tracker_spec.rb +5 -0
- data/spec/ruby/easy_singleton_spec.rb +72 -0
- data/spec/ruby/object_extensions_spec.rb +27 -0
- data/spec/ruby/string_extensions_spec.rb +98 -0
- data/spec/spec_helper.rb +181 -0
- data/spec/stats/activity_spec.rb +193 -0
- data/spec/stats/exceptions_spec.rb +123 -0
- data/spec/stats/helpers_spec.rb +603 -0
- data/spec/validation/openssl_spec.rb +37 -0
- data/spec/validation/ssh_spec.rb +39 -0
- metadata +218 -19
@@ -0,0 +1,160 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe RightSupport::Net::S3Helper do
|
4
|
+
|
5
|
+
def digest
|
6
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, passphrase, @valid_params[:data])
|
7
|
+
end
|
8
|
+
|
9
|
+
def ciphertext
|
10
|
+
"\203\346\271\273\323\377r\246\002\204\231\374h\327!\323"
|
11
|
+
end
|
12
|
+
|
13
|
+
def passphrase
|
14
|
+
"#{@valid_params[:key]}:key"
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
@valid_params = { :key => "foo", :data => "bar" }
|
19
|
+
|
20
|
+
# Mock right_aws config & objects with reasonable default behavior
|
21
|
+
@s3_config = {'creds' =>
|
22
|
+
{'aws_access_key_id' => 'knock_knock',
|
23
|
+
'aws_secret_access_key' => 'open_sesame'},
|
24
|
+
'bucket_name' => 'my_own_personal_bucket',
|
25
|
+
'master_secret' => 'if i told you i would have to kill you'}
|
26
|
+
@s3_class = flexmock("s3")
|
27
|
+
@s3_object = flexmock("s3_object")
|
28
|
+
@s3_bucket = flexmock("s3_bucket")
|
29
|
+
@s3_class.should_receive(:new).with(String, String, Hash).and_return(@s3_object)
|
30
|
+
@s3_object.should_receive(:bucket).with('my_own_personal_bucket').and_return(@s3_bucket).by_default
|
31
|
+
@s3_bucket.should_receive(:key).and_return(@s3_object).by_default
|
32
|
+
@s3_bucket.should_receive(:put).with(String, String, Hash).and_return(true).by_default
|
33
|
+
|
34
|
+
@s3_object.should_receive(:meta_headers).and_return({"digest" => digest})
|
35
|
+
@s3_object.should_receive(:data).and_return(ciphertext)
|
36
|
+
|
37
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:s3_enabled?).and_return(:true)
|
38
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:master_secret).and_return('key')
|
39
|
+
|
40
|
+
@encrypt = flexmock("encrypt")
|
41
|
+
@encrypt.should_receive(:encrypt).with(String, String, Hash).and_return(ciphertext)
|
42
|
+
@encrypt.should_receive(:encrypt).with(Hash).and_return(ciphertext)
|
43
|
+
@encrypt.should_receive(:decrypt).with(Hash).and_return(@valid_params[:data])
|
44
|
+
end
|
45
|
+
|
46
|
+
context :init do
|
47
|
+
context "when all params are valid" do
|
48
|
+
it "succeeds" do
|
49
|
+
RightSupport::Net::S3Helper.init(@s3_config, @s3_class, @encrypt).should be_true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when bucket does not exist" do
|
54
|
+
before(:each) do
|
55
|
+
@bad_s3_config = @s3_config.clone
|
56
|
+
@bad_s3_config['bucket_name'] = "supercallifragilisticexpialidocious"
|
57
|
+
@s3_object.should_receive(:bucket).with("supercallifragilisticexpialidocious").and_return(nil)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "raises BucketNotFound" do
|
61
|
+
lambda {
|
62
|
+
RightSupport::Net::S3Helper.init(@bad_s3_config, @s3_class, @encrypt)
|
63
|
+
}.should raise_error(RightSupport::Net::S3Helper::BucketNotFound)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context :get do
|
69
|
+
before(:each) do
|
70
|
+
RightSupport::Net::S3Helper.init(@s3_config, @s3_class, @encrypt)
|
71
|
+
end
|
72
|
+
|
73
|
+
context "with valid params" do
|
74
|
+
it 'returns plaintext' do
|
75
|
+
RightSupport::Net::S3Helper.get(@valid_params[:key]).should be_eql(@valid_params[:data])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context :post do
|
81
|
+
before(:each) do
|
82
|
+
RightSupport::Net::S3Helper.init(@s3_config, @s3_class, @encrypt)
|
83
|
+
end
|
84
|
+
|
85
|
+
context "with valid params" do
|
86
|
+
it 'encrypts and saves data' do
|
87
|
+
@s3_bucket.should_receive(:put).with(@valid_params[:key], ciphertext, {"digest" => digest}).and_return(true)
|
88
|
+
RightSupport::Net::S3Helper.post(@valid_params[:key], @valid_params[:data]).should be_true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context :health_check do
|
94
|
+
before(:each) do
|
95
|
+
RightSupport::Net::S3Helper.init(@s3_config, @s3_class, @encrypt)
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'with invalid configuration' do
|
99
|
+
before :each do
|
100
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:config).and_return({'creds' => {'aws_access_key_id' => '@@AWS_ACCESS_KEY_ID@@', 'aws_secret_access_key' => '@@AWS_SECRET_ACCESS_KEY@@'}, 'bucket_name' => '@@s3_bucket_NAME@@', 'master_secret' => '@@MASTER_SECRET@@'})
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'return error' do
|
104
|
+
RightSupport::Net::S3Helper.health_check.class.should == String
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'with valid configuration but invalid s3 connection credentials' do
|
109
|
+
before :each do
|
110
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:config).and_return({'creds' => {'aws_access_key_id' => 'AWS_ACCESS_KEY_ID', 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'}, 'bucket_name' => 'BUCKET_NAME', 'master_secret' => 'MASTER_SECRET'})
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'returns error ' do
|
114
|
+
RightSupport::Net::S3Helper.health_check.class.should == String
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'with valid configuration and s3 connection' do
|
119
|
+
before :each do
|
120
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:config).and_return({'creds' => {'aws_access_key_id' => 'dsfgdsfgdsfgdsfg', 'aws_secret_access_key' => 'sdghdhsdg'}, 'bucket_name' => 'dshdshdfgh', 'master_secret' => 'dshdshg'})
|
121
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:post).with('ping', 'heath check').and_return(true)
|
122
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:get).with('ping').and_return('heath check')
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'returns ok' do
|
126
|
+
RightSupport::Net::S3Helper.health_check.should == true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'test/development environment' do
|
132
|
+
|
133
|
+
before :each do
|
134
|
+
@key1 = 'aws_access_key_id'
|
135
|
+
@key2 = 'aws_secret_access_key'
|
136
|
+
@opt_with_no_subdomains = {:no_subdomains => true}
|
137
|
+
@opt_without_subdoamins = {}
|
138
|
+
@config = {}
|
139
|
+
@config["creds"] = {}
|
140
|
+
@config["creds"]["aws_access_key_id"] = @key1
|
141
|
+
@config["creds"]["aws_secret_access_key"] = @key2
|
142
|
+
@s3_class = flexmock('Rightscale::S3')
|
143
|
+
flexmock(RightSupport::Net::S3Helper).should_receive(:bucket).and_return(true)
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'works ok with :no_subdomains' do
|
147
|
+
@s3_class.should_receive(:new).with(@key1, @key2, @opt_with_no_subdomains)
|
148
|
+
RightSupport::Net::S3Helper.init(@config, @s3_class, @s3_class, :no_subdomains => true)
|
149
|
+
RightSupport::Net::S3Helper.s3
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'works ok without subdomains' do
|
153
|
+
@s3_class.should_receive(:new).with(@key1, @key2, @opt_without_subdoamins)
|
154
|
+
RightSupport::Net::S3Helper.init(@config, @s3_class, @s3_class)
|
155
|
+
RightSupport::Net::S3Helper.s3
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightSupport::Net::SSL do
|
4
|
+
PATCH = RightSupport::Net::SSL::OpenSSLPatch
|
5
|
+
|
6
|
+
context :with_expected_hostname do
|
7
|
+
before(:all) do
|
8
|
+
PATCH.enable!
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'works' do
|
12
|
+
OpenSSL::SSL.should respond_to(:verify_certificate_identity_without_hack)
|
13
|
+
PATCH.enabled?.should be_true
|
14
|
+
|
15
|
+
cert = flexmock('SSL certificate')
|
16
|
+
|
17
|
+
flexmock(OpenSSL::SSL).
|
18
|
+
should_receive(:verify_certificate_identity_without_hack).
|
19
|
+
with(cert, 'reposeX.rightscale.com').and_return(true)
|
20
|
+
RightSupport::Net::SSL.with_expected_hostname('reposeX.rightscale.com') do
|
21
|
+
OpenSSL::SSL.verify_certificate_identity(cert, '1.2.3.4').should be_true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with disabled monkey-patch' do
|
26
|
+
before(:all) do
|
27
|
+
PATCH.disable!
|
28
|
+
end
|
29
|
+
it 'does not work' do
|
30
|
+
PATCH.enabled?.should be_false
|
31
|
+
cert = flexmock('SSL certificate')
|
32
|
+
flexmock(OpenSSL::SSL).
|
33
|
+
should_receive(:verify_certificate_identity_without_hack).
|
34
|
+
with(cert, '1.2.3.4').and_return(false)
|
35
|
+
|
36
|
+
RightSupport::Net::SSL.with_expected_hostname('reposeX.rightscale.com') do
|
37
|
+
OpenSSL::SSL.verify_certificate_identity(cert, '1.2.3.4').should be_false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
describe RightSupport::Net::StringEncoder do
|
5
|
+
#Alias for brevity's sake
|
6
|
+
ENCODINGS = RightSupport::Net::StringEncoder::ENCODINGS
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
#Generate some random binary test vectors with varying
|
10
|
+
#lengths, 2-1024 bytes
|
11
|
+
@strings = []
|
12
|
+
(1..10).each do |i|
|
13
|
+
s = ''
|
14
|
+
i.times { s << rand(256) }
|
15
|
+
|
16
|
+
if RUBY_VERSION >= '1.9'
|
17
|
+
@strings << s.force_encoding(Encoding::ASCII_8BIT)
|
18
|
+
else
|
19
|
+
@strings << s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context :initialize do
|
25
|
+
it 'accepts a glob of encodings' do
|
26
|
+
obj = RightSupport::Net::StringEncoder.new(:base64, :url)
|
27
|
+
obj.decode(obj.encode('moo')).should == 'moo'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'accepts an Array of encodings' do
|
31
|
+
obj = RightSupport::Net::StringEncoder.new([:base64, :url])
|
32
|
+
obj.decode(obj.encode('moo')).should == 'moo'
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when unknown encodings are specified' do
|
36
|
+
it 'raises ArgumentError' do
|
37
|
+
lambda do
|
38
|
+
RightSupport::Net::StringEncoder.new(:xyzzy, :foobar)
|
39
|
+
end.should raise_error(ArgumentError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#Ensure that encodings are symmetrical and commutative by testing round-trip
|
45
|
+
#for all combinations.
|
46
|
+
(1..ENCODINGS.length).each do |n|
|
47
|
+
context "when using any #{n} encoding#{n > 1 ? 's' : ''}" do
|
48
|
+
ENCODINGS.combination(n).each do |list|
|
49
|
+
it "round-trips #{list.join(', ')}" do
|
50
|
+
obj = RightSupport::Net::StringEncoder.new(*list)
|
51
|
+
@strings.each do |str|
|
52
|
+
obj.decode(obj.encode(str)).should == str
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightSupport::Rack::RequestLogger do
|
4
|
+
class OhNoes < Exception; end
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@app = flexmock('Rack app')
|
8
|
+
@app.should_receive(:call).and_return([200, {}, 'body']).by_default
|
9
|
+
@logger = mock_logger
|
10
|
+
@env = {'rack.logger' => @logger}
|
11
|
+
@middleware = RightSupport::Rack::RequestLogger.new(@app)
|
12
|
+
end
|
13
|
+
|
14
|
+
context :initialize do
|
15
|
+
context 'without :logger option' do
|
16
|
+
it 'uses rack.logger' do
|
17
|
+
@logger.should_receive(:info)
|
18
|
+
@middleware.call(@env).should == [200, {}, 'body']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context :call do
|
24
|
+
context 'when the app raises an exception' do
|
25
|
+
before(:each) do
|
26
|
+
@app.should_receive(:call).and_raise(OhNoes)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'logs the exception' do
|
30
|
+
@logger.should_receive(:error)
|
31
|
+
lambda {
|
32
|
+
@middleware.call({})
|
33
|
+
}.should raise_error
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when Sinatra stores an exception' do
|
38
|
+
before(:each) do
|
39
|
+
@app.should_receive(:call).and_return([500, {}, 'body'])
|
40
|
+
@env['sinatra.error'] = OhNoes.new
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'logs the exception' do
|
44
|
+
@logger.should_receive(:info)
|
45
|
+
@logger.should_receive(:error)
|
46
|
+
@middleware.call(@env)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'Shard ID logging' do
|
51
|
+
before(:each) do
|
52
|
+
@logger = mock_logger
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'logs X-Shard header if it is present' do
|
56
|
+
@env['HTTP_X_SHARD'] = '9'
|
57
|
+
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /Shard: 9;/ } )
|
58
|
+
@middleware.send(:log_request_begin, @logger, @env)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'logs "default" if X-Shard header is absent' do
|
62
|
+
@logger.should_receive(:info).with(FlexMock.on { |arg| arg.should =~ /Shard: default;/ } )
|
63
|
+
@middleware.send(:log_request_begin, @logger, @env)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Alice
|
4
|
+
include Singleton
|
5
|
+
include RightSupport::Ruby::EasySingleton
|
6
|
+
|
7
|
+
def alice?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Bob
|
13
|
+
include RightSupport::Ruby::EasySingleton
|
14
|
+
|
15
|
+
def bob?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Charlie
|
21
|
+
include RightSupport::Ruby::EasySingleton
|
22
|
+
|
23
|
+
def charlie?(&block)
|
24
|
+
block.call("this is charlie") if block
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def horse(x,y,z)
|
29
|
+
yield("this is horse") if block_given?
|
30
|
+
x+y+z
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe RightSupport::Ruby::EasySingleton do
|
35
|
+
context 'when mixed into a base class' do
|
36
|
+
it 'ensures the base is already a Singleton' do
|
37
|
+
Alice.ancestors.should include(Singleton)
|
38
|
+
Bob.ancestors.should include(Singleton)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'adds a class-level method_missing' do
|
42
|
+
Alice.alice?.should be_true
|
43
|
+
Bob.bob?.should be_true
|
44
|
+
|
45
|
+
lambda { Alice.bob? }.should raise_error(NoMethodError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'modifies class-level respond_to? to be truthful' do
|
49
|
+
Alice.respond_to?(:alice?).should be_true
|
50
|
+
Bob.respond_to?(:bob?).should be_true
|
51
|
+
Alice.respond_to?(:bob?).should be_false
|
52
|
+
Bob.respond_to?(:alice?).should be_false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when proxying class-level method_missing to instance' do
|
57
|
+
it 'preserves parameters as passed' do
|
58
|
+
Charlie.horse(1,2,3).should == 6
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'preserves block semantics' do
|
62
|
+
charlie = nil
|
63
|
+
horse = nil
|
64
|
+
|
65
|
+
Charlie.charlie? { |x| charlie = x }
|
66
|
+
charlie.should == 'this is charlie'
|
67
|
+
|
68
|
+
Charlie.horse(1,2,3) { |x| horse = x }
|
69
|
+
horse.should == 'this is horse'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightSupport::Ruby::ObjectExtensions do
|
4
|
+
context :require_succeeds? do
|
5
|
+
it 'yields to its block when the require succeeds' do
|
6
|
+
@canary = false
|
7
|
+
|
8
|
+
# The 'set' source file ships with Ruby standard library and should
|
9
|
+
# always be available
|
10
|
+
if require_succeeds?('set')
|
11
|
+
@canary = true
|
12
|
+
end
|
13
|
+
|
14
|
+
@canary.should == true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'does not yield when require fails for any reason' do
|
18
|
+
@canary = false
|
19
|
+
|
20
|
+
if require_succeeds?('a_source_file_with_a_wholly_improbable_name')
|
21
|
+
@canary = true
|
22
|
+
end
|
23
|
+
|
24
|
+
@canary.should == false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2012 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
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'spec_helper'
|
24
|
+
|
25
|
+
describe RightSupport::Ruby::StringExtensions do
|
26
|
+
|
27
|
+
context ":snake_case" do
|
28
|
+
|
29
|
+
it "downcases single word" do
|
30
|
+
["FOO", "Foo", "foo"].each do |w|
|
31
|
+
w.snake_case.should == "foo"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "doesn't separate numbers from end of word" do
|
36
|
+
["Foo1234", "foo1234"].each do |w|
|
37
|
+
w.snake_case.should == "foo1234"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "doesn't separate numbers from word that starts with uppercase letter" do
|
42
|
+
"1234Foo".snake_case.should == "1234foo"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "doesn't' separate numbers from word that starts with lowercase letter" do
|
46
|
+
"1234foo".snake_case.should == "1234foo"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "downcases camel-cased words and connect with underscore" do
|
50
|
+
["FooBar", "fooBar"].each do |w|
|
51
|
+
w.snake_case.should == "foo_bar"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "starts new word with uppercase letter before lower case letter" do
|
56
|
+
["FooBARBaz", "fooBARBaz"].each do |w|
|
57
|
+
w.snake_case.should == "foo_bar_baz"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
context ":to_const_path" do
|
64
|
+
|
65
|
+
it "snakes-case the string" do
|
66
|
+
"Hello::World".to_const_path.should == "hello/world"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "leaves (snake-cased) string without '::' unchanged" do
|
70
|
+
"hello".to_const_path.should == "hello"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "replaces single '::' with '/'" do
|
74
|
+
"hello::world".to_const_path.should == "hello/world"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "replaces multiple '::' with '/'" do
|
78
|
+
"hello::rightscale::world".to_const_path.should == "hello/rightscale/world"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
context ':camelize' do
|
84
|
+
|
85
|
+
it 'camelizes the string' do
|
86
|
+
'hello/world_hello'.camelize.should == 'Hello::WorldHello'
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'camelizes strings with integers' do
|
90
|
+
'1hel2lo3/4wor5ld6_7hel8lo9'.camelize.should == '1hel2lo3::4wor5ld67hel8lo9'
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'leaves camelized strings alone' do
|
94
|
+
'1Hel2lo3::4Wor5ld67Hel8lo9'.camelize.should == '1Hel2lo3::4Wor5ld67Hel8lo9'
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|