imw 0.2.1 → 0.2.2
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/VERSION +1 -1
- data/lib/imw.rb +6 -1
- data/lib/imw/archives.rb +17 -4
- data/lib/imw/dataset/workflow.rb +6 -12
- data/lib/imw/repository.rb +1 -0
- data/lib/imw/resource.rb +49 -30
- data/lib/imw/runner.rb +15 -12
- data/lib/imw/schemes/local.rb +41 -0
- data/lib/imw/tools/archiver.rb +10 -6
- data/lib/imw/tools/transferer.rb +17 -4
- data/lib/imw/utils/extensions.rb +1 -0
- data/lib/imw/utils/extensions/array.rb +1 -1
- data/lib/imw/utils/extensions/hash.rb +1 -1
- data/lib/imw/utils/extensions/string.rb +1 -1
- data/lib/imw/utils/log.rb +30 -6
- data/spec/imw/archives/rar_spec.rb +1 -1
- data/spec/imw/archives/tar_spec.rb +1 -1
- data/spec/imw/archives/tarbz2_spec.rb +1 -1
- data/spec/imw/archives/targz_spec.rb +1 -1
- data/spec/imw/archives/zip_spec.rb +1 -1
- data/spec/imw/{archive_spec.rb → archives_spec.rb} +9 -1
- data/spec/imw/compressed_files_spec.rb +0 -1
- data/spec/imw/resource_spec.rb +31 -4
- data/spec/imw/schemes/local_spec.rb +16 -2
- data/spec/imw/schemes/remote_spec.rb +1 -2
- data/spec/imw/tools/transferer_spec.rb +76 -6
- data/spec/spec_helper.rb +1 -1
- data/spec/support/custom_matchers.rb +22 -15
- data/spec/support/file_contents_matcher.rb +21 -41
- data/spec/support/paths_matcher.rb +53 -54
- data/spec/support/without_regard_to_order_matcher.rb +31 -48
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
data/lib/imw.rb
CHANGED
@@ -46,9 +46,14 @@ module IMW
|
|
46
46
|
# Passing in an IMW::Resource will simply return it.
|
47
47
|
#
|
48
48
|
# @param [String, Addressable::URI, IMW::Resource] obj the URI to open
|
49
|
+
# @param [Hash] options
|
50
|
+
# @option options [Array<String,Module>] as same as <tt>:use_modules</tt> in IMW::Resource.extend_resource!
|
51
|
+
# @option options [Array<String,Module>] without same as <tt>:skip_modules</tt> in IMW::Resource.extend_resource!
|
49
52
|
# @return [IMW::Resource] the resulting resource, property extended for the given URI
|
50
53
|
def self.open obj, options={}
|
51
54
|
return obj if obj.is_a?(IMW::Resource)
|
55
|
+
options[:use_modules] ||= (options[:as] || [])
|
56
|
+
options[:skip_modules] ||= (options[:without] || [])
|
52
57
|
IMW::Resource.new(obj, options)
|
53
58
|
end
|
54
59
|
|
@@ -101,7 +106,7 @@ module IMW
|
|
101
106
|
# @param [Hash] options a hash of options (see IMW::Dataset)
|
102
107
|
# @return [IMW::Dataset] the new dataset
|
103
108
|
def self.dataset handle, options={}, &block
|
104
|
-
d = IMW::Dataset.new(handle, options)
|
109
|
+
d = IMW::Dataset.new(handle, options.merge(:repository => IMW.repository))
|
105
110
|
d.instance_eval(&block) if block_given?
|
106
111
|
d
|
107
112
|
end
|
data/lib/imw/archives.rb
CHANGED
@@ -39,7 +39,12 @@ module IMW
|
|
39
39
|
|
40
40
|
# Create an archive of the given +input_paths+.
|
41
41
|
#
|
42
|
-
#
|
42
|
+
# The input paths must be strings and will be shell-escaped
|
43
|
+
# before further processing. This means you cannot use a shell
|
44
|
+
# glob!
|
45
|
+
#
|
46
|
+
# @param [String] input_paths the paths to add to this archive
|
47
|
+
# @return [IMW::Resource] the resutling archive
|
43
48
|
def create *input_paths
|
44
49
|
should_have_archive_setting!("Cannot create archive #{path}", :program, :create)
|
45
50
|
IMW.system archive_settings[:program], archive_settings[:create], path, *input_paths.flatten
|
@@ -48,24 +53,32 @@ module IMW
|
|
48
53
|
|
49
54
|
# Append to this archive the given +input_paths+.
|
50
55
|
#
|
51
|
-
#
|
56
|
+
# The input paths must be strings and will be shell-escaped
|
57
|
+
# before further processing. This means you cannot use a shell
|
58
|
+
# glob!
|
59
|
+
#
|
60
|
+
# @param [String] input_paths the paths to add to this archive
|
61
|
+
# @return [IMW::Resource] the resutling archive
|
52
62
|
def append *input_paths
|
53
|
-
should_have_archive_setting!("Cannot append to archive #{path}", :append)
|
63
|
+
should_have_archive_setting!("Cannot append to archive #{path}", :program, :append)
|
54
64
|
IMW.system archive_settings[:program], archive_settings[:append], path, *input_paths.flatten
|
55
65
|
self
|
56
66
|
end
|
57
67
|
|
58
68
|
# Extract the files from this archive to the current directory.
|
69
|
+
#
|
70
|
+
# @return [IMW::Resource] this archive
|
59
71
|
def extract
|
60
72
|
should_exist!("Cannot extract archive.")
|
61
73
|
should_have_archive_setting!("Cannot extract archive #{path}", :extract, [:unarchving_program, :program])
|
62
74
|
program = archive_settings[:unarchiving_program] || archive_settings[:program]
|
63
75
|
IMW.system program, archive_settings[:extract], path
|
76
|
+
self
|
64
77
|
end
|
65
78
|
|
66
79
|
# Return a (sorted) list of contents in this archive.
|
67
80
|
#
|
68
|
-
# @return [Array] a list of paths in the archive.
|
81
|
+
# @return [Array<String>] a list of paths in the archive.
|
69
82
|
def contents
|
70
83
|
should_exist!("Cannot list archive contents.")
|
71
84
|
should_have_archive_setting!("Cannot list archive #{path}", :list, [:unarchiving_program, :program])
|
data/lib/imw/dataset/workflow.rb
CHANGED
@@ -148,7 +148,6 @@ module IMW
|
|
148
148
|
@options = OpenStruct.new(DEFAULT_OPTIONS)
|
149
149
|
define_initialize_task
|
150
150
|
define_workflow_tasks
|
151
|
-
define_workflow_task_methods
|
152
151
|
define_clean_task
|
153
152
|
define_tasks
|
154
153
|
end
|
@@ -186,16 +185,11 @@ module IMW
|
|
186
185
|
define_workflow_task({:package => [:fix]}, "Package dataset in final form." )
|
187
186
|
end
|
188
187
|
|
189
|
-
|
190
|
-
|
191
|
-
def
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
self[step].enhance(step => deps, &block)
|
196
|
-
end
|
197
|
-
RUBY
|
198
|
-
end
|
199
|
-
end
|
188
|
+
|
189
|
+
def rip(deps=nil, &block); self[:rip].enhance(deps, &block); end
|
190
|
+
def parse(deps=nil, &block); self[:parse].enhance(deps, &block); end
|
191
|
+
def fix(deps=nil, &block); self[:fix].enhance(deps, &block); end
|
192
|
+
def package(deps=nil, &block); self[:package].enhance(deps, &block); end
|
193
|
+
|
200
194
|
end
|
201
195
|
end
|
data/lib/imw/repository.rb
CHANGED
data/lib/imw/resource.rb
CHANGED
@@ -50,11 +50,36 @@ module IMW
|
|
50
50
|
class Resource
|
51
51
|
|
52
52
|
attr_reader :uri, :mode
|
53
|
-
|
53
|
+
|
54
|
+
# Create a new resource representing +uri+.
|
55
|
+
#
|
56
|
+
# IMW will automatically extend the resulting IMW::Resourcen
|
57
|
+
# instance with modules appropriate to the given URI.
|
58
|
+
#
|
59
|
+
# r = IMW::Resource.new("http://www.infochimps.com")
|
60
|
+
# r.resource_modules
|
61
|
+
# => [IMW::Schemes::Remote::Base, IMW::Schemes::Remote::RemoteFile, IMW::Schemes::HTTP, IMW::Formats::Html]
|
62
|
+
#
|
63
|
+
# You can prevent this altogether by passing in
|
64
|
+
# <tt>:no_modules</tt>:
|
65
|
+
#
|
66
|
+
# r = IMW::Resource.new("http://www.infochimps.com")
|
67
|
+
# r.resource_modules
|
68
|
+
# => [IMW::Schemes::Remote::Base, IMW::Schemes::Remote::RemoteFile, IMW::Schemes::HTTP, IMW::Formats::Html]
|
69
|
+
#
|
70
|
+
# And you can exert more fine-grained control with the
|
71
|
+
# <tt>:use_modules</tt> and <tt>:skip_modules</tt> options, see
|
72
|
+
# IMW::Resource.extend_resource! for details.
|
73
|
+
#
|
74
|
+
# @param [String, Addressable::URI] uri
|
75
|
+
# @param [Hash] options
|
76
|
+
# @option options [true, false] no_modules
|
77
|
+
# @option options [String] mode the mode to open the resource in (will be ignored when inapplicable)
|
78
|
+
# @return [IMW::Resource]
|
54
79
|
def initialize uri, options={}
|
55
80
|
self.uri = uri
|
56
81
|
@mode = options[:mode] || 'r'
|
57
|
-
extend_appropriately! unless options[:
|
82
|
+
extend_appropriately!(options) unless options[:no_modules]
|
58
83
|
end
|
59
84
|
|
60
85
|
# Return the modules this resource has been extended by.
|
@@ -73,8 +98,10 @@ module IMW
|
|
73
98
|
|
74
99
|
# Extend this resource with modules by passing it through a
|
75
100
|
# collection of handlers defined by IMW::Resource.handlers.
|
76
|
-
|
77
|
-
|
101
|
+
#
|
102
|
+
# Accepts the same options as Resource.extend_resource!.
|
103
|
+
def extend_appropriately! options={}
|
104
|
+
self.class.extend_resource!(self, options)
|
78
105
|
end
|
79
106
|
|
80
107
|
# Set the URI of this resource by parsing the given +uri+ (if
|
@@ -197,18 +224,26 @@ module IMW
|
|
197
224
|
# +resource+ with modules whose handler conditions match the
|
198
225
|
# resource.
|
199
226
|
#
|
227
|
+
# Passing in <tt>:use_modules</tt> or <tt>:skip_modules</tt>
|
228
|
+
# allows overriding the default behavior of handlers.
|
229
|
+
#
|
200
230
|
# @param [IMW::Resource] resource the resource to extend
|
231
|
+
# @param [Hash] options
|
232
|
+
# @option options [Array<String,Module>] use_modules a list of modules used regardless of handlers
|
233
|
+
# @option options [Array<String,Module>] skip_modules a list of modules not to be used regardless of handlers
|
201
234
|
# @return [IMW::Resource] the extended resource
|
202
|
-
def self.extend_resource! resource
|
235
|
+
def self.extend_resource! resource, options={}
|
236
|
+
options.reverse_merge!(:use_modules => [], :skip_modules => [])
|
203
237
|
handlers.each do |mod_name, handler|
|
204
238
|
case handler
|
205
|
-
when Regexp then extend_resource_with_mod_or_string!(resource, mod_name) if handler =~ resource.uri.to_s
|
206
|
-
when Proc then extend_resource_with_mod_or_string!(resource, mod_name) if handler.call(resource)
|
207
|
-
when TrueClass then extend_resource_with_mod_or_string!(resource, mod_name)
|
239
|
+
when Regexp then extend_resource_with_mod_or_string!(resource, mod_name, options[:skip_modules]) if handler =~ resource.uri.to_s
|
240
|
+
when Proc then extend_resource_with_mod_or_string!(resource, mod_name, options[:skip_modules]) if handler.call(resource)
|
241
|
+
when TrueClass then extend_resource_with_mod_or_string!(resource, mod_name, options[:skip_modules])
|
208
242
|
else
|
209
243
|
raise IMW::TypeError("A handler must be Regexp, Proc, or true")
|
210
244
|
end
|
211
245
|
end
|
246
|
+
options[:use_modules].each { |mod_name| extend_resource_with_mod_or_string!(resource, mod_name, options[:skip_modules]) }
|
212
247
|
resource
|
213
248
|
end
|
214
249
|
|
@@ -257,31 +292,15 @@ module IMW
|
|
257
292
|
#
|
258
293
|
# @param [Module, String] mod_or_string the module or string
|
259
294
|
# representing a module to extend the resource with
|
260
|
-
|
295
|
+
#
|
296
|
+
# @param [Array<Module,String>] skip_modules modules to exclude
|
297
|
+
def self.extend_resource_with_mod_or_string! resource, mod_or_string, skip_modules
|
298
|
+
return if skip_modules.include?(mod_or_string)
|
261
299
|
if mod_or_string.is_a?(Module)
|
262
300
|
resource.extend(mod_or_string)
|
263
301
|
else
|
264
|
-
|
265
|
-
|
266
|
-
# class_eval'ing them in order so that each is class_eval'd in
|
267
|
-
# the scope of the one before it.
|
268
|
-
#
|
269
|
-
# There is almost certainly a better way to do this.
|
270
|
-
# mod_names = mod_or_string.to_s.split('::')
|
271
|
-
# mods = []
|
272
|
-
# mod_names.each_with_index do |name, index|
|
273
|
-
# if index == 0
|
274
|
-
# mods << IMW.class_eval(name)
|
275
|
-
# else
|
276
|
-
# begin
|
277
|
-
# mods << class_eval(name)
|
278
|
-
# rescue NameError
|
279
|
-
# mods << mods[index - 1].class_eval(name)
|
280
|
-
# end
|
281
|
-
# end
|
282
|
-
# end
|
283
|
-
# resource.extend(mods.last)
|
284
|
-
resource.extend(IMW.class_eval(mod_or_string))
|
302
|
+
m = IMW.class_eval(mod_or_string)
|
303
|
+
resource.extend(m) unless skip_modules.include?(m)
|
285
304
|
end
|
286
305
|
end
|
287
306
|
end
|
data/lib/imw/runner.rb
CHANGED
@@ -33,6 +33,14 @@ module IMW
|
|
33
33
|
|
34
34
|
EOF
|
35
35
|
|
36
|
+
opts.on('-v', '--verbose', "Print verbose output") do
|
37
|
+
IMW.verbose = true # class level, see IMW::Runner.verbose?
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on('-d', '--skip-dependencies', "Execute given tasks without invoking dependencies first") do
|
41
|
+
options[:execute] = true
|
42
|
+
end
|
43
|
+
|
36
44
|
opts.on('-l', '--list', "List datasets in repository") do
|
37
45
|
options[:list] = true
|
38
46
|
end
|
@@ -49,7 +57,8 @@ EOF
|
|
49
57
|
end
|
50
58
|
|
51
59
|
def require_files
|
52
|
-
Dir['*.imw'].each { |path| load File.expand_path(path) }
|
60
|
+
Dir['*.imw'].each { |path| load File.expand_path(path) }
|
61
|
+
Dir['*.rb'].each { |path| require path.gsub(/\.rb$/,'') }
|
53
62
|
options[:requires].each do |path|
|
54
63
|
IMW.open(path) do |requireable|
|
55
64
|
if requireable.directory?
|
@@ -67,19 +76,13 @@ EOF
|
|
67
76
|
end
|
68
77
|
|
69
78
|
def handles
|
70
|
-
require 'set'
|
71
|
-
matched_handles = Set.new
|
72
79
|
if options[:selectors].blank?
|
73
|
-
|
80
|
+
IMW.repository.keys.sort
|
74
81
|
else
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
matched_handles += keys.find_all { |key| key =~ Regexp.new(selector) }
|
79
|
-
end
|
80
|
-
end
|
82
|
+
IMW.repository.handles.map do |handle|
|
83
|
+
handle if options[:selectors].all? { |selector| handle.to_s =~ Regexp.new(selector) }
|
84
|
+
end.compact.sort
|
81
85
|
end
|
82
|
-
matched_handles.to_a.sort
|
83
86
|
end
|
84
87
|
|
85
88
|
def datasets
|
@@ -93,7 +96,7 @@ EOF
|
|
93
96
|
|
94
97
|
def run_task!
|
95
98
|
datasets.each do |dataset|
|
96
|
-
dataset[task].invoke
|
99
|
+
dataset[task].send(options[:execute] ? :execute : :invoke)
|
97
100
|
end
|
98
101
|
exit
|
99
102
|
end
|
data/lib/imw/schemes/local.rb
CHANGED
@@ -58,6 +58,13 @@ module IMW
|
|
58
58
|
def mv new_uri
|
59
59
|
IMW::Tools::Transferer.new(:mv, self, new_uri).transfer!
|
60
60
|
end
|
61
|
+
|
62
|
+
# Return the directory of this resource.
|
63
|
+
#
|
64
|
+
# @return [IMW::Resource]
|
65
|
+
def dir
|
66
|
+
IMW.open(dirname)
|
67
|
+
end
|
61
68
|
|
62
69
|
end
|
63
70
|
|
@@ -155,6 +162,7 @@ module IMW
|
|
155
162
|
FileUtils.rmdir path
|
156
163
|
self
|
157
164
|
end
|
165
|
+
alias_method :rmdir!, :rmdir
|
158
166
|
|
159
167
|
# Delete this directory recursively.
|
160
168
|
#
|
@@ -163,6 +171,7 @@ module IMW
|
|
163
171
|
FileUtils.rm_rf path
|
164
172
|
self
|
165
173
|
end
|
174
|
+
alias_method :rm_rf!, :rm_rf
|
166
175
|
|
167
176
|
# Return a list of paths relative to this directory which match
|
168
177
|
# the +selector+. Works just like Dir[].
|
@@ -210,6 +219,38 @@ module IMW
|
|
210
219
|
end.compact
|
211
220
|
end
|
212
221
|
|
222
|
+
# Package the contents of this directory to an archive at
|
223
|
+
# +package_path+.
|
224
|
+
#
|
225
|
+
# @param [String, IMW::Resource] package_path
|
226
|
+
# @return [IMW::Resource] the new package
|
227
|
+
def package package_path
|
228
|
+
temp_package = IMW.open(File.join(dirname, File.basename(package_path)))
|
229
|
+
FileUtils.cd(dirname) { temp_package.create(basename) }
|
230
|
+
temp_package.path == File.expand_path(package_path) ? temp_package : temp_package.mv(package_path)
|
231
|
+
end
|
232
|
+
alias_method :package!, :package
|
233
|
+
|
234
|
+
# Change the working directory to this local directory.
|
235
|
+
#
|
236
|
+
# If passed a black, execute the block in this directory and
|
237
|
+
# then change back to the initial directory.
|
238
|
+
#
|
239
|
+
# This method works the same as FileUtils.cd.
|
240
|
+
def cd &block
|
241
|
+
FileUtils.cd(path, &block)
|
242
|
+
end
|
243
|
+
|
244
|
+
# Create this directory.
|
245
|
+
#
|
246
|
+
# No error if the directory already exists.
|
247
|
+
#
|
248
|
+
# @return [IMW::Resource] this directory
|
249
|
+
def create
|
250
|
+
FileUtils.mkdir_p(path) unless exist?
|
251
|
+
self
|
252
|
+
end
|
253
|
+
|
213
254
|
end
|
214
255
|
end
|
215
256
|
end
|
data/lib/imw/tools/archiver.rb
CHANGED
@@ -65,7 +65,7 @@ module IMW
|
|
65
65
|
|
66
66
|
attr_accessor :name, :local_inputs, :remote_inputs
|
67
67
|
|
68
|
-
def initialize name, raw_inputs
|
68
|
+
def initialize name, *raw_inputs
|
69
69
|
@name = name
|
70
70
|
self.inputs = raw_inputs
|
71
71
|
end
|
@@ -73,12 +73,12 @@ module IMW
|
|
73
73
|
# Set the inputs for this archiver.
|
74
74
|
#
|
75
75
|
# @param [String, IMW::Resource] new_inputs the inputs to archive, local or remote
|
76
|
-
def inputs=
|
76
|
+
def inputs= raw_inputs
|
77
77
|
@local_inputs, @remote_inputs = [], []
|
78
|
-
|
79
|
-
input =
|
78
|
+
raw_inputs.flatten.each do |raw_input|
|
79
|
+
input = IMW.open(raw_input)
|
80
80
|
if input.is_local?
|
81
|
-
@local_inputs <<
|
81
|
+
@local_inputs << input
|
82
82
|
else
|
83
83
|
@remote_inputs << input
|
84
84
|
end
|
@@ -133,17 +133,21 @@ module IMW
|
|
133
133
|
new_path = File.join(dir, existing_file.basename)
|
134
134
|
case
|
135
135
|
when existing_file.is_archive?
|
136
|
+
IMW.announce_if_verbose("Extracting #{existing_file}...")
|
136
137
|
FileUtils.cd(dir) do
|
137
138
|
existing_file.extract
|
138
139
|
end
|
139
140
|
when existing_file.is_compressed?
|
141
|
+
IMW.announce_if_verbose("Decompressing #{existing_file}...")
|
140
142
|
existing_file.cp(new_path).decompress!
|
141
143
|
else
|
144
|
+
IMW.announce_if_verbose("Copying #{existing_file}...")
|
142
145
|
existing_file.cp(new_path)
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
146
149
|
remote_inputs.each do |remote_input|
|
150
|
+
IMW.announce_if_verbose("Downloading #{remote_input}...")
|
147
151
|
remote_input.cp(File.join(dir, remote_input.effective_basename))
|
148
152
|
end
|
149
153
|
end
|
@@ -199,7 +203,7 @@ module IMW
|
|
199
203
|
output = IMW.open(output)
|
200
204
|
FileUtils.mkdir_p(output.dirname) unless File.exist?(output.dirname)
|
201
205
|
output.rm! if output.exist?
|
202
|
-
FileUtils.cd(tmp_dir) { IMW.open(output.basename).create(
|
206
|
+
FileUtils.cd(tmp_dir) { IMW.open(output.basename).create(name).mv(output.path) }
|
203
207
|
add_processing_error "Archiver: couldn't create archive #{output.path}" unless output.exists?
|
204
208
|
output
|
205
209
|
end
|
data/lib/imw/tools/transferer.rb
CHANGED
@@ -11,15 +11,27 @@ module IMW
|
|
11
11
|
raise IMW::PathError.new("Source and destination have the same URI: #{@source.uri}") if @source.uri.to_s == @destination.uri.to_s
|
12
12
|
end
|
13
13
|
|
14
|
+
# Transfer source to destination.
|
15
|
+
#
|
16
|
+
# For local transfer, will raise errors unless the necessary
|
17
|
+
# paths exist.
|
14
18
|
def transfer!
|
15
19
|
if source.is_local?
|
16
|
-
source.should_exist!("Cannot
|
17
|
-
source_scheme = 'file'
|
20
|
+
source.should_exist!("Cannot #{action}")
|
21
|
+
source_scheme = 'file'
|
18
22
|
else
|
19
23
|
source_scheme = source.scheme
|
20
24
|
end
|
21
|
-
|
25
|
+
|
26
|
+
if destination.is_local?
|
27
|
+
destination.dir.should_exist!("Cannot #{action}")
|
28
|
+
destination_scheme = 'file'
|
29
|
+
else
|
30
|
+
destination_scheme = destination.scheme
|
31
|
+
end
|
32
|
+
|
22
33
|
method = "#{source_scheme}_to_#{destination_scheme}"
|
34
|
+
|
23
35
|
if respond_to?(method)
|
24
36
|
send(method)
|
25
37
|
else
|
@@ -43,7 +55,8 @@ module IMW
|
|
43
55
|
#
|
44
56
|
|
45
57
|
def file_to_file
|
46
|
-
|
58
|
+
fu_action = (action == :cp && source.is_directory?) ? :cp_r : action
|
59
|
+
FileUtils.send(fu_action, source.path, destination.path)
|
47
60
|
end
|
48
61
|
|
49
62
|
#
|
data/lib/imw/utils/extensions.rb
CHANGED
@@ -57,6 +57,7 @@ module IMW
|
|
57
57
|
# which will work fine since +flags+ will automatically be flattend.
|
58
58
|
def self.system *commands
|
59
59
|
stripped_commands = commands.flatten.map { |command| command.to_s unless command.blank? }.compact
|
60
|
+
IMW.announce_if_verbose(stripped_commands.join(" "))
|
60
61
|
Kernel.system(*stripped_commands)
|
61
62
|
raise IMW::SystemCallError.new($?.dup, commands.join(' ')) unless $?.success?
|
62
63
|
end
|
data/lib/imw/utils/log.rb
CHANGED
@@ -4,10 +4,26 @@ module IMW
|
|
4
4
|
|
5
5
|
# Default log file.
|
6
6
|
LOG_FILE_DESTINATION = STDERR unless defined?(LOG_FILE_DESTINATION)
|
7
|
-
|
8
|
-
LOG_TIMEFORMAT = "%Y%m%d-%H:%M:%S " unless defined?(LOG_TIMEFORMAT)
|
9
7
|
|
10
|
-
|
8
|
+
# Default log file time format
|
9
|
+
LOG_TIMEFORMAT = "%Y-%m-%d %H:%M:%S " unless defined?(LOG_TIMEFORMAT)
|
10
|
+
|
11
|
+
# Default verbosity
|
12
|
+
VERBOSE = false
|
13
|
+
|
14
|
+
class << self; attr_accessor :log, :verbose end
|
15
|
+
|
16
|
+
# Is IMW operating in verbose mode?
|
17
|
+
#
|
18
|
+
# Calls to <tt>IMW.warn_if_verbose</tt> and friends utilize this
|
19
|
+
# method. Verbosity is controlled on the command line (see
|
20
|
+
# IMW::Runner) or by setting IMW::VERBOSE in your configuration
|
21
|
+
# file.
|
22
|
+
#
|
23
|
+
# @return [nil, false, true]
|
24
|
+
def self.verbose?
|
25
|
+
VERBOSE || verbose
|
26
|
+
end
|
11
27
|
|
12
28
|
# Create a Logger and point it at IMW::LOG_FILE_DESTINATION which is
|
13
29
|
# set in ~/.imwrc and defaults to STDERR.
|
@@ -17,21 +33,29 @@ module IMW
|
|
17
33
|
IMW.log.level = Logger::INFO
|
18
34
|
end
|
19
35
|
|
20
|
-
def announce *events
|
36
|
+
def self.announce *events
|
21
37
|
options = events.flatten.extract_options!
|
22
38
|
options.reverse_merge! :level => Logger::INFO
|
23
39
|
IMW.log.add options[:level], events.join("\n")
|
24
40
|
end
|
25
|
-
def
|
41
|
+
def self.announce_if_verbose *events
|
42
|
+
announce(*events) if IMW.verbose?
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.banner *events
|
26
46
|
options = events.flatten.extract_options!
|
27
47
|
options.reverse_merge! :level => Logger::INFO
|
28
48
|
announce(["*"*75, events, "*"*75], options)
|
29
49
|
end
|
30
|
-
|
50
|
+
|
51
|
+
def self.warn *events
|
31
52
|
options = events.flatten.extract_options!
|
32
53
|
options.reverse_merge! :level => Logger::WARN
|
33
54
|
announce events, options
|
34
55
|
end
|
56
|
+
def self.warn_if_verbose *events
|
57
|
+
warn(*events) if IMW.verbose?
|
58
|
+
end
|
35
59
|
|
36
60
|
PROGRESS_TRACKERS = {}
|
37
61
|
#
|
@@ -20,7 +20,6 @@ require File.join(File.dirname(__FILE__),'../spec_helper')
|
|
20
20
|
# variable should be defined OUTSIDE a before block.
|
21
21
|
|
22
22
|
share_examples_for "an archive of files" do
|
23
|
-
include Spec::Matchers::IMW
|
24
23
|
|
25
24
|
before do
|
26
25
|
@root = File.join(IMWTest::TMP_DIR, 'an_archive_of_files_shared_example_group')
|
@@ -40,6 +39,10 @@ share_examples_for "an archive of files" do
|
|
40
39
|
@archive.should contain_paths_like(@initial_directory, :relative_to => @root)
|
41
40
|
end
|
42
41
|
|
42
|
+
it "returns an IMW resource when creating" do
|
43
|
+
@archive.create(*Dir[@initial_directory + '/**/*']).class.should == IMW::Resource
|
44
|
+
end
|
45
|
+
|
43
46
|
if @cannot_append
|
44
47
|
it "cannot append to an archive which already exists" do
|
45
48
|
@archive.create(*Dir[@initial_directory + "/**/*"])
|
@@ -56,7 +59,12 @@ share_examples_for "an archive of files" do
|
|
56
59
|
@archive.append(*Dir[@appending_directory + "/**/*"])
|
57
60
|
@archive.should contain_paths_like(@appending_directory, :relative_to => @root)
|
58
61
|
end
|
62
|
+
|
63
|
+
it "returns an IMW resource when appending" do
|
64
|
+
@archive.append(*Dir[@appending_directory + "/**/*"]).class.should == IMW::Resource
|
65
|
+
end
|
59
66
|
end
|
67
|
+
|
60
68
|
|
61
69
|
it "can extract files which match the original ones it archived" do
|
62
70
|
@archive.create(*Dir[@initial_directory + "/**/*"])
|
data/spec/imw/resource_spec.rb
CHANGED
@@ -4,7 +4,7 @@ describe IMW::Resource do
|
|
4
4
|
|
5
5
|
describe "handling missing methods" do
|
6
6
|
before do
|
7
|
-
@resource = IMW::Resource.new('/home/foof.txt', :
|
7
|
+
@resource = IMW::Resource.new('/home/foof.txt', :no_modules => true)
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should return false when querying with a method that isn't defined" do
|
@@ -28,7 +28,7 @@ describe IMW::Resource do
|
|
28
28
|
describe "parsing various and sundry URIs should correctly parse a" do
|
29
29
|
|
30
30
|
before do
|
31
|
-
IMW::Resource.should_receive(:extend_resource!).with(an_instance_of(IMW::Resource))
|
31
|
+
IMW::Resource.should_receive(:extend_resource!).with(an_instance_of(IMW::Resource), {})
|
32
32
|
end
|
33
33
|
|
34
34
|
it "local file path" do
|
@@ -69,9 +69,36 @@ describe IMW::Resource do
|
|
69
69
|
|
70
70
|
it "should open a URI without attempting to extend with modules if so asked" do
|
71
71
|
IMW::Resource.should_not_receive(:extend_resource!)
|
72
|
-
IMW::Resource.new("/path/to/some/file.txt", :
|
72
|
+
IMW::Resource.new("/path/to/some/file.txt", :no_modules => true)
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
|
+
describe "extending resources with specific modules" do
|
76
|
+
before do
|
77
|
+
@resource = IMW::Resource.new('http://www.infochimps.com/data', :no_modules => true)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should use a specific module when asked with a string" do
|
81
|
+
IMW::Resource.extend_resource!(@resource, :use_modules => ["Formats::Csv"])
|
82
|
+
@resource.resource_modules.should include(IMW::Formats::Csv)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should use a specific module when asked with a module" do
|
86
|
+
IMW::Resource.extend_resource!(@resource, :use_modules => [IMW::Formats::Csv])
|
87
|
+
@resource.resource_modules.should include(IMW::Formats::Csv)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should not use a specific module when asked with a string" do
|
91
|
+
IMW::Resource.extend_resource!(@resource, :skip_modules => ["Schemes::HTTP"])
|
92
|
+
@resource.resource_modules.should_not include(IMW::Schemes::HTTP)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should not use a specific module when asked with a module" do
|
96
|
+
IMW::Resource.extend_resource!(@resource, :skip_modules => [IMW::Schemes::HTTP])
|
97
|
+
@resource.resource_modules.should_not include(IMW::Schemes::HTTP)
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
75
102
|
end
|
76
103
|
|
77
104
|
|
@@ -3,13 +3,13 @@ require File.join(File.dirname(__FILE__),'../../spec_helper')
|
|
3
3
|
describe IMW::Schemes::Local::Base do
|
4
4
|
|
5
5
|
it "should not extend a local file with LocalDirectory" do
|
6
|
-
@file = IMW::Resource.new('foo.txt', :
|
6
|
+
@file = IMW::Resource.new('foo.txt', :no_modules => true)
|
7
7
|
@file.should_not_receive(:extend).with(IMW::Schemes::Local::LocalDirectory)
|
8
8
|
@file.extend_appropriately!
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should not extend a local directory with LocalFile" do
|
12
|
-
@dir = IMW::Resource.new(IMWTest::TMP_DIR, :
|
12
|
+
@dir = IMW::Resource.new(IMWTest::TMP_DIR, :no_modules => true)
|
13
13
|
@dir.should_not_receive(:extend).with(IMW::Schemes::Local::LocalFile)
|
14
14
|
@dir.extend_appropriately!
|
15
15
|
end
|
@@ -17,6 +17,13 @@ describe IMW::Schemes::Local::Base do
|
|
17
17
|
it "should correctly resolve relative paths" do
|
18
18
|
IMW.open('foobar').dirname.should == IMWTest::TMP_DIR
|
19
19
|
end
|
20
|
+
|
21
|
+
it "should be able to return its directory as an IMW object" do
|
22
|
+
IMW.open('/path/to/file').dir.path.should == '/path/to'
|
23
|
+
IMW.open('/').dir.path.should == '/'
|
24
|
+
end
|
25
|
+
|
26
|
+
|
20
27
|
end
|
21
28
|
|
22
29
|
describe IMW::Schemes::Local::LocalFile do
|
@@ -93,6 +100,13 @@ describe IMW::Schemes::Local::LocalDirectory do
|
|
93
100
|
@dir.resources.map(&:class).uniq.first.should == IMW::Resource
|
94
101
|
end
|
95
102
|
|
103
|
+
describe 'can package itself to' do
|
104
|
+
['tar', 'tar.bz2', 'tar.gz', 'zip', 'rar'].each do |extension|
|
105
|
+
it "a #{extension} archive" do
|
106
|
+
@dir.package("package.#{extension}").exist?.should be_true # FIXME should explicitly check paths are correct in archive
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
96
110
|
end
|
97
111
|
|
98
112
|
|
@@ -7,8 +7,7 @@ describe IMW::Schemes::Remote::RemoteFile do
|
|
7
7
|
|
8
8
|
before do
|
9
9
|
# skip modules or else it will automatically become HTML!
|
10
|
-
@file = IMW.open('http://www.google.com', :skip_modules =>
|
11
|
-
@file.extend(IMW::Schemes::Remote::Base)
|
10
|
+
@file = IMW.open('http://www.google.com', :skip_modules => ["Schemes::HTTP", "Formats::HTML"])
|
12
11
|
end
|
13
12
|
|
14
13
|
describe 'with the file' do
|
@@ -2,10 +2,14 @@ require File.dirname(__FILE__) + "/../../spec_helper"
|
|
2
2
|
|
3
3
|
describe IMW::Tools::Transferer do
|
4
4
|
before do
|
5
|
-
@
|
6
|
-
@
|
7
|
-
@
|
8
|
-
@
|
5
|
+
@dir = IMW.open("dir")
|
6
|
+
@new_dir = IMW.open("new_dir")
|
7
|
+
@nested = IMW.open('new_dir/nested.txt')
|
8
|
+
@nested_dir = IMW.open('new_dir/nested')
|
9
|
+
@local = IMW.open("foobar.txt")
|
10
|
+
@http = IMW.open("http://www.google.com")
|
11
|
+
@hdfs = IMW.open("hdfs:///path/to/foobar.txt")
|
12
|
+
@s3 = IMW.open("s3://mybucket/foo/bar")
|
9
13
|
end
|
10
14
|
|
11
15
|
it "should raise an error unless the action is one of :cp, :copy, :mv :move, or :mv!" do
|
@@ -22,25 +26,91 @@ describe IMW::Tools::Transferer do
|
|
22
26
|
end
|
23
27
|
|
24
28
|
describe "transfering local files" do
|
29
|
+
|
30
|
+
before do
|
31
|
+
IMWTest::Random.file @local.path
|
32
|
+
end
|
33
|
+
|
25
34
|
it "should raise an error if the source doesn't exist" do
|
35
|
+
@local.rm!
|
26
36
|
lambda { IMW::Tools::Transferer.new(:cp, @local, 'barbaz.txt').transfer! }.should raise_error(IMW::PathError)
|
27
37
|
end
|
28
38
|
|
39
|
+
it "should raise an error if the directory of the destination doesn't exist" do
|
40
|
+
lambda { IMW::Tools::Transferer.new(:cp, @local, @nested).transfer! }.should raise_error(IMW::PathError)
|
41
|
+
end
|
42
|
+
|
29
43
|
it "can copy a local file" do
|
30
|
-
IMWTest::Random.file @local.path
|
31
44
|
IMW::Tools::Transferer.new(:cp, @local, 'barbaz.txt').transfer!
|
32
45
|
@local.exist?.should be_true
|
33
46
|
IMW.open('barbaz.txt').exist?.should be_true
|
34
47
|
end
|
35
48
|
|
49
|
+
it "can copy a local file to a directory" do
|
50
|
+
FileUtils.mkdir(@dir.path)
|
51
|
+
IMW::Tools::Transferer.new(:cp, @local, @dir).transfer!
|
52
|
+
IMW.open(File.join(@dir.path, @local.basename)).exist?.should be_true
|
53
|
+
end
|
54
|
+
|
36
55
|
it "can move a local file" do
|
37
|
-
IMWTest::Random.file @local.path
|
38
56
|
IMW::Tools::Transferer.new(:mv, @local, 'barbaz.txt').transfer!
|
39
57
|
@local.exist?.should be_false
|
40
58
|
IMW.open('barbaz.txt').exist?.should be_true
|
41
59
|
end
|
42
60
|
|
61
|
+
it "can move a local file to a directory" do
|
62
|
+
FileUtils.mkdir(@dir.path)
|
63
|
+
IMW::Tools::Transferer.new(:mv, @local, @dir).transfer!
|
64
|
+
IMW.open(File.join(@dir.path, @local.basename)).exist?.should be_true
|
65
|
+
@local.exist?.should be_false
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "transfering local directories" do
|
72
|
+
|
73
|
+
before do
|
74
|
+
IMWTest::Random.directory_with_files @dir.path
|
75
|
+
@dir = @dir.reopen
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should raise an error if the source doesn't exist" do
|
79
|
+
@dir.rm_rf!
|
80
|
+
lambda { IMW::Tools::Transferer.new(:cp, @dir, @new_dir).transfer! }.should raise_error(IMW::PathError)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should raise an error if the directory of the destination doesn't exist" do
|
84
|
+
lambda { IMW::Tools::Transferer.new(:cp, @dir, @nested_dir).transfer! }.should raise_error(IMW::PathError)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "can copy a local directory" do
|
88
|
+
IMW::Tools::Transferer.new(:cp, @dir, @new_dir).transfer!
|
89
|
+
@dir.exist?.should be_true
|
90
|
+
@new_dir.exist?.should be_true
|
91
|
+
end
|
92
|
+
|
93
|
+
it "can move a local directory" do
|
94
|
+
IMW::Tools::Transferer.new(:mv, @dir, @new_dir).transfer!
|
95
|
+
@dir.exist?.should be_false
|
96
|
+
@new_dir.exist?.should be_true
|
97
|
+
end
|
98
|
+
|
99
|
+
it "can copy a local directory to an existing directory" do
|
100
|
+
FileUtils.mkdir(@new_dir.path)
|
101
|
+
IMW::Tools::Transferer.new(:cp, @dir, @nested_dir).transfer!
|
102
|
+
@dir.exist?.should be_true
|
103
|
+
@nested_dir.exist?.should be_true
|
104
|
+
end
|
105
|
+
|
106
|
+
it "can move a local directory to an existing directory" do
|
107
|
+
FileUtils.mkdir(@new_dir.path)
|
108
|
+
IMW::Tools::Transferer.new(:mv, @dir, @nested_dir).transfer!
|
109
|
+
@dir.exist?.should_not be_true
|
110
|
+
@nested_dir.exist?.should be_true
|
111
|
+
end
|
43
112
|
end
|
113
|
+
|
44
114
|
|
45
115
|
describe "transferring HTTP files" do
|
46
116
|
it "can copy a remote file to a local path" do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,21 +1,28 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module IMWTest
|
2
|
+
module CustomMatchers
|
3
|
+
|
4
|
+
# Check to see whether the given directory (a String) contains the
|
5
|
+
# given +paths+
|
6
|
+
#
|
7
|
+
# @param [Array<String>] paths
|
8
|
+
def contain *paths
|
9
|
+
paths = paths.flatten
|
10
|
+
simple_matcher("contain #{paths.inspect}") do |given, matcher|
|
11
|
+
given_contents = Dir[given + "/**/*"].map do |abs_path|
|
12
|
+
abs_path[(given.length + 1)..-1]
|
13
|
+
end
|
14
|
+
matcher.failure_message = "expected #{given} to contain #{paths.inspect}, instead it contained #{given_contents.inspect}"
|
15
|
+
matcher.negative_failure_message = "expected #{given} not to contain #{paths.inspect}"
|
16
|
+
paths.all? { |path| given_contents.include?(path.gsub(/\/+$/,'')) }
|
7
17
|
end
|
8
|
-
matcher.failure_message = "expected #{given} to contain #{paths.inspect}, instead it contained #{given_contents.inspect}"
|
9
|
-
matcher.negative_failure_message = "expected #{given} not to contain #{paths.inspect}"
|
10
|
-
paths.all? { |path| given_contents.include?(path) }
|
11
18
|
end
|
12
|
-
end
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
def exist
|
21
|
+
simple_matcher("exist") do |given, matcher|
|
22
|
+
matcher.failure_message = "expected #{given} to exist on disk"
|
23
|
+
matcher.failure_message = "expected #{given} not to exist on disk"
|
24
|
+
File.exist?(given)
|
25
|
+
end
|
19
26
|
end
|
20
27
|
end
|
21
28
|
end
|
@@ -1,50 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
#
|
4
|
-
# == About
|
5
|
-
#
|
6
|
-
# An RSpec matcher which tests that two files have the same contents
|
7
|
-
# on disk.
|
8
|
-
#
|
9
|
-
# Author:: (Philip flip Kromer, Dhruv Bansal) for Infinite Monkeywrench Project (mailto:coders@infochimps.org)
|
10
|
-
# Copyright:: Copyright (c) 2008 infochimps.org
|
11
|
-
# License:: GPL 3.0
|
12
|
-
# Website:: http://infinitemonkeywrench.org/
|
13
|
-
#
|
1
|
+
module IMWTest
|
2
|
+
module CustomMatchers
|
14
3
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
module IMW
|
20
|
-
|
21
|
-
class FileContentsMatcher
|
22
|
-
def initialize orig
|
23
|
-
@orig = File.expand_path orig
|
24
|
-
end
|
25
|
-
|
26
|
-
def matches? copy
|
27
|
-
@copy = File.expand_path copy
|
28
|
-
File.compare(@orig,@copy)
|
29
|
-
end
|
4
|
+
class FileContentsMatcher
|
5
|
+
def initialize orig
|
6
|
+
@orig = File.expand_path orig
|
7
|
+
end
|
30
8
|
|
31
|
-
|
32
|
-
|
33
|
-
|
9
|
+
def matches? copy
|
10
|
+
@copy = File.expand_path copy
|
11
|
+
File.compare(@orig,@copy)
|
12
|
+
end
|
34
13
|
|
35
|
-
|
36
|
-
|
37
|
-
end
|
14
|
+
def failure_message
|
15
|
+
"files #{@orig} and #{@copy} are different"
|
38
16
|
end
|
39
17
|
|
40
|
-
|
41
|
-
|
42
|
-
def have_contents_matching_those_of path
|
43
|
-
FileContentsMatcher.new(path)
|
18
|
+
def negative_failure_message
|
19
|
+
"expected files #{@orig} and #{@copy} to differ"
|
44
20
|
end
|
45
|
-
|
46
21
|
end
|
22
|
+
|
23
|
+
# Matches the contents of one file against another using
|
24
|
+
# File.compare.
|
25
|
+
def have_contents_matching_those_of path
|
26
|
+
FileContentsMatcher.new(path)
|
27
|
+
end
|
28
|
+
|
47
29
|
end
|
48
30
|
end
|
49
|
-
|
50
|
-
# puts "#{File.basename(__FILE__)}: From far away, the folders appear the same; from up close, they are different." # at bottom
|
@@ -1,67 +1,66 @@
|
|
1
1
|
require 'set'
|
2
2
|
|
3
|
-
module
|
4
|
-
module Matchers
|
5
|
-
module IMW
|
3
|
+
module IMWTest
|
6
4
|
|
7
|
-
|
5
|
+
module CustomMatchers
|
8
6
|
|
9
|
-
|
7
|
+
class PathsMatcher
|
10
8
|
|
11
|
-
|
12
|
-
@given_base = options[:given_base] || options[:relative_to]
|
13
|
-
@to_match_base = options[:to_match_base]
|
14
|
-
@given = given
|
15
|
-
@given_contents = get_contents(given, given_base)
|
16
|
-
end
|
17
|
-
|
18
|
-
def matches? to_match
|
19
|
-
@to_match = to_match
|
20
|
-
@to_match_contents = get_contents(to_match, to_match_base)
|
21
|
-
to_match_contents == given_contents
|
22
|
-
end
|
9
|
+
attr_accessor :given, :given_contents, :given_base, :to_match, :to_match_contents, :to_match_base
|
23
10
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
11
|
+
def initialize given, options={}
|
12
|
+
@given_base = options[:given_base] || options[:relative_to]
|
13
|
+
@to_match_base = options[:to_match_base]
|
14
|
+
@given = given
|
15
|
+
@given_contents = get_contents(given, given_base)
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches? to_match
|
19
|
+
@to_match = to_match
|
20
|
+
@to_match_contents = get_contents(to_match, to_match_base)
|
21
|
+
to_match_contents == given_contents
|
22
|
+
end
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
def failure_message
|
25
|
+
given_string = given_contents.to_a.join("\n\t")
|
26
|
+
to_match_string = to_match_contents.to_a.join("\n\t")
|
27
|
+
"expected contents to be identical.\n\ngiven #{given.inspect}:\n\t#{given_string}\n\nto match #{to_match}:\n\t#{to_match_string}"
|
28
|
+
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
if obj.is_a?(String) || obj.is_a?(Array)
|
37
|
-
contents = [obj].flatten.map do |raw_path|
|
38
|
-
path = File.expand_path(raw_path)
|
39
|
-
if File.directory?(path)
|
40
|
-
Dir[path + "/**/*"]
|
41
|
-
else
|
42
|
-
path
|
43
|
-
end
|
44
|
-
end.flatten
|
45
|
-
else
|
46
|
-
# obj is an IMW obj (archive or directory) so it has a
|
47
|
-
# contents method
|
48
|
-
contents = obj.contents
|
49
|
-
end
|
50
|
-
if base
|
51
|
-
contents.map do |path|
|
52
|
-
new_path = path[base.length + 1..-1]
|
53
|
-
new_path = nil if !new_path.nil? && new_path.size == 0
|
54
|
-
new_path
|
55
|
-
end.compact.to_set
|
56
|
-
else
|
57
|
-
contents.to_set
|
58
|
-
end
|
59
|
-
end
|
30
|
+
def negative_failure_message
|
31
|
+
"expected contents of #{given} and #{to_match} to be different"
|
60
32
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
33
|
+
|
34
|
+
protected
|
35
|
+
def get_contents obj, base=nil
|
36
|
+
if obj.is_a?(String) || obj.is_a?(Array)
|
37
|
+
contents = [obj].flatten.map do |raw_path|
|
38
|
+
path = File.expand_path(raw_path)
|
39
|
+
if File.directory?(path)
|
40
|
+
Dir[path + "/**/*"]
|
41
|
+
else
|
42
|
+
path
|
43
|
+
end
|
44
|
+
end.flatten
|
45
|
+
else
|
46
|
+
# obj is an IMW obj (archive or directory) so it has a
|
47
|
+
# contents method
|
48
|
+
contents = obj.send(obj.respond_to?(:all_contents) ? :all_contents : :contents)
|
49
|
+
end
|
50
|
+
if base
|
51
|
+
contents.map do |path|
|
52
|
+
new_path = path[base.length + 1..-1]
|
53
|
+
new_path = nil if !new_path.nil? && new_path.size == 0
|
54
|
+
new_path
|
55
|
+
end.compact.to_set
|
56
|
+
else
|
57
|
+
contents.to_set
|
58
|
+
end
|
64
59
|
end
|
65
60
|
end
|
61
|
+
|
62
|
+
def contain_paths_like given, options={}
|
63
|
+
PathsMatcher.new(given, options)
|
64
|
+
end
|
66
65
|
end
|
67
66
|
end
|
@@ -1,58 +1,41 @@
|
|
1
|
-
#
|
2
|
-
# h2. spec/imw/matchers/without_regard_to_order_matcher.rb -- set matcher for non-sets
|
3
|
-
#
|
4
|
-
# == About
|
5
|
-
#
|
6
|
-
# A simple matcher which compares two objects as though they were
|
7
|
-
# sets, i.e. - without regard to the order of their elements.
|
8
|
-
#
|
9
|
-
# Author:: (Philip flip Kromer, Dhruv Bansal) for Infinite Monkeywrench Project (mailto:coders@infochimps.org)
|
10
|
-
# Copyright:: Copyright (c) 2008 infochimps.org
|
11
|
-
# License:: GPL 3.0
|
12
|
-
# Website:: http://infinitemonkeywrench.org/
|
13
|
-
#
|
14
|
-
|
15
1
|
require 'set'
|
16
2
|
require 'imw/utils'
|
17
3
|
|
18
|
-
module
|
19
|
-
module
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@array_to_test == @known_array
|
35
|
-
end
|
36
|
-
|
37
|
-
def failure_message
|
38
|
-
missing_from_array_to_test = "missing from array to test: #{(@known_array - @array_to_test).to_a.quote_items_with "and"}\n"
|
39
|
-
missing_from_known_array = "missing from known array: #{(@array_to_test - @known_array).to_a.quote_items_with "and"}\n"
|
40
|
-
common_to_both = "common to both: #{(@array_to_test & @known_array).to_a.quote_items_with "and"}\n"
|
41
|
-
"expected contents of the arrays to be identical:\n\n#{missing_from_array_to_test}\n#{missing_from_known_array}\n#{common_to_both}"
|
42
|
-
end
|
43
|
-
|
44
|
-
def negative_failure_message
|
45
|
-
"expected contents of the arrays to differ."
|
46
|
-
end
|
4
|
+
module IMWTest
|
5
|
+
module CustomMatchers
|
6
|
+
|
7
|
+
# Match the contents of two arrays without regard to the order
|
8
|
+
# of their elements by treating each as a set.
|
9
|
+
class WithoutRegardToOrder
|
10
|
+
|
11
|
+
private
|
12
|
+
def initialize known_array
|
13
|
+
@known_array = known_array.to_set
|
14
|
+
end
|
15
|
+
|
16
|
+
public
|
17
|
+
def matches? array_to_test
|
18
|
+
@array_to_test = array_to_test.to_set
|
19
|
+
@array_to_test == @known_array
|
47
20
|
end
|
48
21
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
22
|
+
def failure_message
|
23
|
+
missing_from_array_to_test = "missing from array to test: #{(@known_array - @array_to_test).to_a.quote_items_with "and"}\n"
|
24
|
+
missing_from_known_array = "missing from known array: #{(@array_to_test - @known_array).to_a.quote_items_with "and"}\n"
|
25
|
+
common_to_both = "common to both: #{(@array_to_test & @known_array).to_a.quote_items_with "and"}\n"
|
26
|
+
"expected contents of the arrays to be identical:\n\n#{missing_from_array_to_test}\n#{missing_from_known_array}\n#{common_to_both}"
|
53
27
|
end
|
28
|
+
|
29
|
+
def negative_failure_message
|
30
|
+
"expected contents of the arrays to differ."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Check that the contents of one array match another without
|
35
|
+
# regard to ordering.
|
36
|
+
def match_without_regard_to_order known_array
|
37
|
+
WithoutRegardToOrder.new(known_array)
|
54
38
|
end
|
55
39
|
end
|
56
40
|
end
|
57
41
|
|
58
|
-
# puts "#{File.basename(__FILE__)}: The leg bone's connected to the...knee bone, the knee bone's connected...wait, isn't it the other way 'round?" # at bottom
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: imw
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dhruv Bansal
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2010-05-
|
13
|
+
date: 2010-05-17 00:00:00 -05:00
|
14
14
|
default_executable: imw
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -95,12 +95,12 @@ files:
|
|
95
95
|
- spec/data/sample.txt
|
96
96
|
- spec/data/sample.xml
|
97
97
|
- spec/data/sample.yaml
|
98
|
-
- spec/imw/archive_spec.rb
|
99
98
|
- spec/imw/archives/rar_spec.rb
|
100
99
|
- spec/imw/archives/tar_spec.rb
|
101
100
|
- spec/imw/archives/tarbz2_spec.rb
|
102
101
|
- spec/imw/archives/targz_spec.rb
|
103
102
|
- spec/imw/archives/zip_spec.rb
|
103
|
+
- spec/imw/archives_spec.rb
|
104
104
|
- spec/imw/compressed_files/bz2_spec.rb
|
105
105
|
- spec/imw/compressed_files/compressible_spec.rb
|
106
106
|
- spec/imw/compressed_files/gz_spec.rb
|
@@ -168,7 +168,6 @@ test_files:
|
|
168
168
|
- spec/imw/archives/rar_spec.rb
|
169
169
|
- spec/imw/tools/archiver_spec.rb
|
170
170
|
- spec/imw/tools/transferer_spec.rb
|
171
|
-
- spec/imw/archive_spec.rb
|
172
171
|
- spec/imw/compressed_files/compressible_spec.rb
|
173
172
|
- spec/imw/compressed_files/bz2_spec.rb
|
174
173
|
- spec/imw/compressed_files/gz_spec.rb
|
@@ -182,6 +181,7 @@ test_files:
|
|
182
181
|
- spec/imw/formats/yaml_spec.rb
|
183
182
|
- spec/imw/formats/delimited_spec.rb
|
184
183
|
- spec/imw/formats/sgml_spec.rb
|
184
|
+
- spec/imw/archives_spec.rb
|
185
185
|
- spec/imw/schemes/http_spec.rb
|
186
186
|
- spec/imw/schemes/local_spec.rb
|
187
187
|
- spec/imw/schemes/remote_spec.rb
|