kronk 1.6.2 → 1.7.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.
Files changed (48) hide show
  1. data/History.rdoc +29 -1
  2. data/Manifest.txt +6 -1
  3. data/README.rdoc +74 -28
  4. data/Rakefile +4 -3
  5. data/TODO.rdoc +7 -5
  6. data/bin/kronk +2 -11
  7. data/lib/kronk/async/em_ext.rb +34 -0
  8. data/lib/kronk/async/request.rb +73 -0
  9. data/lib/kronk/async/response.rb +70 -0
  10. data/lib/kronk/async.rb +118 -0
  11. data/lib/kronk/cmd.rb +111 -43
  12. data/lib/kronk/constants.rb +1 -0
  13. data/lib/kronk/core_ext.rb +1 -1
  14. data/lib/kronk/data_string.rb +251 -0
  15. data/lib/kronk/diff/output.rb +132 -100
  16. data/lib/kronk/diff.rb +20 -24
  17. data/lib/kronk/path/matcher.rb +8 -4
  18. data/lib/kronk/path/path_match.rb +48 -4
  19. data/lib/kronk/path/transaction.rb +74 -53
  20. data/lib/kronk/path.rb +11 -6
  21. data/lib/kronk/player/benchmark.rb +11 -12
  22. data/lib/kronk/player/input_reader.rb +40 -3
  23. data/lib/kronk/player/request_parser.rb +4 -1
  24. data/lib/kronk/player/stream.rb +2 -2
  25. data/lib/kronk/player/suite.rb +16 -9
  26. data/lib/kronk/player.rb +93 -143
  27. data/lib/kronk/queue_runner.rb +238 -0
  28. data/lib/kronk/request.rb +25 -20
  29. data/lib/kronk/response.rb +39 -10
  30. data/lib/kronk/test/assertions.rb +2 -2
  31. data/lib/kronk/test/helper_methods.rb +1 -1
  32. data/lib/kronk.rb +56 -24
  33. data/test/test_assertions.rb +4 -4
  34. data/test/test_cmd.rb +38 -10
  35. data/test/test_data_string.rb +242 -1
  36. data/test/test_diff.rb +8 -303
  37. data/test/test_helper.rb +1 -1
  38. data/test/test_kronk.rb +21 -28
  39. data/test/test_path.rb +29 -0
  40. data/test/test_path_match.rb +47 -2
  41. data/test/test_path_matcher.rb +42 -1
  42. data/test/test_player.rb +71 -72
  43. data/test/test_request.rb +31 -6
  44. data/test/test_request_parser.rb +7 -1
  45. data/test/test_response.rb +1 -1
  46. data/test/test_transaction.rb +78 -30
  47. metadata +64 -8
  48. data/lib/kronk/data_renderer.rb +0 -219
data/History.rdoc CHANGED
@@ -1,6 +1,34 @@
1
+ === 1.7.0 / 2011-10-09
2
+
3
+ * Major Enhancements:
4
+
5
+ * EventMachine backend support for Player.
6
+
7
+ * Enhancements:
8
+
9
+ * Full URL support for player input.
10
+
11
+ * Move and map path transaction support with matches and splats.
12
+
13
+ * Block support for player input and result.
14
+
15
+ * Request proxy :address key changed to :host.
16
+
17
+ * Many Player performance improvements, especially on Ubuntu.
18
+
19
+ * Bugfixes:
20
+
21
+ * Support relative URLs in redirects.
22
+
23
+ * More accurate data diff metadata output.
24
+
25
+ * Lots of Diff::Output and DataString cleanup.
26
+
27
+ * Assign URI options to redirects.
28
+
1
29
  === 1.6.2 / 2011-09-12
2
30
 
3
- * Bugfixes
31
+ * Bugfixes:
4
32
 
5
33
  * Handling of stream output with Diff#formatted is nil.
6
34
 
data/Manifest.txt CHANGED
@@ -5,10 +5,14 @@ README.rdoc
5
5
  Rakefile
