kronk 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc CHANGED
@@ -1,3 +1,17 @@
1
+ === 1.1.1 / 2010-12-22
2
+
3
+ * Enhancements:
4
+
5
+ * Added diff-like brief option.
6
+
7
+ * Added support for loading alternate Kronk configs from the command line.
8
+
9
+ * Bugfixes:
10
+
11
+ * Changed uri options config to allow matching of multiple keys.
12
+
13
+ * Implementing smart merging of uri options with command line options.
14
+
1
15
  === 1.1.0 / 2010-12-12
2
16
 
3
17
  * Enhancements:
data/README.rdoc CHANGED
@@ -198,7 +198,7 @@ are supported:
198
198
 
199
199
  * | effectively works as an "OR" character, matches /^val1|val2$/
200
200
 
201
- * = is used to match values and may be used in conjuction with a key or not.
201
+ * \= is used to match values and may be used in conjuction with a key or not.
202
202
 
203
203
  * Parentheses are ok to use if in conjunction with other special characters
204
204
  for a given path item, such as: /path(1|2)
data/Rakefile CHANGED
@@ -17,6 +17,7 @@ Hoe.spec 'kronk' do
17
17
  self.extra_deps << ['i18n', '~>0.5']
18
18
  self.extra_deps << ['activesupport', '>=2.0.0']
19
19
  self.extra_deps << ['cookiejar', '~>0.3.0']
20
+ self.extra_deps << ['rack', '~>1.0']
20
21
 
21
22
  self.extra_dev_deps << ['mocha', '~>0.9.10']
22
23
  end
data/lib/kronk.rb CHANGED
@@ -3,6 +3,7 @@ require 'plist'
3
3
  require 'json'
4
4
  require 'nokogiri'
5
5
  require 'cookiejar'
6
+ require 'rack'
6
7
 
7
8
  # Support for new and old versions of ActiveSupport
8
9
  begin
@@ -19,7 +20,7 @@ require 'yaml'
19
20
  class Kronk
20
21
 
21
22
  # This gem's version.
22
- VERSION = '1.1.0'
23
+ VERSION = '1.1.1'
23
24
 
24
25
 
25
26
  require 'kronk/data_set'
@@ -175,15 +176,64 @@ class Kronk
175
176
 
176
177
 
177
178
  ##
178
- # Returns config-defined options for a given uri.
179
- # Returns empty Hash if none found.
179
+ # Returns merged config-defined options for a given uri.
180
+ # Values in cmd_opts take precedence.
181
+ # Returns cmd_opts Hash if none found.
180
182
 
