imw 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/.gitignore +15 -0
  2. data/CHANGELOG +0 -0
  3. data/LICENSE +674 -0
  4. data/README.rdoc +101 -0
  5. data/Rakefile +20 -0
  6. data/VERSION +1 -0
  7. data/etc/imwrc.rb +76 -0
  8. data/lib/imw.rb +42 -0
  9. data/lib/imw/boot.rb +58 -0
  10. data/lib/imw/dataset.rb +233 -0
  11. data/lib/imw/dataset/datamapper.rb +66 -0
  12. data/lib/imw/dataset/datamapper/time_and_user_stamps.rb +37 -0
  13. data/lib/imw/dataset/loaddump.rb +50 -0
  14. data/lib/imw/dataset/old/file_collection.rb +88 -0
  15. data/lib/imw/dataset/old/file_collection_utils.rb +71 -0
  16. data/lib/imw/dataset/scaffold.rb +132 -0
  17. data/lib/imw/dataset/scraped_uri.rb +305 -0
  18. data/lib/imw/dataset/scrub/old_working_scrubber.rb +87 -0
  19. data/lib/imw/dataset/scrub/scrub.rb +147 -0
  20. data/lib/imw/dataset/scrub/scrub_simple_url.rb +38 -0
  21. data/lib/imw/dataset/scrub/scrub_test.rb +60 -0
  22. data/lib/imw/dataset/scrub/slug.rb +101 -0
  23. data/lib/imw/dataset/stats.rb +73 -0
  24. data/lib/imw/dataset/stats/counter.rb +23 -0
  25. data/lib/imw/dataset/task.rb +38 -0
  26. data/lib/imw/dataset/workflow.rb +81 -0
  27. data/lib/imw/files.rb +110 -0
  28. data/lib/imw/files/archive.rb +113 -0
  29. data/lib/imw/files/basicfile.rb +122 -0
  30. data/lib/imw/files/binary.rb +28 -0
  31. data/lib/imw/files/compressed_file.rb +93 -0
  32. data/lib/imw/files/compressed_files_and_archives.rb +348 -0
  33. data/lib/imw/files/compressible.rb +103 -0
  34. data/lib/imw/files/csv.rb +112 -0
  35. data/lib/imw/files/json.rb +41 -0
  36. data/lib/imw/files/sgml.rb +65 -0
  37. data/lib/imw/files/text.rb +68 -0
  38. data/lib/imw/files/yaml.rb +46 -0
  39. data/lib/imw/packagers.rb +8 -0
  40. data/lib/imw/packagers/archiver.rb +108 -0
  41. data/lib/imw/packagers/s3_mover.rb +28 -0
  42. data/lib/imw/parsers.rb +7 -0
  43. data/lib/imw/parsers/html_parser.rb +382 -0
  44. data/lib/imw/parsers/html_parser/matchers.rb +306 -0
  45. data/lib/imw/parsers/line_parser.rb +87 -0
  46. data/lib/imw/parsers/regexp_parser.rb +72 -0
  47. data/lib/imw/utils.rb +24 -0
  48. data/lib/imw/utils/components.rb +61 -0
  49. data/lib/imw/utils/config.rb +46 -0
  50. data/lib/imw/utils/error.rb +54 -0
  51. data/lib/imw/utils/extensions/array.rb +125 -0
  52. data/lib/imw/utils/extensions/class/attribute_accessors.rb +8 -0
  53. data/lib/imw/utils/extensions/core.rb +43 -0
  54. data/lib/imw/utils/extensions/dir.rb +24 -0
  55. data/lib/imw/utils/extensions/file_core.rb +64 -0
  56. data/lib/imw/utils/extensions/hash.rb +218 -0
  57. data/lib/imw/utils/extensions/hpricot.rb +48 -0
  58. data/lib/imw/utils/extensions/string.rb +49 -0
  59. data/lib/imw/utils/extensions/struct.rb +42 -0
  60. data/lib/imw/utils/extensions/symbol.rb +28 -0
  61. data/lib/imw/utils/extensions/typed_struct.rb +22 -0
  62. data/lib/imw/utils/extensions/uri.rb +59 -0
  63. data/lib/imw/utils/log.rb +67 -0
  64. data/lib/imw/utils/misc.rb +63 -0
  65. data/lib/imw/utils/paths.rb +115 -0
  66. data/lib/imw/utils/uri.rb +59 -0
  67. data/lib/imw/utils/uuid.rb +33 -0
  68. data/lib/imw/utils/validate.rb +38 -0
  69. data/lib/imw/utils/version.rb +12 -0
  70. data/lib/imw/utils/view.rb +113 -0
  71. data/lib/imw/utils/view/dump_csv.rb +112 -0
  72. data/lib/imw/utils/view/dump_csv_older.rb +117 -0
  73. data/spec/data/sample.csv +131 -0
  74. data/spec/data/sample.tsv +131 -0
  75. data/spec/data/sample.txt +131 -0
  76. data/spec/data/sample.xml +653 -0
  77. data/spec/data/sample.yaml +652 -0
  78. data/spec/imw/dataset/datamapper/uri_spec.rb +43 -0
  79. data/spec/imw/dataset/datamapper_spec_helper.rb +11 -0
  80. data/spec/imw/files/archive_spec.rb +118 -0
  81. data/spec/imw/files/basicfile_spec.rb +121 -0
  82. data/spec/imw/files/bz2_spec.rb +32 -0
  83. data/spec/imw/files/compressed_file_spec.rb +96 -0
  84. data/spec/imw/files/compressible_spec.rb +100 -0
  85. data/spec/imw/files/file_spec.rb +144 -0
  86. data/spec/imw/files/gz_spec.rb +32 -0
  87. data/spec/imw/files/rar_spec.rb +33 -0
  88. data/spec/imw/files/tar_spec.rb +31 -0
  89. data/spec/imw/files/text_spec.rb +23 -0
  90. data/spec/imw/files/zip_spec.rb +31 -0
  91. data/spec/imw/files_spec.rb +38 -0
  92. data/spec/imw/packagers/archiver_spec.rb +125 -0
  93. data/spec/imw/packagers/s3_mover_spec.rb +7 -0
  94. data/spec/imw/parsers/line_parser_spec.rb +96 -0
  95. data/spec/imw/parsers/regexp_parser_spec.rb +42 -0
  96. data/spec/imw/utils/extensions/file_core_spec.rb +72 -0
  97. data/spec/imw/utils/extensions/find_spec.rb +113 -0
  98. data/spec/imw/utils/paths_spec.rb +38 -0
  99. data/spec/imw/workflow/rip/local_spec.rb +89 -0
  100. data/spec/imw/workflow/rip_spec.rb +27 -0
  101. data/spec/rcov.opts +1 -0
  102. data/spec/spec.opts +4 -0
  103. data/spec/spec_helper.rb +32 -0
  104. data/spec/support/archive_contents_matcher.rb +94 -0
  105. data/spec/support/custom_matchers.rb +21 -0
  106. data/spec/support/directory_contents_matcher.rb +61 -0
  107. data/spec/support/extensions.rb +18 -0
  108. data/spec/support/file_contents_matcher.rb +50 -0
  109. data/spec/support/random.rb +210 -0
  110. data/spec/support/without_regard_to_order_matcher.rb +58 -0
  111. metadata +196 -0
