Skip to content

Instantly share code, notes, and snippets.

@ben0x539
Last active October 16, 2021 11:26
Show Gist options
  • Save ben0x539/ec236bdf998ac130cb205f625cc3d53b to your computer and use it in GitHub Desktop.
Save ben0x539/ec236bdf998ac130cb205f625cc3d53b to your computer and use it in GitHub Desktop.
pronounced jasopts
require 'json'
class Cell < Struct.new(:item); end
class Args
attr_reader :pos, :top
def initialize()
@pos = []
@top = {}
@stack = [Cell.new(@top)]
end
def current_hash()
c = @stack.last
return c.item if c.item.is_a?(Hash)
return c.item = {} if c.item == nil
if c.item.is_a?(Array)
h = Cell.new({})
c.item << h
@stack.push h
return h.item
end
raise "stack top is weird"
end
def current_array()
c = @stack.last
return c.item if c.item.is_a?(Array)
return c.item = [] if c.item == nil
@pos
end
def parse(arg)
if @stack.empty?
@pos << arg
return
end
if arg == '--'
@stack = []
return
end
if m = arg.match(/^-(\/+)$/)
m[1].length.times do
@stack.pop
end
return
end
if m = arg.match(/^-(,+)$/)
m[1].length.times do
if @stack.last.item == nil
@stack.last.item = []
else
v = Cell.new([])
current_array << v
@stack << v
end
end
return
end
if m = arg.match(/^-\/(.*)$/)
literal(JSON.load(m[1]))
return
end
if m = arg.match(/^--([^:=]+):$/)
v = Cell.new(nil)
current_hash[m[1]] = v
@stack << v
return
end
if m = arg.match(/^--([^=]+)(?:=(.*))?$/)
current_hash[m[1]] = m[2] || true
return
end
current_array << arg
end
def literal(v)
if @stack.last.item == nil
@stack.pop.item = cell(v)
else
current_array << cell(v)
end
return
end
end
def uncell(v)
if v.is_a?(Hash)
v.transform_values { |i| uncell(i) }
elsif v.is_a?(Array)
v.map { |i| uncell(i) }
elsif v.is_a?(Cell)
uncell(v.item)
else
v
end
end
def cell(v)
if v.is_a?(Hash)
v.transform_values { |i| cell(i) }
elsif v.is_a?(Array)
v.map { |i| cell(i) }
elsif v.is_a?(Cell)
v
else
Cell.new(v)
end
end
args = Args.new
ARGV.each do |v| args.parse(v) end
puts JSON.dump(uncell(args.top))
puts JSON.dump(uncell(args.pos))
@ben0x539
Copy link
Author

$ ruby jsopts.rb leading positional args --toplevel=value --nested: --inner=value -/ --toplevel2=value --some-array: 1 2 3 4 --object-in-array -// --nested-array: -,,,, lol -//// --explicit-null: -/null --a-number: -/42 -- trailing positional args | jq .
{
  "toplevel": "value",
  "nested": {
    "inner": "value"
  },
  "toplevel2": "value",
  "some-array": [
    "1",
    "2",
    "3",
    "4",
    {
      "object-in-array": true
    }
  ],
  "nested-array": [
    [
      [
        [
          "lol"
        ]
      ]
    ]
  ],
  "explicit-null": null,
  "a-number": 42
}
[
  "leading",
  "positional",
  "args",
  "trailing",
  "positional",
  "args"
]

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