solutious-rudy 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ require 'aws_sdb/error'
2
+ require 'aws_sdb/service'
3
+
@@ -0,0 +1,42 @@
1
+ module AwsSdb
2
+
3
+ class Error < RuntimeError ; end
4
+
5
+ class RequestError < Error
6
+ attr_reader :request_id
7
+
8
+ def initialize(message, request_id=nil)
9
+ super(message)
10
+ @request_id = request_id
11
+ end
12
+ end
13
+
14
+ class InvalidDomainNameError < RequestError ; end
15
+ class InvalidParameterValueError < RequestError ; end
16
+ class InvalidNextTokenError < RequestError ; end
17
+ class InvalidNumberPredicatesError < RequestError ; end
18
+ class InvalidNumberValueTestsError < RequestError ; end
19
+ class InvalidQueryExpressionError < RequestError ; end
20
+ class MissingParameterError < RequestError ; end
21
+ class NoSuchDomainError < RequestError ; end
22
+ class NumberDomainsExceededError < RequestError ; end
23
+ class NumberDomainAttributesExceededError < RequestError ; end
24
+ class NumberDomainBytesExceededError < RequestError ; end
25
+ class NumberItemAttributesExceededError < RequestError ; end
26
+ class RequestTimeoutError < RequestError ; end
27
+
28
+ class FeatureDeprecatedError < RequestError ; end
29
+
30
+ class ConnectionError < Error
31
+ attr_reader :response
32
+
33
+ def initialize(response)
34
+ super(
35
+ "#{response.code} \
36
+ #{response.message if response.respond_to?(:message)}"
37
+ )
38
+ @response = response
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,215 @@
1
+ require 'logger'
2
+ require 'time'
3
+ require 'cgi'
4
+ require 'uri'
5
+ require 'net/http'
6
+ require 'base64'
7
+ require 'openssl'
8
+ require 'rexml/document'
9
+ require 'rexml/xpath'
10
+
11
+ module AwsSdb
12
+
13
+ class Service
14
+ def initialize(options={})
15
+ @access_key_id = options[:access_key_id] || ENV['AMAZON_ACCESS_KEY_ID']
16
+ @secret_access_key = options[:secret_access_key] || ENV['AMAZON_SECRET_ACCESS_KEY']
17
+ @base_url = options[:url] || 'http://sdb.amazonaws.com'
18
+ @logger = options[:logger] || Logger.new("aws_sdb.log")
19
+ end
20
+
21
+ def list_domains(max = nil, token = nil)
22
+ params = { 'Action' => 'ListDomains' }
23
+ params['NextToken'] =
24
+ token unless token.nil? || token.empty?
25
+ params['MaxNumberOfDomains'] =
26
+ max.to_s unless max.nil? || max.to_i == 0
27
+ doc = call(:get, params)
28
+ results = []
29
+ REXML::XPath.each(doc, '//DomainName/text()') do |domain|
30
+ results << domain.to_s
31
+ end
32
+ return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
33
+ end
34
+
35
+ def create_domain(domain)
36
+ call(:post, { 'Action' => 'CreateDomain', 'DomainName'=> domain.to_s })
37
+ nil
38
+ end
39
+
40
+ def delete_domain(domain)
41
+ call(
42
+ :delete,
43
+ { 'Action' => 'DeleteDomain', 'DomainName' => domain.to_s }
44
+ )
45
+ nil
46
+ end
47
+ # <QueryWithAttributesResult><Item><Name>in-c2ffrw</Name><Attribute><Name>code</Name><Value>in-c2ffrw</Value></Attribute><Attribute><Name>date_created</Name><Value>2008-10-31</Value></Attribute></Item><Item>
48
+ def query_with_attributes(domain, query, max = nil, token = nil)
49
+ params = {
50
+ 'Action' => 'QueryWithAttributes',
51
+ 'QueryExpression' => query,
52
+ 'DomainName' => domain.to_s
53
+ }
54
+ params['NextToken'] =
55
+ token unless token.nil? || token.empty?
56
+ params['MaxNumberOfItems'] =
57
+ max.to_s unless max.nil? || max.to_i == 0
58
+
59
+ doc = call(:get, params)
60
+ results = []
61
+ REXML::XPath.each(doc, "//Item") do |item|
62
+ name = REXML::XPath.first(item, './Name/text()').to_s
63
+
64
+
65
+ attributes = {'Name' => name}
66
+ REXML::XPath.each(item, "./Attribute") do |attr|
67
+ key = REXML::XPath.first(attr, './Name/text()').to_s
68
+ value = REXML::XPath.first(attr, './Value/text()').to_s
69
+ ( attributes[key] ||= [] ) << value
70
+ end
71
+ results << attributes
72
+ end
73
+ return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
74
+ end
75
+
76
+ # <QueryResult><ItemName>in-c2ffrw</ItemName><ItemName>in-72yagt</ItemName><ItemName>in-52j8gj</ItemName>
77
+ def query(domain, query, max = nil, token = nil)
78
+ params = {
79
+ 'Action' => 'Query',
80
+ 'QueryExpression' => query,
81
+ 'DomainName' => domain.to_s
82
+ }
83
+ params['NextToken'] =
84
+ token unless token.nil? || token.empty?
85
+ params['MaxNumberOfItems'] =
86
+ max.to_s unless max.nil? || max.to_i == 0
87
+
88
+
89
+ doc = call(:get, params)
90
+ results = []
91
+ REXML::XPath.each(doc, '//ItemName/text()') do |item|
92
+ results << item.to_s
93
+ end
94
+ return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
95
+
96
+ end
97
+
98
+ def put_attributes(domain, item, attributes, replace = true)
99
+ params = {
100
+ 'Action' => 'PutAttributes',
101
+ 'DomainName' => domain.to_s,
102
+ 'ItemName' => item.to_s
103
+ }
104
+ count = 0
105
+ attributes.each do | key, values |
106
+ ([]<<values).flatten.each do |value|
107
+ params["Attribute.#{count}.Name"] = key.to_s
108
+ params["Attribute.#{count}.Value"] = value.to_s
109
+ params["Attribute.#{count}.Replace"] = replace
110
+ count += 1
111
+ end
112
+ end
113
+ call(:put, params)
114
+ nil
115
+ end
116
+
117
+ def get_attributes(domain, item)
118
+ doc = call(
119
+ :get,
120
+ {
121
+ 'Action' => 'GetAttributes',
122
+ 'DomainName' => domain.to_s,
123
+ 'ItemName' => item.to_s
124
+ }
125
+ )
126
+ attributes = {}
127
+ REXML::XPath.each(doc, "//Attribute") do |attr|
128
+ key = REXML::XPath.first(attr, './Name/text()').to_s
129
+ value = REXML::XPath.first(attr, './Value/text()').to_s
130
+ ( attributes[key] ||= [] ) << value
131
+ end
132
+ attributes
133
+ end
134
+
135
+ def delete_attributes(domain, item)
136
+ call(
137
+ :delete,
138
+ {
139
+ 'Action' => 'DeleteAttributes',
140
+ 'DomainName' => domain.to_s,
141
+ 'ItemName' => item.to_s
142
+ }
143
+ )
144
+ nil
145
+ end
146
+
147
+ def select(select, token = nil)
148
+ params = {
149
+ 'Action' => 'Select',
150
+ 'SelectExpression' => select,
151
+ }
152
+ params['NextToken'] =
153
+ token unless token.nil? || token.empty?
154
+
155
+ doc = call(:get, params)
156
+ results = []
157
+ REXML::XPath.each(doc, "//Item") do |item|
158
+ name = REXML::XPath.first(item, './Name/text()').to_s
159
+
160
+ attributes = {'Name' => name}
161
+ REXML::XPath.each(item, "./Attribute") do |attr|
162
+ key = REXML::XPath.first(attr, './Name/text()').to_s
163
+ value = REXML::XPath.first(attr, './Value/text()').to_s
164
+ ( attributes[key] ||= [] ) << value
165
+ end
166
+ results << attributes
167
+ end
168
+ return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
169
+ end
170
+
171
+ protected
172
+
173
+ def call(method, params)
174
+ params.merge!( {
175
+ 'Version' => '2007-11-07',
176
+ 'SignatureVersion' => '1',
177
+ 'AWSAccessKeyId' => @access_key_id,
178
+ 'Timestamp' => Time.now.gmtime.iso8601
179
+ }
180
+ )
181
+ data = ''
182
+ query = []
183
+ params.keys.sort_by { |k| k.upcase }.each do |key|
184
+ data << "#{key}#{params[key].to_s}"
185
+ query << "#{key}=#{CGI::escape(params[key].to_s)}"
186
+ end
187
+ digest = OpenSSL::Digest::Digest.new('sha1')
188
+ hmac = OpenSSL::HMAC.digest(digest, @secret_access_key, data)
189
+ signature = Base64.encode64(hmac).strip
190
+ query << "Signature=#{CGI::escape(signature)}"
191
+ query = query.join('&')
192
+ url = "#{@base_url}?#{query}"
193
+ uri = URI.parse(url)
194
+ @logger.debug("#{url}") if @logger
195
+ response =
196
+ Net::HTTP.new(uri.host, uri.port).send_request(method, uri.request_uri)
197
+ @logger.debug("#{response.code}\n#{response.body}") if @logger
198
+ raise(ConnectionError.new(response)) unless (200..400).include?(
199
+ response.code.to_i
200
+ )
201
+ doc = REXML::Document.new(response.body)
202
+ error = doc.get_elements('*/Errors/Error')[0]
203
+ raise(
204
+ Module.class_eval(
205
+ "AwsSdb::#{error.get_elements('Code')[0].text}Error"
206
+ ).new(
207
+ error.get_elements('Message')[0].text,
208
+ doc.get_elements('*/RequestID')[0].text
209
+ )
210
+ ) unless error.nil?
211
+ doc
212
+ end
213
+ end
214
+
215
+ end
@@ -0,0 +1,385 @@
1
+ #---
2
+ # Adapted from: http://github.com/oneup/ruby-console/tree/tput
3
+ # See: http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html
4
+ # See: man terminfo
5
+ #+++
6
+
7
+
8
+ class String
9
+
10
+ # +col+, +bgcol+, and +attribute+ are symbols corresponding
11
+ # to Console::COLOURS, Console::BGCOLOURS, and Console::ATTRIBUTES.
12
+ # Returns the string in the format attributes + string + defaults.
13
+ #
14
+ # "MONKEY_JUNK".colour(:blue, :white, :blink) # => "\e[34;47;5mMONKEY_JUNK\e[39;49;0m"
15
+ #
16
+ def colour(col, bgcol = nil, attribute = nil)
17
+ Console.style(col, bgcol, attribute) +
18
+ self +
19
+ Console.style(:default, :default, :default)
20
+ end
21
+ alias :color :colour
22
+
23
+ # See colour
24
+ def bgcolour(bgcol = :default)
25
+ Console.style(nil, bgcol, nil) +
26
+ self +
27
+ Console.style(nil, :default, nil)
28
+ end
29
+ alias :bgcolor :bgcolour
30
+
31
+ # See colour
32
+ def att(a = :default)
33
+ Console.style(nil, nil, a) +
34
+ self +
35
+ Console.style(nil, nil, :default)
36
+ end
37
+
38
+
39
+ # Print the string at +x+ +y+. When +minus+ is any true value
40
+ # the length of the string is subtracted from the value of x
41
+ # before printing.
42
+ def print_at(x=nil, y=nil, minus=false)
43
+ args = {:minus=>minus}
44
+ args[:x] &&= x
45
+ args[:y] &&= y
46
+ Console.print_at(self, args)
47
+ end
48
+
49
+ # Returns the string with escape code attributes removed.
50
+ # NOTE: The non-printable attributes count towards the string size.
51
+ # You can use this method to get the "visible" size:
52
+ #
53
+ # "\e[34;47;5mMONKEY_JUNK\e[39;49;0m".noatt.size # => 11
54
+ # "\e[34;47;5mMONKEY_JUNK\e[39;49;0m".size # => 31
55
+ #
56
+ def noatt
57
+ gsub(/\e\[[\d;]*m/, '')
58
+ end
59
+ end
60
+
61
+ class Object
62
+
63
+ # Executes tput +capnam+ with +args+. Returns true if tcap gives
64
+ # 0 exit status and false otherwise.
65
+ #
66
+ # tput :cup, 1, 4
67
+ # $ tput cup 1 4
68
+ #
69
+ def tput(capnam, *args)
70
+ system("tput #{capnam} #{args.flatten.join(' ')}")
71
+ end
72
+
73
+ # Executes tput +capnam+ with +args+. Returns the output of tput.
74
+ #
75
+ # tput_val :cols # => 16
76
+ # $ tput cols # => 16
77
+ #
78
+ def tput_val(capnam, *args)
79
+ `tput #{capnam} #{args.flatten.join(' ')}`.chomp
80
+ end
81
+ end
82
+
83
+
84
+
85
+ module Console
86
+ extend self
87
+ require 'timeout'
88
+ require 'thread'
89
+
90
+ # ANSI escape sequence numbers for text attributes
91
+ ATTRIBUTES = {
92
+ :normal => 0,
93
+ :bright => 1,
94
+ :dim => 2,
95
+ :underline => 4,
96
+ :blink => 5,
97
+ :reverse => 7,
98
+ :hidden => 8,
99
+ :default => 0,
100
+ }.freeze unless defined? ATTRIBUTES
101
+
102
+ # ANSI escape sequence numbers for text colours
103
+ COLOURS = {
104
+ :black => 30,
105
+ :red => 31,
106
+ :green => 32,
107
+ :yellow => 33,
108
+ :blue => 34,
109
+ :magenta => 35,
110
+ :cyan => 36,
111
+ :white => 37,
112
+ :default => 39,
113
+ :random => 30 + rand(10).to_i
114
+ }.freeze unless defined? COLOURS
115
+
116
+ # ANSI escape sequence numbers for background colours
117
+ BGCOLOURS = {
118
+ :black => 40,
119
+ :red => 41,
120
+ :green => 42,
121
+ :yellow => 43,
122
+ :blue => 44,
123
+ :magenta => 45,
124
+ :cyan => 46,
125
+ :white => 47,
126
+ :default => 49,
127
+ :random => 40 + rand(10).to_i
128
+ }.freeze unless defined? BGCOLOURS
129
+
130
+
131
+ def print_left(str, props={})
132
+ props[:x] ||= 0
133
+ props[:y] ||= Cursor.y
134
+ # print_at("x:#{props[:x]} y:#{props[:y]}", {:x => 0, :y => 10})
135
+ print_at(str, props)
136
+ end
137
+ def print_right(str, props={})
138
+ props[:x] ||= width
139
+ props[:y] ||= Cursor.y
140
+ props[:minus] = true unless props.has_key?(:minus)
141
+ print_at(str, props)
142
+ end
143
+ def print_spaced(*args)
144
+ props = (args.last.is_a? Hash) ? args.pop : {}
145
+ props[:y] = Cursor.y
146
+ chunk_width = (width / args.flatten.size).to_i
147
+ chunk_at = 0
148
+ args.each do |chunk|
149
+ props[:x] = chunk_at
150
+ print_at(chunk.to_s[0, chunk_width], props)
151
+ chunk_at += chunk_width
152
+ end
153
+ puts
154
+ end
155
+ def print_center(str, props={})
156
+ props[:x] = ((width - str.noatt.length) / 2).to_i-1
157
+ props[:y] ||= height
158
+ print_at(str, props)
159
+ end
160
+ def print_at(str, props={})
161
+ print_at_lamb = lambda {
162
+ #props[:x] ||= 0
163
+ #props[:y] ||= 0
164
+ props[:minus] = false unless props.has_key?(:minus)
165
+ props[:x] = props[:x]-str.noatt.size if props[:x] && props[:minus] # Subtract the str length from the position
166
+ Cursor.save
167
+ Cursor.move = 0
168
+ print str
169
+ Cursor.restore
170
+ }
171
+ RUBY_VERSION =~ /1.9/ ? Thread.exclusive(&print_at_lamb) : print_at_lamb.call
172
+ end
173
+
174
+ def self.style(col, bgcol=nil, att=nil)
175
+ valdor = []
176
+ valdor << COLOURS[col] if COLOURS.has_key?(col)
177
+ valdor << BGCOLOURS[bgcol] if BGCOLOURS.has_key?(bgcol)
178
+ valdor << ATTRIBUTES[att] if ATTRIBUTES.has_key?(att)
179
+ "\e[#{valdor.join(";")}m" # => \e[8;34;42m
180
+ end
181
+
182
+ def self.clear
183
+ tput :clear
184
+ end
185
+
186
+ def reset
187
+ tput :reset
188
+ end
189
+
190
+ def width
191
+ tput_val(:cols).to_i
192
+ end
193
+
194
+ def height
195
+ tput_val(:lines).to_i
196
+ end
197
+ end
198
+
199
+ module Cursor
200
+ extend self
201
+
202
+ # Returns [x,y] for the current cursor position.
203
+ def position
204
+ yx = [0,0]
205
+
206
+ position_lamb = lambda {
207
+ begin
208
+ # NOTE: Can we get cursor position from tput?
209
+ termsettings = `stty -g`
210
+
211
+ # DEBUGGING: The following code works in Ruby 1.9 but not 1.8.
212
+
213
+ system("stty raw -echo")
214
+ print "\e[6n" # Forces output of: \e[49;1R (\e is not printable)
215
+ c = ''
216
+ (pos ||= '') << c while (c = STDIN.getc) != 'R'# NOTE: There must be a better way!
217
+ yx = pos.scan(/(\d+);(\d+)/).flatten
218
+ yx[0] = yx[0].to_i - 1 # It returns 1 for the first column, but we want 0
219
+ yx[1] = yx[1].to_i - 1
220
+ ensure
221
+ system("stty #{termsettings}") # Get out of raw mode
222
+ end
223
+ }
224
+
225
+ RUBY_VERSION =~ /1.9/ ? Thread.exclusive(&position_lamb) : position_lamb.call
226
+ yx.reverse
227
+ end
228
+
229
+ def x; position[0]; end
230
+ def y; position[1]; end
231
+
232
+ def move=(*args)
233
+ x,y = *args.flatten
234
+ tput(:cup, y, x) # "tput cup" takes y before x
235
+ end
236
+
237
+ def up(n=1)
238
+ tput :cuu, n
239
+ end
240
+
241
+ def down(n=1)
242
+ tput :cud, n
243
+ end
244
+
245
+ def right(x=1)
246
+ tput :cuf, x
247
+ end
248
+
249
+ def left(x=1)
250
+ tput :cub, x
251
+ end
252
+
253
+ def line(n=1)
254
+ tput :il, n
255
+ end
256
+
257
+ def save
258
+ tput :sc
259
+ end
260
+
261
+ def restore
262
+ tput :rc
263
+ end
264
+
265
+ def clear_line
266
+ tput :el
267
+ end
268
+
269
+ # TODO: replace methods with this kinda thing
270
+ #@@capnames = {
271
+ # :restore => [:rc],
272
+ # :save => [:sc],
273
+ # :clear_line => [:el],
274
+ # :line => [:il, 1, 1],
275
+ #
276
+ # :up => [:cuu, 1, 1],
277
+ # :down => [:cud, 1, 1],
278
+ # :right => [:cuf, 1, 1],
279
+ # :left => [:cub, 1, 1],
280
+ #
281
+ # :move => [:cup, 2, 0, 0]
282
+ #}
283
+ #
284
+ #@@capnames.each_pair do |meth, cap|
285
+ # module_eval <<-RUBY
286
+ # def #{meth}(*args)
287
+ # tput '#{cap[0]}'
288
+ # end
289
+ # RUBY
290
+ #end
291
+
292
+ end
293
+
294
+ class Window
295
+ attr_accessor :row, :col, :width, :height, :text, :fg, :bg
296
+ attr_reader :threads
297
+
298
+ def initialize(*args)
299
+ @row = 1
300
+ @col = 1
301
+ @width = 10
302
+ @height = 5
303
+ @text = ""
304
+ @fg = :default
305
+ @bg = :default
306
+ @threads = []
307
+ end
308
+
309
+ def position=(x,y=nil)
310
+ @x = x
311
+ @y = y if y
312
+ end
313
+
314
+ def position
315
+ [@row, @col]
316
+ end
317
+
318
+ def self.bar(len, unit='=')
319
+ unit*len
320
+ end
321
+
322
+
323
+ # Execute the given block every +n+ seconds in a separate thread.
324
+ # The lower limit for +n+ is 1 second.
325
+ # Returns a Thread object.
326
+ def every_n_seconds(n)
327
+ #n = 1 if n < 1
328
+ thread = Thread.new do
329
+
330
+ begin
331
+ while true
332
+ before = Time.now
333
+ yield
334
+ interval = n - (Time.now - before)
335
+ sleep(interval) if interval > 0
336
+ end
337
+ rescue Interrupt
338
+ break
339
+ ensure
340
+ thread
341
+ end
342
+ end
343
+ end
344
+
345
+ # Print text to the screen via +type+ every +refresh+ seconds.
346
+ # Print the return value of the block to the screen using the
347
+ # print_+type+ method. +refresh+ is number of seconds to wait
348
+ # +props+ is the hash sent to print_+type+.
349
+ # Returns a Thread object.
350
+ #
351
+ # # Print the time in the upper right corner every second
352
+ # thread1 = Console.static(:right, 1, {:y => 0}) do
353
+ # Time.now.utc.strftime("%Y-%m-%d %H:%M:%S").colour(:blue, :white, :underline)
354
+ # end
355
+ #
356
+ def static(type, refresh=2, props={}, &b)
357
+ meth = "print_#{type}"
358
+ raise "#{meth} is not supported" unless Console.respond_to?(meth)
359
+
360
+ refresh ||= 0
361
+ refreh = refresh.to_s.to_i
362
+
363
+ thread = every_n_seconds(refresh) do
364
+ Console.send(meth, b.call, props.clone)
365
+ end
366
+
367
+ @threads << thread
368
+
369
+ thread
370
+ end
371
+
372
+ def join_threads
373
+ begin
374
+ @threads.each do |t|
375
+ t.join
376
+ end
377
+ rescue Interrupt
378
+ ensure
379
+ @threads.each do |t|
380
+ t.kill
381
+ end
382
+ end
383
+ end
384
+
385
+ end