6
6
  bin/kronk
7
7
  lib/kronk.rb
8
+ lib/kronk/async.rb
9
+ lib/kronk/async/em_ext.rb
10
+ lib/kronk/async/request.rb
11
+ lib/kronk/async/response.rb
8
12
  lib/kronk/cmd.rb
9
13
  lib/kronk/constants.rb
10
14
  lib/kronk/core_ext.rb
11
- lib/kronk/data_renderer.rb
15
+ lib/kronk/data_string.rb
12
16
  lib/kronk/diff.rb
13
17
  lib/kronk/diff/ascii_format.rb
14
18
  lib/kronk/diff/color_format.rb
@@ -25,6 +29,7 @@ lib/kronk/player/request_parser.rb
25
29
  lib/kronk/player/suite.rb
26
30
  lib/kronk/player/stream.rb
27
31
  lib/kronk/plist_parser.rb
32
+ lib/kronk/queue_runner.rb
28
33
  lib/kronk/request.rb
29
34
  lib/kronk/response.rb
30
35
  lib/kronk/test.rb
data/README.rdoc CHANGED
@@ -11,10 +11,14 @@ Kronk was made possible by the sponsoring of AT&T Interactive.
11
11
 
12
12
  * Parse and display or diff data from http response body and/or headers.
13
13
 
14
- * Include or exclude specific data points with file-glob-like paths.
14
+ * Include, exclude or map specific data points with file-glob-like paths.
15
+
16
+ * Query and logfile playback with custom output.
15
17
 
16
18
  * Supports json, rails-ish xml, and plist.
17
19
 
20
+ * URI-specific configuration.
21
+
18
22
  * Support for custom data parsers and diff formatters.
19
23
 
20
24
  * Launch IRB console with the retrieved response data.
@@ -25,12 +29,8 @@ Kronk was made possible by the sponsoring of AT&T Interactive.
25
29
 
26
30
  * Easy-to-read output (color or ascii, line numbers, etc).
27
31
 
28
- * URI-specific configuration.
29
-
30
32
  * Helper methods for test suites.
31
33
 
32
- * Query and logfile playback with custom output.
33
-
34
34
  * Yes, it works on Windows.
35
35
 
36
36
  == SYNOPSIS:
@@ -79,12 +79,12 @@ Kronk pulls it's config from $HOME/.kronk/rc and supports the following:
79
79
 
80
80
  Set the file to save the last http response retrieved in:
81
81
 
82
- :cache_file: ~/.kronk_cache
82
+ cache_file: ~/.kronk_cache
83
83
 
84
84
  Content types to match to a parser. Keys are used as a part of
85
85
  a regexp and values are evaluated by const_get.
86
86
 
87
- :content_types:
87
+ content_types:
88
88
  xml: XMLParser
89
89
  plist: PlistParser
90
90
  json: JSON
@@ -92,23 +92,23 @@ a regexp and values are evaluated by const_get.
92
92
  Number of lines of context to use for diff. Full diff is returned when
93
93
  set to false:
94
94
 
95
- :context: 5 # show 5 lines before and after diff
96
- :context: false # show the full file
95
+ context: 5 # show 5 lines before and after diff
96
+ context: false # show the full file
97
97
 
98
- How to format the diff output. Supports the "special" values
99
- :ascii_diff and :color_diff or any string that will correctly
98
+ How to format the diff output. Supports the special values
99
+ 'ascii' and 'color' or any string that will correctly
100
100
  resolve to a constant:
101
101
 
102
- :diff_format: :ascii_diff
102
+ diff_format: ascii
103
103
 
104
104
  Adding User-Agent aliases is useful and simple!
105
105
 
106
- :user_agents:
106
+ user_agents:
107
107
  win_ie9: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.0)
108
108
 
109
109
  Disabling cookies altogether may be done as so:
110
110
 
111
- :use_cookies: false
111
+ use_cookies: false
112
112
 
113
113
  Setting URI-specific config options - useful if you always need to send
