kronk 1.0.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/.autotest +23 -0
- data/History.txt +6 -0
- data/Manifest.txt +14 -0
- data/README.txt +118 -0
- data/Rakefile +20 -0
- data/bin/kronk +13 -0
- data/lib/kronk.rb +404 -0
- data/lib/kronk/data_set.rb +230 -0
- data/lib/kronk/diff.rb +210 -0
- data/lib/kronk/plist_parser.rb +15 -0
- data/lib/kronk/request.rb +191 -0
- data/lib/kronk/response.rb +226 -0
- data/lib/kronk/xml_parser.rb +108 -0
- data/test/test_data_set.rb +410 -0
- data/test/test_diff.rb +427 -0
- data/test/test_helper.rb +37 -0
- data/test/test_kronk.rb +192 -0
- data/test/test_request.rb +225 -0
- data/test/test_response.rb +258 -0
- data/test/test_xml_parser.rb +101 -0
- metadata +225 -0
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
.autotest
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/kronk
|
7
|
+
lib/kronk.rb
|
8
|
+
lib/kronk/data_set.rb
|
9
|
+
lib/kronk/diff.rb
|
10
|
+
lib/kronk/plist_parser.rb
|
11
|
+
lib/kronk/request.rb
|
12
|
+
lib/kronk/response.rb
|
13
|
+
lib/kronk/xml_parser.rb
|
14
|
+
test/test_kronk.rb
|
data/README.txt
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
= kronk
|
2
|
+
|
3
|
+
* https://github.com/yaksnrainbows/kronk
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Kronk runs diffs against data from live and cached http responses.
|
8
|
+
Kronk was made possible by the sponsoring of AT&T Interactive.
|
9
|
+
|
10
|
+
== FEATURES/PROBLEMS:
|
11
|
+
|
12
|
+
* Parse and diff data from http response body and/or headers.
|
13
|
+
|
14
|
+
* Include or exclude particular data points.
|
15
|
+
|
16
|
+
* Supports json, rails-ish xml, and plist.
|
17
|
+
|
18
|
+
* Support for custom data parsers.
|
19
|
+
|
20
|
+
== FUTURE:
|
21
|
+
|
22
|
+
* Line numbered and custom diff output.
|
23
|
+
|
24
|
+
* Auto-queryer with optional param randomizing.
|
25
|
+
|
26
|
+
* Support for test suites.
|
27
|
+
|
28
|
+
* Support for proxies, ssl, and http auth.
|
29
|
+
|
30
|
+
== SYNOPSIS:
|
31
|
+
|
32
|
+
Check if your json response returns the same data as your xml variety:
|
33
|
+
|
34
|
+
$ kronk http://host.com/path.json http://host.com/path.xml
|
35
|
+
|
36
|
+
Compare headers only but only content type and date:
|
37
|
+
|
38
|
+
$ kronk http://host.com/path1 http://host.com/path2 -I Content-Type,Date
|
39
|
+
|
40
|
+
Compare body structure only:
|
41
|
+
|
42
|
+
$ kronk http://host.com/path.json http://host.com/path.xml --struct
|
43
|
+
|
44
|
+
Call comparison with similar uri suffixes:
|
45
|
+
|
46
|
+
$ kronk http://host.com/path.json http://host.com/path.xml --suff '?page=1'
|
47
|
+
|
48
|
+
Compare body and headers:
|
49
|
+
|
50
|
+
$ kronk http://host.com/path.json http://host.com/path.xml -i
|
51
|
+
|
52
|
+
Compare body and content type header:
|
53
|
+
|
54
|
+
$ kronk http://host.com/path.json http://host.com/path.xml -i Content-Type
|
55
|
+
|
56
|
+
Compare response with the previous call:
|
57
|
+
|
58
|
+
$ kronk http://host.com/path --prev
|
59
|
+
|
60
|
+
Compare response with a local file:
|
61
|
+
|
62
|
+
$ kronk http://host.com/path.json ./saved_response.json
|
63
|
+
|
64
|
+
Do a simple text diff on the http response, including headers:
|
65
|
+
|
66
|
+
$ kronk http://host.com/A/path.json http://host.com/B/path.json --raw -i
|
67
|
+
|
68
|
+
Run it to display formatted data:
|
69
|
+
|
70
|
+
$ kronk http://host.com/path.json
|
71
|
+
|
72
|
+
$ kronk http://host.com/path.json -i
|
73
|
+
|
74
|
+
Run it to display raw data with headers:
|
75
|
+
|
76
|
+
$ kronk http://host.com/path.json --raw -i
|
77
|
+
|
78
|
+
== REQUIREMENTS:
|
79
|
+
|
80
|
+
* FIX (list of requirements)
|
81
|
+
|
82
|
+
== INSTALL:
|
83
|
+
|
84
|
+
* sudo gem install kronk
|
85
|
+
|
86
|
+
== DEVELOPERS:
|
87
|
+
|
88
|
+
After checking out the source, run:
|
89
|
+
|
90
|
+
$ rake newb
|
91
|
+
|
92
|
+
This task will install any missing dependencies, run the tests/specs,
|
93
|
+
and generate the RDoc.
|
94
|
+
|
95
|
+
== LICENSE:
|
96
|
+
|
97
|
+
(The MIT License)
|
98
|
+
|
99
|
+
Copyright (c) 2010 Jeremie Castagna
|
100
|
+
|
101
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
102
|
+
a copy of this software and associated documentation files (the
|
103
|
+
'Software'), to deal in the Software without restriction, including
|
104
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
105
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
106
|
+
permit persons to whom the Software is furnished to do so, subject to
|
107
|
+
the following conditions:
|
108
|
+
|
109
|
+
The above copyright notice and this permission notice shall be
|
110
|
+
included in all copies or substantial portions of the Software.
|
111
|
+
|
112
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
113
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
114
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
115
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
116
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
117
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
118
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
|
6
|
+
Hoe.plugin :isolate
|
7
|
+
|
8
|
+
Hoe.spec 'kronk' do
|
9
|
+
developer('Jeremie Castagna', 'yaksnrainbows@gmail.com')
|
10
|
+
|
11
|
+
self.extra_deps << ['plist', '>=3.1.0']
|
12
|
+
self.extra_deps << ['json', '>=1.2.0']
|
13
|
+
self.extra_deps << ['nokogiri', '>=1.3.3']
|
14
|
+
self.extra_deps << ['i18n', '>=0.5.0']
|
15
|
+
self.extra_deps << ['activesupport', '>=2.0.0']
|
16
|
+
|
17
|
+
self.extra_dev_deps << ['mocha', '>=0.9.10']
|
18
|
+
end
|
19
|
+
|
20
|
+
# vim: syntax=ruby
|
data/bin/kronk
ADDED
data/lib/kronk.rb
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'plist'
|
3
|
+
require 'json'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
# Support for new and old versions of ActiveSupport
|
7
|
+
begin
|
8
|
+
require 'active_support/inflector'
|
9
|
+
rescue LoadError
|
10
|
+
require 'activesupport'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'net/http'
|
14
|
+
require 'optparse'
|
15
|
+
|
16
|
+
class Kronk
|
17
|
+
|
18
|
+
# This gem's version.
|
19
|
+
VERSION = '1.0.0'
|
20
|
+
|
21
|
+
|
22
|
+
require 'kronk/data_set'
|
23
|
+
require 'kronk/diff'
|
24
|
+
require 'kronk/response'
|
25
|
+
require 'kronk/request'
|
26
|
+
require 'kronk/plist_parser'
|
27
|
+
require 'kronk/xml_parser'
|
28
|
+
|
29
|
+
|
30
|
+
# Default config file to load. Defaults to ~/.kronk.
|
31
|
+
DEFAULT_CONFIG_FILE = File.expand_path "~/.kronk"
|
32
|
+
|
33
|
+
|
34
|
+
# Default cache file.
|
35
|
+
DEFAULT_CACHE_FILE = File.expand_path "~/.kronk_cache"
|
36
|
+
|
37
|
+
|
38
|
+
# Default Content-Type header to parser mapping.
|
39
|
+
DEFAULT_CONTENT_TYPES = {
|
40
|
+
'js' => 'JSON',
|
41
|
+
'json' => 'JSON',
|
42
|
+
'plist' => 'PlistParser',
|
43
|
+
'xml' => 'XMLParser'
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
# Default config to use.
|
48
|
+
DEFAULT_CONFIG = {
|
49
|
+
:content_types => DEFAULT_CONTENT_TYPES.dup,
|
50
|
+
:diff_format => :ascii_diff,
|
51
|
+
:cache_file => DEFAULT_CACHE_FILE,
|
52
|
+
:requires => []
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
##
|
57
|
+
# Read the Kronk config hash.
|
58
|
+
|
59
|
+
def self.config
|
60
|
+
@config ||= DEFAULT_CONFIG
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
##
|
65
|
+
# Load a config file and apply to Kronk.config.
|
66
|
+
|
67
|
+
def self.load_config filepath=DEFAULT_CONFIG_FILE
|
68
|
+
conf = YAML.load_file DEFAULT_CONFIG_FILE
|
69
|
+
content_types = conf.delete :content_types
|
70
|
+
|
71
|
+
if conf[:requires]
|
72
|
+
requires = [*conf.delete(:requires)]
|
73
|
+
self.config[:requires] ||= []
|
74
|
+
self.config[:requires].concat requires
|
75
|
+
end
|
76
|
+
|
77
|
+
self.config[:content_types].merge!(content_types) if content_types
|
78
|
+
self.config.merge! conf
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
##
|
83
|
+
# Load the config-based requires.
|
84
|
+
|
85
|
+
def self.load_requires
|
86
|
+
return unless config[:requires]
|
87
|
+
config[:requires].each{|lib| require lib }
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
##
|
92
|
+
# Creates the default config file at the given path.
|
93
|
+
|
94
|
+
def self.make_config_file filepath=DEFAULT_CONFIG_FILE
|
95
|
+
File.open filepath, "w+" do |file|
|
96
|
+
file << DEFAULT_CONFIG.to_yaml
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
##
|
102
|
+
# Find a fully qualified ruby namespace/constant.
|
103
|
+
|
104
|
+
def self.find_const namespace
|
105
|
+
consts = namespace.split "::"
|
106
|
+
curr = self
|
107
|
+
|
108
|
+
until consts.empty? do
|
109
|
+
curr = curr.const_get consts.shift
|
110
|
+
end
|
111
|
+
|
112
|
+
curr
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
##
|
117
|
+
# Returns the config-defined parser class for a given content type.
|
118
|
+
|
119
|
+
def self.parser_for content_type
|
120
|
+
parser_pair =
|
121
|
+
config[:content_types].select do |key, value|
|
122
|
+
(content_type =~ %r{#{key}}) && value
|
123
|
+
end
|
124
|
+
|
125
|
+
return if parser_pair.empty?
|
126
|
+
|
127
|
+
parser = parser_pair[0][1]
|
128
|
+
parser = find_const parser if String === parser || Symbol === parser
|
129
|
+
parser
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
##
|
134
|
+
# Make requests, parse the responses and compare the data.
|
135
|
+
# If the second argument is omitted or is passed :cache, will
|
136
|
+
# attempt to compare with the last made request. If there was no last
|
137
|
+
# request will compare against nil.
|
138
|
+
#
|
139
|
+
# Supports the following options:
|
140
|
+
# :data:: Hash/String - the data to pass to the http request
|
141
|
+
# :headers:: Hash - extra headers to pass to the request
|
142
|
+
# :http_method:: Symbol - the http method to use; defaults to :get
|
143
|
+
# :ignore_data:: String/Array - defines which data points to exclude
|
144
|
+
# :with_headers:: Bool/String/Array - defines which headers to include
|
145
|
+
# :raw:: Bool - run diff on raw strings
|
146
|
+
#
|
147
|
+
# Returns a diff object.
|
148
|
+
|
149
|
+
def self.compare query1, query2=:cache, options={}
|
150
|
+
diff =
|
151
|
+
if options[:raw]
|
152
|
+
raw_diff query1, query2, options
|
153
|
+
else
|
154
|
+
data_diff query1, query2, options
|
155
|
+
end
|
156
|
+
|
157
|
+
diff
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
##
|
162
|
+
# Return a diff object from two responses' raw data.
|
163
|
+
|
164
|
+
def self.raw_diff query1, query2, options={}
|
165
|
+
resp1 = Request.retrieve query1, options
|
166
|
+
resp2 = Request.retrieve query2, options
|
167
|
+
|
168
|
+
Diff.new resp1.selective_string(options), resp2.selective_string(options)
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
##
|
173
|
+
# Return a diff object from two parsed responses.
|
174
|
+
|
175
|
+
def self.data_diff query1, query2, options={}
|
176
|
+
resp1 = Request.retrieve query1, options
|
177
|
+
resp2 = Request.retrieve query2, options
|
178
|
+
|
179
|
+
Diff.new_from_data resp1.selective_data(options),
|
180
|
+
resp2.selective_data(options),
|
181
|
+
options
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
##
|
186
|
+
# Runs the kronk command with the given terminal args.
|
187
|
+
|
188
|
+
def self.run argv=ARGV
|
189
|
+
begin
|
190
|
+
load_config
|
191
|
+
|
192
|
+
rescue Errno::ENOENT
|
193
|
+
make_config_file
|
194
|
+
|
195
|
+
$stderr << "\nNo config file was found.\n\n"
|
196
|
+
$stderr << "Created default config in #{DEFAULT_CONFIG_FILE}\n"
|
197
|
+
$stderr << "Edit file if necessary and try again.\n"
|
198
|
+
exit 1
|
199
|
+
end
|
200
|
+
|
201
|
+
options = parse_args argv
|
202
|
+
|
203
|
+
config[:requires].concat options[:requires] if options[:requires]
|
204
|
+
load_requires
|
205
|
+
|
206
|
+
options[:cache_response] = config[:cache_file] if config[:cache_file]
|
207
|
+
|
208
|
+
uri1, uri2 = options.delete :uris
|
209
|
+
|
210
|
+
if uri1 && uri2
|
211
|
+
diff = compare uri1, uri2, options
|
212
|
+
puts diff.formatted(config[:diff_format])
|
213
|
+
|
214
|
+
elsif options[:raw]
|
215
|
+
puts Request.retrieve(uri1, options).selective_string(options)
|
216
|
+
|
217
|
+
else
|
218
|
+
data = Request.retrieve(uri1, options).selective_data options
|
219
|
+
puts Diff.ordered_data_string(data, options[:struct])
|
220
|
+
end
|
221
|
+
|
222
|
+
rescue Request::NotFoundError, Response::MissingParser => e
|
223
|
+
$stderr << "\nError: #{e.message}\n"
|
224
|
+
exit 2
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
##
|
229
|
+
# Parse ARGV
|
230
|
+
|
231
|
+
def self.parse_args argv
|
232
|
+
options = {
|
233
|
+
:with_headers => false,
|
234
|
+
:no_body => false,
|
235
|
+
:uris => []
|
236
|
+
}
|
237
|
+
|
238
|
+
options[:only_data], options[:ignore_data] = parse_data_path_args argv
|
239
|
+
|
240
|
+
opts = OptionParser.new do |opt|
|
241
|
+
opt.program_name = File.basename $0
|
242
|
+
opt.version = VERSION
|
243
|
+
opt.release = nil
|
244
|
+
|
245
|
+
opt.banner = <<-STR
|
246
|
+
Kronk runs diffs against data from live and cached http responses.
|
247
|
+
|
248
|
+
Usage:
|
249
|
+
#{opt.program_name} --help
|
250
|
+
#{opt.program_name} --version
|
251
|
+
#{opt.program_name} uri1 [uri2] [options...] [-- data-paths]
|
252
|
+
|
253
|
+
Examples:
|
254
|
+
#{opt.program_name} http://example.com/A
|
255
|
+
#{opt.program_name} http://example.com/B --prev --raw
|
256
|
+
#{opt.program_name} http://example.com/B.xml local/file/B.json
|
257
|
+
#{opt.program_name} file1.json file2.json -- **/key1=val1 -root/key?
|
258
|
+
|
259
|
+
Arguments after -- will be used to focus the diff on specific data points.
|
260
|
+
If the data paths start with a '-' the matched data points will be removed.
|
261
|
+
|
262
|
+
Options:
|
263
|
+
STR
|
264
|
+
|
265
|
+
opt.on('-d', '--data STR', String,
|
266
|
+
'Post data with the request') do |value|
|
267
|
+
options[:data] = value
|
268
|
+
options[:http_method] ||= 'POST'
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
opt.on('--prev', 'Use last response to diff against') do
|
273
|
+
options[:uris] << :cache
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
opt.on('--suff STR', String,
|
278
|
+
'Add common path items to the end of each URI') do |value|
|
279
|
+
options[:uri_suffix] = value
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
opt.on('-H', '--header STR', String,
|
284
|
+
'Header to pass to the server request') do |value|
|
285
|
+
options[:headers] ||= {}
|
286
|
+
|
287
|
+
key, value = value.split ": ", 2
|
288
|
+
options[:headers][key] = value
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
opt.on('-i', '--include [header1,header2]', Array,
|
293
|
+
'Include all or given headers in response') do |value|
|
294
|
+
options[:with_headers] ||= []
|
295
|
+
|
296
|
+
if value
|
297
|
+
options[:with_headers].concat value if
|
298
|
+
Array === options[:with_headers]
|
299
|
+
else
|
300
|
+
options[:with_headers] = true
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
opt.on('-I', '--head [header1,header2]', Array,
|
306
|
+
'Use all or given headers only in the response') do |value|
|
307
|
+
options[:with_headers] ||= []
|
308
|
+
|
309
|
+
if value
|
310
|
+
options[:with_headers].concat value if
|
311
|
+
Array === options[:with_headers]
|
312
|
+
else
|
313
|
+
options[:with_headers] = true
|
314
|
+
end
|
315
|
+
|
316
|
+
options[:no_body] = true
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
opt.on('-L', '--location [NUM]', Integer,
|
321
|
+
'Follow the location header always or num times') do |value|
|
322
|
+
options[:follow_redirects] = value || true
|
323
|
+
end
|
324
|
+
|
325
|
+
|
326
|
+
opt.on('-X', '--request STR', String,
|
327
|
+
'The request method to use') do |value|
|
328
|
+
options[:http_method] = value
|
329
|
+
end
|
330
|
+
|
331
|
+
|
332
|
+
opt.on('-r', '--require lib1,lib2', Array,
|
333
|
+
'Require a library or gem') do |value|
|
334
|
+
options[:requires] ||= []
|
335
|
+
options[:requires].concat value
|
336
|
+
end
|
337
|
+
|
338
|
+
|
339
|
+
opt.on('--raw', 'Run diff on the raw data returned') do
|
340
|
+
options[:raw] = true
|
341
|
+
end
|
342
|
+
|
343
|
+
|
344
|
+
opt.on('--struct', 'Run diff on the data structure') do
|
345
|
+
options[:struct] = true
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
opt.on('--ascii', 'Return ascii formatted diff') do
|
350
|
+
config[:diff_format] = :ascii_diff
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
opt.on('--color', 'Return color formatted diff') do
|
355
|
+
config[:diff_format] = :color_diff
|
356
|
+
end
|
357
|
+
|
358
|
+
|
359
|
+
#opt.on('-v', '--verbose', 'Make the operation more talkative') do
|
360
|
+
# options[:verbose] = true
|
361
|
+
#end
|
362
|
+
|
363
|
+
opt.separator nil
|
364
|
+
end
|
365
|
+
|
366
|
+
opts.parse! argv
|
367
|
+
|
368
|
+
options[:uris].concat argv
|
369
|
+
options[:uris].slice!(2..-1)
|
370
|
+
|
371
|
+
if options[:uris].empty?
|
372
|
+
$stderr << "\nError: You must enter at least one URI\n\n"
|
373
|
+
$stderr << opts.to_s
|
374
|
+
exit 1
|
375
|
+
end
|
376
|
+
|
377
|
+
options
|
378
|
+
end
|
379
|
+
|
380
|
+
|
381
|
+
##
|
382
|
+
# Searches ARGV and returns data paths to add or exclude in the diff.
|
383
|
+
# Returns the array [only_paths, except_paths]
|
384
|
+
|
385
|
+
def self.parse_data_path_args argv
|
386
|
+
return unless argv.include? "--"
|
387
|
+
|
388
|
+
data_paths = argv.slice! argv.index("--")..-1
|
389
|
+
data_paths.shift
|
390
|
+
|
391
|
+
only_paths = nil
|
392
|
+
except_paths = nil
|
393
|
+
|
394
|
+
data_paths.each do |path|
|
395
|
+
if path[0,1] == "-"
|
396
|
+
(except_paths ||= []) << path[1..-1]
|
397
|
+
else
|
398
|
+
(only_paths ||= []) << path
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
[only_paths, except_paths]
|
403
|
+
end
|
404
|
+
end
|