Skip to content

Instantly share code, notes, and snippets.

@vidarh
Last active July 9, 2017 16:25
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vidarh/d088d6e342e665f0b6554ec4fbaa5e53 to your computer and use it in GitHub Desktop.
Save vidarh/d088d6e342e665f0b6554ec4fbaa5e53 to your computer and use it in GitHub Desktop.
Stupid / simple JSON command line processing with Ruby

Based on an example for Elvish.

From comment posted to HN:

I love the structured pipes, but as mentioned in another discussion, replacing the shell is a big leap for a lot of people. And you can get quite far without it with tools like "jq". And when I saw this, I just had to tinker a bit to see what I could do with Ruby, based on the example on the homepage:

$ curl -s https://api.github.com/repos/elves/elvish/issues | jr 'each{|issue| puts "#{issue["number"]}: #{issue["title"]}"} ' | head -n 11

Or (I expect pitchforks when you see the implementation for this):

$ curl -s https://api.github.com/repos/elves/elvish/issues | puts{"#{$I["number"]}: #{$I["title"]}"}' | head -n 11

$J holds the full JSON. $I holds each item processed via #each or any method in Enumerable built on top of each, if you really want to make things brief.

This also lets you process a file. E.g. if you've redirected the curl to "/tmp/elves.json", you can do "jr /tmp/elves.json 'puts{$I["title"]}'

#!/usr/bin/ruby
require 'json'
script = ARGV.pop
$J = JSON.parse(ARGF.read)
# I'm going to burn in hell for this. These let you use all of
# Enumerable on the main object, so you can e.g. call "each",
# "collect" etc. without a receiver. This is not good practice
# in a bigger app..
include Enumerable
def each █
$J.each{|i| $I = i; block.call(i)}
end
def puts *args, &block
args << collect(&block)
Kernel.puts(*args)
end
eval(script)
@vidarh
Copy link
Author

vidarh commented Jul 5, 2017

You can further simplify by doing this:

    def each &block;
       $J.each do |i|
         $I = i;
         i.keys.each {|k| eval("$#{k} = $I[k].to_s")}
         block.call(i)
       end
     end

Which lets you do:

    jr 'puts{$number+": "+$title}'

(Warning: will happily clobber pre-defined globals, like $stdin; don't use on data users can manipulate the keys of)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment