Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fe9ac55
Showing
13 changed files
with
410 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules/ | ||
tmp/* | ||
.rvmrc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/node_modules/ | ||
.travis.yml | ||
/features/ | ||
/tmp/ | ||
Gemfile | ||
Gemfile.lock | ||
Guardfile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
source :rubygems | ||
|
||
gem "cucumber" | ||
gem "aruba" | ||
gem "rspec" | ||
gem "guard" | ||
gem "guard-cucumber" | ||
gem "rb-inotify", "~> 0.8.8" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
GEM | ||
remote: http://rubygems.org/ | ||
specs: | ||
aruba (0.5.1) | ||
childprocess (~> 0.3.6) | ||
cucumber (>= 1.1.1) | ||
rspec-expectations (>= 2.7.0) | ||
builder (3.1.4) | ||
childprocess (0.3.6) | ||
ffi (~> 1.0, >= 1.0.6) | ||
coderay (1.0.8) | ||
cucumber (1.2.1) | ||
builder (>= 2.1.2) | ||
diff-lcs (>= 1.1.3) | ||
gherkin (~> 2.11.0) | ||
json (>= 1.4.6) | ||
diff-lcs (1.1.3) | ||
ffi (1.3.1) | ||
gherkin (2.11.5) | ||
json (>= 1.4.6) | ||
guard (1.6.1) | ||
listen (>= 0.6.0) | ||
lumberjack (>= 1.0.2) | ||
pry (>= 0.9.10) | ||
thor (>= 0.14.6) | ||
guard-cucumber (1.3.1) | ||
cucumber (>= 1.2.0) | ||
guard (>= 1.1.0) | ||
json (1.7.6) | ||
listen (0.7.2) | ||
lumberjack (1.0.2) | ||
method_source (0.8.1) | ||
pry (0.9.10) | ||
coderay (~> 1.0.5) | ||
method_source (~> 0.8) | ||
slop (~> 3.3.1) | ||
rb-inotify (0.8.8) | ||
ffi (>= 0.5.0) | ||
rspec (2.12.0) | ||
rspec-core (~> 2.12.0) | ||
rspec-expectations (~> 2.12.0) | ||
rspec-mocks (~> 2.12.0) | ||
rspec-core (2.12.2) | ||
rspec-expectations (2.12.1) | ||
diff-lcs (~> 1.1.3) | ||
rspec-mocks (2.12.1) | ||
slop (3.3.3) | ||
thor (0.16.0) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
aruba | ||
cucumber | ||
guard | ||
guard-cucumber | ||
rb-inotify (~> 0.8.8) | ||
rspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# A sample Guardfile | ||
# More info at https://github.com/guard/guard#readme | ||
|
||
guard 'cucumber' do | ||
watch(%r{^features/.+\.feature$}) | ||
watch(%r{^features/support/.+$}) { 'features' } | ||
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' } | ||
watch(%r{^lib/*.js}) { 'features' } | ||
watch(%r{^bin/*}) { 'features' } | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# jsong | ||
|
||
Filter JSON with regexen and display the complete path of keys to the results. Streaming-friendly. | ||
|
||
When you know roughly what you need, but you can't remember the path to get there. | ||
|
||
Given some nested JSON, `my.json`: | ||
|
||
{ | ||
"foo": { | ||
"bar": { | ||
"zip": "val1", | ||
"zap": "val2", | ||
"arr": [1, 2, 3, 4, 5, 6] | ||
} | ||
}, | ||
"quux": { | ||
"zip": "val" | ||
} | ||
} | ||
|
||
Filter by regex matching key with `-k`: | ||
|
||
$ cat my.json | jsong -k 'z\wp' | ||
|
||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
quux.zip: val | ||
|
||
It will return everything nested below a matching key: | ||
|
||
$ cat my.json | jsong -k fo | ||
|
||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
|
||
Filter by regex matching value with `-v`: | ||
|
||
cat my.json | jsong -v 'val\d' | ||
|
||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
|
||
Filter by regex matching key or value with `-a`: | ||
|
||
cat my.json | jsong -a '[\w]{4}' | ||
|
||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
quux.zip: val | ||
|
||
It will show paths including array indices: | ||
|
||
cat my.json | jsong -v 5 | ||
|
||
foo.bar.arr[4]: 5 | ||
|
||
## Requirements | ||
|
||
* `nodejs` | ||
* `npm` | ||
|
||
## Installation | ||
|
||
It usually makes sense to install `jsong` globally so all users can use it: | ||
|
||
$ npm install -g jsong | ||
|
||
## Usage | ||
|
||
`jsong [filename] [options]` | ||
|
||
If no filename is given, `jsong` reads from `STDIN`. | ||
|
||
Filtering is disjunctive - the result will be displayed if at least one of the filters match. | ||
|
||
Depending on the vagaries of your shell, you may have to single-quote your regexen. | ||
|
||
### Options | ||
|
||
* `-k`, `--key`: optional regex, default null | ||
|
||
Display result line if any of the keys match the regex. | ||
|
||
* `-v`, `--value`: optional regex, default null | ||
|
||
Display result line if the value matches the regex. | ||
|
||
* `-a`, `--any`: optional regex, default null | ||
|
||
Display path of keys/array indices to values if any of the keys or the value match the regex. | ||
|
||
* `-h`, `--help`: display help |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env node | ||
|
||
var jsong = require("../lib/jsong") | ||
jsong.cli(process.argv); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Feature: cli features | ||
|
||
Scenario: get help | ||
When I run `jsong -h` | ||
Then jsong fails with a help message |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
Feature: filter JSON | ||
|
||
Background: | ||
Given a file named "my.json" with: | ||
""" | ||
{ | ||
"foo": { | ||
"bar": { | ||
"zip": "val1", | ||
"zap": "val2", | ||
"arr": [1, 2, 3, 4, 5, 6] | ||
} | ||
}, | ||
"quux": { | ||
"zip": "val" | ||
} | ||
} | ||
""" | ||
|
||
Scenario: filter by key regex | ||
When I run `jsong my.json -k 'z\wp'` | ||
Then the output should contain exactly: | ||
""" | ||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
quux.zip: val | ||
""" | ||
|
||
Scenario: filter by key regex shows nested objects | ||
When I run `jsong my.json -k foo` | ||
Then the output should contain: | ||
""" | ||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
""" | ||
|
||
Scenario: filter by value regex | ||
When I run `jsong my.json -v 'val\d'` | ||
Then the output should contain exactly: | ||
""" | ||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
""" | ||
|
||
Scenario: filter by regex matching either key or value | ||
When I run `jsong my.json -a '[\w]{4}'` | ||
Then the output should contain exactly: | ||
""" | ||
foo.bar.zip: val1 | ||
foo.bar.zap: val2 | ||
quux.zip: val | ||
""" | ||
|
||
Scenario: display array indices | ||
When I run `jsong my.json -v 5` | ||
Then the output should contain exactly: | ||
""" | ||
foo.bar.arr[4]: 5 | ||
""" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Then /^jsong fails with a help message$/ do | ||
assert_failing_with "Usage:" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
require 'aruba/cucumber' | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
'use strict'; | ||
|
||
var fs = require("fs"), | ||
streamin = require("streamin"), | ||
nopt = require("nopt"), | ||
clarinet = require("clarinet"); | ||
|
||
var filter = function(options) { | ||
var parser = clarinet.createStream(), | ||
stack = [], | ||
key_match = false, | ||
value_match = false, | ||
any_match = false; | ||
|
||
var incrementArrayIndex = function() { | ||
if(typeof stack[stack.length - 1] === 'number') { // it's an array index | ||
stack[stack.length - 1] += 1; | ||
}; | ||
}; | ||
|
||
var print = function(val) { | ||
var str = ""; | ||
stack.forEach(function(key) { | ||
if(typeof key === 'number') { | ||
str += "[" + key + "]"; | ||
} else { | ||
if (str == "") { | ||
str = key; | ||
} else { | ||
str += "." + key; | ||
}; | ||
}; | ||
}); | ||
str = str + ": " + val; | ||
console.log(str); | ||
}; | ||
|
||
var updateKeyMatch = function(key) { | ||
if(stack.length <= key_match) { | ||
key_match = false; | ||
}; | ||
|
||
if(!key_match) { | ||
key_match = ((options.key && key.match(options.key)) || | ||
(options.any && key.match(options.any))) ? | ||
stack.length : false; | ||
}; | ||
}; | ||
|
||
parser.onopenobject = function(key) { | ||
incrementArrayIndex(); | ||
stack.push(key); | ||
updateKeyMatch(key); | ||
}; | ||
|
||
parser.oncloseobject = function() { | ||
stack.pop(); | ||
}; | ||
|
||
parser.onopenarray = function() { | ||
incrementArrayIndex(); | ||
// the first element in the array will increment this to 0 (i.e. its index) | ||
stack.push(-1); | ||
}; | ||
|
||
parser.onclosearray = function() { | ||
stack.pop(); | ||
}; | ||
|
||
parser.onkey = function(key) { | ||
incrementArrayIndex(); | ||
|
||
stack.pop(); | ||
stack.push(key); | ||
|
||
updateKeyMatch(key); | ||
}; | ||
|
||
parser.onvalue = function(v) { | ||
incrementArrayIndex(); | ||
|
||
value_match = ((options.value && v.toString().match(options.value)) || | ||
(options.any && v.toString().match(options.any))) ? | ||
true : false; | ||
|
||
if(!options.filter || (key_match || value_match)) { | ||
print(v); | ||
}; | ||
}; | ||
|
||
streamin(options.input).pipe(parser); | ||
}; | ||
|
||
// exports | ||
|
||
exports.cli = function(args) { | ||
var options = nopt({ | ||
"key": String, | ||
"value": String, | ||
"any": String, | ||
"help": String | ||
}, {}, args); | ||
|
||
if(options.help) { | ||
console.log("Usage: jsong [filename] [[-k key regexp] [-v value regex] [-a any regex]]"); | ||
console.log("If [filename] is not supplied, STDIN is used."); | ||
process.exit(1); | ||
} | ||
|
||
if (options.argv.remain.length == 1) { // filename given | ||
options.input = options.argv.remain.shift(); | ||
} else { // use STDIN | ||
options.input = process.stdin; | ||
} | ||
if(options.key || options.value || options.any) { | ||
options.filter = true; | ||
} | ||
filter(options); | ||
}; |
Oops, something went wrong.