right_aws 1.10.0 → 2.0.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.
- 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
|