Class: Jrf::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/jrf/cli.rb,
lib/jrf/cli/runner.rb

Defined Under Namespace

Classes: Runner

Constant Summary collapse

USAGE =
"usage: jrf [options] 'STAGE >> STAGE >> ...'"
HELP_TEXT =
<<~'TEXT'
  usage: jrf [options] 'STAGE >> STAGE >> ...'

  JSON filter with the power and speed of Ruby.

  Options:
    -v, --verbose  print parsed stage expressions
    --lax          allow multiline JSON texts; split inputs by whitespace (also detects JSON-SEQ RS 0x1e)
    -p, --pretty   pretty-print JSON output instead of compact NDJSON
    --no-jit       do not enable YJIT, even when supported by the Ruby runtime
    --atomic-write-bytes N
                   group short outputs into atomic writes of up to N bytes
    -V, --version  show version and exit
    -h, --help     show this help and exit

  Pipeline:
    Connect stages with top-level >>.
    The current value in each stage is available as _.

  Examples:
    jrf '_["foo"]'
    jrf 'select(_["x"] > 10) >> _["foo"]'
    jrf '_["items"] >> flat'
    jrf 'sort(_["at"]) >> _["id"]'
    jrf '_["msg"] >> reduce(nil) { |acc, v| acc ? "#{acc} #{v}" : v }'

  See Also:
    https://github.com/kazuho/jrf#readme
TEXT

Class Method Summary collapse

Class Method Details

.enable_yjitObject



116
117
118
119
120
# File 'lib/jrf/cli.rb', line 116

def self.enable_yjit
  return unless defined?(RubyVM::YJIT) && RubyVM::YJIT.respond_to?(:enable)

  RubyVM::YJIT.enable
end

.run(argv = ARGV, input: ARGF, out: $stdout, err: $stderr) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/jrf/cli.rb', line 41

def self.run(argv = ARGV, input: ARGF, out: $stdout, err: $stderr)
  verbose = false
  lax = false
  pretty = false
  jit = true
  atomic_write_bytes = Runner::DEFAULT_OUTPUT_BUFFER_LIMIT
  begin
    parser = OptionParser.new do |opts|
      opts.banner = USAGE
      opts.on("-v", "--verbose", "print parsed stage expressions") { verbose = true }
      opts.on("--lax", "allow multiline JSON texts; split inputs by whitespace (also detects JSON-SEQ RS 0x1e)") { lax = true }
      opts.on("-p", "--pretty", "pretty-print JSON output instead of compact NDJSON") { pretty = true }
      opts.on("--no-jit", "do not enable YJIT, even when supported by the Ruby runtime") { jit = false }
      opts.on("--atomic-write-bytes N", Integer, "group short outputs into atomic writes of up to N bytes") do |value|
        if value.positive?
          atomic_write_bytes = value
        else
          raise OptionParser::InvalidArgument, "--atomic-write-bytes requires a positive integer"
        end
      end
      opts.on("-V", "--version", "show version and exit") do
        out.puts Jrf::VERSION
        exit
      end
      opts.on("-h", "--help", "show this help and exit") do
        out.puts HELP_TEXT
        exit
      end
    end

    parser.order!(argv)
  rescue OptionParser::ParseError => e
    err.puts e.message
    err.puts USAGE
    exit 1
  end

  if argv.empty?
    err.puts USAGE
    exit 1
  end

  expression = argv.shift
  enable_yjit if jit

  inputs = Enumerator.new do |y|
    if argv.empty?
      y << input
    else
      argv.each do |path|
        if path == "-"
          y << input
        elsif path.end_with?(".gz")
          require "zlib"
          Zlib::GzipReader.open(path) do |source|
            y << source
          end
        else
          File.open(path, "rb") do |source|
            y << source
          end
        end
      end
    end
  end
  Runner.new(
    inputs: inputs,
    out: out,
    err: err,
    lax: lax,
    pretty: pretty,
    atomic_write_bytes: atomic_write_bytes
  ).run(expression, verbose: verbose)
end