Skip to content

Commit

Permalink
Implement argument parser
Browse files Browse the repository at this point in the history
  • Loading branch information
apexatoll committed Sep 18, 2023
1 parent a70d5f2 commit 947027e
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 0 deletions.
30 changes: 30 additions & 0 deletions lib/kangaru/input_parsers/argument_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module Kangaru
module InputParsers
class ArgumentParser < InputParser
using Patches::Inflections

def parse
grouped_argument_tokens.to_h do |tokens|
key = parse_key(tokens.shift || raise)
value = parse_value(tokens)

[key, value]
end
end

private

def grouped_argument_tokens
argument_tokens.slice_before(ARGUMENT_TOKEN).to_a
end

def parse_key(key)
key.gsub(/^-+/, "").to_snakecase.to_sym
end

def parse_value(tokens)
tokens.empty? || tokens.join(" ")
end
end
end
end
15 changes: 15 additions & 0 deletions sig/kangaru/input_parsers/argument_parser.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Kangaru
module InputParsers
class ArgumentParser < InputParser
def parse: -> Hash[Symbol, untyped]

private

def grouped_argument_tokens: -> Array[InputParser::tokens]

def parse_key: (String) -> Symbol

def parse_value: (Array[untyped]) -> untyped
end
end
end
111 changes: 111 additions & 0 deletions spec/kangaru/input_parsers/argument_parser_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
RSpec.describe Kangaru::InputParsers::ArgumentParser do
subject(:argument_parser) { described_class.new(tokens) }

let(:tokens) { [command_tokens, argument_tokens].flatten.compact }

describe "#parse" do
subject(:arguments) { argument_parser.parse }

shared_examples :parses_arguments_hash do |options|
let(:expected_hash) { options[:to] }

it "returns a hash" do
expect(arguments).to be_a(Hash)
end

it "has symbol keys" do
expect(arguments.keys).to all be_a(Symbol)
end

it "is the expected hash" do
expect(arguments).to eq(expected_hash)
end
end

context "when input does not contain command tokens" do
let(:command_tokens) { nil }

context "and single unary argument is passed" do
context "and terse flag form given" do
let(:argument_tokens) { ["-f"] }

include_examples :parses_arguments_hash, to: { f: true }
end

context "and verbose flag form given" do
let(:argument_tokens) { ["--foo-bar"] }

include_examples :parses_arguments_hash, to: { foo_bar: true }
end
end

context "and single binary argument is passed" do
context "and terse flag form given" do
let(:argument_tokens) { %w[-t Hello world] }

include_examples :parses_arguments_hash, to: { t: "Hello world" }
end

context "and verbose flag form given" do
let(:argument_tokens) { %w[--full-title Hello world] }

include_examples :parses_arguments_hash,
to: { full_title: "Hello world" }
end
end

context "and multiple arguments are passed" do
let(:argument_tokens) do
%w[--title This is the title -d Foobar --cleanup -f]
end

include_examples :parses_arguments_hash, to: {
title: "This is the title", d: "Foobar", cleanup: true, f: true
}
end
end

context "when input contains command tokens" do
let(:command_tokens) { %w[foo bar baz] }

context "and single unary argument is passed" do
context "and terse flag form given" do
let(:argument_tokens) { ["-f"] }

include_examples :parses_arguments_hash, to: { f: true }
end

context "and verbose flag form given" do
let(:argument_tokens) { ["--foo-bar"] }

include_examples :parses_arguments_hash, to: { foo_bar: true }
end
end

context "and single binary argument is passed" do
context "and terse flag form given" do
let(:argument_tokens) { %w[-t Hello world] }

include_examples :parses_arguments_hash, to: { t: "Hello world" }
end

context "and verbose flag form given" do
let(:argument_tokens) { %w[--full-title Hello world] }

include_examples :parses_arguments_hash,
to: { full_title: "Hello world" }
end
end

context "and multiple arguments are passed" do
let(:argument_tokens) do
%w[--title This is the title -d Foobar --cleanup -f]
end

include_examples :parses_arguments_hash, to: {
title: "This is the title", d: "Foobar", cleanup: true, f: true
}
end
end
end
end

0 comments on commit 947027e

Please sign in to comment.