jgrep 1.3.3 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
data/bin/jgrep CHANGED
@@ -3,17 +3,67 @@
3
3
  require 'jgrep'
4
4
  require 'optparse'
5
5
 
6
- options = {:flat => false, :start => nil, :field => []}
6
+ @options = {:flat => false, :start => nil, :field => [], :slice => nil}
7
+
8
+ def print_json(result)
9
+ unless @options[:flat]
10
+ result = result.first if @options[:stream]
11
+ puts(JSON.pretty_generate(result))
12
+ else
13
+ puts(result.first.to_json)
14
+ end
15
+ end
16
+
17
+ def do_grep(json, expression)
18
+ if @options[:field].empty?
19
+ result = JGrep::jgrep((json), expression, nil, @options[:start])
20
+ result = result.slice(@options[:slice]) if @options[:slice]
21
+ unless result == [] or @options[:quiet] == true
22
+ print_json(result)
23
+ end
24
+ else
25
+ if @options[:field].size > 1
26
+ JGrep::validate_filters(@options[:field])
27
+ result = JGrep::jgrep((json), expression, @options[:field], @options[:start])
28
+ result = result.slice(@options[:slice]) if @options[:slice]
29
+ unless result == [] or @options[:quiet] == true
30
+ print_json(result)
31
+ end
32
+
33
+ else
34
+ JGrep::validate_filters(@options[:field][0])
35
+ result = JGrep::jgrep((json), expression, @options[:field][0], @options[:start])
36
+ result = result.slice(@options[:slice]) if @options[:slice]
37
+ if result.is_a?(Array) && !(result.first.is_a?(Hash) || result.flatten.first.is_a?(Hash))
38
+ unless @options[:quiet] == true
39
+ result.map{|x| puts x unless x.nil?}
40
+ end
41
+ else
42
+ unless @options[:quiet] == true
43
+ print_json(result)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
7
49
 
8
50
  begin
9
51
  OptionParser.new do |opts|
10
52
  opts.banner = "Usage: jgrep [options] \"expression\""
11
53
  opts.on("-s", "--simple [FIELDS]", "Display only one or more fields from each of the resulting json documents") do |field|
12
- options[:field].concat(field.split(" "))
54
+ unless field.nil?
55
+ @options[:field].concat(field.split(" "))
56
+ else
57
+ raise "-s flag requires a field value"
58
+ end
13
59
  end
14
60
 
15
61
  opts.on("-c", "--compact", "Display non pretty json") do
16
- options[:flat] = true
62
+ @options[:flat] = true
63
+ end
64
+
65
+ opts.on("-n", "--stream", "Display continuous output from continuous input") do
66
+ @options[:stream] = true
17
67
  end
18
68
 
19
69
  opts.on("-f", "--flatten", "Makes output as flat as possible") do
@@ -21,11 +71,11 @@ begin
21
71
  end
22
72
 
23
73
  opts.on("-i", "--input [FILENAME]", "Specify input file to parse") do |filename|
24
- options[:file] = filename
74
+ @options[:file] = filename
25
75
  end
26
76
 
27
77
  opts.on("-q", "--quiet", "Quiet; don't write to stdout. Exit with zero status if match found.") do
28
- options[:quiet] = true
78
+ @options[:quiet] = true
29
79
  end
30
80
 
31
81
  opts.on("-v", "--verbose", "Verbose output") do
@@ -33,12 +83,21 @@ begin
33
83
  end
34
84
 
35
85
  opts.on("--start [FIELD]", "Where in the data to start from") do |field|
36
- options[:start] = field
86
+ @options[:start] = field
87
+ end
88
+
89
+ opts.on("--slice [RANGE]", "A range of the form 'n' or 'n..m', indicating which documents to extract from the final output") do |field|
90
+ range_nums = field.split('..').map{ |x| x.to_i }
91
+ @options[:slice] = range_nums.length == 1 ? range_nums[0] : Range.new(*range_nums)
37
92
  end
38
93
  end.parse!
39
94
  rescue OptionParser::InvalidOption => e
40
95
  puts e.to_s.capitalize
41
96
  exit 1