114
114
  headers or use one-off configs. Each URI option key is dropped in a regexp
@@ -116,40 +116,40 @@ to match against the given URIs so this also works for local files.
116
116
  See Kronk::Request.retrieve and Kronk::Response#selective_data
117
117
  for all options supported:
118
118
 
119
- :uri_options:
119
+ uri_options:
120
120
  example.com:
121
- :parser: XMLParser
122
- :http_method: POST
121
+ parser: XMLParser
122
+ http_method: POST
123
123
 
124
- :follow_redirects: true
124
+ follow_redirects: true
125
125
 
126
- :ignore_data:
126
+ ignore_data:
127
127
  - path/to/data/point
128
128
 
129
- :headers:
129
+ headers:
130
130
  X-Something: custom header value
131
131
 
132
- :query:
132
+ query:
133
133
  offset: 1
134
134
  limit: 10
135
135
 
136
136
  Require specific files or gems in the ruby runtime:
137
137
 
138
- :requires:
138
+ requires:
139
139
  - kronk-my_custom_parser
140
140
  - kronk-my_custom_diff_formatter
141
141
 
142
142
  Show line numbers in the output:
143
143
 
144
- :show_lines: true
144
+ show_lines: true
145
145
 
146
146
  Assign a default host to use when none is specified:
147
147
 
148
- :default_host: http://localhost:3000
148
+ default_host: http://localhost:3000
149
149
 
150
150
  Set the number of spaces for indentation:
151
151
 
152
- :indentation: 2
152
+ indentation: 2
153
153
 
154
154
  === Bash Completion:
155
155
 
@@ -158,10 +158,15 @@ Bash completion is available by sourcing the file returned by:
158
158
  $ kronk --completion
159
159
  [gem path]/script/kronk_completion
160
160
 
161
- == DATA TRAVERSING:
161
+ == DATA MANIPULATION:
162
162
 
163
163
  One of Kronk's most powerful features is its ability to segregate data.
164
- From the command line, this is done by passing data paths after '--':
164
+ From the command line, this is done by passing data paths after '--'
165
+
166
+ === Selecting and Deleting:
167
+
168
+ The first kind of data transformation is the ability to select and delete
169
+ data by path:
165
170
 
166
171
  $ kronk http://host.com -- data/path1 data/path2/1/child
167
172
 
@@ -240,6 +245,37 @@ end of the path in the following fashion:
240
245
  }
241
246
  }
242
247
 
248
+ === Mapping and Moving:
249
+
250
+ In Kronk, mapping equates to selecting and renaming a given path in an empty
251
+ data structure. Moving refers to deleting the path value and placing it
252
+ back in the original data structure at the new path.
253
+
254
+ # Mapping is done with the > operator:
255
+ $ kronk host.com -- data/path3 "data/path(1|2)>moved%1"
256
+
257
+ {
258
+ "data": {
259
+ "path3": "value3"
260
+ }
261
+ "moved1": "value1",
262
+ "moved2": "value2"
263
+ }
264
+
265
+
266
+ # Moving is done with the >> operator:
267
+ $ kronk host.com -- "data/path(1|2)>moved%1"
268
+
269
+ {
270
+ "data": {
271
+ "path3": "value3",
272
+ "path4": "value4"
273
+ }
274
+ "moved1": "value1",
275
+ "moved2": "value2"
276
+ }
277
+
278
+ === Special Characters:
243
279
 
244
280
  There are additionally a variety of wildcard and special characters that
245
281
  are supported:
@@ -263,7 +299,17 @@ are supported:
263
299
 
264
300
  * \\ escapes any special path character
265
301
 
266
- Check out Kronk::Path and Kronk::DataSet for more details on data traversing.
302
+ * > is used to exclusively map one path to another
303
+
304
+ * >> moves a path to another within the original data structure
305
+
306
+ * %NUM is used in the target path to reference a given match
307
+
308
+ * %% is used to reference splats from the original path and assign it in the
309
+ target path
310
+
311
+ Check out Kronk::Path and Kronk::Path::Transaction for more details
312
+ on data manipulation.
267
313
 
