jgrep 1.3.3 → 1.4.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.
@@ -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