181
- def self.options_for_uri uri
182
- config[:uri_options].each do |key, options|
183
- return options if uri == key || uri =~ %r{#{key}}
183
+ def self.merge_options_for_uri uri, cmd_opts={}
184
+ out_opts = Hash.new.merge cmd_opts
185
+
186
+ config[:uri_options].each do |matcher, options|
187
+ next unless (uri == matcher || uri =~ %r{#{matcher}}) && Hash === options
188
+
189
+ options.each do |key, val|
190
+ if !out_opts[key]
191
+ out_opts[key] = val
192
+ next
193
+ end
194
+
195
+
196
+ case key
197
+
198
+ # Hash or uri query String
199
+ when :data, :query
200
+ val = Rack::Utils.parse_nested_query val if String === val
201
+
202
+ out_opts[key] = Rack::Utils.parse_nested_query out_opts[key] if
203
+ String === out_opts[key]
204
+
205
+ out_opts[key] = val.merge out_opts[key], &DataSet::DEEP_MERGE
206
+
207
+ # Hashes
208
+ when :headers, :auth
209
+ out_opts[key] = val.merge out_opts[key]
210
+
211
+ # Proxy hash or String
212
+ when :proxy
213
+ if Hash === val && Hash === out_opts[key]
214
+ out_opts[key] = val.merge out_opts[key]
215
+
216
+ elsif Hash === val && String === out_opts[key]
217
+ val[:address] = out_opts[key]
218
+ out_opts[key] = val
219
+
220
+ elsif String === val && Hash === out_opts[key]
221
+ out_opts[key][:address] ||= val
222
+ end
223
+
224
+ # Response headers - Boolean, String, or Array
225
+ when :with_headers
226
+ next if out_opts[key] == true || out_opts[key] && val == true
227
+ out_opts[key] = [*out_opts[key]] | [*val]
228
+
229
+ # String or Array
230
+ when :only_data, :only_data_with, :ignore_data, :ignore_data_with
231
+ out_opts[key] = [*out_opts[key]] | [*val]
232
+ end
233
+ end
184
234
  end
185
235
 
186
- Hash.new
236
+ out_opts
187
237
  end
188
238
 
189
239
 
@@ -218,8 +268,8 @@ class Kronk
218
268
 
219
269
  def self.save_cookie_jar file=nil
220
270
  file ||= config[:cookies_file]
221
- File.open(file, "w") do |file|
222
- file.write @cookie_jar.to_yaml
271
+ File.open(file, "w") do |f|
272
+ f.write @cookie_jar.to_yaml
223
273
  end
224
274
  end
225
275
 
@@ -255,9 +305,11 @@ class Kronk
255
305
  # :auth:: Hash - must contain :username and :password; defaults to nil
256
306
  # :proxy:: Hash/String - http proxy to use; defaults to nil
257
307
  # :only_data:: String/Array - extracts the data from given data paths
308
+ # :only_data_with:: String/Array - extracts the data from given parent paths
258
309
  # :ignore_data:: String/Array - defines which data points to exclude
310
+ # :ignore_data_with:: String/Array - defines which parent data to exclude
259
311
  # :with_headers:: Bool/String/Array - defines which headers to include
260
- # :parser:: Object - The parser to use for the body; default nil
312
+ # :parser:: Object/String - The parser to use for the body; default nil
261
313
  # :raw:: Bool - run diff on raw strings
262
314
  #
263
315
  # Returns a diff object.
@@ -275,7 +327,7 @@ class Kronk
275
327
  # See Kronk.compare for supported options.
276
328
 
277
329
  def self.retrieve_data_string query, options={}
278
- options = options.merge options_for_uri(query)
330
+ options = merge_options_for_uri query, options
279
331
 
280
332
  resp = Request.retrieve query, options
281
333
 
@@ -306,7 +358,7 @@ class Kronk
306
358
  $stderr << "\nNo config file was found.\n\n"
307
359
  $stderr << "Created default config in #{DEFAULT_CONFIG_FILE}\n"
308
360
  $stderr << "Edit file if necessary and try again.\n"
309
- exit 1
361
+ exit 2
310
362
  end
311
363
 
312
364
  load_cookie_jar
@@ -325,8 +377,13 @@ class Kronk
325
377
 
326
378
  if uri1 && uri2
327
379
  diff = compare uri1, uri2, options
328
- puts diff.formatted
329
- verbose "\n\nFound #{diff.count} diff(s).\n"
380
+ puts "#{diff.formatted}\n" unless config[:brief]
381
+
382
+ if config[:verbose] || config[:brief]
383
+ $stdout << "Found #{diff.count} diff(s).\n"
384
+ end
385
+
386
+ exit 1 if diff.count > 0
330
387
 
331
388
  else
332
389
  out = retrieve_data_string uri1, options
@@ -399,6 +456,17 @@ Kronk runs diffs against data from live and cached http responses.
399
456
  end
400
457
 
401
458
 
459
+ opt.on('--config STR', String,
460
+ 'Load the given Kronk config file') do |value|
461
+ load_config value
462
+ end
463
+
464
+
465
+ opt.on('-q', '--brief', 'Output only whether URI responses differ') do
466
+ config[:brief] = true
467
+ end
468
+
469
+
402
470
  opt.on('--format STR', String,
403
471
  'Use a custom diff formatter') do |value|
404
472
  config[:diff_format] = value
@@ -5,6 +5,13 @@ class Kronk
5
5
 
6
6
  class DataSet
7
7
 
8
+ # Deep merge proc for recursive Hash merging.
9
+ DEEP_MERGE =
10
+ proc do |key,v1,v2|
11
+ Hash === v1 && Hash === v2 ? v1.merge(v2,&DEEP_MERGE) : v2
12
+ end
13
+
14
+
8
15
  attr_accessor :data
9
16
 
10
17
  def initialize data
@@ -31,9 +38,9 @@ class Kronk
31
38
  ##
32
39
  # Modify the data object by passing inclusive or exclusive data paths.
33
40
  # Supports the following options:
34
- # :only_data:: String/Array - keep data with that matches the paths
41
+ # :only_data:: String/Array - keep data that matches the paths
35
42
  # :only_data_with:: String/Array - keep data with a matched child
36
- # :ignore_data:: String/Array - remove data with that matches the paths
43
+ # :ignore_data:: String/Array - remove data that matches the paths
37
44
  # :ignore_data_with:: String/Array - remove data with a matched child
38
45
  #
39
46
  # Note: the data is processed in the following order:
data/lib/kronk/diff.rb CHANGED
@@ -235,7 +235,10 @@ class Kronk
235
235
 
236
236
  ##
237
237
  # Returns a formatted output as a string.
238
- # Custom formats may be achieved by passing a block.
238
+ # Supported options are:
239
+ # :join_char:: String - The string used to join lines; default "\n"
240
+ # :show_lines:: Boolean - Insert line numbers or not; default @show_lines
241
+ # :formatter:: Object - The formatter to use; default @formatter
239
242
 
240
243
  def formatted options={}
241
244
  options = {
@@ -47,9 +47,9 @@ class TestDataSet < Test::Unit::TestCase
47
47
  end
48
48
 
49
49
 
50
- def test_modify_only_data
51
- data = @dataset_mock.modify :only_data => "subs/1"
52
- assert_equal({"subs" => [nil, "b"]}, data)
50
+ def test_modify_only_data_with
51
+ data = @dataset_mock.modify :only_data_with => "subs/1"
52
+ assert_equal({"subs" => ["a", "b"]}, data)
53
53
  end
54
54
 
55
55
 
data/test/test_kronk.rb CHANGED
@@ -119,17 +119,180 @@ class TestKronk < Test::Unit::TestCase
119
119
  end
120
120
 
121
121
 
122
- def test_options_for_uri
123
- old_uri_opts = Kronk.config[:uri_options].dup
124
- Kronk.config[:uri_options] = {
125
- 'example' => 'options1',
126
- 'example.com' => 'options2'
122
+ def test_merge_options_for_uri
123
+ with_uri_options do
124
+ assert_equal mock_uri_options['example'],
125
+ Kronk.merge_options_for_uri("http://example.com/path")
126
+
127
+ assert_equal Hash.new,
128
+ Kronk.merge_options_for_uri("http://thing.com/path")
129
+ end
130
+ end
131
+
132
+
133
+ def test_merge_options_for_uri_query
134
+ data = {
135
+ "add" => "this",
136
+ "foo" => {
137
+ "bar1" => "one",
138
+ "bar2" => 2,
139
+ "bar3" => "three"},
140
+ "key"=>"otherval"}
141
+
142
+ expected = {:query => data, :data => data}
143
+
144
+ with_uri_options do
145
+ new_data = {
146
+ "add" => "this",
147
+ "foo" => {'bar2' => 2, 'bar3' => "three"},
148
+ "key" => "otherval"
149
+ }
150
+
151
+ %w{uri_query hash_query}.each do |qtype|
152
+ opts = Kronk.merge_options_for_uri("http://#{qtype}.com",
153
+ :query => data, :data => data)
154
+
155
+ assert_equal expected, opts
156
+ end
157
+
158
+ opts = Kronk.merge_options_for_uri("http://uri_query.com")
159
+ assert_equal mock_uri_options['uri_query'], opts
160
+ end
161
+ end
162
+
163
+
164
+ def test_merge_options_for_uri_headers
165
+ with_uri_options do
166
+ opts = Kronk.merge_options_for_uri("http://headers.example.com",
167
+ :headers => {'hdr2' => 2, 'hdr3' => 3})
168
+
169
+ expected = {
170
+ :headers => {
171
+ 'hdr1' => 'one',
172
+ 'hdr2' => 2,
173
+ 'hdr3' => 3
174
+ },
175
+ :parser => "XMLParser"
176
+ }
177
+
178
+ assert_equal expected, opts
179
+ end
180
+ end
181
+
182
+
183
+ def test_merge_options_for_uri_auth
184
+ with_uri_options do
185
+ opts = Kronk.merge_options_for_uri("http://auth.example.com",
186
+ :auth => {:username => "bob"})
187
+
188
+ expected = {
189
+ :auth => {
190
+ :username => "bob",
191
+ :password => "pass"
192
+ },
193
+ :parser => "XMLParser"
194
+ }
195
+
196
+ assert_equal expected, opts
197
+ end
198
+ end
199
+
200
+
201
+ def test_merge_options_for_uri_proxy
202
+ with_uri_options do
203
+ expected = {
204
+ :proxy => {
205
+ :address => "proxy.com",
206
+ :port => 1234,
207
+ :username => "user",
208
+ :password => "pass"
209
+ }
210
+ }
211
+
212
+ opts = Kronk.merge_options_for_uri("http://proxy.com",
213
+ :proxy => "proxy.com")
214
+
215
+ assert_equal expected, opts
216
+
217
+ opts = Kronk.merge_options_for_uri("http://proxy.com",
218
+ :proxy => {:address => "proxy.com"})
219
+
220
+ assert_equal expected, opts
221
+ end
222
+ end
223
+
224
+
225
+ def test_merge_options_for_uri_str_proxy
226
+ with_uri_options do
227
+ expected = {
228
+ :proxy => {
229
+ :address => "someproxy.com",
230
+ :username => "user",
231
+ :password => "pass"
232
+ }
233
+ }
234
+
235
+ opts = Kronk.merge_options_for_uri("http://strprox.com",
236
+ :proxy => {:username => "user", :password => "pass"})
237
+
238
+ assert_equal expected, opts
239
+
240
+ opts = Kronk.merge_options_for_uri("http://strprox.com",
241
+ :proxy => "proxy.com")
242
+
243
+ assert_equal "proxy.com", opts[:proxy]
244
+ end
245
+ end
246
+
247
+
248
+ def test_merge_options_for_uri_with_headers
249
+ with_uri_options do
250
+ %w{withhdrs withstrhdrs withtruehdrs}.each do |type|
251
+ opts = Kronk.merge_options_for_uri "http://#{type}.com",
252
+ :with_headers => true
253
+
254
+ assert_equal true, opts[:with_headers]
255
+ end
256
+ end
257
+ end
258
+
259
+
260
+ def test_merge_options_for_uri_with_headers_arr
261
+ with_uri_options do
262
+ %w{withhdrs withstrhdrs}.each do |type|
263
+ opts = Kronk.merge_options_for_uri "http://#{type}.com",
264
+ :with_headers => %w{hdr2 hdr3}
265
+
266
+ assert_equal %w{hdr1 hdr2 hdr3}.sort, opts[:with_headers].sort
267
+ end
268
+
269
+ opts = Kronk.merge_options_for_uri "http://withtruehdrs.com",
270
+ :with_headers => %w{hdr2 hdr3}
271
+
272
+ assert_equal %w{hdr2 hdr3}, opts[:with_headers]
273
+ end
274
+ end
275
+
276
+
277
+ def test_merge_options_for_uri_data_paths
278
+ expected = {
279
+ :only_data => %w{path1 path2 path3},
280
+ :only_data_with => %w{only1 only2},
281
+ :ignore_data => "ign1",
282
+ :ignore_data_with => %w{ign2 ign3}
127
283
  }
128
284
 
129
- assert_equal 'options1', Kronk.options_for_uri("http://example.com/path")
130
- assert_equal Hash.new, Kronk.options_for_uri("http://thing.com/path")
285
+ with_uri_options do
286
+ opts = Kronk.merge_options_for_uri "http://focus_data.com",
287
+ :only_data => %w{path2 path3},
288
+ :only_data_with => "only2",
289
+ :ignore_data_with => %w{ign2 ign3}
131
290
 
132
- Kronk.config[:uri_options] = old_uri_opts
291
+ opts[:only_data].sort!
292
+ opts[:only_data_with].sort!
293
+
294
+ assert_equal expected, opts
295
+ end
133
296
  end
134
297
 
135
298
 
@@ -326,4 +489,80 @@ STR
326
489
 
327
490
  assert_equal %w{this is --argv}, argv
328
491
  end
492
+
493
+
494
+ private
495
+
496
+ def mock_uri_options
497
+ {
498
+ 'example' => {
499
+ :parser => "XMLParser"
500
+ },
501
+ 'example.com' => {
502
+ :parser => "PlistParser"
503
+ },
504
+ 'uri_query' => {
505
+ :query => "foo[bar1]=one&foo[bar2]=two&key=val",
506
+ :data => "foo[bar1]=one&foo[bar2]=two&key=val"
507
+ },
508
+ 'hash_query' => {
509
+ :query => {
510
+ 'foo' => {'bar1'=>'one', 'bar2'=>'two'},
511
+ 'key' => "val"
512
+ },
513
+ :data => {
514
+ 'foo' => {'bar1'=>'one', 'bar2'=>'two'},
515
+ 'key' => "val"
516
+ }
517
+ },
518
+ 'headers' => {
519
+ :headers => {
520
+ 'hdr1' => 'one',
521
+ 'hdr2' => 'two'
522
+ }
523
+ },
524
+ 'auth' => {
525
+ :auth => {
526
+ :username => "user",
527
+ :password => "pass"
528
+ }
529
+ },
530
+ 'proxy' => {
531
+ :proxy => {
532
+ :username => "user",
533
+ :password => "pass",
534
+ :address => "someproxy.com",
535
+ :port => 1234
536
+ }
537
+ },
538
+ 'strprox' => {
539
+ :proxy => "someproxy.com"
540
+ },
541
+ 'withhdrs' => {
542
+ :with_headers => %w{hdr1 hdr2 hdr3}
543
+ },
544
+ 'withstrhdrs' => {
545
+ :with_headers => "hdr1"
546
+ },
547
+ 'withtruehdrs' => {
548
+ :with_headers => true
549
+ },
550
+ 'focus_data' => {
551
+ :only_data => %w{path1 path2},
552
+ :only_data_with => "only1",
553
+ :ignore_data => "ign1"
554
+ }
555
+ }
556
+ end
557
+
558
+
559
+ def with_uri_options
560
+ old_uri_opts = Kronk.config[:uri_options].dup
561
+ Kronk.config[:uri_options] = mock_uri_options
562
+
563
+ yield if block_given?
564
+
565
+ ensure
566
+ Kronk.config[:uri_options] = old_uri_opts
567
+ end
329
568
  end
@@ -258,7 +258,7 @@ class TestResponse < Test::Unit::TestCase
258
258
  end
259
259
 
260
260
 
261
- def test_selective_data_multiple_only_data
261
+ def test_selective_data_multiple_ignore_data
262
262
  expected = JSON.parse @json_resp.body
263
263
  expected['business'].delete 'id'
264
264
  expected.delete 'request_id'
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kronk
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
7
  - 1
9
- - 0
10
- version: 1.1.0
8
+ - 1
9
+ version: 1.1.1
11
10
  platform: ruby
12
11
  authors:
13
12
  - Jeremie Castagna
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-12-12 00:00:00 -08:00
17
+ date: 2010-12-22 00:00:00 -08:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ~>
28
27
  - !ruby/object:Gem::Version
29
- hash: 3
30
28
  segments:
31
29
  - 3
32
30
  - 1
@@ -42,7 +40,6 @@ dependencies:
42
40
  requirements:
43
41
  - - ~>
44
42
  - !ruby/object:Gem::Version
45
- hash: 11
46
43
  segments:
47
44
  - 1
48
45
  - 2
@@ -57,7 +54,6 @@ dependencies:
57
54
  requirements:
58
55
  - - ~>
59
56
  - !ruby/object:Gem::Version
60
- hash: 9
61
57
  segments:
62
58
  - 1
63
59
  - 3
@@ -72,7 +68,6 @@ dependencies:
72
68
  requirements:
73
69
  - - ~>
74
70
  - !ruby/object:Gem::Version
75
- hash: 1
76
71
  segments:
77
72
  - 0
78
73
  - 5
@@ -87,7 +82,6 @@ dependencies:
87
82
  requirements:
88
83
  - - ">="
89
84
  - !ruby/object:Gem::Version
90
- hash: 15
91
85
  segments:
92
86
  - 2
93
87
  - 0
@@ -103,7 +97,6 @@ dependencies:
103
97
  requirements:
104
98
  - - ~>
105
99
  - !ruby/object:Gem::Version
106
- hash: 19
107
100
  segments:
108
101
  - 0
109
102
  - 3
@@ -112,37 +105,64 @@ dependencies:
112
105
  type: :runtime
113
106
  version_requirements: *id006
114
107
  - !ruby/object:Gem::Dependency
115
- name: mocha
108
+ name: rack
116
109
  prerelease: false
117
110
  requirement: &id007 !ruby/object:Gem::Requirement
118
111
  none: false
119
112
  requirements:
120
113
  - - ~>
121
114
  - !ruby/object:Gem::Version
122
- hash: 47
115
+ segments:
116
+ - 1
117
+ - 0
118
+ version: "1.0"
119
+ type: :runtime
120
+ version_requirements: *id007
121
+ - !ruby/object:Gem::Dependency
122
+ name: rubyforge
123
+ prerelease: false
124
+ requirement: &id008 !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ segments:
130
+ - 2
131
+ - 0
132
+ - 4
133
+ version: 2.0.4
134
+ type: :development
135
+ version_requirements: *id008
136
+ - !ruby/object:Gem::Dependency
137
+ name: mocha
138
+ prerelease: false
139
+ requirement: &id009 !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ~>
143
+ - !ruby/object:Gem::Version
123
144
  segments:
124
145
  - 0
125
146
  - 9
126
147
  - 10
127
148
  version: 0.9.10
128
149
  type: :development
129
- version_requirements: *id007
150
+ version_requirements: *id009
130
151
  - !ruby/object:Gem::Dependency
131
152
  name: hoe
132
153
  prerelease: false
133
- requirement: &id008 !ruby/object:Gem::Requirement
154
+ requirement: &id010 !ruby/object:Gem::Requirement
134
155
  none: false
135
156
  requirements:
136
157
  - - ">="
137
158
  - !ruby/object:Gem::Version
138
- hash: 47
139
159
  segments:
140
160
  - 2
141
- - 8
142
- - 0
143
- version: 2.8.0
161
+ - 6
162
+ - 2
163
+ version: 2.6.2
144
164
  type: :development
145
- version_requirements: *id008
165
+ version_requirements: *id010
146
166
  description: |-
147
167
  Kronk runs diffs against data from live and cached http responses.
148
168
  Kronk was made possible by the sponsoring of AT&T Interactive.
@@ -198,7 +218,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
198
218
  requirements:
199
219
  - - ">="
200
220
  - !ruby/object:Gem::Version
201
- hash: 3
221
+ hash: -1939027826967097857
202
222
  segments:
203
223
  - 0
204
224
  version: "0"
@@ -207,7 +227,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
227
  requirements:
208
228
  - - ">="
209
229
  - !ruby/object:Gem::Version
210
- hash: 3
211
230
  segments:
212
231
  - 0
213
232
  version: "0"