kronk 1.4.0 → 1.5.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/lib/kronk/cmd.rb CHANGED
@@ -6,7 +6,7 @@ class Kronk
6
6
  class Cmd
7
7
 
8
8
  ##
9
- # Start an IRB console with the given http response object.
9
+ # Start an IRB console with the given Kronk::Response object.
10
10
 
11
11
  def self.irb resp
12
12
  require 'irb'
@@ -18,11 +18,11 @@ class Kronk
18
18
  resp.body
19
19
  end
20
20
 
21
- puts "\nHTTP Response is in $http_response"
22
- puts "Response data is in $response\n\n"
21
+ $stdout.puts "\nHTTP Response is in $http_response"
22
+ $stdout.puts "Response data is in $response\n\n"
23
23
 
24
24
  IRB.start
25
- exit 1
25
+ false
26
26
  end
27
27
 
28
28
 
@@ -47,21 +47,6 @@ class Kronk
47
47
  end
48
48
 
49
49
 
50
- ##
51
- # Moves the old config file to the new directory structure.
52
-
53
- def self.move_config_file
54
- require 'fileutils'
55
-
56
- kronk_tmp_config = ".kronk.tmp"
57
- File.rename Kronk::CONFIG_DIR, kronk_tmp_config
58
-
59
- Dir.mkdir Kronk::CONFIG_DIR
60
-
61
- FileUtils.mv kronk_tmp_config, Kronk::DEFAULT_CONFIG_FILE
62
- end
63
-
64
-
65
50
  ##
66
51
  # Parse ARGV
67
52
 