97
+
98
+ rescue Exception => e
99
+ puts e
100
+ exit 1
42
101
  end
43
102
 
44
103
  begin
@@ -54,49 +113,33 @@ begin
54
113
 
55
114
  expression = "" if expression.nil?
56
115
 
116
+ #Continuously gets if inputstream in constant
57
117
  #Load json from standard input if tty is false
58
118
  #else find and load file from command line arugments
59
- unless STDIN.tty?
60
- json = STDIN.read
61
- else
62
- if options[:file]
63
- json = File.read(options[:file])
119
+
120
+ if @options[:stream]
121
+ unless STDIN.tty?
122
+ while json = gets
123
+ do_grep(json, expression)
124
+ end
64
125
  else
65
126
  raise "No json input specified"
66
127
  end
67
- end
68
-
69
- if options[:field].empty?
70
- result = JGrep::jgrep((json), expression, nil, options[:start])
71
- unless options[:quiet] == true
72
- (options[:flat] == false) ? puts(JSON.pretty_generate(result)) : puts(result.to_json)
73
- end
74
128
  else
75
- if options[:field].size > 1
76
- JGrep::validate_filters(options[:field])
77
- result = JGrep::jgrep((json), expression, options[:field], options[:start])
78
- unless result == [] or options[:quiet] == true
79
- puts(JSON.pretty_generate(result))
80
- end
81
-
129
+ if @options[:file]
130
+ json = File.read(@options[:file])
131
+ do_grep(json, expression)
132
+ elsif ! STDIN.tty?
133
+ json = STDIN.read
134
+ do_grep(json, expression)
82
135
  else
83
- JGrep::validate_filters(options[:field][0])
84
- result = JGrep::jgrep((json), expression, options[:field][0], options[:start])
85
- unless result.first.is_a?(Hash) || result.flatten.first.is_a?(Hash)
86
- unless options[:quiet] == true
87
- result.map{|x| puts x unless x.nil?}
88
- end
89
- else
90
- unless options[:quiet] == true
91
- puts(JSON.pretty_generate(result))
92
- end
93
- end
94
- unless result.length > 0
95
- exit 1
96
- end
136
+ raise "No json input specified"
97
137
  end
98
138
  end
99
139
 
140
+ rescue Interrupt
141
+ STDERR.puts "Exiting..."
142
+ exit 1
100
143
  rescue Exception => e
101
144
  if e.is_a?(SystemExit)
102
145
  exit e.status
@@ -257,6 +257,13 @@ module JGrep
257
257
  return true
258
258
  end
259
259
 
260
+ # Deal with booleans
261
+ if tmp == true and value == 'true'
262
+ return true
263
+ elsif tmp == false and value == 'false'
264
+ return true
265
+ end
266
+
260
267
  #Deal with regex matching
261
268
  if ((value =~ /^\/.*\/$/) && tmp != nil)
262
269
  (tmp.match(Regexp.new(value.gsub("/", "")))) ? (return true) : (return false)
@@ -303,7 +310,7 @@ module JGrep
303
310
  break
304
311
  end
305
312
  end
306
- field = field[1].first.split(/=|<|>/).first
313
+ field = field[1].split(/=|<|>/).first
307
314
 
308
315
  field.split(".").each_with_index do |item, i|
309
316
  tmp = tmp[item]
@@ -385,7 +392,7 @@ module JGrep
385
392
 
386
393
  if json.is_a? Hash
387
394
  json.keys.each do |k|
