right_aws 1.10.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +53 -15
- data/Manifest.txt +16 -0
- data/README.txt +10 -9
- data/Rakefile +13 -15
- data/lib/acf/right_acf_interface.rb +224 -118
- data/lib/acf/right_acf_origin_access_identities.rb +230 -0
- data/lib/acf/right_acf_streaming_interface.rb +236 -0
- data/lib/acw/right_acw_interface.rb +249 -0
- data/lib/as/right_as_interface.rb +699 -0
- data/lib/awsbase/right_awsbase.rb +232 -51
- data/lib/awsbase/support.rb +4 -0
- data/lib/ec2/right_ec2.rb +33 -1375
- data/lib/ec2/right_ec2_ebs.rb +452 -0
- data/lib/ec2/right_ec2_images.rb +373 -0
- data/lib/ec2/right_ec2_instances.rb +755 -0
- data/lib/ec2/right_ec2_monitoring.rb +70 -0
- data/lib/ec2/right_ec2_reserved_instances.rb +170 -0
- data/lib/ec2/right_ec2_security_groups.rb +280 -0
- data/lib/ec2/right_ec2_spot_instances.rb +399 -0
- data/lib/ec2/right_ec2_vpc.rb +571 -0
- data/lib/elb/right_elb_interface.rb +496 -0
- data/lib/rds/right_rds_interface.rb +998 -0
- data/lib/right_aws.rb +18 -4
- data/lib/s3/right_s3.rb +39 -7
- data/lib/s3/right_s3_interface.rb +77 -53
- data/lib/sdb/active_sdb.rb +203 -11
- data/lib/sdb/right_sdb_interface.rb +68 -45
- data/lib/sqs/right_sqs_gen2.rb +73 -16
- data/lib/sqs/right_sqs_gen2_interface.rb +131 -51
- data/lib/sqs/right_sqs_interface.rb +2 -4
- data/test/acf/test_right_acf.rb +10 -18
- data/test/rds/test_helper.rb +2 -0
- data/test/rds/test_right_rds.rb +120 -0
- data/test/s3/test_right_s3.rb +10 -8
- data/test/s3/test_right_s3_stubbed.rb +6 -4
- data/test/sdb/test_active_sdb.rb +70 -12
- data/test/sdb/test_right_sdb.rb +13 -7
- data/test/sqs/test_right_sqs_gen2.rb +104 -49
- metadata +103 -14
data/lib/right_aws.rb
CHANGED
@@ -39,6 +39,17 @@ require 'awsbase/benchmark_fix'
|
|
39
39
|
require 'awsbase/support'
|
40
40
|
require 'awsbase/right_awsbase'
|
41
41
|
require 'ec2/right_ec2'
|
42
|
+
require 'ec2/right_ec2_images'
|
43
|
+
require 'ec2/right_ec2_instances'
|
44
|
+
require 'ec2/right_ec2_security_groups'
|
45
|
+
require 'ec2/right_ec2_spot_instances'
|
46
|
+
require 'ec2/right_ec2_ebs'
|
47
|
+
require 'ec2/right_ec2_reserved_instances'
|
48
|
+
require 'ec2/right_ec2_vpc'
|
49
|
+
require 'ec2/right_ec2_monitoring'
|
50
|
+
require 'elb/right_elb_interface'
|
51
|
+
require 'acw/right_acw_interface'
|
52
|
+
require 'as/right_as_interface'
|
42
53
|
require 's3/right_s3_interface'
|
43
54
|
require 's3/right_s3'
|
44
55
|
require 'sqs/right_sqs_interface'
|
@@ -47,15 +58,18 @@ require 'sqs/right_sqs_gen2_interface'
|
|
47
58
|
require 'sqs/right_sqs_gen2'
|
48
59
|
require 'sdb/right_sdb_interface'
|
49
60
|
require 'acf/right_acf_interface'
|
61
|
+
require 'acf/right_acf_streaming_interface'
|
62
|
+
require 'acf/right_acf_origin_access_identities'
|
63
|
+
require 'rds/right_rds_interface'
|
50
64
|
|
51
65
|
|
52
66
|
module RightAws #:nodoc:
|
53
67
|
module VERSION #:nodoc:
|
54
|
-
MAJOR =
|
55
|
-
MINOR =
|
56
|
-
TINY = 0
|
68
|
+
MAJOR = 2 unless defined?(MAJOR)
|
69
|
+
MINOR = 0 unless defined?(MINOR)
|
70
|
+
TINY = 0 unless defined?(TINY)
|
57
71
|
|
58
|
-
STRING = [MAJOR, MINOR, TINY].join('.')
|
72
|
+
STRING = [MAJOR, MINOR, TINY].join('.') unless defined?(STRING)
|
59
73
|
end
|
60
74
|
end
|
61
75
|
|
data/lib/s3/right_s3.rb
CHANGED
@@ -460,6 +460,30 @@ module RightAws
|
|
460
460
|
get if !@data and exists?
|
461
461
|
@data
|
462
462
|
end
|
463
|
+
|
464
|
+
# Getter for the 'content-type' metadata
|
465
|
+
def content_type
|
466
|
+
@headers['content-type'] if @headers
|
467
|
+
end
|
468
|
+
|
469
|
+
# Helper to get and URI-decode a header metadata.
|
470
|
+
# Metadata have to be HTTP encoded (rfc2616) as we use the Amazon S3 REST api
|
471
|
+
# see http://docs.amazonwebservices.com/AmazonS3/latest/index.html?UsingMetadata.html
|
472
|
+
def decoded_meta_headers(key = nil)
|
473
|
+
if key
|
474
|
+
# Get one metadata value by its key
|
475
|
+
URI.decode(@meta_headers[key.to_s])
|
476
|
+
else
|
477
|
+
# Get a hash of all metadata with a decoded value
|
478
|
+
@decoded_meta_headers ||= begin
|
479
|
+
metadata = {}
|
480
|
+
@meta_headers.each do |key, value|
|
481
|
+
metadata[key.to_sym] = URI.decode(value)
|
482
|
+
end
|
483
|
+
metadata
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
463
487
|
|
464
488
|
# Retrieve object data and attributes from Amazon.
|
465
489
|
# Returns a +String+.
|
@@ -759,11 +783,11 @@ module RightAws
|
|
759
783
|
@thing = thing
|
760
784
|
@id = id
|
761
785
|
@name = name
|
762
|
-
@perms = perms
|
786
|
+
@perms = Array(perms)
|
763
787
|
case action
|
764
|
-
when :apply
|
765
|
-
when :refresh
|
766
|
-
when :apply_and_refresh
|
788
|
+
when :apply then apply
|
789
|
+
when :refresh then refresh
|
790
|
+
when :apply_and_refresh then apply; refresh
|
767
791
|
end
|
768
792
|
end
|
769
793
|
|
@@ -775,9 +799,13 @@ module RightAws
|
|
775
799
|
false
|
776
800
|
end
|
777
801
|
|
778
|
-
# Return Grantee type (+String+): "Group" or "CanonicalUser".
|
802
|
+
# Return Grantee type (+String+): "Group", "AmazonCustomerByEmail" or "CanonicalUser".
|
779
803
|
def type
|
780
|
-
@id
|
804
|
+
case @id
|
805
|
+
when /^http:/ then "Group"
|
806
|
+
when /@/ then "AmazonCustomerByEmail"
|
807
|
+
else "CanonicalUser"
|
808
|
+
end
|
781
809
|
end
|
782
810
|
|
783
811
|
# Return a name or an id.
|
@@ -872,7 +900,11 @@ module RightAws
|
|
872
900
|
end
|
873
901
|
|
874
902
|
def to_xml # :nodoc:
|
875
|
-
id_str =
|
903
|
+
id_str = case @id
|
904
|
+
when /^http/ then "<URI>#{@id}</URI>"
|
905
|
+
when /@/ then "<EmailAddress>#{@id}</EmailAddress>"
|
906
|
+
else "<ID>#{@id}</ID>"
|
907
|
+
end
|
876
908
|
grants = ''
|
877
909
|
@perms.each do |perm|
|
878
910
|
grants << "<Grant>" +
|
@@ -47,6 +47,19 @@ module RightAws
|
|
47
47
|
@@bench.service
|
48
48
|
end
|
49
49
|
|
50
|
+
# Params supported:
|
51
|
+
# :no_subdomains => true # do not use bucket as a part of domain name but as a part of path
|
52
|
+
@@params = {}
|
53
|
+
def self.params
|
54
|
+
@@params
|
55
|
+
end
|
56
|
+
|
57
|
+
# get custom option
|
58
|
+
def param(name)
|
59
|
+
# - check explicitly defined param (@params)
|
60
|
+
# - otherwise check implicitly defined one (@@params)
|
61
|
+
@params.has_key?(name) ? @params[name] : @@params[name]
|
62
|
+
end
|
50
63
|
|
51
64
|
# Creates new RightS3 instance.
|
52
65
|
#
|
@@ -80,7 +93,11 @@ module RightAws
|
|
80
93
|
s3_headers = {}
|
81
94
|
headers.each do |key, value|
|
82
95
|
key = key.downcase
|
83
|
-
|
96
|
+
value = case
|
97
|
+
when value.is_a?(Array) then value.join('')
|
98
|
+
else value.to_s
|
99
|
+
end
|
100
|
+
s3_headers[key] = value.strip if key[/^#{AMAZON_HEADER_PREFIX}|^content-md5$|^content-type$|^date$/o]
|
84
101
|
end
|
85
102
|
s3_headers['content-type'] ||= ''
|
86
103
|
s3_headers['content-md5'] ||= ''
|
@@ -120,7 +137,7 @@ module RightAws
|
|
120
137
|
headers[:url].to_s[%r{^([a-z0-9._-]*)(/[^?]*)?(\?.+)?}i]
|
121
138
|
bucket_name, key_path, params_list = $1, $2, $3
|
122
139
|
# select request model
|
123
|
-
if is_dns_bucket?(bucket_name)
|
140
|
+
if !param(:no_subdomains) && is_dns_bucket?(bucket_name)
|
124
141
|
# fix a path
|
125
142
|
server = "#{bucket_name}.#{server}"
|
126
143
|
key_path ||= '/'
|
@@ -164,12 +181,9 @@ module RightAws
|
|
164
181
|
# Sends request to Amazon and parses the response.
|
165
182
|
# Raises AwsError if any banana happened.
|
166
183
|
def request_info(request, parser, &block) # :nodoc:
|
167
|
-
|
168
|
-
thread[:s3_connection] ||= Rightscale::HttpConnection.new(:exception => RightAws::AwsError, :logger => @logger)
|
169
|
-
request_info_impl(thread[:s3_connection], @@bench, request, parser, &block)
|
184
|
+
request_info_impl(:s3_connection, @@bench, request, parser, &block)
|
170
185
|
end
|
171
186
|
|
172
|
-
|
173
187
|
# Returns an array of customer's buckets. Each item is a +hash+.
|
174
188
|
#
|
175
189
|
# s3.list_all_my_buckets #=>
|
@@ -194,8 +208,14 @@ module RightAws
|
|
194
208
|
#
|
195
209
|
def create_bucket(bucket, headers={})
|
196
210
|
data = nil
|
197
|
-
|
198
|
-
|
211
|
+
location = case headers[:location].to_s
|
212
|
+
when 'us','US' then ''
|
213
|
+
when 'eu' then 'EU'
|
214
|
+
else headers[:location].to_s
|
215
|
+
end
|
216
|
+
|
217
|
+
unless location.blank?
|
218
|
+
data = "<CreateBucketConfiguration><LocationConstraint>#{location}</LocationConstraint></CreateBucketConfiguration>"
|
199
219
|
end
|
200
220
|
req_hash = generate_rest_request('PUT', headers.merge(:url=>bucket, :data => data))
|
201
221
|
request_info(req_hash, RightHttp2xxParser.new)
|
@@ -245,7 +265,7 @@ module RightAws
|
|
245
265
|
AwsUtils.allow_only([:bucket,:xmldoc, :headers], params)
|
246
266
|
params[:headers] = {} unless params[:headers]
|
247
267
|
req_hash = generate_rest_request('PUT', params[:headers].merge(:url=>"#{params[:bucket]}?logging", :data => params[:xmldoc]))
|
248
|
-
request_info(req_hash,
|
268
|
+
request_info(req_hash, RightHttp2xxParser.new)
|
249
269
|
rescue
|
250
270
|
on_exception
|
251
271
|
end
|
@@ -724,7 +744,7 @@ module RightAws
|
|
724
744
|
else
|
725
745
|
result[:grantees][key] =
|
726
746
|
{ :display_name => grantee[:display_name] || grantee[:uri].to_s[/[^\/]*$/],
|
727
|
-
:permissions => grantee[:permissions]
|
747
|
+
:permissions => Array(grantee[:permissions]),
|
728
748
|
:attributes => grantee[:attributes] }
|
729
749
|
end
|
730
750
|
end
|
@@ -880,7 +900,7 @@ module RightAws
|
|
880
900
|
# s3.put_link('my_awesome_bucket',key, object) #=> url string
|
881
901
|
#
|
882
902
|
def put_link(bucket, key, data=nil, expires=nil, headers={})
|
883
|
-
generate_link('PUT', headers.merge(:url=>"#{bucket}/#{
|
903
|
+
generate_link('PUT', headers.merge(:url=>"#{bucket}/#{CGI::escape key}", :data=>data), expires)
|
884
904
|
rescue
|
885
905
|
on_exception
|
886
906
|
end
|
@@ -898,7 +918,7 @@ module RightAws
|
|
898
918
|
#
|
899
919
|
# see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html
|
900
920
|
def get_link(bucket, key, expires=nil, headers={})
|
901
|
-
generate_link('GET', headers.merge(:url=>"#{bucket}/#{
|
921
|
+
generate_link('GET', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"), expires)
|
902
922
|
rescue
|
903
923
|
on_exception
|
904
924
|
end
|
@@ -908,7 +928,7 @@ module RightAws
|
|
908
928
|
# s3.head_link('my_awesome_bucket',key) #=> url string
|
909
929
|
#
|
910
930
|
def head_link(bucket, key, expires=nil, headers={})
|
911
|
-
generate_link('HEAD', headers.merge(:url=>"#{bucket}/#{
|
931
|
+
generate_link('HEAD', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"), expires)
|
912
932
|
rescue
|
913
933
|
on_exception
|
914
934
|
end
|
@@ -918,7 +938,7 @@ module RightAws
|
|
918
938
|
# s3.delete_link('my_awesome_bucket',key) #=> url string
|
919
939
|
#
|
920
940
|
def delete_link(bucket, key, expires=nil, headers={})
|
921
|
-
generate_link('DELETE', headers.merge(:url=>"#{bucket}/#{
|
941
|
+
generate_link('DELETE', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"), expires)
|
922
942
|
rescue
|
923
943
|
on_exception
|
924
944
|
end
|
@@ -929,7 +949,7 @@ module RightAws
|
|
929
949
|
# s3.get_acl_link('my_awesome_bucket',key) #=> url string
|
930
950
|
#
|
931
951
|
def get_acl_link(bucket, key='', headers={})
|
932
|
-
return generate_link('GET', headers.merge(:url=>"#{bucket}/#{
|
952
|
+
return generate_link('GET', headers.merge(:url=>"#{bucket}/#{CGI::escape key}?acl"))
|
933
953
|
rescue
|
934
954
|
on_exception
|
935
955
|
end
|
@@ -939,7 +959,7 @@ module RightAws
|
|
939
959
|
# s3.put_acl_link('my_awesome_bucket',key) #=> url string
|
940
960
|
#
|
941
961
|
def put_acl_link(bucket, key='', headers={})
|
942
|
-
return generate_link('PUT', headers.merge(:url=>"#{bucket}/#{
|
962
|
+
return generate_link('PUT', headers.merge(:url=>"#{bucket}/#{CGI::escape key}?acl"))
|
943
963
|
rescue
|
944
964
|
on_exception
|
945
965
|
end
|
@@ -978,11 +998,11 @@ module RightAws
|
|
978
998
|
end
|
979
999
|
def tagend(name)
|
980
1000
|
case name
|
981
|
-
when 'ID'
|
982
|
-
when 'DisplayName'
|
983
|
-
when 'Name'
|
984
|
-
when 'CreationDate'
|
985
|
-
when 'Bucket'
|
1001
|
+
when 'ID' then @owner[:owner_id] = @text
|
1002
|
+
when 'DisplayName' then @owner[:owner_display_name] = @text
|
1003
|
+
when 'Name' then @current_bucket[:name] = @text
|
1004
|
+
when 'CreationDate'then @current_bucket[:creation_date] = @text
|
1005
|
+
when 'Bucket' then @result << @current_bucket.merge(@owner)
|
986
1006
|
end
|
987
1007
|
end
|
988
1008
|
end
|
@@ -999,21 +1019,23 @@ module RightAws
|
|
999
1019
|
def tagend(name)
|
1000
1020
|
case name
|
1001
1021
|
# service info
|
1002
|
-
when 'Name'
|
1003
|
-
when 'Prefix'
|
1004
|
-
when 'Marker'
|
1005
|
-
when 'MaxKeys'
|
1006
|
-
when 'Delimiter'
|
1007
|
-
when 'IsTruncated'
|
1022
|
+
when 'Name' then @service['name'] = @text
|
1023
|
+
when 'Prefix' then @service['prefix'] = @text
|
1024
|
+
when 'Marker' then @service['marker'] = @text
|
1025
|
+
when 'MaxKeys' then @service['max-keys'] = @text
|
1026
|
+
when 'Delimiter' then @service['delimiter'] = @text
|
1027
|
+
when 'IsTruncated' then @service['is_truncated'] = (@text =~ /false/ ? false : true)
|
1008
1028
|
# key data
|
1009
|
-
when 'Key'
|
1010
|
-
when 'LastModified'
|
1011
|
-
when 'ETag'
|
1012
|
-
when 'Size'
|
1013
|
-
when 'StorageClass'
|
1014
|
-
when 'ID'
|
1015
|
-
when 'DisplayName'
|
1016
|
-
when 'Contents'
|
1029
|
+
when 'Key' then @current_key[:key] = @text
|
1030
|
+
when 'LastModified'then @current_key[:last_modified] = @text
|
1031
|
+
when 'ETag' then @current_key[:e_tag] = @text
|
1032
|
+
when 'Size' then @current_key[:size] = @text.to_i
|
1033
|
+
when 'StorageClass'then @current_key[:storage_class] = @text
|
1034
|
+
when 'ID' then @current_key[:owner_id] = @text
|
1035
|
+
when 'DisplayName' then @current_key[:owner_display_name] = @text
|
1036
|
+
when 'Contents'
|
1037
|
+
@current_key[:service] = @service
|
1038
|
+
@result << @current_key
|
1017
1039
|
end
|
1018
1040
|
end
|
1019
1041
|
end
|
@@ -1035,27 +1057,29 @@ module RightAws
|
|
1035
1057
|
def tagend(name)
|
1036
1058
|
case name
|
1037
1059
|
# service info
|
1038
|
-
when 'Name'
|
1060
|
+
when 'Name' then @result[:name] = @text
|
1039
1061
|
# Amazon uses the same tag for the search prefix and for the entries
|
1040
1062
|
# in common prefix...so use our simple flag to see which element
|
1041
1063
|
# we are parsing
|
1042
|
-
when 'Prefix'
|
1043
|
-
when 'Marker'
|
1044
|
-
when 'MaxKeys'
|
1045
|
-
when 'Delimiter'
|
1046
|
-
when 'IsTruncated'
|
1047
|
-
when 'NextMarker'
|
1064
|
+
when 'Prefix' then @in_common_prefixes ? @common_prefixes << @text : @result[:prefix] = @text
|
1065
|
+
when 'Marker' then @result[:marker] = @text
|
1066
|
+
when 'MaxKeys' then @result[:max_keys] = @text
|
1067
|
+
when 'Delimiter' then @result[:delimiter] = @text
|
1068
|
+
when 'IsTruncated' then @result[:is_truncated] = (@text =~ /false/ ? false : true)
|
1069
|
+
when 'NextMarker' then @result[:next_marker] = @text
|
1048
1070
|
# key data
|
1049
|
-
when 'Key'
|
1050
|
-
when 'LastModified'
|
1051
|
-
when 'ETag'
|
1052
|
-
when 'Size'
|
1053
|
-
when 'StorageClass'
|
1054
|
-
when 'ID'
|
1055
|
-
when 'DisplayName'
|
1056
|
-
when 'Contents'
|
1071
|
+
when 'Key' then @current_key[:key] = @text
|
1072
|
+
when 'LastModified'then @current_key[:last_modified] = @text
|
1073
|
+
when 'ETag' then @current_key[:e_tag] = @text
|
1074
|
+
when 'Size' then @current_key[:size] = @text.to_i
|
1075
|
+
when 'StorageClass'then @current_key[:storage_class] = @text
|
1076
|
+
when 'ID' then @current_key[:owner_id] = @text
|
1077
|
+
when 'DisplayName' then @current_key[:owner_display_name] = @text
|
1078
|
+
when 'Contents' then @result[:contents] << @current_key
|
1057
1079
|
# Common Prefix stuff
|
1058
|
-
when 'CommonPrefixes'
|
1080
|
+
when 'CommonPrefixes'
|
1081
|
+
@result[:common_prefixes] = @common_prefixes
|
1082
|
+
@in_common_prefixes = false
|
1059
1083
|
end
|
1060
1084
|
end
|
1061
1085
|
end
|
@@ -1130,8 +1154,8 @@ module RightAws
|
|
1130
1154
|
end
|
1131
1155
|
def tagend(name)
|
1132
1156
|
case name
|
1133
|
-
when 'LastModified'
|
1134
|
-
when 'ETag'
|
1157
|
+
when 'LastModified' then @result[:last_modified] = @text
|
1158
|
+
when 'ETag' then @result[:e_tag] = @text
|
1135
1159
|
end
|
1136
1160
|
end
|
1137
1161
|
end
|
data/lib/sdb/active_sdb.rb
CHANGED
@@ -92,6 +92,59 @@ module RightAws
|
|
92
92
|
# # remove domain
|
93
93
|
# Client.delete_domain
|
94
94
|
#
|
95
|
+
# # Dynamic attribute accessors
|
96
|
+
#
|
97
|
+
# class KdClient < RightAws::ActiveSdb::Base
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# client = KdClient.select(:all, :order => 'expiration').first
|
101
|
+
# pp client.attributes #=>
|
102
|
+
# {"name"=>["Putin"],
|
103
|
+
# "post"=>["president"],
|
104
|
+
# "country"=>["Russia"],
|
105
|
+
# "expiration"=>["2008"],
|
106
|
+
# "id"=>"376d2e00-75b0-11dd-9557-001bfc466dd7",
|
107
|
+
# "gender"=>["male"]}
|
108
|
+
#
|
109
|
+
# pp client.name #=> ["Putin"]
|
110
|
+
# pp client.country #=> ["Russia"]
|
111
|
+
# pp client.post #=> ["president"]
|
112
|
+
#
|
113
|
+
# # Columns and simple typecasting
|
114
|
+
#
|
115
|
+
# class Person < RightAws::ActiveSdb::Base
|
116
|
+
# columns do
|
117
|
+
# name
|
118
|
+
# email
|
119
|
+
# score :Integer
|
120
|
+
# is_active :Boolean
|
121
|
+
# registered_at :DateTime
|
122
|
+
# created_at :DateTime, :default => lambda{ Time.now }
|
123
|
+
# end
|
124
|
+
# end
|
125
|
+
# Person::create( :name => 'Yetta E. Andrews', :email => 'nulla.facilisis@metus.com', :score => 100, :is_active => true, :registered_at => Time.local(2000, 1, 1) )
|
126
|
+
#
|
127
|
+
# person = Person.find_by_email 'nulla.facilisis@metus.com'
|
128
|
+
# person.reload
|
129
|
+
#
|
130
|
+
# pp person.attributes #=>
|
131
|
+
# {"name"=>["Yetta E. Andrews"],
|
132
|
+
# "created_at"=>["2010-04-02T20:51:58+0400"],
|
133
|
+
# "id"=>"0ee24946-3e60-11df-9d4c-0025b37efad0",
|
134
|
+
# "registered_at"=>["2000-01-01T00:00:00+0300"],
|
135
|
+
# "is_active"=>["T"],
|
136
|
+
# "score"=>["100"],
|
137
|
+
# "email"=>["nulla.facilisis@metus.com"]}
|
138
|
+
# pp person.name #=> "Yetta E. Andrews"
|
139
|
+
# pp person.name.class #=> String
|
140
|
+
# pp person.registered_at.to_s #=> "2000-01-01T00:00:00+03:00"
|
141
|
+
# pp person.registered_at.class #=> DateTime
|
142
|
+
# pp person.is_active #=> true
|
143
|
+
# pp person.is_active.class #=> TrueClass
|
144
|
+
# pp person.score #=> 100
|
145
|
+
# pp person.score.class #=> Fixnum
|
146
|
+
# pp person.created_at.to_s #=> "2010-04-02T20:51:58+04:00"
|
147
|
+
#
|
95
148
|
class ActiveSdb
|
96
149
|
|
97
150
|
module ActiveSdbConnect
|
@@ -242,7 +295,31 @@ module RightAws
|
|
242
295
|
def delete_domain
|
243
296
|
connection.delete_domain(domain)
|
244
297
|
end
|
245
|
-
|
298
|
+
|
299
|
+
def columns(&block)
|
300
|
+
@columns ||= ColumnSet.new
|
301
|
+
@columns.instance_eval(&block) if block
|
302
|
+
@columns
|
303
|
+
end
|
304
|
+
|
305
|
+
def column?(col_name)
|
306
|
+
columns.include?(col_name)
|
307
|
+
end
|
308
|
+
|
309
|
+
def type_of(col_name)
|
310
|
+
columns.type_of(col_name)
|
311
|
+
end
|
312
|
+
|
313
|
+
def serialize(attribute, value)
|
314
|
+
s = serialization_for_type(type_of(attribute))
|
315
|
+
s ? s.serialize(value) : value.to_s
|
316
|
+
end
|
317
|
+
|
318
|
+
def deserialize(attribute, value)
|
319
|
+
s = serialization_for_type(type_of(attribute))
|
320
|
+
s ? s.deserialize(value) : value
|
321
|
+
end
|
322
|
+
|
246
323
|
# Perform a find request.
|
247
324
|
#
|
248
325
|
# Single record:
|
@@ -364,7 +441,11 @@ module RightAws
|
|
364
441
|
end
|
365
442
|
|
366
443
|
def generate_id # :nodoc:
|
367
|
-
UUID.
|
444
|
+
if UUID::VERSION::STRING < '2.0.0'
|
445
|
+
UUID.timestamp_create().to_s
|
446
|
+
else
|
447
|
+
UUIDTools::UUID.timestamp_create().to_s
|
448
|
+
end
|
368
449
|
end
|
369
450
|
|
370
451
|
protected
|
@@ -376,7 +457,7 @@ module RightAws
|
|
376
457
|
# detect amount of records requested
|
377
458
|
bunch_of_records_requested = args.size > 1 || args.first.is_a?(Array)
|
378
459
|
# flatten ids
|
379
|
-
args = args.
|
460
|
+
args = Array(args).flatten
|
380
461
|
args.each { |id| cond << "id=#{self.connection.escape(id)}" }
|
381
462
|
ids_cond = "(#{cond.join(' OR ')})"
|
382
463
|
# user defined :conditions to string (if it was defined)
|
@@ -518,7 +599,7 @@ module RightAws
|
|
518
599
|
# detect amount of records requested
|
519
600
|
bunch_of_records_requested = args.size > 1 || args.first.is_a?(Array)
|
520
601
|
# flatten ids
|
521
|
-
args = args.
|
602
|
+
args = Array(args).flatten
|
522
603
|
args.each { |id| cond << "'id'=#{self.connection.escape(id)}" }
|
523
604
|
ids_cond = "[#{cond.join(' OR ')}]"
|
524
605
|
# user defined :conditions to string (if it was defined)
|
@@ -590,6 +671,13 @@ module RightAws
|
|
590
671
|
end
|
591
672
|
end
|
592
673
|
|
674
|
+
def serialization_for_type(type)
|
675
|
+
@serializations ||= {}
|
676
|
+
unless @serializations.has_key? type
|
677
|
+
@serializations[type] = ::RightAws::ActiveSdb.const_get("#{type}Serialization") rescue false
|
678
|
+
end
|
679
|
+
@serializations[type]
|
680
|
+
end
|
593
681
|
end
|
594
682
|
|
595
683
|
public
|
@@ -661,7 +749,11 @@ module RightAws
|
|
661
749
|
self.attributes
|
662
750
|
end
|
663
751
|
|
664
|
-
def
|
752
|
+
def columns
|
753
|
+
self.class.columns
|
754
|
+
end
|
755
|
+
|
756
|
+
def connection
|
665
757
|
self.class.connection
|
666
758
|
end
|
667
759
|
|
@@ -675,7 +767,8 @@ module RightAws
|
|
675
767
|
# puts item['Cat'].inspect #=> ["Jons socks", "clew", "mice"]
|
676
768
|
#
|
677
769
|
def [](attribute)
|
678
|
-
@attributes[attribute.to_s]
|
770
|
+
raw = @attributes[attribute.to_s]
|
771
|
+
self.class.column?(attribute) && raw ? self.class.deserialize(attribute, raw.first) : raw
|
679
772
|
end
|
680
773
|
|
681
774
|
# Updates the attribute identified by +attribute+ with the specified +values+.
|
@@ -686,7 +779,14 @@ module RightAws
|
|
686
779
|
#
|
687
780
|
def []=(attribute, values)
|
688
781
|
attribute = attribute.to_s
|
689
|
-
@attributes[attribute] =
|
782
|
+
@attributes[attribute] = case
|
783
|
+
when attribute == 'id'
|
784
|
+
values.to_s
|
785
|
+
when self.class.column?(attribute)
|
786
|
+
self.class.serialize(attribute, values)
|
787
|
+
else
|
788
|
+
Array(values).uniq
|
789
|
+
end
|
690
790
|
end
|
691
791
|
|
692
792
|
# Reload attributes from SDB. Replaces in-memory attributes.
|
@@ -906,25 +1006,117 @@ module RightAws
|
|
906
1006
|
@new_record = false
|
907
1007
|
end
|
908
1008
|
|
909
|
-
|
910
|
-
|
1009
|
+
# support accessing attribute values via method call
|
1010
|
+
def method_missing(method_sym, *args)
|
1011
|
+
method_name = method_sym.to_s
|
1012
|
+
setter = method_name[-1,1] == '='
|
1013
|
+
method_name.chop! if setter
|
1014
|
+
|
1015
|
+
if @attributes.has_key?(method_name) || self.class.column?(method_name)
|
1016
|
+
setter ? self[method_name] = args.first : self[method_name]
|
1017
|
+
else
|
1018
|
+
super
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
private
|
1023
|
+
|
911
1024
|
def raise_on_id_absence
|
912
1025
|
raise ActiveSdbError.new('Unknown record id') unless id
|
913
1026
|
end
|
914
1027
|
|
915
1028
|
def prepare_for_update
|
916
1029
|
@attributes['id'] = self.class.generate_id if @attributes['id'].blank?
|
1030
|
+
columns.all.each do |col_name|
|
1031
|
+
self[col_name] ||= columns.default(col_name)
|
1032
|
+
end
|
917
1033
|
end
|
918
1034
|
|
919
1035
|
def uniq_values(attributes=nil) # :nodoc:
|
920
1036
|
attrs = {}
|
921
1037
|
attributes.each do |attribute, values|
|
922
1038
|
attribute = attribute.to_s
|
923
|
-
attrs[attribute] =
|
1039
|
+
attrs[attribute] = case
|
1040
|
+
when attribute == 'id'
|
1041
|
+
values.to_s
|
1042
|
+
when self.class.column?(attribute)
|
1043
|
+
values.is_a?(String) ? values : self.class.serialize(attribute, values)
|
1044
|
+
else
|
1045
|
+
Array(values).uniq
|
1046
|
+
end
|
924
1047
|
attrs.delete(attribute) if values.blank?
|
925
1048
|
end
|
926
1049
|
attrs
|
927
1050
|
end
|
928
1051
|
end
|
1052
|
+
|
1053
|
+
class ColumnSet
|
1054
|
+
attr_accessor :columns
|
1055
|
+
def initialize
|
1056
|
+
@columns = {}
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
def all
|
1060
|
+
@columns.keys
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
def column(col_name)
|
1064
|
+
@columns[col_name.to_s]
|
1065
|
+
end
|
1066
|
+
alias_method :include?, :column
|
1067
|
+
|
1068
|
+
def type_of(col_name)
|
1069
|
+
column(col_name) && column(col_name)[:type]
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
def default(col_name)
|
1073
|
+
return nil unless include?(col_name)
|
1074
|
+
default = column(col_name)[:default]
|
1075
|
+
default.respond_to?(:call) ? default.call : default
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
def method_missing(method_sym, *args)
|
1079
|
+
data_type = args.shift || :String
|
1080
|
+
options = args.shift || {}
|
1081
|
+
@columns[method_sym.to_s] = options.merge( :type => data_type )
|
1082
|
+
end
|
1083
|
+
end
|
1084
|
+
|
1085
|
+
class DateTimeSerialization
|
1086
|
+
class << self
|
1087
|
+
def serialize(date)
|
1088
|
+
date.strftime('%Y-%m-%dT%H:%M:%S%z')
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
def deserialize(string)
|
1092
|
+
r = DateTime.parse(string) rescue nil
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
class BooleanSerialization
|
1098
|
+
class << self
|
1099
|
+
def serialize(boolean)
|
1100
|
+
boolean ? 'T' : 'F'
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
def deserialize(string)
|
1104
|
+
string == 'T'
|
1105
|
+
end
|
1106
|
+
end
|
1107
|
+
end
|
1108
|
+
|
1109
|
+
class IntegerSerialization
|
1110
|
+
class << self
|
1111
|
+
def serialize(int)
|
1112
|
+
int.to_s
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
def deserialize(string)
|
1116
|
+
string.to_i
|
1117
|
+
end
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
929
1121
|
end
|
930
|
-
end
|
1122
|
+
end
|