@@ -69,6 +54,7 @@ class Kronk
69
54
  options = {
70
55
  :auth => {},
71
56
  :no_body => false,
57
+ :player => {},
72
58
  :proxy => {},
73
59
  :uris => [],
74
60
  :with_headers => false
@@ -115,8 +101,10 @@ Parse and run diffs against data from live and cached http responses.
115
101
 
116
102
 
117
103
  opt.on('--completion', 'Print bash completion file path and exit') do
118
- file = File.join(File.dirname(__FILE__), "../script/kronk_completion")
119
- puts File.expand_path(file)
104
+ file = File.join(File.dirname(__FILE__),
105
+ "../../script/kronk_completion")
106
+
107
+ $stdout.puts File.expand_path(file)
120
108
  exit 2
121
109
  end
122
110
 
@@ -138,7 +126,7 @@ Parse and run diffs against data from live and cached http responses.
138
126
  end
139
127
 
140
128
 
141
- opt.on('-i', '--include [header1,header2]', Array,
129
+ opt.on('-i', '--include [HEADER1,HEADER2]', Array,
142
130
  'Include all or given headers in response') do |value|
143
131
  options[:with_headers] ||= []
144
132
 
@@ -148,10 +136,12 @@ Parse and run diffs against data from live and cached http responses.
148
136
  else
149
137
  options[:with_headers] = true
150
138
  end
139
+
140
+ options[:no_body] = false
151
141
  end
152
142
 
153
143
 
154
- opt.on('-I', '--head [header1,header2]', Array,
144
+ opt.on('-I', '--head [HEADER1,HEADER2]', Array,
155
145
  'Use all or given headers only in the response') do |value|
156
146
  options[:with_headers] ||= []
157
147
 
@@ -187,7 +177,7 @@ Parse and run diffs against data from live and cached http responses.
187
177
 
188
178
 
189
179
  opt.on('-P', '--parser STR', String,
190
- 'Override default parser') do |value|
180
+ 'Override default response body parser') do |value|
191
181
  options[:parser] = value
192
182
  end
193
183
 
@@ -202,13 +192,18 @@ Parse and run diffs against data from live and cached http responses.
202
192
  end
203
193
 
204
194
 
205
- opt.on('-r', '--require lib1,lib2', Array,
195
+ opt.on('-r', '--require LIB1,LIB2', Array,
206
196
  'Require a library or gem') do |value|
207
197
  options[:requires] ||= []
208
198
  options[:requires].concat value
209
199
  end
210
200
 
211
201
 
202
+ opt.on('--ruby', 'Use legacy Ruby renderer') do
203
+ Kronk.config[:render_lang] = 'ruby'
204
+ end
205
+
206
+
212
207
  opt.on('--struct', 'Run diff on the data structure') do
213
208
  options[:struct] = true
214
209
  end
@@ -219,6 +214,51 @@ Parse and run diffs against data from live and cached http responses.
219
214
  end
220
215
 
221
216
 
217
+ opt.separator <<-STR
218
+
219
+ Player Options:
220
+ STR
221
+
222
+ opt.on('-c', '--concurrency NUM', Integer,
223
+ 'Number of concurrent requests to make; default: 1') do |num|
224
+ options[:player][:concurrency] = num
225
+ end
226
+
227
+
228
+ opt.on('-n', '--number NUM', Integer,
229
+ 'Total number of requests to make') do |num|
230
+ options[:player][:number] = num
231
+ end
232
+
233
+
234
+ opt.on('-o', '--replay-out [FORMAT]',
235
+ 'Output format used by --replay; default: stream') do |output|
236
+ options[:player][:output] = output || :stream
237
+ end
238
+
239
+
240
+ opt.on('-p', '--replay [FILE]',
241
+ 'Replay the given file or STDIN against URIs') do |file|
242
+ options[:player][:io] = File.open(file, "r") if file
243
+ options[:player][:io] ||= $stdin if !$stdin.tty?
244
+ options[:player][:output] ||= :suite
245
+ end
246
+
247
+
248
+ opt.on('--benchmark [FILE]', 'Same as -p [FILE] -o benchmark') do |file|
249
+ options[:player][:io] = File.open(file, "r") if file
250
+ options[:player][:io] ||= $stdin if !$stdin.tty?
251
+ options[:player][:output] = :benchmark
252
+ end
253
+
254
+
255
+ opt.on('--stream [FILE]', 'Same as -p [FILE] -o stream') do |file|
256
+ options[:player][:io] = File.open(file, "r") if file
257
+ options[:player][:io] ||= $stdin if !$stdin.tty?
258
+ options[:player][:output] = :stream
259
+ end
260
+
261
+
222
262
  opt.separator <<-STR
223
263
 
224
264
  HTTP Options:
@@ -240,8 +280,8 @@ Parse and run diffs against data from live and cached http responses.
240
280
  'Header to pass to the server request') do |value|
241
281
  options[:headers] ||= {}
242
282
 
243
- key, value = value.split ": ", 2
244
- options[:headers][key] = value.strip
283
+ key, value = value.split /:\s*/, 2
284
+ options[:headers][key] = value.to_s.strip
245
285
  end
246
286
 
247
287
 
@@ -274,7 +314,7 @@ Parse and run diffs against data from live and cached http responses.
274
314
  end
275
315
 
276
316
 
277
- opt.on('--timeout INT', Integer,
317
+ opt.on('-t', '--timeout INT', Integer,
278
318
  'Timeout for http connection in seconds') do |value|
279
319
  Kronk.config[:timeout] = value
280
320
  end
@@ -314,7 +354,14 @@ Parse and run diffs against data from live and cached http responses.
314
354
 
315
355
  opts.parse! argv
316
356
 
317
- unless $stdin.tty?
357
+ unless options[:player].empty?
358
+ options[:player] = Player.new options[:player]
359
+ else
360
+ options.delete :player
361
+ end
362
+
363
+ if !$stdin.tty? && !(options[:player] && options[:player].input.io)
364
+ io = $stdin
318
365
  io = StringIO.new $stdin.read
319
366
  options[:uris] << io
320
367
  end
@@ -322,22 +369,22 @@ Parse and run diffs against data from live and cached http responses.
322
369
  options[:uris].concat argv
323
370
  options[:uris].slice!(2..-1)
324
371
 
325
- if options[:uris].empty? && File.file?(Kronk.config[:cache_file])
372
+ if options[:uris].empty? && File.file?(Kronk.config[:cache_file]) &&
373
+ options[:player].nil?
326
374
  verbose "No URI specified - using kronk cache"
327
375
  options[:uris] << Kronk.config[:cache_file]
328
376
  end
329
377
 
330
378
  argv.clear
331
379
 
332
- raise OptionParser::MissingArgument, "You must enter at least one URI" if
333
- options[:uris].empty?
380
+ raise "You must enter at least one URI" if options[:uris].empty?
334
381
 
335
382
  options
336
383
 
337
384
  rescue => e
338
- $stderr << "\nError: #{e.message}\n"
339
- $stderr << "See 'kronk --help' for usage\n\n"
340
- exit 1
385
+ error e.message, e.backtrace
386
+ $stderr.puts "See 'kronk --help' for usage\n\n"
387
+ exit 2
341
388
  end
342
389
 
343
390
 
@@ -354,15 +401,6 @@ Parse and run diffs against data from live and cached http responses.
354
401
  data_paths.each do |path|
355
402
  if path[0,1] == "-"
356
403
  (options[:ignore_data] ||= []) << path[1..-1]
357
-
358
- elsif path[0,2] == ":-"
359
- warn "The :path notation is deprecated, use path/.."
360
- (options[:ignore_data_with] ||= []) << path[2..-1]
361
-
362
- elsif path[0,1] == ":"
363
- warn "The :path notation is deprecated, use path/.."
364
- (options[:only_data_with] ||= []) << path[1..-1]
365
-
366
404
  else
367
405
  (options[:only_data] ||= []) << path
368
406
  end
@@ -395,17 +433,9 @@ Parse and run diffs against data from live and cached http responses.
395
433
 
396
434
  rescue Errno::ENOENT
397
435
  make_config_file
398
-
399
- $stderr << "\nNo config file was found.\n"
400
- $stderr << "Created default config in #{DEFAULT_CONFIG_FILE}\n"
401
- $stderr << "Edit file if necessary and try again.\n"
402
- exit 2
403
-
404
- rescue Errno::ENOTDIR
405
- move_config_file
406
-
407
- $stderr << "\nOld config file was moved to #{DEFAULT_CONFIG_FILE}\n"
408
- $stderr << "Edit file if necessary and try again.\n"
436
+ error "No config file was found.\n" +
437
+ "Created default config in #{DEFAULT_CONFIG_FILE}\n" +
438
+ "Edit file if necessary and try again.\n"
409
439
  exit 2
410
440
  end
411
441
 
@@ -413,7 +443,7 @@ Parse and run diffs against data from live and cached http responses.
413
443
 
414
444
  Kronk.load_cookie_jar
415
445
 
416
- load_requires options[:requires]
446
+ load_requires options.delete(:requires)
417
447
 
418
448
  at_exit do
419
449
  Kronk.save_cookie_jar
@@ -424,32 +454,115 @@ Parse and run diffs against data from live and cached http responses.
424
454
  exit 2
425
455
  end
426
456
 
457
+ uri1, uri2 = options.delete :uris
458
+ runner = options.delete(:player) || self
459
+
460
+ success =
461
+ if uri1 && uri2
462
+ runner.compare uri1, uri2, options
463
+ else
464
+ runner.request uri1, options
465
+ end
466
+
467
+ exit 1 unless success
468
+
469
+ rescue Kronk::Exception, Response::MissingParser, Errno::ECONNRESET => e
470
+ error e.message, e.backtrace
471
+ exit 2
472
+ end
473
+
474
+
475
+ ##
476
+ # Performs a Kronk compare and renders it to $stdout.
477
+
478
+ def self.compare uri1, uri2, options={}
479
+ kronk = Kronk.new options
480
+ kronk.compare uri1, uri2
481
+ render kronk, options
482
+ end
483
+
484
+
485
+ ##
486
+ # Performs a single Kronk request and renders it to $stdout.
487
+
488
+ def self.request uri, options={}
489
+ kronk = Kronk.new options
490
+ kronk.retrieve uri
491
+ render kronk, options
492
+ end
493
+
494
+
495
+ ##
496
+ # Renders the results of a Kronk compare or retrieve
497
+ # to $stdout.
498
+
499
+ def self.render kronk, options={}
500
+ cache_response kronk.response
501
+
502
+ if options[:irb]
503
+ irb kronk.response
504
+
505
+ elsif kronk.diff
506
+ render_diff kronk.diff
507
+
508
+ elsif kronk.response
509
+ render_response kronk.response, kronk.options
510
+ end
511
+ end
512
+
513
+
514
+ ##
515
+ # Renders a Diff instance to $stdout
427
516
 
428
- options[:cache_response] =
429
- Kronk.config[:cache_file] if Kronk.config[:cache_file]
517
+ def self.render_diff diff
518
+ $stdout.puts diff.formatted unless Kronk.config[:brief]
430
519
 
431
- uri1, uri2 = options.delete :uris
520
+ if Kronk.config[:verbose] || Kronk.config[:brief]
521
+ $stdout.puts "Found #{diff.count} diff(s)."
522
+ end
432
523
 
433
- if uri1 && uri2
434
- diff = Kronk.compare uri1, uri2, options
524
+ diff.count == 0
525
+ end
435
526
 
436
- puts "#{diff.formatted}\n" unless Kronk.config[:brief]
437
527
 
438
- if Kronk.config[:verbose] || Kronk.config[:brief]
439
- $stdout << "Found #{diff.count} diff(s).\n"
440
- end
528
+ ##
529
+ # Output a Kronk::Response instance. Returns true if response code
530
+ # is in the 200 range.
441
531
 
442
- exit 1 if diff.count > 0
532
+ def self.render_response response, options={}
533
+ str = response.stringify options
534
+ str = Diff.insert_line_nums str if Kronk.config[:show_lines]
535
+ $stdout.puts str
443
536
 
444
- else
445
- out = Kronk.retrieve_data_string uri1, options
446
- out = Diff.insert_line_nums out if Kronk.config[:show_lines]
447
- puts out
537
+ verbose "\nResp. Time: #{response.time.to_f}"
538
+
539
+ response.success?
540
+ end
541
+
542
+
543
+ ##
544
+ # Saves the raw http response to a cache file.
545
+
546
+ def self.cache_response resp, filepath=nil
547
+ filepath ||= Kronk.config[:cache_file]
548
+ return unless filepath
549
+
550
+ begin
551
+ File.open(filepath, "wb+") do |file|
552
+ file.write resp.raw
553
+ end
554
+ rescue => e
555
+ error "#{e.class}: #{e.message}"
448
556
  end
557
+ end
449
558
 
450
- rescue Request::Exception, Response::MissingParser, Errno::ECONNRESET => e
451
- $stderr << "\nError: #{e.message}\n"
452
- exit 2
559
+
560
+ ##
561
+ # Print and error string
562
+
563
+ def self.error str, more=nil
564
+ $stderr.puts "\nError: #{str}"
565
+ $stderr.puts more if Kronk.config[:verbose] && more
453
566
  end
454
567
 
455
568
 
@@ -473,7 +586,8 @@ Parse and run diffs against data from live and cached http responses.
473
586
  # Returns true if kronk is running on ruby for windows.
474
587
 
475
588
  def self.windows?
476
- !!(RUBY_PLATFORM.downcase =~ /mswin|mingw|cygwin/)
589
+ $RUBY_PLATFORM ||= RUBY_PLATFORM
590
+ !!($RUBY_PLATFORM.downcase =~ /mswin|mingw|cygwin/)
477
591
  end
478
592
  end
479
593
  end
@@ -0,0 +1,90 @@
1
+ class Kronk
2
+
3
+ # Generic Request exception.
4
+ class Exception < ::Exception; end
5
+
6
+ # Raised when the URI was not resolvable.
7
+ class NotFoundError < Exception; end
8
+
9
+ # Raised when HTTP times out.
10
+ class TimeoutError < Exception; end
11
+
12
+ # Raised when a missing (but non-mandatory) dependency can't be loaded.
13
+ class MissingDependency < Exception; end
14
+
15
+
16
+ # Config directory.
17
+ CONFIG_DIR = File.expand_path "~/.kronk"
18
+
19
+ # Default config file to load. Defaults to ~/.kronk.
20
+ DEFAULT_CONFIG_FILE = File.join CONFIG_DIR, "rc"
21
+
22
+ # Default cache file.
23
+ DEFAULT_CACHE_FILE = File.join CONFIG_DIR, "cache"
24
+
25
+ # Default cookies file.
26
+ DEFAULT_COOKIES_FILE = File.join CONFIG_DIR, "cookies"
27
+
28
+ # Default file with history of unique URIs. (Used for autocomplete)
29
+ DEFAULT_HISTORY_FILE = File.join CONFIG_DIR, "history"
30
+
31
+
32
+ # Default Content-Type header to parser mapping.
33
+ DEFAULT_CONTENT_TYPES = {
34
+ 'js' => 'JSON',
35
+ 'json' => 'JSON',
36
+ 'plist' => 'PlistParser',
37
+ 'xml' => 'XMLParser'
38
+ }
39
+
40
+
41
+ # Recursive Hash merge proc.
42
+ DEEP_MERGE =
43
+ proc do |key,v1,v2|
44
+ Hash === v1 && Hash === v2 ? v1.merge(v2,&DEEP_MERGE) : v2
45
+ end
46
+
47
+
48
+ # Aliases for various user-agents. Thanks Mechanize! :)
49
+ USER_AGENTS = {
50
+ 'kronk' =>
51
+ "Kronk/#{VERSION} (http://github.com/yaksnrainbows/kronk)",
52
+ 'iphone' =>
53
+ "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1C28 Safari/419.3",
54
+ 'linux_firefox' =>
55
+ "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.1) Gecko/20100122 firefox/3.6.1",
56
+ 'linux_mozilla' =>
57
+ "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624",
58
+ 'mac_mozilla' =>
59
+ "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.4a) Gecko/20030401",
60
+ 'linux_konqueror' =>
61
+ "Mozilla/5.0 (compatible; Konqueror/3; Linux)",
62
+ 'mac_firefox' =>
63
+ "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6",
64
+ 'mac_safari' =>
65
+ "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",
66
+ 'win_ie6' =>
67
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
68
+ 'win_ie7' =>
69
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
70
+ 'win_mozilla' =>
71
+ "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4b) Gecko/20030516 Mozilla Firebird/0.6"
72
+ }
73
+
74
+
75
+ # Default config to use.
76
+ DEFAULT_CONFIG = {
77
+ :content_types => DEFAULT_CONTENT_TYPES.dup,
78
+ :cache_file => DEFAULT_CACHE_FILE,
79
+ :cookies_file => DEFAULT_COOKIES_FILE,
80
+ :default_host => "http://localhost:3000",
81
+ :diff_format => :ascii_diff,
82
+ :history_file => DEFAULT_HISTORY_FILE,
83
+ :indentation => 1,
84
+ :requires => [],
85
+ :show_lines => false,
86
+ :uri_options => {},
87
+ :use_cookies => true,
88
+ :user_agents => USER_AGENTS.dup
89
+ }
90
+ end