388
- if path.match(/^#{k}/) && k.match(/\./)
395
+ if path.start_with?(k) && k.include?('.')
389
396
  return dig_path(json[k], path.gsub(k, ""))
390
397
  end
391
398
  end
@@ -408,7 +415,7 @@ module JGrep
408
415
  if path == path_array.first
409
416
  return json
410
417
  else
411
- return dig_path(json, (path.match(/\./) ? path_array.drop(1).join(".") : path))
418
+ return dig_path(json, (path.include?('.') ? path_array.drop(1).join(".") : path))
412
419
  end
413
420
 
414
421
  elsif json.is_a? Array
@@ -417,7 +424,7 @@ module JGrep
417
424
  else
418
425
  tmp = []
419
426
  json.each do |j|
420
- tmp_path = dig_path(j, (path.match(/\./) ? path_array.drop(1).join(".") : path))
427
+ tmp_path = dig_path(j, (path.include?('.') ? path_array.drop(1).join(".") : path))
421
428
  unless tmp_path.nil?
422
429
  tmp << tmp_path
423
430
  end
@@ -14,7 +14,7 @@ module JGrep
14
14
  end
15
15
 
16
16
  begin
17
- case @arguments.split("")[@token_index]
17
+ case chr(@arguments[@token_index])
18
18
  when "["
19
19
  return "statement", gen_substatement
20
20
 
@@ -28,7 +28,7 @@ module JGrep
28
28
  return ")", ")"
29
29
 
30
30
  when "n"
31
- if (@arguments.split("")[@token_index + 1] == "o") && (@arguments.split("")[@token_index + 2] == "t") && ((@arguments.split("")[@token_index + 3] == " ") || (@arguments.split("")[@token_index + 3] == "("))
31
+ if (chr(@arguments[@token_index + 1]) == "o") && (chr(@arguments[@token_index + 2]) == "t") && ((chr(@arguments[@token_index + 3]) == " ") || (chr(@arguments[@token_index + 3]) == "("))
32
32
  @token_index += 2
33
33
  return "not", "not"
34
34
  else
@@ -39,7 +39,7 @@ module JGrep
39
39
  return "not", "not"
40
40
 
41
41
  when "a"
42
- if (@arguments.split("")[@token_index + 1] == "n") && (@arguments.split("")[@token_index + 2] == "d") && ((@arguments.split("")[@token_index + 3] == " ") || (@arguments.split("")[@token_index + 3] == "("))
42
+ if (chr(@arguments[@token_index + 1]) == "n") && (chr(@arguments[@token_index + 2]) == "d") && ((chr(@arguments[@token_index + 3]) == " ") || (chr(@arguments[@token_index + 3]) == "("))
43
43
  @token_index += 2
44
44
  return "and", "and"
45
45
  else
@@ -47,7 +47,7 @@ module JGrep
47
47
  end
48
48
 
49
49
  when "&"
50
- if(@arguments.split("")[@token_index +1] == "&")
50
+ if(chr(@arguments[@token_index +1]) == "&")
51
51
  @token_index +=1
52
52
  return "and", "and"
53
53
  else
@@ -55,7 +55,7 @@ module JGrep
55
55
  end
56
56
 
57
57
  when "o"
58
- if (@arguments.split("")[@token_index + 1] == "r") && ((@arguments.split("")[@token_index + 2] == " ") || (@arguments.split("")[@token_index + 2] == "("))
58
+ if (chr(@arguments[@token_index + 1]) == "r") && ((chr(@arguments[@token_index + 2]) == " ") || (chr(@arguments[@token_index + 2]) == "("))
59
59
  @token_index += 1
60
60
  return "or", "or"
61
61
  else
@@ -63,7 +63,7 @@ module JGrep
63
63
  end
64
64
 
65
65
  when "|"
66
- if(@arguments.split("")[@token_index +1] == "|")
66
+ if(chr(@arguments[@token_index +1]) == "|")
67
67
  @token_index +=1
68
68
  return "or", "or"
69
69
  else
@@ -75,9 +75,9 @@ module JGrep
75
75
  i = @token_index + 1
76
76
 
77
77
  begin
78
- value += @arguments.split("")[i]
78
+ value += chr(@arguments[i])
79
79
  i += 1
80
- end until (i >= @arguments.size) || (@arguments.split("")[i] =~ /\s|\)/)
80
+ end until (i >= @arguments.size) || (chr(@arguments[i]) =~ /\s|\)/)
81
81
 
82
82
  @token_index = i - 1
83
83
  return "+", value
@@ -87,9 +87,9 @@ module JGrep
87
87
  i = @token_index + 1
88
88
 
89
89
  begin
90
- value += @arguments.split("")[i]
90
+ value += chr(@arguments[i])
91
91
  i += 1
92
- end until (i >= @arguments.size) || (@arguments.split("")[i] =~ /\s|\)/)
92
+ end until (i >= @arguments.size) || (chr(@arguments[i]) =~ /\s|\)/)
93
93
 