268
314
  Note: Bash may try to parse your data paths, especially if they start with
269
315
  wildcards or if they contain the pipe "|" character, so you may need to put
data/Rakefile CHANGED
@@ -25,9 +25,10 @@ Hoe.spec 'kronk' do
25
25
  self.extra_deps << ['json', '~>1.5']
26
26
  self.extra_deps << ['cookiejar', '~>0.3.0']
27
27
 
28
- self.extra_dev_deps << ['plist', '~>3.1.0']
29
- self.extra_dev_deps << ['nokogiri', '~>1.4']
30
- self.extra_dev_deps << ['mocha', '~>0.9.12']
28
+ self.extra_dev_deps << ['plist', '~>3.1.0']
29
+ self.extra_dev_deps << ['nokogiri', '~>1.4']
30
+ self.extra_dev_deps << ['mocha', '~>0.9.12']
31
+ self.extra_dev_deps << ['em-http-request', '~>1.0.0']
31
32
  end
32
33
 
33
34
 
data/TODO.rdoc CHANGED
@@ -1,18 +1,20 @@
1
1
  = TODO
2
2
 
3
- == Path
3
+ * Investigate Kronk console.
4
4
 
5
- * Support move and map for path transactions.
5
+ == Done
6
6
 
7
- == Player
7
+ * Investigate the use of EM for QueueRunner.
8
+
9
+ * Refactor Kronk::Player into a Player and a QueueRunner.
10
+
11
+ * Support move and map for path transactions.
8
12
 
9
13
  * Read full URIs for player input but strip off the protocol and host.
10
14
 
11
15
  * When using player and no host is given, support reading a full URI for
12
16
  player input.
13
17
 
14
- == Done
15
-
16
18
  * Support data diffing for arrays (including data struct).
17
19
 
18
20
  * Allow for showing diffed sections of a diff only.
data/bin/kronk CHANGED
@@ -1,15 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $: << File.join(File.dirname(__FILE__), "../lib") if $0 =~ %r{bin/kronk$}
4
-
5
- begin
6
- require 'kronk'
7
-
8
- rescue LoadError => e
9
- raise unless e.message =~ %r{no such file to load -- kronk}
10
-
11
- $: << File.join(File.dirname(__FILE__), "../lib")
12
- require 'kronk'
13
- end
3
+ $: << File.join(File.dirname(__FILE__), "../lib") if $0 == "bin/kronk"
14
4
 
5
+ require 'kronk'
15
6
  Kronk::Cmd.run
