solutious-rudy 0.4.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.
@@ -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