94
94
  @token_index = i - 1
95
95
  return "-", value
@@ -124,26 +124,26 @@ module JGrep
124
124
  j = @token_index
125
125
 
126
126
  begin
127
- if (@arguments.split("")[j] == "/")
127
+ if (chr(@arguments[j]) == "/")
128
128
  begin
129
- current_token_value << @arguments.split("")[j]
129
+ current_token_value << chr(@arguments[j])
130
130
  j += 1
131
- if @arguments.split("")[j] == "/"
131
+ if chr(@arguments[j]) == "/"
132
132
  current_token_value << "/"
133
133
  break
134
134
  end
135
- end until (j >= @arguments.size) || (@arguments.split("")[j] =~ /\//)
135
+ end until (j >= @arguments.size) || (chr(@arguments[j]) =~ /\//)
136
136
  else
137
137
  begin
138
- current_token_value << @arguments.split("")[j]
138
+ current_token_value << chr(@arguments[j])
139
139
  j += 1
140
- if @arguments.split("")[j] =~ /'|"/
140
+ if chr(@arguments[j]) =~ /'|"/
141
141
  begin
142
- current_token_value << @arguments.split("")[j]
142
+ current_token_value << chr(@arguments[j])
143
143
  j +=1
144
- end until (j >= @arguments.size) || (@arguments.split("")[j] =~ /'|"/)
144
+ end until (j >= @arguments.size) || (chr(@arguments[j]) =~ /'|"/)
145
145
  end
146
- end until (j >= @arguments.size) || (@arguments.split("")[j] =~ /\s|\)|\]/)
146
+ end until (j >= @arguments.size) || (chr(@arguments[j]) =~ /\s|\)|\]/)
147
147
  end
148
148
  rescue Exception => e
149
149
  raise "Invalid token found - '#{current_token_value}'"
@@ -156,5 +156,10 @@ module JGrep
156
156
  @token_index += current_token_value.size - 1
157
157
  return "statement", current_token_value
158
158
  end
159
+
160
+ # Compatibility with 1.8.7, which returns a Fixnum from String#[]
161
+ def chr(character)
162
+ character.chr unless character.nil?
163
+ end
159
164
  end
160
165
  end
