Add param handling to command router

This commit is contained in:
Anton Vakhrushev 2019-10-04 16:07:03 +03:00
parent 1f494c5a63
commit 1eea71177f
3 changed files with 64 additions and 10 deletions

View File

@ -24,5 +24,5 @@ format:
.PHONY: spec .PHONY: spec
spec: format spec: format
./crystal spec --no-debug --warnings all --error-on-warnings ./crystal spec --no-debug --warnings all --error-on-warnings --error-trace

View File

@ -2,13 +2,42 @@ require "./spec_helper"
require "../src/cli/*" require "../src/cli/*"
describe CLI::CommandRouter do describe CLI::CommandRouter do
it "should handle simple command" do it "should handle simple command as block" do
router = CLI::CommandRouter.new router = CLI::CommandRouter.new
x = 10 x = 10
router.add "plus" do router.add "plus" do |p|
x += 5 x += 5
end end
router.handle "plus" router.handle "plus"
x.should eq 15 x.should eq 15
end end
it "should handle simple command as proc" do
router = CLI::CommandRouter.new
x = 10
cb = ->(params : Hash(String, String)) { x += 5 }
router.add "plus", &cb
router.handle "plus"
x.should eq 15
end
it "should handle command with argument" do
router = CLI::CommandRouter.new
x = 10
router.add "plus {x}" do |params|
x += params["x"].to_i32
end
router.handle "plus 5"
x.should eq 15
end
it "should handle command with three arguments" do
router = CLI::CommandRouter.new
x = 0
router.add "plus {x} {y} {z}" do |p|
x = p["x"].to_i32 + p["y"].to_i32 + p["z"].to_i32
end
router.handle "plus 1 3 6"
x.should eq 10
end
end end

View File

@ -1,17 +1,42 @@
class CLI::CommandRouter class CLI::CommandRouter
def initialize def initialize
@mappings = [] of {String, Proc(Nil)} @mappings = [] of {Regex, Proc(Hash(String, String), Nil)}
end end
def add(route, &block) def add(route, &block : Hash(String, String) -> Nil)
@mappings.push({route, block}) pattern = route_to_regex(route)
@mappings.push({pattern, block})
end end
def handle(command) def handle(command)
@mappings.each do |i| @mappings.each do |handler|
if i[0] == command handle_pattern(command, *handler)
i[1].call
end
end end
end end
private def handle_pattern(command, pattern, cb)
m = command.match(pattern)
return if m.nil?
groups = m.named_captures
nil_groups = groups.select { |k, v| v.nil? }
return if nil_groups.size != 0
params = groups.transform_values { |v| v.to_s }
cb.call params
end
private def route_to_regex(route) : Regex
vals = route.partition(/\{[a-z]+?\}/)
param = vals[1].lstrip('{').rstrip('}')
result = ""
if vals[0] != ""
result += Regex.escape(vals[0])
end
if vals[1] != ""
result += sprintf "(?P<%s>.+?)", param
end
if vals[2] != ""
result += route_to_regex(vals[2]).source
end
Regex.new(result)
end
end end