imw 0.1.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/.gitignore +15 -0
- data/CHANGELOG +0 -0
- data/LICENSE +674 -0
- data/README.rdoc +101 -0
- data/Rakefile +20 -0
- data/VERSION +1 -0
- data/etc/imwrc.rb +76 -0
- data/lib/imw.rb +42 -0
- data/lib/imw/boot.rb +58 -0
- data/lib/imw/dataset.rb +233 -0
- data/lib/imw/dataset/datamapper.rb +66 -0
- data/lib/imw/dataset/datamapper/time_and_user_stamps.rb +37 -0
- data/lib/imw/dataset/loaddump.rb +50 -0
- data/lib/imw/dataset/old/file_collection.rb +88 -0
- data/lib/imw/dataset/old/file_collection_utils.rb +71 -0
- data/lib/imw/dataset/scaffold.rb +132 -0
- data/lib/imw/dataset/scraped_uri.rb +305 -0
- data/lib/imw/dataset/scrub/old_working_scrubber.rb +87 -0
- data/lib/imw/dataset/scrub/scrub.rb +147 -0
- data/lib/imw/dataset/scrub/scrub_simple_url.rb +38 -0
- data/lib/imw/dataset/scrub/scrub_test.rb +60 -0
- data/lib/imw/dataset/scrub/slug.rb +101 -0
- data/lib/imw/dataset/stats.rb +73 -0
- data/lib/imw/dataset/stats/counter.rb +23 -0
- data/lib/imw/dataset/task.rb +38 -0
- data/lib/imw/dataset/workflow.rb +81 -0
- data/lib/imw/files.rb +110 -0
- data/lib/imw/files/archive.rb +113 -0
- data/lib/imw/files/basicfile.rb +122 -0
- data/lib/imw/files/binary.rb +28 -0
- data/lib/imw/files/compressed_file.rb +93 -0
- data/lib/imw/files/compressed_files_and_archives.rb +348 -0
- data/lib/imw/files/compressible.rb +103 -0
- data/lib/imw/files/csv.rb +112 -0
- data/lib/imw/files/json.rb +41 -0
- data/lib/imw/files/sgml.rb +65 -0
- data/lib/imw/files/text.rb +68 -0
- data/lib/imw/files/yaml.rb +46 -0
- data/lib/imw/packagers.rb +8 -0
- data/lib/imw/packagers/archiver.rb +108 -0
- data/lib/imw/packagers/s3_mover.rb +28 -0
- data/lib/imw/parsers.rb +7 -0
- data/lib/imw/parsers/html_parser.rb +382 -0
- data/lib/imw/parsers/html_parser/matchers.rb +306 -0
- data/lib/imw/parsers/line_parser.rb +87 -0
- data/lib/imw/parsers/regexp_parser.rb +72 -0
- data/lib/imw/utils.rb +24 -0
- data/lib/imw/utils/components.rb +61 -0
- data/lib/imw/utils/config.rb +46 -0
- data/lib/imw/utils/error.rb +54 -0
- data/lib/imw/utils/extensions/array.rb +125 -0
- data/lib/imw/utils/extensions/class/attribute_accessors.rb +8 -0
- data/lib/imw/utils/extensions/core.rb +43 -0
- data/lib/imw/utils/extensions/dir.rb +24 -0
- data/lib/imw/utils/extensions/file_core.rb +64 -0
- data/lib/imw/utils/extensions/hash.rb +218 -0
- data/lib/imw/utils/extensions/hpricot.rb +48 -0
- data/lib/imw/utils/extensions/string.rb +49 -0
- data/lib/imw/utils/extensions/struct.rb +42 -0
- data/lib/imw/utils/extensions/symbol.rb +28 -0
- data/lib/imw/utils/extensions/typed_struct.rb +22 -0
- data/lib/imw/utils/extensions/uri.rb +59 -0
- data/lib/imw/utils/log.rb +67 -0
- data/lib/imw/utils/misc.rb +63 -0
- data/lib/imw/utils/paths.rb +115 -0
- data/lib/imw/utils/uri.rb +59 -0
- data/lib/imw/utils/uuid.rb +33 -0
- data/lib/imw/utils/validate.rb +38 -0
- data/lib/imw/utils/version.rb +12 -0
- data/lib/imw/utils/view.rb +113 -0
- data/lib/imw/utils/view/dump_csv.rb +112 -0
- data/lib/imw/utils/view/dump_csv_older.rb +117 -0
- data/spec/data/sample.csv +131 -0
- data/spec/data/sample.tsv +131 -0
- data/spec/data/sample.txt +131 -0
- data/spec/data/sample.xml +653 -0
- data/spec/data/sample.yaml +652 -0
- data/spec/imw/dataset/datamapper/uri_spec.rb +43 -0
- data/spec/imw/dataset/datamapper_spec_helper.rb +11 -0
- data/spec/imw/files/archive_spec.rb +118 -0
- data/spec/imw/files/basicfile_spec.rb +121 -0
- data/spec/imw/files/bz2_spec.rb +32 -0
- data/spec/imw/files/compressed_file_spec.rb +96 -0
- data/spec/imw/files/compressible_spec.rb +100 -0
- data/spec/imw/files/file_spec.rb +144 -0
- data/spec/imw/files/gz_spec.rb +32 -0
- data/spec/imw/files/rar_spec.rb +33 -0
- data/spec/imw/files/tar_spec.rb +31 -0
- data/spec/imw/files/text_spec.rb +23 -0
- data/spec/imw/files/zip_spec.rb +31 -0
- data/spec/imw/files_spec.rb +38 -0
- data/spec/imw/packagers/archiver_spec.rb +125 -0
- data/spec/imw/packagers/s3_mover_spec.rb +7 -0
- data/spec/imw/parsers/line_parser_spec.rb +96 -0
- data/spec/imw/parsers/regexp_parser_spec.rb +42 -0
- data/spec/imw/utils/extensions/file_core_spec.rb +72 -0
- data/spec/imw/utils/extensions/find_spec.rb +113 -0
- data/spec/imw/utils/paths_spec.rb +38 -0
- data/spec/imw/workflow/rip/local_spec.rb +89 -0
- data/spec/imw/workflow/rip_spec.rb +27 -0
- data/spec/rcov.opts +1 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/archive_contents_matcher.rb +94 -0
- data/spec/support/custom_matchers.rb +21 -0
- data/spec/support/directory_contents_matcher.rb +61 -0
- data/spec/support/extensions.rb +18 -0
- data/spec/support/file_contents_matcher.rb +50 -0
- data/spec/support/random.rb +210 -0
- data/spec/support/without_regard_to_order_matcher.rb +58 -0
- 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
|