@@ -0,0 +1,11 @@
1
+ require "spec_helper.rb"
2
+ require "rake"
3
+ require "rspec/core/rake_task"
4
+
5
+ desc "Run JGrep tests"
6
+ RSpec::Core::RakeTask.new(:test) do |t|
7
+ t.pattern = "unit/*_spec.rb"
8
+ t.rspec_opts = "--format s --color --backtrace"
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,10 @@
1
+ require "rubygems"
2
+ require "rspec"
3
+ require "rspec/mocks"
4
+ require "mocha"
5
+ require File.dirname(__FILE__) + "/../lib/jgrep"
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_with :mocha
9
+ end
10
+
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.dirname(__FILE__) + "/../spec_helper"
4
+
5
+ module JGrep
6
+ describe JGrep do
7
+ describe "#jgrep" do
8
+
9
+ it "should return a valid json document" do
10
+ result = JGrep::jgrep("[{\"foo\":1}]", "foo=1")
11
+ result.should == [{"foo"=>1}]
12
+ end
13
+
14
+ it "should fail on an invalid json document" do
15
+ STDERR.expects(:puts).with("Error. Invalid JSON given")
16
+ result = JGrep::jgrep("[foo:]", "foo=1")
17
+ end
18
+
19
+ it "should return '[]' if value is not present in document" do
20
+ result = JGrep::jgrep("[{\"bar\":1}]", "foo=1")
21
+ result.should == []
22
+ end
23
+
24
+ it "should correctly return 'null' if a null value is present in the document" do
25
+ result = JGrep::jgrep("[{\"foo\":null}]", "foo=null")
26
+ result.should == [{"foo" => nil}]
27
+ end
28
+
29
+ it "should return the origional json document if no expression is given" do
30
+ result = JGrep::jgrep("[{\"foo\":\"bar\"}]", "")
31
+ result.should == [{"foo" => "bar"}]
32
+ end
33
+
34
+ it "should filter on the origional json document if not expression is given and a filter is given" do
35
+ result = JGrep::jgrep("[{\"foo\":\"bar\"}]", "", "foo")
36
+ result.should == ["bar"]
37
+ end
38
+
39
+ it "should support starting from a subdocument" do
40
+ doc = %q(
41
+ {"results": [
42
+ {"foo":"bar"},
43
+ {"foo":"baz"}
44
+ ]
45
+ }
46
+ )
47
+
48
+ JGrep.verbose_on
49
+ results = JGrep::jgrep(doc, "foo=bar", nil, "results")
50
+ results.should == [{"foo"=>"bar"}]
51
+ end
52
+ end
53
+
54
+ describe "#format" do
55
+
56
+ it "should correctly format integers" do
57
+ result1, result2 = JGrep::format("1",1)
58
+ result1.is_a?(Fixnum).should == true
59
+ result2.is_a?(Fixnum).should == true
60
+ end
61
+
62
+ it "should correctly format floating point numbers" do
63
+ result1, result2 = JGrep::format("1.1", 1.1)
64
+ result1.is_a?(Float).should == true
65
+ result2.is_a?(Float).should == true
66
+ end
67
+
68
+ it "should not format strings" do
69
+ result1, result2 = JGrep::format("foo", "bar")
70
+ result1.is_a?(String).should == true
71
+ result2.is_a?(String).should == true
72
+ end
73
+ end
74
+
75
+ describe "#has_object?" do
76
+
77
+ it "should compare on a '=' operator" do
78
+ result = JGrep::has_object?({"foo"=> 1}, "foo=1")
79
+ result.should == true
80
+ end
81
+
82
+ it "should compare on a '<=' operator" do
83
+ result = JGrep::has_object?({"foo"=> 1}, "foo<=0")
84
+ result.should == false
85
+ end
86
+
87
+ it "should compare on a '>=' operator" do
88
+ result = JGrep::has_object?({"foo"=> 1}, "foo>=0")
89
+ result.should == true
90
+ end
91
+
92
+ it "should compare on a '<' operator" do
93
+ result = JGrep::has_object?({"foo"=> 1}, "foo<1")
94
+ result.should == false
95
+ end
96
+
97
+ it "should compare on a '>' operator" do
98
+ result = JGrep::has_object?({"foo"=> 1}, "foo>0")
99
+ result.should == true
100
+ end
101
+
102
+ it "should compare based on regular expression" do
103
+ result = JGrep::has_object?({"foo"=> "bar"}, "foo=/ba/")
104
+ result.should == true
105
+ end
106
+
107
+ it "should compare true booleans" do
108
+ result = JGrep::has_object?({"foo"=> true}, "foo=true")
109
+ result.should == true
110
+ result = JGrep::has_object?({"foo"=> false}, "foo=true")
111
+ result.should == false
112
+ end
113
+
114
+ it "should compare true booleans" do
115
+ result = JGrep::has_object?({"foo"=> false}, "foo=false")
116
+ result.should == true
117
+ result = JGrep::has_object?({"foo"=> true}, "foo=false")
118
+ result.should == false
119
+ end
120
+ end
121
+
122
+ describe "#is_object_in_array?" do
123
+
124
+ it "should return true if key=value is present in array" do
125
+ result = JGrep::is_object_in_array?([{"foo" => 1},{"foo" => 0}], "foo=1")
126
+ result.should == true
127
+ end
128
+
129
+ it "should return false if key=value is not present in array" do
130
+ result = JGrep::is_object_in_array?([{"foo" => 1},{"foo" => 0}], "foo=2")
131
+ result.should == false
132
+ end
133
+ end
134
+
135
+ describe "#has_complex?" do
136
+
137
+ it "should return true if complex statement is present in an array" do
138
+ result = JGrep::has_complex?({"foo" => ["bar" => 1]}, [["statement","foo.bar=1"]])
139
+ result.should == true
140
+ end
141
+
142
+ it "should return false if complex statement is not present in an array" do
143
+ result = JGrep::has_complex?({"foo" => ["bar" => 1]}, [["statement","foo.bar=0"]])
144
+ result.should == false
145
+ end
146
+ end
147
+
148
+ describe "#eval_statement" do
149
+
150
+ it "should return true if if document matches logical expression" do
151
+ result = JGrep::eval_statement({"foo" => 1, "bar" => 1}, [{"statement" => "foo=1"}, {"and" => "and"}, {"statement" => "bar=1"}])
152
+ result.should == true
153
+ end
154
+
155
+ it "should return true if if document matches logical expression array" do
156
+ result = JGrep::eval_statement({"foo" => ["bar" => 1]}, [{"statement" => [["statement", "foo.bar=1"]]}] )
157
+ result.should == true
158
+ end
159
+
160
+ it "should return false if if document doesn't match logical expression" do
161
+ result = JGrep::eval_statement({"foo" => 1, "bar" => 1}, [{"statement" => "foo=0"}, {"and" => "and"}, {"statement" => "bar=1"}])
162
+ result.should == false
163
+ end
164
+ end
165
+
166
+ describe "#filter_json" do
167
+ it "should return the correct values if there is a single filter" do
168
+ result = JGrep::filter_json([{"foo" => 1, "bar" => 1}], "foo")
169
+ result.should == [1]
170
+ end
171
+
172
+ it "should return the correct values if there are multiple filters" do
173
+ result = JGrep::filter_json([{"foo" => 1, "foo1" => 1, "foo2" => 1}], ["foo2", "foo1"])
174
+ result.should == [{"foo2"=>1, "foo1"=>1}]
175
+ end
176
+
177
+ it "should return an empty set if the filter has not been found and there is only 1 filter" do
178
+ result = JGrep::filter_json([{"foo" => 1}], "bar")
179
+ result.should == []
180
+ end
181
+
182
+ it "should not return a structure containing a key if that key is not specified in the document" do
183
+ result = JGrep::filter_json([{"foo" => 1}], ["foo", "bar"])
184
+ result.should == [{"foo" => 1}]
185
+ end
186
+ end
187
+
188
+ describe "#validate_filters" do
189
+
190
+ it "should validate correct single filter" do
191
+ result = JGrep::validate_filters("foo")
192
+ result.should be_nil
193
+ end
194
+
195
+ it "should not validate if a single filter contains an invalid field" do
196
+ expect{
197
+ result = JGrep::validate_filters("and")
198
+ }.to raise_error "Invalid field for -s filter : 'and'"
199
+ end
200
+
201
+ it "should correctly validate an array of filters" do
202
+ result = JGrep::validate_filters(["foo", "bar"])
203
+ result.should be_nil
204
+ end
205
+
206
+ it "should not validate if an array of filters contain an illegal filter" do
207
+ expect{
208
+ result = JGrep::validate_filters(["foo", "or"])
209
+ }.to raise_error "Invalid field for -s filter : 'or'"
210
+ end
211
+ end
212
+
213
+ describe "#dig_path" do
214
+
215
+ it "should return the correct key value for a hash" do
216
+ result = JGrep::dig_path({"foo" => 1}, "foo")
217
+ result.should == 1
218
+ end
219
+
220
+ it "should return the correct value for any value that is not a hash or an array" do
221
+ result = JGrep::dig_path(1, "foo")
222
+ result.should == 1
223
+ end
224
+
225
+ it "should return the correct value for a subvalue in an array" do
226
+ result = JGrep::dig_path([{"foo" => 1}, {"foo" => 2}], "foo")
227
+ result.should == [1,2]
228
+ end
229
+
230
+ it "should return the correct value if a wildcard is specified" do
231
+ result = JGrep::dig_path([{"foo" => {"bar" => 1}}], "foo.*")
232
+ result.should == [[{"bar"=>1}]]
233
+ end
234
+
235
+ it "should return the correct value if the path contains a dot seperated key" do
236
+ result = JGrep::dig_path({"foo.bar" => 1}, "foo.bar")
237
+ result.should == 1
238
+ result = JGrep::dig_path({"foo" => {"foo.bar" =>1}}, "foo.foo.bar")
239
+ result.should == 1
240
+ end
241
+ end
242
+ end
243
+ end