✔️ Custom (block based) validator for `PrimaryNode`s
parent
fbdc6469bc
commit
7c3ef8f57f
|
@ -68,6 +68,7 @@ module CeleryScript
|
|||
def validate_node(node)
|
||||
check_arity(node)
|
||||
node.args.map { |array| check_arg_validity(*array) }
|
||||
corpus.validate_node(node)
|
||||
end
|
||||
|
||||
def check_arity(node)
|
||||
|
@ -149,7 +150,7 @@ module CeleryScript
|
|||
end
|
||||
|
||||
def run_additional_validations(node, expectation)
|
||||
corpus.validator(expectation).call(node, TypeCheckError, corpus)
|
||||
corpus.arg_validator(expectation).call(node, TypeCheckError, corpus)
|
||||
end
|
||||
|
||||
# Calling this method with only one paramter
|
||||
|
|
|
@ -4,33 +4,31 @@ module CeleryScript
|
|||
class Corpus
|
||||
BAD_NODE_NAME = "Can't find validation rules for node "
|
||||
NO_ARG_SPEC = "CANT FIND ARG SPEC"
|
||||
NO_NODE_SPEC =
|
||||
|
||||
def initialize
|
||||
@arg_def_list = {}
|
||||
@node_def_list = {}
|
||||
@arg_def_list = HashWithIndifferentAccess.new
|
||||
@node_def_list = HashWithIndifferentAccess.new
|
||||
end
|
||||
|
||||
def fetchArg(name)
|
||||
@arg_def_list[name.to_sym] or raise NO_ARG_SPEC
|
||||
end
|
||||
|
||||
def arg(arg_name, allowed_values, &blk)
|
||||
@arg_def_list[arg_name.to_sym] = ArgumentSpecification.new(arg_name,
|
||||
allowed_values,
|
||||
blk)
|
||||
self
|
||||
@arg_def_list[name] or raise NO_ARG_SPEC
|
||||
end
|
||||
|
||||
def fetchNode(name)
|
||||
n = @node_def_list[name.to_sym]
|
||||
n = @node_def_list[name]
|
||||
n ? n : raise(TypeCheckError, BAD_NODE_NAME + name.to_s)
|
||||
end
|
||||
|
||||
def node(kind, allowed_args, allowed_body_nodes = [], &blk = nil)
|
||||
@node_def_list[kind.to_sym] = NodeSpecification.new(kind,
|
||||
allowed_args,
|
||||
allowed_body_nodes,
|
||||
blk)
|
||||
def arg(arg_name, allowed_values, &blk)
|
||||
@arg_def_list[arg_name] = \
|
||||
ArgumentSpecification.new(arg_name, allowed_values, blk)
|
||||
self
|
||||
end
|
||||
|
||||
def node(kind, allowed_args, allowed_body_nodes = [], &blk)
|
||||
@node_def_list[kind] = \
|
||||
NodeSpecification.new(kind, allowed_args, allowed_body_nodes, blk)
|
||||
self
|
||||
end
|
||||
|
||||
|
@ -49,7 +47,15 @@ module CeleryScript
|
|||
Array(fetchNode(node.kind).allowed_body_types).map(&:to_sym)
|
||||
end
|
||||
|
||||
def validator(name)
|
||||
# Grab validator for a fully formed node.
|
||||
def validate_node(node)
|
||||
defn = @node_def_list[node.kind] or raise(TypeCheckError,
|
||||
BAD_NODE_NAME + name.to_s)
|
||||
defn.additional_validation&.call(node)
|
||||
end
|
||||
|
||||
# Grabs validator for an __ARG__ type.
|
||||
def arg_validator(name)
|
||||
fetchArg(name).additional_validation || CeleryScript::NOOP
|
||||
end
|
||||
|
||||
|
|
|
@ -2,12 +2,26 @@
|
|||
# Eg: Which arguments does it take? Which nodes can be placed in the body field?
|
||||
module CeleryScript
|
||||
class NodeSpecification
|
||||
attr_reader :name, :allowed_args, :allowed_body_types
|
||||
NOOP = ->(*_) { }
|
||||
|
||||
def initialize(name, allowed_args, allowed_body_types)
|
||||
attr_reader :name,
|
||||
:allowed_args,
|
||||
:allowed_body_types,
|
||||
:additional_validation
|
||||
|
||||
def initialize(name, allowed_args, allowed_body_types, additional_validation = NOOP)
|
||||
@name = name
|
||||
@allowed_args = allowed_args
|
||||
@allowed_body_types = allowed_body_types
|
||||
@additional_validation = additional_validation
|
||||
end
|
||||
|
||||
def as_json(*)
|
||||
{
|
||||
"allowed_args" => allowed_args,
|
||||
"allowed_body_types" => allowed_body_types,
|
||||
"name" => name,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -51,10 +51,11 @@ module CeleryScriptSettingsBag
|
|||
BAD_PACKAGE = '"%s" is not a valid package. Allowed values: %s'
|
||||
BAD_AXIS = '"%s" is not a valid axis. Allowed values: %s'
|
||||
BAD_POINTER_ID = "Bad point ID: %s"
|
||||
BAD_PIN_ID = "Can't find %s with id of %s"
|
||||
BAD_POINTER_TYPE = '"%s" is not a type of point. Allowed values: %s'
|
||||
BAD_PIN_TYPE = '"%s" is not a type of pin. Allowed values: %s'
|
||||
BAD_SPEED = "Speed must be a percentage between 1-100"
|
||||
|
||||
PIN_TYPE_MAP = { "Peripheral" => Peripheral, "Sensor" => Sensor }
|
||||
Corpus = CeleryScript::Corpus
|
||||
.new
|
||||
.arg(:_else, [:execute, :nothing])
|
||||
|
@ -166,7 +167,11 @@ module CeleryScriptSettingsBag
|
|||
end
|
||||
end
|
||||
.node(:named_pin, [:pin_type, :pin_id]) do |node|
|
||||
binding.pry
|
||||
klass = \
|
||||
PIN_TYPE_MAP[node.args[:pin_type].value] or raise "IMPOSSIBLE"
|
||||
id = node.args[:pin_id].value
|
||||
bad_node = !klass.exists?(id)
|
||||
node.invalidate!(BAD_PIN_ID % [klass, id]) if bad_node
|
||||
end
|
||||
.node(:read_peripheral, [:peripheral_id, :pin_mode])
|
||||
.node(:nothing, [])
|
||||
|
|
|
@ -116,7 +116,6 @@ describe CeleryScript::Checker do
|
|||
end
|
||||
|
||||
it "Catches bad `pin_type`s in `read_pin`" do
|
||||
p = FactoryBot.create(:peripheral)
|
||||
hash[:body] = [
|
||||
{
|
||||
kind: "read_pin",
|
||||
|
@ -125,13 +124,13 @@ describe CeleryScript::Checker do
|
|||
label: "pin",
|
||||
pin_number: {
|
||||
kind: "named_pin",
|
||||
args: { pin_type: p.class.name, pin_id: p.id }
|
||||
args: { pin_type: "Peripheral", pin_id: 900 }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
chk = CeleryScript::Checker.new(tree, corpus)
|
||||
expect(chk.valid?).to be false
|
||||
expect(chk.error.message).to include("not a type of pin")
|
||||
expect(chk.error.message).to include("Can't find Peripheral with id of 900")
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue