kronk 1.0.3 → 1.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/{History.txt → History.rdoc} +22 -0
- data/Manifest.txt +14 -2
- data/README.rdoc +258 -0
- data/Rakefile +4 -0
- data/lib/kronk.rb +239 -102
- data/lib/kronk/diff.rb +2 -2
- data/lib/kronk/request.rb +146 -20
- data/lib/kronk/xml_parser.rb +1 -1
- data/test/mocks/200_response.json +28 -0
- data/test/mocks/200_response.plist +97 -0
- data/test/mocks/200_response.txt +23 -0
- data/test/mocks/200_response.xml +58 -0
- data/test/mocks/301_response.txt +16 -0
- data/test/mocks/302_response.txt +17 -0
- data/test/test_kronk.rb +142 -32
- data/test/test_request.rb +319 -12
- metadata +36 -20
- data/README.txt +0 -122
@@ -1,3 +1,25 @@
|
|
1
|
+
=== 1.1.0 / 2010-12-12
|
2
|
+
|
3
|
+
* Enhancements:
|
4
|
+
|
5
|
+
* Support for http ssl, proxy, and basic auth.
|
6
|
+
|
7
|
+
* Support for cookies and sessions.
|
8
|
+
|
9
|
+
* URL queries can now be set from the command line or the config file.
|
10
|
+
|
11
|
+
* Support for piping to the kronk bin.
|
12
|
+
|
13
|
+
* Support for customizing User-Agent and added user agent aliases.
|
14
|
+
|
15
|
+
* Bugfixes:
|
16
|
+
|
17
|
+
* No longer need to explicitely specify raw mode for content types
|
18
|
+
with no parsers.
|
19
|
+
|
20
|
+
* Updated how --prev option does cache retrieval, so cache is always
|
21
|
+
the left side of the diff.
|
22
|
+
|
1
23
|
=== 1.0.3 / 2010-12-09
|
2
24
|
|
3
25
|
* Enhancements:
|
data/Manifest.txt
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
.autotest
|
2
|
-
History.
|
2
|
+
History.rdoc
|
3
3
|
Manifest.txt
|
4
|
-
README.
|
4
|
+
README.rdoc
|
5
5
|
Rakefile
|
6
6
|
bin/kronk
|
7
7
|
lib/kronk.rb
|
@@ -11,4 +11,16 @@ lib/kronk/plist_parser.rb
|
|
11
11
|
lib/kronk/request.rb
|
12
12
|
lib/kronk/response.rb
|
13
13
|
lib/kronk/xml_parser.rb
|
14
|
+
test/mocks/200_response.json
|
15
|
+
test/mocks/200_response.plist
|
16
|
+
test/mocks/200_response.txt
|
17
|
+
test/mocks/200_response.xml
|
18
|
+
test/mocks/301_response.txt
|
19
|
+
test/mocks/302_response.txt
|
20
|
+
test/test_data_set.rb
|
21
|
+
test/test_diff.rb
|
22
|
+
test/test_helper.rb
|
14
23
|
test/test_kronk.rb
|
24
|
+
test/test_request.rb
|
25
|
+
test/test_response.rb
|
26
|
+
test/test_xml_parser.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,258 @@
|
|
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:
|
11
|
+
|
12
|
+
* Parse and display or diff data from http response body and/or headers.
|
13
|
+
|
14
|
+
* Follow redirects automatically.
|
15
|
+
|
16
|
+
* Include or exclude specific data points with file-glob-like paths.
|
17
|
+
|
18
|
+
* Supports json, rails-ish xml, and plist.
|
19
|
+
|
20
|
+
* Support for custom data parsers and diff formatters.
|
21
|
+
|
22
|
+
* Support for proxies, ssl, and basic auth.
|
23
|
+
|
24
|
+
* Cookie/session handling.
|
25
|
+
|
26
|
+
* Easy-to-read output (color or ascii, line numbers, etc).
|
27
|
+
|
28
|
+
== FUTURE:
|
29
|
+
|
30
|
+
* Auto-queryer with optional param randomizing.
|
31
|
+
|
32
|
+
* Support for test suites.
|
33
|
+
|
34
|
+
== SYNOPSIS:
|
35
|
+
|
36
|
+
Check if your json response returns the same data as your xml variety:
|
37
|
+
|
38
|
+
$ kronk http://host.com/path.json http://host.com/path.xml
|
39
|
+
|
40
|
+
Compare body structure only (uses datatypes instead of values):
|
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 response with the previous call:
|
49
|
+
|
50
|
+
$ kronk http://host.com/path --prev
|
51
|
+
|
52
|
+
Compare response with a local file:
|
53
|
+
|
54
|
+
$ kronk http://host.com/path.json ./saved_response.json
|
55
|
+
|
56
|
+
Do a simple text diff on the http response, including headers:
|
57
|
+
|
58
|
+
$ kronk http://host.com/A/path.json http://host.com/B/path.json --raw -i
|
59
|
+
|
60
|
+
Run it to display formatted data:
|
61
|
+
|
62
|
+
$ kronk http://host.com/path.json
|
63
|
+
|
64
|
+
Run it to display raw data with headers:
|
65
|
+
|
66
|
+
$ kronk http://host.com/path.json --raw -i
|
67
|
+
|
68
|
+
== CONFIGURATION:
|
69
|
+
|
70
|
+
Kronk pulls it's config from $HOME/.kronk and supports the following:
|
71
|
+
|
72
|
+
Set the file to save the last http response retrieved in:
|
73
|
+
|
74
|
+
:cache_file: ~/.kronk_cache
|
75
|
+
|
76
|
+
Content types to match to a parser. Keys are used as a part of
|
77
|
+
a regexp and values are evaluated by const_get.
|
78
|
+
|
79
|
+
:content_types:
|
80
|
+
xml: XMLParser
|
81
|
+
plist: PlistParser
|
82
|
+
json: JSON
|
83
|
+
|
84
|
+
How to format the diff output. Supports the "special" values
|
85
|
+
:ascii_diff and :color_diff or any string that will correctly
|
86
|
+
resolve to a constant:
|
87
|
+
|
88
|
+
:diff_format: :ascii_diff
|
89
|
+
|
90
|
+
Adding User-Agent aliases is useful and simple!
|
91
|
+
|
92
|
+
:user_agents:
|
93
|
+
win_ie9: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.0)
|
94
|
+
|
95
|
+
Disabling cookies altogether may be done as so:
|
96
|
+
|
97
|
+
:use_cookies: false
|
98
|
+
|
99
|
+
Setting URI-specific config options - useful if you always need to send
|
100
|
+
headers or use one-off configs. Each URI option key is dropped in a regexp
|
101
|
+
to match against the given URIs so this also works for local files.
|
102
|
+
See Kronk::Request.retrieve and Kronk::Response#selective_data
|
103
|
+
for all options supported:
|
104
|
+
|
105
|
+
:uri_options:
|
106
|
+
example.com:
|
107
|
+
:parser: XMLParser
|
108
|
+
:http_method: POST
|
109
|
+
|
110
|
+
:follow_redirects: true
|
111
|
+
|
112
|
+
:ignore_data:
|
113
|
+
- path/to/data/point
|
114
|
+
|
115
|
+
:headers:
|
116
|
+
X-Something: custom header value
|
117
|
+
|
118
|
+
:query:
|
119
|
+
offset: 1
|
120
|
+
limit: 10
|
121
|
+
|
122
|
+
Require specific files or gems in the ruby runtime:
|
123
|
+
|
124
|
+
:requires:
|
125
|
+
- kronk-my_custom_parser
|
126
|
+
- kronk-my_custom_diff_formatter
|
127
|
+
|
128
|
+
Show line numbers in the output:
|
129
|
+
|
130
|
+
:show_lines: true
|
131
|
+
|
132
|
+
== DATA TRAVERSING:
|
133
|
+
|
134
|
+
One of Kronk's most powerful features is its ability to segregate data.
|
135
|
+
From the command line, this is done by passing data paths after '--':
|
136
|
+
|
137
|
+
$ kronk http://host.com -- data/path1 data/path2/1/child
|
138
|
+
|
139
|
+
The previous example will narrow down the parsed data returned to
|
140
|
+
something like:
|
141
|
+
|
142
|
+
{
|
143
|
+
"data" => {
|
144
|
+
"path1" => "value1",
|
145
|
+
"path2" => [
|
146
|
+
nil,
|
147
|
+
{
|
148
|
+
"child" => "child value"
|
149
|
+
},
|
150
|
+
nil,
|
151
|
+
nil
|
152
|
+
]
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
If excluding data points is preferred, prepending a '-' to the path will
|
157
|
+
flag it to remove data:
|
158
|
+
|
159
|
+
$ kronk http://host.com -- -data/path2
|
160
|
+
|
161
|
+
{
|
162
|
+
"data" => {
|
163
|
+
"path1" => "value1",
|
164
|
+
"path3" => "value3",
|
165
|
+
"path4" => "value4"
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
If you would like to exclude or include only items with a specific child
|
170
|
+
attribute, you can do so by prepending the path with a ':'.
|
171
|
+
Both ':' and '-' can be combined as ':-'.
|
172
|
+
|
173
|
+
$ kronk http://host.com -- :data/path2/1/child
|
174
|
+
|
175
|
+
{
|
176
|
+
"data" => {
|
177
|
+
"path2" => [
|
178
|
+
nil,
|
179
|
+
{
|
180
|
+
"first_child" => "first value",
|
181
|
+
"child" => "child value",
|
182
|
+
"last_child" => "last value"
|
183
|
+
},
|
184
|
+
nil,
|
185
|
+
nil
|
186
|
+
]
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
There are additionally a variety of wildcard and special characters that
|
191
|
+
are supported:
|
192
|
+
|
193
|
+
* \* matches /.*/, meaning zero or more characters
|
194
|
+
|
195
|
+
* \*\*/ matches any key recursively down the data structure
|
196
|
+
|
197
|
+
* ? matches zero or one character
|
198
|
+
|
199
|
+
* | effectively works as an "OR" character, matches /^val1|val2$/
|
200
|
+
|
201
|
+
* = is used to match values and may be used in conjuction with a key or not.
|
202
|
+
|
203
|
+
* Parentheses are ok to use if in conjunction with other special characters
|
204
|
+
for a given path item, such as: /path(1|2)
|
205
|
+
|
206
|
+
Check out Kronk::DataSet for more details on data traversing.
|
207
|
+
|
208
|
+
Note: Bash may try to parse your data paths, especially if they start with
|
209
|
+
wildcards or if they contain the pipe "|" character, so you may need to put
|
210
|
+
single quotes around some of your paths.
|
211
|
+
|
212
|
+
== REQUIREMENTS:
|
213
|
+
|
214
|
+
* activesupport gem
|
215
|
+
|
216
|
+
* nokogiri gem
|
217
|
+
|
218
|
+
* plist gem
|
219
|
+
|
220
|
+
* json gem
|
221
|
+
|
222
|
+
== INSTALL:
|
223
|
+
|
224
|
+
$ sudo gem install kronk
|
225
|
+
|
226
|
+
== DEVELOPERS:
|
227
|
+
|
228
|
+
After checking out the source, run:
|
229
|
+
|
230
|
+
$ rake newb
|
231
|
+
|
232
|
+
This task will install any missing dependencies, run the tests/specs,
|
233
|
+
and generate the RDoc.
|
234
|
+
|
235
|
+
== LICENSE:
|
236
|
+
|
237
|
+
(The MIT License)
|
238
|
+
|
239
|
+
Copyright (c) 2010 Jeremie Castagna
|
240
|
+
|
241
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
242
|
+
a copy of this software and associated documentation files (the
|
243
|
+
'Software'), to deal in the Software without restriction, including
|
244
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
245
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
246
|
+
permit persons to whom the Software is furnished to do so, subject to
|
247
|
+
the following conditions:
|
248
|
+
|
249
|
+
The above copyright notice and this permission notice shall be
|
250
|
+
included in all copies or substantial portions of the Software.
|
251
|
+
|
252
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
253
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
254
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
255
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
256
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
257
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
258
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -7,12 +7,16 @@ Hoe.plugin :isolate
|
|
7
7
|
|
8
8
|
Hoe.spec 'kronk' do
|
9
9
|
developer('Jeremie Castagna', 'yaksnrainbows@gmail.com')
|
10
|
+
self.readme_file = "README.rdoc"
|
11
|
+
self.history_file = "History.rdoc"
|
12
|
+
self.extra_rdoc_files = FileList['*.rdoc']
|
10
13
|
|
11
14
|
self.extra_deps << ['plist', '~>3.1.0']
|
12
15
|
self.extra_deps << ['json', '~>1.2']
|
13
16
|
self.extra_deps << ['nokogiri', '~>1.3']
|
14
17
|
self.extra_deps << ['i18n', '~>0.5']
|
15
18
|
self.extra_deps << ['activesupport', '>=2.0.0']
|
19
|
+
self.extra_deps << ['cookiejar', '~>0.3.0']
|
16
20
|
|
17
21
|
self.extra_dev_deps << ['mocha', '~>0.9.10']
|
18
22
|
end
|
data/lib/kronk.rb
CHANGED
@@ -2,22 +2,24 @@ require 'rubygems'
|
|
2
2
|
require 'plist'
|
3
3
|
require 'json'
|
4
4
|
require 'nokogiri'
|
5
|
+
require 'cookiejar'
|
5
6
|
|
6
7
|
# Support for new and old versions of ActiveSupport
|
7
8
|
begin
|
8
9
|
require 'active_support/inflector'
|
9
|
-
rescue LoadError
|
10
|
+
rescue LoadError => e
|
11
|
+
raise unless e.message =~ /-- active_support/
|
10
12
|
require 'activesupport'
|
11
13
|
end
|
12
14
|
|
13
|
-
require 'net/
|
15
|
+
require 'net/https'
|
14
16
|
require 'optparse'
|
15
17
|
require 'yaml'
|
16
18
|
|
17
19
|
class Kronk
|
18
20
|
|
19
21
|
# This gem's version.
|
20
|
-
VERSION = '1.0
|
22
|
+
VERSION = '1.1.0'
|
21
23
|
|
22
24
|
|
23
25
|
require 'kronk/data_set'
|
@@ -36,6 +38,10 @@ class Kronk
|
|
36
38
|
DEFAULT_CACHE_FILE = File.expand_path "~/.kronk_cache"
|
37
39
|
|
38
40
|
|
41
|
+
# Default cookies file.
|
42
|
+
DEFAULT_COOKIES_FILE = File.expand_path "~/.kronk_cookies"
|
43
|
+
|
44
|
+
|
39
45
|
# Default Content-Type header to parser mapping.
|
40
46
|
DEFAULT_CONTENT_TYPES = {
|
41
47
|
'js' => 'JSON',
|
@@ -45,14 +51,44 @@ class Kronk
|
|
45
51
|
}
|
46
52
|
|
47
53
|
|
54
|
+
# Aliases for various user-agents. Thanks Mechanize! :)
|
55
|
+
USER_AGENTS = {
|
56
|
+
'kronk' =>
|
57
|
+
"Kronk/#{VERSION} (http://github.com/yaksnrainbows/kronk)",
|
58
|
+
'iphone' =>
|
59
|
+
"Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1C28 Safari/419.3",
|
60
|
+
'linux_firefox' =>
|
61
|
+
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.1) Gecko/20100122 firefox/3.6.1",
|
62
|
+
'linux_mozilla' =>
|
63
|
+
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624",
|
64
|
+
'mac_mozilla' =>
|
65
|
+
"Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401",
|
66
|
+
'linux_konqueror' =>
|
67
|
+
"Mozilla/5.0 (compatible; Konqueror/3; Linux)",
|
68
|
+
'mac_firefox' =>
|
69
|
+
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6",
|
70
|
+
'mac_safari' =>
|
71
|
+
"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; de-at) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10",
|
72
|
+
'win_ie6' =>
|
73
|
+
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
|
74
|
+
'win_ie7' =>
|
75
|
+
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
|
76
|
+
'win_mozilla' =>
|
77
|
+
"Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6"
|
78
|
+
}
|
79
|
+
|
80
|
+
|
48
81
|
# Default config to use.
|
49
82
|
DEFAULT_CONFIG = {
|
50
83
|
:content_types => DEFAULT_CONTENT_TYPES.dup,
|
51
84
|
:diff_format => :ascii_diff,
|
52
85
|
:show_lines => false,
|
53
86
|
:cache_file => DEFAULT_CACHE_FILE,
|
87
|
+
:cookies_file => DEFAULT_COOKIES_FILE,
|
88
|
+
:use_cookies => true,
|
54
89
|
:requires => [],
|
55
|
-
:uri_options => {}
|
90
|
+
:uri_options => {},
|
91
|
+
:user_agents => USER_AGENTS.dup
|
56
92
|
}
|
57
93
|
|
58
94
|
|
@@ -71,6 +107,7 @@ class Kronk
|
|
71
107
|
conf = YAML.load_file DEFAULT_CONFIG_FILE
|
72
108
|
content_types = conf.delete :content_types
|
73
109
|
uri_options = conf.delete :uri_options
|
110
|
+
user_agents = conf.delete :user_agents
|
74
111
|
|
75
112
|
if conf[:requires]
|
76
113
|
requires = [*conf.delete(:requires)]
|
@@ -78,9 +115,10 @@ class Kronk
|
|
78
115
|
self.config[:requires].concat requires
|
79
116
|
end
|
80
117
|
|
81
|
-
self.config[:uri_options].merge! uri_options
|
118
|
+
self.config[:uri_options].merge! uri_options if uri_options
|
119
|
+
self.config[:content_types].merge! content_types if content_types
|
120
|
+
self.config[:user_agents].merge! user_agents if user_agents
|
82
121
|
|
83
|
-
self.config[:content_types].merge!(content_types) if content_types
|
84
122
|
self.config.merge! conf
|
85
123
|
end
|
86
124
|
|
@@ -88,9 +126,9 @@ class Kronk
|
|
88
126
|
##
|
89
127
|
# Load the config-based requires.
|
90
128
|
|
91
|
-
def self.load_requires
|
92
|
-
return unless config[:requires]
|
93
|
-
config[:requires].each{|lib| require lib }
|
129
|
+
def self.load_requires more_requires=nil
|
130
|
+
return unless config[:requires] || more_requires
|
131
|
+
(config[:requires] | more_requires.to_a).each{|lib| require lib }
|
94
132
|
end
|
95
133
|
|
96
134
|
|
@@ -149,16 +187,73 @@ class Kronk
|
|
149
187
|
end
|
150
188
|
|
151
189
|
|
190
|
+
##
|
191
|
+
# Ask the user for a password from stdinthe command line.
|
192
|
+
|
193
|
+
def self.query_password str=nil
|
194
|
+
$stderr << "#{(str || "Password:")} "
|
195
|
+
system "stty -echo"
|
196
|
+
password = $stdin.gets.chomp
|
197
|
+
ensure
|
198
|
+
system "stty echo"
|
199
|
+
$stderr << "\n"
|
200
|
+
password
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
##
|
205
|
+
# Load the saved cookies file.
|
206
|
+
|
207
|
+
def self.load_cookie_jar file=nil
|
208
|
+
file ||= config[:cookies_file]
|
209
|
+
@cookie_jar = YAML.load_file file if File.file? file
|
210
|
+
@cookie_jar ||= CookieJar::Jar.new
|
211
|
+
@cookie_jar.expire_cookies
|
212
|
+
@cookie_jar
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
##
|
217
|
+
# Save the cookie jar to file.
|
218
|
+
|
219
|
+
def self.save_cookie_jar file=nil
|
220
|
+
file ||= config[:cookies_file]
|
221
|
+
File.open(file, "w") do |file|
|
222
|
+
file.write @cookie_jar.to_yaml
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
##
|
228
|
+
# Deletes all cookies from the runtime.
|
229
|
+
# If Kronk.run is in use, will write the change to the cookies file as well.
|
230
|
+
|
231
|
+
def self.clear_cookies!
|
232
|
+
@cookie_jar = CookieJar::Jar.new
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
##
|
237
|
+
# Returns the kronk cookie jar.
|
238
|
+
|
239
|
+
def self.cookie_jar
|
240
|
+
@cookie_jar ||= load_cookie_jar
|
241
|
+
end
|
242
|
+
|
243
|
+
|
152
244
|
##
|
153
245
|
# Make requests, parse the responses and compare the data.
|
154
|
-
#
|
155
|
-
#
|
156
|
-
# request will compare against nil.
|
246
|
+
# Query arguments may be set to the special value :cache to use the
|
247
|
+
# last live http response retrieved.
|
157
248
|
#
|
158
249
|
# Supports the following options:
|
159
250
|
# :data:: Hash/String - the data to pass to the http request
|
251
|
+
# :query:: Hash/String - the data to append to the http request path
|
160
252
|
# :headers:: Hash - extra headers to pass to the request
|
161
253
|
# :http_method:: Symbol - the http method to use; defaults to :get
|
254
|
+
# :user_agent:: String - user agent string or alias; defaults to 'kronk'
|
255
|
+
# :auth:: Hash - must contain :username and :password; defaults to nil
|
256
|
+
# :proxy:: Hash/String - http proxy to use; defaults to nil
|
162
257
|
# :only_data:: String/Array - extracts the data from given data paths
|
163
258
|
# :ignore_data:: String/Array - defines which data points to exclude
|
164
259
|
# :with_headers:: Bool/String/Array - defines which headers to include
|
@@ -167,45 +262,34 @@ class Kronk
|
|
167
262
|
#
|
168
263
|
# Returns a diff object.
|
169
264
|
|
170
|
-
def self.compare query1, query2
|
171
|
-
|
172
|
-
|
173
|
-
raw_diff query1, query2, options
|
174
|
-
else
|
175
|
-
data_diff query1, query2, options
|
176
|
-
end
|
265
|
+
def self.compare query1, query2, options={}
|
266
|
+
str1 = retrieve_data_string query1, options
|
267
|
+
str2 = retrieve_data_string query2, options
|
177
268
|
|
178
|
-
|
269
|
+
Diff.new str1, str2
|
179
270
|
end
|
180
271
|
|
181
272
|
|
182
273
|
##
|
183
|
-
# Return a
|
184
|
-
|
185
|
-
def self.raw_diff query1, query2, options={}
|
186
|
-
opts1 = options.merge options_for_uri(query1)
|
187
|
-
opts2 = options.merge options_for_uri(query2)
|
274
|
+
# Return a data string, parsed or raw.
|
275
|
+
# See Kronk.compare for supported options.
|
188
276
|
|
189
|
-
|
190
|
-
|
277
|
+
def self.retrieve_data_string query, options={}
|
278
|
+
options = options.merge options_for_uri(query)
|
191
279
|
|
192
|
-
|
193
|
-
end
|
280
|
+
resp = Request.retrieve query, options
|
194
281
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
Diff.new_from_data resp1.selective_data(opts1),
|
207
|
-
resp2.selective_data(opts2),
|
208
|
-
options
|
282
|
+
if options[:raw]
|
283
|
+
resp.selective_string options
|
284
|
+
else
|
285
|
+
begin
|
286
|
+
data = resp.selective_data options
|
287
|
+
Diff.ordered_data_string data, options[:struct]
|
288
|
+
rescue Response::MissingParser
|
289
|
+
verbose "Warning: No parser for #{resp['Content-Type']} [#{query}]"
|
290
|
+
resp.selective_string options
|
291
|
+
end
|
292
|
+
end
|
209
293
|
end
|
210
294
|
|
211
295
|
|
@@ -225,10 +309,15 @@ class Kronk
|
|
225
309
|
exit 1
|
226
310
|
end
|
227
311
|
|
312
|
+
load_cookie_jar
|
313
|
+
|
228
314
|
options = parse_args argv
|
229
315
|
|
230
|
-
|
231
|
-
|
316
|
+
load_requires options[:requires]
|
317
|
+
|
318
|
+
at_exit do
|
319
|
+
save_cookie_jar
|
320
|
+
end
|
232
321
|
|
233
322
|
options[:cache_response] = config[:cache_file] if config[:cache_file]
|
234
323
|
|
@@ -239,19 +328,9 @@ class Kronk
|
|
239
328
|
puts diff.formatted
|
240
329
|
verbose "\n\nFound #{diff.count} diff(s).\n"
|
241
330
|
|
242
|
-
elsif options[:raw]
|
243
|
-
options = options.merge options_for_uri(uri1)
|
244
|
-
|
245
|
-
out = Request.retrieve(uri1, options).selective_string options
|
246
|
-
out = Diff.insert_line_nums out if config[:show_lines]
|
247
|
-
puts out
|
248
|
-
|
249
331
|
else
|
250
|
-
|
251
|
-
|
252
|
-
data = Request.retrieve(uri1, options).selective_data options
|
253
|
-
out = Diff.ordered_data_string data, options[:struct]
|
254
|
-
out = Diff.insert_line_nums out if config[:show_lines]
|
332
|
+
out = retrieve_data_string uri1, options
|
333
|
+
out = Diff.insert_line_nums out if config[:show_lines]
|
255
334
|
puts out
|
256
335
|
end
|
257
336
|
|
@@ -274,9 +353,11 @@ class Kronk
|
|
274
353
|
|
275
354
|
def self.parse_args argv
|
276
355
|
options = {
|
277
|
-
:
|
278
|
-
:no_body
|
279
|
-
:
|
356
|
+
:auth => {},
|
357
|
+
:no_body => false,
|
358
|
+
:proxy => {},
|
359
|
+
:uris => [],
|
360
|
+
:with_headers => false
|
280
361
|
}
|
281
362
|
|
282
363
|
options = parse_data_path_args options, argv
|
@@ -308,30 +389,19 @@ Kronk runs diffs against data from live and cached http responses.
|
|
308
389
|
Options:
|
309
390
|
STR
|
310
391
|
|
311
|
-
opt.on('
|
312
|
-
|
313
|
-
options[:data] = value
|
314
|
-
options[:http_method] ||= 'POST'
|
315
|
-
end
|
316
|
-
|
317
|
-
|
318
|
-
opt.on('--prev', 'Use last response to diff against') do
|
319
|
-
options[:uris] << :cache
|
392
|
+
opt.on('--ascii', 'Return ascii formatted diff') do
|
393
|
+
config[:diff_format] = :ascii_diff
|
320
394
|
end
|
321
395
|
|
322
396
|
|
323
|
-
opt.on('--
|
324
|
-
|
325
|
-
options[:uri_suffix] = value
|
397
|
+
opt.on('--color', 'Return color formatted diff') do
|
398
|
+
config[:diff_format] = :color_diff
|
326
399
|
end
|
327
400
|
|
328
401
|
|
329
|
-
opt.on('
|
330
|
-
'
|
331
|
-
|
332
|
-
|
333
|
-
key, value = value.split ": ", 2
|
334
|
-
options[:headers][key] = value
|
402
|
+
opt.on('--format STR', String,
|
403
|
+
'Use a custom diff formatter') do |value|
|
404
|
+
config[:diff_format] = value
|
335
405
|
end
|
336
406
|
|
337
407
|
|
@@ -363,22 +433,19 @@ Kronk runs diffs against data from live and cached http responses.
|
|
363
433
|
end
|
364
434
|
|
365
435
|
|
366
|
-
opt.on('
|
367
|
-
|
368
|
-
options[:follow_redirects] = value || true
|
436
|
+
opt.on('--lines', 'Show line numbers') do
|
437
|
+
config[:show_lines] = true
|
369
438
|
end
|
370
439
|
|
371
440
|
|
372
|
-
opt.on('
|
373
|
-
'
|
374
|
-
options[:
|
441
|
+
opt.on('--parser STR', String,
|
442
|
+
'Override default parser') do |value|
|
443
|
+
options[:parser] = value
|
375
444
|
end
|
376
445
|
|
377
446
|
|
378
|
-
opt.on('
|
379
|
-
|
380
|
-
options[:requires] ||= []
|
381
|
-
options[:requires].concat value
|
447
|
+
opt.on('--prev', 'Use last response to diff against') do
|
448
|
+
options[:uris].unshift :cache
|
382
449
|
end
|
383
450
|
|
384
451
|
|
@@ -387,40 +454,105 @@ Kronk runs diffs against data from live and cached http responses.
|
|
387
454
|
end
|
388
455
|
|
389
456
|
|
457
|
+
opt.on('-r', '--require lib1,lib2', Array,
|
458
|
+
'Require a library or gem') do |value|
|
459
|
+
options[:requires] ||= []
|
460
|
+
options[:requires].concat value
|
461
|
+
end
|
462
|
+
|
463
|
+
|
390
464
|
opt.on('--struct', 'Run diff on the data structure') do
|
391
465
|
options[:struct] = true
|
392
466
|
end
|
393
467
|
|
394
468
|
|
395
|
-
opt.on('--
|
396
|
-
config[:
|
469
|
+
opt.on('-V', '--verbose', 'Make the operation more talkative') do
|
470
|
+
config[:verbose] = true
|
397
471
|
end
|
398
472
|
|
399
473
|
|
400
|
-
opt.
|
401
|
-
|
474
|
+
opt.separator <<-STR
|
475
|
+
|
476
|
+
HTTP Options:
|
477
|
+
STR
|
478
|
+
|
479
|
+
opt.on('--clear-cookies', 'Delete all saved cookies') do
|
480
|
+
clear_cookies!
|
402
481
|
end
|
403
482
|
|
404
483
|
|
405
|
-
opt.on('--
|
406
|
-
'
|
407
|
-
|
484
|
+
opt.on('-d', '--data STR', String,
|
485
|
+
'Post data with the request') do |value|
|
486
|
+
options[:data] = value
|
487
|
+
options[:http_method] ||= 'POST'
|
408
488
|
end
|
409
489
|
|
410
490
|
|
411
|
-
opt.on('
|
412
|
-
|
491
|
+
opt.on('-H', '--header STR', String,
|
492
|
+
'Header to pass to the server request') do |value|
|
493
|
+
options[:headers] ||= {}
|
494
|
+
|
495
|
+
key, value = value.split ": ", 2
|
496
|
+
options[:headers][key] = value.strip
|
413
497
|
end
|
414
498
|
|
415
499
|
|
416
|
-
opt.on('--
|
417
|
-
'
|
418
|
-
options[:
|
500
|
+
opt.on('-A', '--user-agent STR', String,
|
501
|
+
'User-Agent to send to server or a valid alias') do |value|
|
502
|
+
options[:user_agent] = value
|
419
503
|
end
|
420
504
|
|
421
505
|
|
422
|
-
opt.on('-
|
423
|
-
|
506
|
+
opt.on('-L', '--location [NUM]', Integer,
|
507
|
+
'Follow the location header always or num times') do |value|
|
508
|
+
options[:follow_redirects] = value || true
|
509
|
+
end
|
510
|
+
|
511
|
+
|
512
|
+
opt.on('--no-cookies', 'Don\'t use cookies for this session') do
|
513
|
+
options[:no_cookies] = true
|
514
|
+
end
|
515
|
+
|
516
|
+
|
517
|
+
opt.on('-?', '--query STR', String,
|
518
|
+
'Append query to URLs') do |value|
|
519
|
+
options[:query] = value
|
520
|
+
end
|
521
|
+
|
522
|
+
|
523
|
+
opt.on('--suff STR', String,
|
524
|
+
'Add common path items to the end of each URL') do |value|
|
525
|
+
options[:uri_suffix] = value
|
526
|
+
end
|
527
|
+
|
528
|
+
|
529
|
+
opt.on('-U', '--proxy-user STR', String,
|
530
|
+
'Set proxy user and/or password: usr[:pass]') do |value|
|
531
|
+
options[:proxy][:username], options[:proxy][:password] =
|
532
|
+
value.split ":", 2
|
533
|
+
|
534
|
+
options[:proxy][:password] ||= query_password "Proxy password:"
|
535
|
+
end
|
536
|
+
|
537
|
+
|
538
|
+
opt.on('-u', '--user STR', String,
|
539
|
+
'Set server auth user and/or password: usr[:pass]') do |value|
|
540
|
+
options[:auth][:username], options[:auth][:password] =
|
541
|
+
value.split ":", 2
|
542
|
+
|
543
|
+
options[:auth][:password] ||= query_password "Server password:"
|
544
|
+
end
|
545
|
+
|
546
|
+
|
547
|
+
opt.on('-X', '--request STR', String,
|
548
|
+
'The request method to use') do |value|
|
549
|
+
options[:http_method] = value
|
550
|
+
end
|
551
|
+
|
552
|
+
|
553
|
+
opt.on('-x', '--proxy STR', String,
|
554
|
+
'Use HTTP proxy on given port: host[:port]') do |value|
|
555
|
+
options[:proxy][:address], options[:proxy][:port] = value.split ":", 2
|
424
556
|
end
|
425
557
|
|
426
558
|
opt.separator nil
|
@@ -428,6 +560,11 @@ Kronk runs diffs against data from live and cached http responses.
|
|
428
560
|
|
429
561
|
opts.parse! argv
|
430
562
|
|
563
|
+
unless $stdin.tty?
|
564
|
+
io = StringIO.new $stdin.read
|
565
|
+
options[:uris] << io
|
566
|
+
end
|
567
|
+
|
431
568
|
options[:uris].concat argv
|
432
569
|
options[:uris].slice!(2..-1)
|
433
570
|
|