@@ -0,0 +1,34 @@
1
+ require 'em-http-request'
2
+
3
+ module EventMachine
4
+ class HttpClient
5
+ attr_accessor :raw_response
6
+
7
+ alias em_parse_response_header parse_response_header
8
+
9
+ def parse_response_header header, version, status
10
+ out = em_parse_response_header header, version, status
11
+
12
+ rheader = @response_header
13
+
14
+ @raw_response = "HTTP/#{rheader.http_version} "
15
+ @raw_response << "#{rheader.status} #{rheader.http_reason}\r\n"
16
+
17
+ header.each do |key, val|
18
+ @raw_response << "#{key}: #{val}\r\n"
19
+ end
20
+
21
+ @raw_response << "\r\n"
22
+
23
+ out
24
+ end
25
+
26
+
27
+ alias em_on_decoded_body_data on_decoded_body_data
28
+
29
+ def on_decoded_body_data data
30
+ @raw_response << data
31
+ em_on_decoded_body_data data
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,73 @@
1
+ class Kronk
2
+ class Request
3
+
4
+ class EMError < Kronk::Exception; end
5
+
6
+ ##
7
+ # Retrieve this requests' response asynchronously with em-http-request.
8
+ # Returns a EM::HttpConnection instance.
9
+ #
10
+ # Passing a block will yield a Kronk::Response instance and/or
11
+ # an Exception instance if an error was caught.
12
+ #
13
+ # req = Request.new "example.com"
14
+ # em_req = req.retrieve_async do |kronk_response, err|
15
+ # # do something with Kronk::Response instance here
16
+ # end
17
+ #
18
+ # em_req.callback { ... }
19
+ # em_req.error { ... }
20
+
21
+ def retrieve_async &block
22
+ header_opts = @headers.dup
23
+
24
+ if @auth && !@auth.empty?
25
+ header_opts['Authorization'] ||= []
26
+ header_opts['Authorization'][0] = @auth[:username] if @auth[:username]
27
+ header_opts['Authorization'][1] = @auth[:password] if @auth[:password]
28
+ end
29
+
30
+ conn = async_http
31
+
32
+ start_time = Time.now
33
+ req = conn.setup_request @http_method,
34
+ :head => header_opts, :body => @body, &block
35
+
36
+ req.callback do |resp|
37
+ elapsed_time = Time.now - start_time
38
+ @response = Response.new resp.raw_response, nil, self
39
+ @response.time = elapsed_time
40
+ yield @response, nil
41
+ end if block_given?
42
+
43
+ req.errback do |c|
44
+ err = c.error ?
45
+ EMError.new(c.error) :
46
+ Kronk::NotFoundError.new("#{@uri} could not be found")
47
+
48
+ yield nil, err
49
+ end
50
+
51
+ req
52
+ end
53
+
54
+
55
+ ##
56
+ # Return an EM::HttpRequest instance.
57
+
58
+ def async_http
59
+ unless @proxy.empty?
60
+ proxy_opts = @proxy.dup
61
+ proxy_opts[:authorization] = [
62
+ proxy_opts.delete(:username),
63
+ proxy_opts.delete(:password)
64
+ ] if proxy_opts[:username] || proxy_opts[:password]
65
+ end
66
+
67
+ EventMachine::HttpRequest.new @uri,
68
+ :connect_timeout => @timeout,
69
+ :inactivity_timeout => @timeout,
70
+ :proxy => proxy_opts
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,70 @@
1
+ class Kronk
2
+ class Response
3
+
4
+ class AsyncHandler < EM::Connection
5
+ attr_accessor :buffer
6
+
7
+ def initialize req
8
+ @buffer = ""
9
+ @callback = nil
10
+ @_req = req
11
+ @_res = nil
12
+ end
13
+
14
+
15
+ def callback &block
16
+ @callback = block
17
+ end
18
+
19
+
20
+ def receive_data str
21
+ @buffer << str
22
+ end
23
+
24
+
25
+ def unbind
26
+ return unless @callback
27
+
28
+ @_res = Kronk::Response.new @buffer, nil, @_req
29
+ err = Kronk::Request::EMError.new "IO read error" if error?
30
+
31
+ @callback.call @_res, err
32
+
33
+ rescue => e
34
+ @callback.call @_res, e
35
+ end
36
+ end
37
+
38
+
39
+ ##
40
+ # Response.new with asynchronous IO input.
41
+ # Returns an EM::Connection subclass (AsyncHandler) instance.
42
+ #
43
+ # Passing a block will yield a Kronk::Response instance and/or
44
+ # an Exception instance if an error was caught.
45
+ #
46
+ # conn = Response.from_async_io do |resp, err|
47
+ # # do something with Kronk::Response instance here
48
+ # end
49
+
50
+ def self.from_async_io io, req=nil, &block
51
+ conn = EM.attach io, AsyncHandler, req
52
+ conn.comm_inactivity_timeout = 2
53
+ conn.callback(&block)
54
+ conn
55
+ end
56
+
57
+
58
+ ##
59
+ # Follow the redirect and return a new Response instance.
60
+ # Returns nil if not redirect-able.
61
+ #
62
+ # Passing a block will yield a Kronk::Response instance and/or
63
+ # an Exception instance if an error was caught.
64
+
65
+ def follow_redirect_async opts={}, &block
66
+ return if !redirect?
67
+ Request.new(self.location, opts).retrieve_async(&block)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,118 @@
1
+ require 'kronk'
2
+ require 'kronk/async/em_ext'
3
+ require 'kronk/async/request'
4
+ require 'kronk/async/response'
5
+
6
+ class Kronk
7
+
8
+ ##
9
+ # Returns an EM::MultiRequest instance from a url, file, or IO pair.
10
+ # Calls the given block with a Kronk::Diff object on completion or error.
11
+ # Assigns @response, @responses, @diff. Must be called from an EM loop.
12
+ #
13
+ # kronk.compare_async uri1, uri2 do |diff, err|
14
+ # # handle diff, responses, or error
15
+ # end
16
+
17
+ def compare_async uri1, uri2
18
+ multi = EM::MultiRequest.new
19
+
20
+ str1 = str2 = ""
21
+ res1 = res2 = nil
22
+ err1 = err2 = nil
23
+
24
+ conn1 = request_async uri1 do |res, err|
25
+ err1 = err and next if err
26
+ res1 = res
27
+ str1 = res.stringify
28
+ end
29
+
30
+ conn2 = request_async uri2 do |res, err|
31
+ err2 = err and next if err
32
+ res2 = res
33
+ str2 = res.stringify
34
+ end
35
+
36
+ multi.add :left, conn1
37
+ multi.add :right, conn2
38
+
39
+ multi.callback do
40
+ next yield(nil, (err1 || err2)) if err1 || err2
41
+
42
+ @responses = [res1, res2]
43
+ @response = res2
44
+
45
+ opts = {:labels => [res1.uri, res2.uri]}.merge @options
46
+ @diff = Diff.new str1, str2, opts
47
+
48
+ yield @diff
49
+ end
50
+
51
+ multi
52
+
53
+ rescue => e
54
+ yield nil, e
55
+ end
56
+
57
+
58
+ ##
59
+ # Returns an EventMachine Connection instance from a url, file, or IO.
60
+ # Calls the given block with a Kronk::Response object on completion or error.
61
+ # Assigns @response, @responses, @diff. Must be called from an EM loop.
62
+ #
63
+ # kronk.request_async uri do |resp, err|
64
+ # # handle response or error
65
+ # end
66
+
67
+ def request_async uri
68
+ options = Kronk.config[:no_uri_options] ? @options : options_for_uri(uri)
69
+
70
+ rdir = options[:follow_redirects]
71
+
72
+ handler = Proc.new do |resp, err|
73
+ next yield(resp, err) if err
74
+
75
+ resp.parser = options[:parser] if options[:parser]
76
+ resp.stringify_opts = options
77
+
78
+ if resp.redirect? && (rdir == true || Fixnum === rdir && rdir > 0)
79
+ Cmd.verbose "Following redirect to #{resp.location}"
80
+
81
+ rdir = rdir - 1 if Fixnum === rdir
82
+ opts = options_for_uri resp.location
83
+ resp.follow_redirect_async(opts, &handler)
84
+
85
+ else
86
+ @responses = [resp]
87
+ @response = resp
88
+ @diff = nil
89
+
90
+ yield resp if block_given?
91
+
92
+ resp
93
+ end
94
+ end
95
+
96
+ if IO === uri
97
+ Cmd.verbose "Reading IO #{uri}"
98
+ Response.from_async_io(uri, &handler)
99
+
100
+ elsif StringIO === uri
101
+ Cmd.verbose "Reading IO #{uri}"
102
+ handler.call Response.new(uri)
103
+
104
+ elsif File.file? uri.to_s
105
+ Cmd.verbose "Reading file: #{uri}\n"
106
+ handler.call Response.read_file(uri)
107
+
108
+ else
109
+ req = Request.new uri, options
110
+ Cmd.verbose "Retrieving URL: #{req.uri}\n"
111
+ conn = req.retrieve_async(&handler)
112
+ conn.callback{ Kronk.history << uri }
113
+ end
114
+
115
+ rescue => e
116
+ yield nil, e
117
+ end
118
+ end