@@ -0,0 +1,218 @@
1
+ #
2
+ # h2. lib/imw/utils/extensions/hash.rb -- hash extensions
3
+ #
4
+ # == About
5
+ #
6
+ # Extensions to the built-in +Hash+ class.
7
+ #
8
+ # Author:: (Philip flip Kromer, Dhruv Bansal) for Infinite Monkeywrench Project (mailto:coders@infochimps.org)
9
+ # Copyright:: Copyright (c) 2008 infochimps.org
10
+ # License:: GPL 3.0
11
+ # Website:: http://infinitemonkeywrench.org/
12
+ #
13
+
14
+ require 'active_support/core_ext/hash/reverse_merge'
15
+
16
+ class Hash
17
+ # Return the elements of this hash in a pretty-printed string,
18
+ # inserting +final_string+ between the last two items.
19
+ #
20
+ # >> {:one => 1, :two => 2, :three => 3}.quote_keys_with "or"
21
+ # `one', `two', or `three'
22
+ #
23
+ def quote_keys_with final_string = nil
24
+ self.keys.quote_items_with final_string
25
+ end
26
+
27
+ # Stolen from ActiveSupport::CoreExtensions::Hash::ReverseMerge.
28
+ def reverse_merge(other_hash)
29
+ other_hash.merge(self)
30
+ end
31
+
32
+ # Stolen from ActiveSupport::CoreExtensions::Hash::ReverseMerge.
33
+ def reverse_merge!(other_hash)
34
+ replace(reverse_merge(other_hash))
35
+ end
36
+
37
+ # Create a hash from an array of keys and corresponding values.
38
+ def self.zip(keys, values, default=nil, &block)
39
+ hash = block_given? ? Hash.new(&block) : Hash.new(default)
40
+ keys.zip(values) { |k,v| hash[k]=v }
41
+ hash
42
+ end
43
+
44
+ # Turns a collection of pairs into a hash. The first of each pair
45
+ # make the keys and the second the values. Elements with length
46
+ # longer than two will lose those values.
47
+ #
48
+ # If there are multiple values of
49
+ #
50
+ def from_pairs()
51
+ hsh = { }
52
+ self.each{ |k,v| hsh[k] = v }
53
+ hsh
54
+ end
55
+
56
+ # Merges self with another hash, recursively.
57
+ #
58
+ # first = {
59
+ # :balls=> "monkey",
60
+ # :data=> {
61
+ # :name=> {:first=> "Sam", :middle=>"I", :last=>"am"}}}
62
+ # second = {
63
+ # :data=> {
64
+ # :name=> {:middle=>["you", "me", "everyone we know"], :last => "are"}},
65
+ # 1 => [1,2,5] }
66
+ #
67
+ # p first.deep_merge(second)
68
+ # # => {:data=>{:name=>{:last=>"are", :middle=>["you", "me", "everyone we know"], :first=>"Sam"}}, 1=>[1, 2, 5], :balls=>"monkey"}
69
+ # from http://snippets.dzone.com/posts/show/4706
70
+ # From: http://pastie.textmate.org/pastes/30372, Elliott Hird
71
+ def deep_merge(second)
72
+ target = dup
73
+ second.keys.each do |key|
74
+ if second[key].is_a?(Hash) && self[key].is_a?(Hash)
75
+ target[key] = target[key].deep_merge(second[key])
76
+ else
77
+ target[key] = second[key]
78
+ end
79
+ end
80
+ target
81
+ end
82
+
83
+ # Merges self in-place with another hash, recursively.
84
+ #
85
+ # first = {
86
+ # :balls=> "monkey",
87
+ # :data=> {
88
+ # :name=> {:first=> "Sam", :middle=>"I", :last=>"am"}}}
89
+ # second = {
90
+ # :data=> {
91
+ # :name=> {:middle=>["you", "me", "everyone we know"], :last => "are"}},
92
+ # 1 => [1,2,5] }
93
+ #
94
+ # p first.deep_merge(second)
95
+ # # => {:data=>{:name=>{:last=>"are", :middle=>["you", "me", "everyone we know"], :first=>"Sam"}}, 1=>[1, 2, 5], :balls=>"monkey"}
96
+ #
97
+ # From: http://www.gemtacular.com/gemdocs/cerberus-0.2.2/doc/classes/Hash.html
98
+ # File lib/cerberus/utils.rb, line 42
99
+ def deep_merge!(second)
100
+ second.keys.each do |key|
101
+ if second[key].is_a?(Hash) && self[key].is_a?(Hash)
102
+ self[key].deep_merge!(second[key])
103
+ else
104
+ self[key] = second[key]
105
+ end
106
+ end
107
+ self
108
+ end
109
+
110
+ # Merge another array with this one, accumulating values that appear in both
111
+ # into arrays.
112
+ #
113
+ # Note: array values will be flatten'ed. Sorry.
114
+ #
115
+ # first = {
116
+ # :balls=> "monkey",
117
+ # :data=> {
118
+ # :name=> {:first=> "Sam", :middle=>"I", :last=>"am"}}}
119
+ # second = {
120
+ # :data=> {
121
+ # :name=> {:middle=>["you", "me", "everyone we know"], :last => "are"}},
122
+ # 1 => [1,2,5] }
123
+ #
124
+ # p first.deep_merge(second)
125
+ # # => {:data=>{:name=>{:last=>"are", :middle=>["you", "me", "everyone we know"], :first=>"Sam"}}, 1=>[1, 2, 5], :balls=>"monkey"}
126
+ # p first.keep_merge(second)
127
+ # # => {:data=>{:name=>{:last=>["am", "are"], :middle=>["I", "you", "me", "everyone we know"], :first=>"Sam"}}, 1=>[1, 2, 5], :balls=>"monkey"}
128
+ def keep_merge(second)
129
+ target = dup
130
+ second.each do |key, val2|
131
+ if second[key].is_a?(Hash) && self[key].is_a?(Hash)
132
+ target[key] = target[key].keep_merge(val2)
133
+ else
134
+ target[key] = target.include?(key) ? [target[key], val2].flatten.uniq : val2
135
+ end
136
+ end
137
+ target
138
+ end
139
+
140
+ # This is polymorphic to Array#assoc -- that is, it allows you treat a Hash
141
+ # and an array of pairs equivalently using assoc(). We remind you that Array#assoc
142
+ #
143
+ # "Searches through an array whose elements are also arrays comparing obj
144
+ # with the first element of each contained array using obj.== . Returns the
145
+ # first contained array that matches (that is, the first associated array)
146
+ # or nil if no match is found. See also Array#rassoc."
147
+ #
148
+ # Note that this returns an /array/ of [key, val] pairs.
149
+ def assoc(key)
150
+ self.include?(key) ? [key, self[key]] : nil
151
+ end
152
+ def rassoc(key)
153
+ self.has_value?(key) ? [key, self[key]] : nil
154
+ end
155
+
156
+ # Allows loading ostruct directly from YAML
157
+ def to_openstruct
158
+ map{ |el| el.to_openstruct }
159
+ end
160
+
161
+
162
+ # Slice a hash to include only the given keys. This is useful for
163
+ # limiting an options hash to valid keys before passing to a method:
164
+ #
165
+ # def search(criteria = {})
166
+ # assert_valid_keys(:mass, :velocity, :time)
167
+ # end
168
+ #
169
+ # search(options.slice(:mass, :velocity, :time))
170
+ # Returns a new hash with only the given keys.
171
+ def slice(*keys)
172
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
173
+ reject { |key,| !allowed.include?(key) }
174
+ end
175
+
176
+ # Replaces the hash with only the given keys.
177
+ def slice!(*keys)
178
+ replace(slice(*keys))
179
+ end
180
+
181
+ # remove all key-value pairs where the value is nil
182
+ def compact
183
+ reject{|k,v| v.nil? }
184
+ end
185
+
186
+ # Replaces the hash with its compacted self
187
+ def compact!
188
+ replace(compact)
189
+ end
190
+
191
+ # Works like <tt>Enumerable::find</tt> but loops over the keys of
192
+ # this Hash instead of of arrays of [key,value] and, in the absence
193
+ # of a matching key, doesn't call the default argument, merely
194
+ # returns it instead.
195
+ def dispatch(default=nil, &block)
196
+ match = self.keys.find(nil,&block)
197
+ match ? self[match] : default
198
+ end
199
+
200
+
201
+ # Recurses through the pairs of this Hash collecting all String or
202
+ # Symbol "terminal" nodes.
203
+ def terminals &block
204
+ terminals = []
205
+ each_value do |value|
206
+ if value.respond_to? :terminals then
207
+ terminals += value.terminals
208
+ else
209
+ terminals << value
210
+ end
211
+ end
212
+ terminals.map! {|terminal| yield terminal } if block
213
+ terminals
214
+ end
215
+
216
+ end
217
+
218
+ # puts "#{File.basename(__FILE__)}: To each improvement there corresponds another, yes?" # at bottom
@@ -0,0 +1,48 @@
1
+ #
2
+ # h2. lib/imw/utils/extensions/hpricot.rb -- extensions to hpricot
3
+ #
4
+ # == About
5
+ #
6
+ # Some IMW extensions for Why's Hpricot library.
7
+ #
8
+ # Author:: (Philip flip Kromer, Dhruv Bansal) for Infinite Monkeywrench Project (mailto:coders@infochimps.org)
9
+ # Copyright:: Copyright (c) 2008 infochimps.org
10
+ # License:: GPL 3.0
11
+ # Website:: http://infinitemonkeywrench.org/
12
+ #
13
+ # puts "#{File.basename(__FILE__)}: Something clever" # at bottom
14
+
15
+ require 'hpricot'
16
+
17
+ module Hpricot::IMWExtensions
18
+
19
+ # Return the contents of the first element to match +path+.
20
+ def contents_of path
21
+ cnts = self.at path
22
+ cnts.inner_html if cnts
23
+ end
24
+
25
+ # Return the value of +attr+ for the first element to match +path+.
26
+ def path_attr path, attr
27
+ cnts = self.at path
28
+ cnts.attributes[attr] if cnts
29
+ end
30
+
31
+ # Return the value of the +class+ attribute of the first element to
32
+ # match +path+.
33
+ def class_of path
34
+ self.path_attr(path, 'class')
35
+ end
36
+ end
37
+
38
+ class Hpricot::Elem
39
+ include Hpricot::IMWExtensions
40
+ end
41
+
42
+ class Hpricot::Elements
43
+ include Hpricot::IMWExtensions
44
+ end
45
+
46
+ class Hpricot::Doc
47
+ include Hpricot::IMWExtensions
48
+ end
@@ -0,0 +1,49 @@
1
+ #
2
+ # h2. lib/imw/utils/extensions/string.rb -- string extensions
3
+ #
4
+ # == About
5
+ #
6
+ # Implements some useful extensions to the +String+ class.
7
+ #
8
+ # Author:: (Philip flip Kromer, Dhruv Bansal) for Infinite Monkeywrench Project (mailto:coders@infochimps.org)
9
+ # Copyright:: Copyright (c) 2008 infochimps.org
10
+ # License:: GPL 3.0
11
+ # Website:: http://infinitemonkeywrench.org/
12
+ #
13
+
14
+ class String
15
+
16
+ # Does the string end with the specified +suffix+ (stolen from
17
+ # <tt>ActiveSupport::CoreExtensions::String::StartsEndsWith</tt>)?
18
+ def ends_with?(suffix)
19
+ suffix = suffix.to_s
20
+ self[-suffix.length, suffix.length] == suffix
21
+ end
22
+
23
+ # Does the string start with the specified +prefix+ (stolen from
24
+ # <tt>ActiveSupport::CoreExtensions::String::StartsEndsWith</tt>)?
25
+ def starts_with?(prefix)
26
+ prefix = prefix.to_s
27
+ self[0, prefix.length] == prefix
28
+ end
29
+
30
+ # # Downcases a string and replaces spaces with underscores. This
31
+ # # works slightly differently than
32
+ # # <tt>ActiveSupport::CoreExtensions::String::Inflections.underscore</tt>
33
+ # # which is intended to be used for camel-cased Ruby constants.
34
+ # #
35
+ # # "A long and unwieldy phrase".underscore #=> "a_long_and_unwieldy_phrase"
36
+ # def underscore
37
+ # self.to_s.tr("-", "_").tr(" ","_").downcase
38
+ # end
39
+
40
+ # Returns the handle corresponding to this string as a symbol:
41
+ #
42
+ # "A possible title of a dataset".handle #=> :a_possible_title_of_a_dataset
43
+ def to_handle
44
+ self.downcase.underscore.to_sym
45
+ end
46
+
47
+ end
48
+
49
+ # puts "#{File.basename(__FILE__)}: You tie a long string to your Monkeywrench, place it on the ground, and hide around the corner with the string in your hand, waiting for passersby to try and make a grab for it." # at bottom
@@ -0,0 +1,42 @@
1
+ Struct.class_eval do
2
+ def slice *attrs
3
+ hsh = {}
4
+ attrs.each{|attr| hsh[attr] = self.send(attr) }
5
+ hsh
6
+ end
7
+
8
+ def to_hash
9
+ slice(*self.class.members)
10
+ end
11
+ def self.from_hash(hsh)
12
+ self.new *hsh.values_at(*self.members.map(&:to_sym))
13
+ end
14
+
15
+
16
+ #
17
+ # values_at like a hash
18
+ #
19
+ def values_of *attrs
20
+ slice(*attrs).values_at(*attrs)
21
+ end
22
+ def each_pair *args, &block
23
+ self.to_hash.each_pair(*args, &block)
24
+ end
25
+
26
+ def merge *args
27
+ self.dup.merge! *args
28
+ end
29
+ def merge! hashlike, &block
30
+ raise "can't handle block arg yet" if block
31
+ hashlike.each_pair{|k,v| self[k] = v }
32
+ self
33
+ end
34
+ alias_method :update, :merge!
35
+ def indifferent_merge *args, &block
36
+ self.dup.indifferent_merge! *args
37
+ end
38
+ def indifferent_merge! hashlike, &block
39
+ merge! hashlike.reject{|k,v| ! self.members.include?(k.to_s) }
40
+ end
41
+
42
+ end
@@ -0,0 +1,28 @@
1
+ #
2
+ # h2. lib/imw/utils/extensions/symbol.rb -- extensions to symbol class
3
+ #
4
+ # == About
5
+ #
6
+ # Author:: (Philip flip Kromer, Dhruv Bansal) for Infinite Monkeywrench Project (mailto:coders@infochimps.org)
7
+ # Copyright:: Copyright (c) 2008 infochimps.org
8
+ # License:: GPL 3.0
9
+ # Website:: http://infinitemonkeywrench.org/
10
+ #
11
+
12
+ class Symbol
13
+
14
+ # Turn the symbol into a simple proc (stolen from
15
+ # <tt>ActiveSupport::CoreExtensions::Symbol</tt>).
16
+ def to_proc
17
+ Proc.new { |*args| args.shift.__send__(self, *args) }
18
+ end
19
+
20
+ # Returns the symbol itself (for compatibility with
21
+ # <tt>String.uniqnae</tt> and so on.
22
+ def handle
23
+ self
24
+ end
25
+
26
+ end
27
+
28
+ # puts "#{File.basename(__FILE__)}: You whisper a word of power and smile as the the Ruby Palace thunders with the sound of falling blocks." # at bottom
@@ -0,0 +1,22 @@
1
+ #
2
+ # A struct
3
+ # but has an idea of what type attributes should be
4
+ #
5
+ #
6
+ class TypedStruct < Struct
7
+ def self.new attrs, convs
8
+ struct = super *attrs
9
+ struct_attr_convs = Hash.zip(attrs, convs).reject{|a,t| t.nil? }
10
+ struct.class_eval do
11
+ cattr_accessor :attr_convs
12
+ self.attr_convs = struct_attr_convs
13
+ def remap!
14
+ attr_convs.each do |attr, conv|
15
+ curr = self.send(attr)
16
+ self.send("#{attr}=", curr.send(conv)) if curr.respond_to?(conv)
17
+ end
18
+ end
19
+ end # class_eval
20
+ struct
21
+ end
22
+ end
@@ -0,0 +1,59 @@
1
+ #
2
+ # h2. lib/imw/utils/extensions/uri.rb -- extensions to uri module
3
+ #
4
+ # == About
5
+ #
6
+ # Some useful extensions to the +URI+ module.
7
+ #
8
+ # Author:: (Philip flip Kromer, Dhruv Bansal) for Infinite Monkeywrench Project (mailto:coders@infochimps.org)
9
+ # Copyright:: Copyright (c) 2008 infochimps.org
10
+ # License:: GPL 3.0
11
+ # Website:: http://infinitemonkeywrench.org/
12
+ #
13
+
14
+ require 'uri'
15
+
16
+ module URI
17
+
18
+ # List of prefixes ignored when returning domains (or reversed
19
+ # domains).
20
+ IGNORED_PREFIXES = ['www']
21
+
22
+ # Returns the domain of the given URI, first scrubbing it of any
23
+ # prefixes we can ignore.
24
+ def self.domain(uri)
25
+ uriobj = self.parse(uri)
26
+ if uriobj.host then
27
+ host = uriobj.host
28
+ elsif uriobj.path then
29
+ host = uriobj.path.split('/')[0]
30
+ else
31
+ raise ArgumentError, "Invalid URI: #{uri}"
32
+ end
33
+ # remove any ignored prefixes from the hostname (i.e. - 'www')
34
+ parts = host.split('.')
35
+ parts = (IGNORED_PREFIXES.member?(parts[0]) ? parts[1...parts.size] : parts)
36
+ host = parts.join('.')
37
+ host
38
+ end
39
+
40
+ # Returns the reversed domain of the given URI, first scrubbing it of
41
+ # any prefixes we can ignore. Will not reverse numeric addresses of
42
+ # the form 127.0.0.1
43
+ def self.reverse_domain(uri)
44
+ begin
45
+ d = self.domain(uri)
46
+ # check for numeric ip
47
+ # in a TERRIBLE way that needs to be fixed!`
48
+ if d=~/^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$/ then
49
+ return d
50
+ else
51
+ return d.split('.').reverse.join('.')
52
+ end
53
+ rescue URI::InvalidURIError,ArgumentError
54
+ raise $!
55
+ end
56
+ end
57
+ end
58
+
59
+ # puts "#{File.basename(__FILE__)}: In the end, it's either you or I." # at bottom