language: create and use Integer and PreValue generics

This commit is contained in:
Aldo Cortesi 2015-05-02 21:42:09 +12:00
parent 0ffd14372a
commit fffee660e5
4 changed files with 65 additions and 79 deletions

View File

@ -11,6 +11,9 @@ from . import generators, exceptions
TRUNCATE = 1024 TRUNCATE = 1024
Sep = pp.Optional(pp.Literal(":")).suppress()
v_integer = pp.Word(pp.nums)\ v_integer = pp.Word(pp.nums)\
.setName("integer")\ .setName("integer")\
.setParseAction(lambda toks: int(toks[0])) .setParseAction(lambda toks: int(toks[0]))
@ -318,28 +321,6 @@ class ShortcutUserAgent(_Header):
return ShortcutUserAgent(self.value.freeze(settings)) return ShortcutUserAgent(self.value.freeze(settings))
class Body(_Component):
def __init__(self, value):
self.value = value
@classmethod
def expr(klass):
e = pp.Literal("b").suppress()
e = e + Value
return e.setParseAction(lambda x: klass(*x))
def values(self, settings):
return [
self.value.get_generator(settings),
]
def spec(self):
return "b%s"%(self.value.spec())
def freeze(self, settings):
return Body(self.value.freeze(settings))
class PathodSpec(_Token): class PathodSpec(_Token):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
@ -457,9 +438,9 @@ class OptionsOrValue(_Component):
return self.__class__(self.value.freeze(settings)) return self.__class__(self.value.freeze(settings))
class Code(_Component): class Integer(_Component):
def __init__(self, code): def __init__(self, value):
self.code = str(code) self.value = str(value)
@classmethod @classmethod
def expr(klass): def expr(klass):
@ -467,22 +448,25 @@ class Code(_Component):
return e.setParseAction(lambda x: klass(*x)) return e.setParseAction(lambda x: klass(*x))
def values(self, settings): def values(self, settings):
return [generators.LiteralGenerator(self.code)] return [generators.LiteralGenerator(self.value)]
def spec(self): def spec(self):
return "%s"%(self.code) return "%s"%(self.value)
def freeze(self, settings): def freeze(self, settings):
return self return self
class Reason(_Component): class PreValue(_Component):
"""
A value lead by self.preamble.
"""
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
@classmethod @classmethod
def expr(klass): def expr(klass):
e = pp.Literal("m").suppress() e = pp.Literal(klass.preamble).suppress()
e = e + Value e = e + Value
return e.setParseAction(lambda x: klass(*x)) return e.setParseAction(lambda x: klass(*x))
@ -490,10 +474,10 @@ class Reason(_Component):
return [self.value.get_generator(settings)] return [self.value.get_generator(settings)]
def spec(self): def spec(self):
return "m%s"%(self.value.spec()) return "%s%s"%(self.preamble, self.value.spec())
def freeze(self, settings): def freeze(self, settings):
return Reason(self.value.freeze(settings)) return self.__class__(self.value.freeze(settings))
class _Action(_Token): class _Action(_Token):
@ -633,10 +617,6 @@ class _Message(object):
def actions(self): def actions(self):
return self.toks(_Action) return self.toks(_Action)
@property
def body(self):
return self.tok(Body)
@property @property
def headers(self): def headers(self):
return self.toks(_Header) return self.toks(_Header)
@ -695,6 +675,3 @@ class _Message(object):
def __repr__(self): def __repr__(self):
return self.spec() return self.spec()
Sep = pp.Optional(pp.Literal(":")).suppress()

View File

@ -20,6 +20,18 @@ class Path(base.SimpleValue):
pass pass
class Code(base.Integer):
pass
class Reason(base.PreValue):
preamble = "m"
class Body(base.PreValue):
preamble = "b"
class Method(base.OptionsOrValue): class Method(base.OptionsOrValue):
options = [ options = [
"get", "get",
@ -47,10 +59,14 @@ def get_header(val, headers):
class _HTTPMessage(base._Message): class _HTTPMessage(base._Message):
version = "HTTP/1.1" version = "HTTP/1.1"
@property @property
def raw(self): def raw(self):
return bool(self.tok(Raw)) return bool(self.tok(Raw))
@property
def body(self):
return self.tok(Body)
@abc.abstractmethod @abc.abstractmethod
def preamble(self, settings): # pragma: no cover def preamble(self, settings): # pragma: no cover
@ -69,7 +85,7 @@ class _HTTPMessage(base._Message):
class Response(_HTTPMessage): class Response(_HTTPMessage):
comps = ( comps = (
base.Body, Body,
base.Header, base.Header,
base.PauseAt, base.PauseAt,
base.DisconnectAt, base.DisconnectAt,
@ -77,7 +93,7 @@ class Response(_HTTPMessage):
base.ShortcutContentType, base.ShortcutContentType,
base.ShortcutLocation, base.ShortcutLocation,
Raw, Raw,
base.Reason Reason
) )
logattrs = ["code", "reason", "version", "body"] logattrs = ["code", "reason", "version", "body"]
@ -87,16 +103,16 @@ class Response(_HTTPMessage):
@property @property
def code(self): def code(self):
return self.tok(base.Code) return self.tok(Code)
@property @property
def reason(self): def reason(self):
return self.tok(base.Reason) return self.tok(Reason)
def preamble(self, settings): def preamble(self, settings):
l = [self.version, " "] l = [self.version, " "]
l.extend(self.code.values(settings)) l.extend(self.code.values(settings))
code = int(self.code.code) code = int(self.code.value)
l.append(" ") l.append(" ")
if self.reason: if self.reason:
l.extend(self.reason.values(settings)) l.extend(self.reason.values(settings))
@ -121,7 +137,7 @@ class Response(_HTTPMessage):
if not self.code: if not self.code:
tokens.insert( tokens.insert(
1, 1,
base.Code(101) Code(101)
) )
hdrs = netlib.websockets.server_handshake_headers( hdrs = netlib.websockets.server_handshake_headers(
settings.websocket_key settings.websocket_key
@ -159,9 +175,9 @@ class Response(_HTTPMessage):
pp.MatchFirst( pp.MatchFirst(
[ [
WS.expr() + pp.Optional( WS.expr() + pp.Optional(
base.Sep + base.Code.expr() base.Sep + Code.expr()
), ),
base.Code.expr(), Code.expr(),
] ]
), ),
pp.ZeroOrMore(base.Sep + atom) pp.ZeroOrMore(base.Sep + atom)
@ -176,7 +192,7 @@ class Response(_HTTPMessage):
class Request(_HTTPMessage): class Request(_HTTPMessage):
comps = ( comps = (
base.Body, Body,
base.Header, base.Header,
base.PauseAt, base.PauseAt,
base.DisconnectAt, base.DisconnectAt,
@ -285,12 +301,12 @@ class PathodErrorResponse(Response):
def make_error_response(reason, body=None): def make_error_response(reason, body=None):
tokens = [ tokens = [
base.Code("800"), Code("800"),
base.Header( base.Header(
base.ValueLiteral("Content-Type"), base.ValueLiteral("Content-Type"),
base.ValueLiteral("text/plain") base.ValueLiteral("text/plain")
), ),
base.Reason(base.ValueLiteral(reason)), Reason(base.ValueLiteral(reason)),
base.Body(base.ValueLiteral("pathod error: " + (body or reason))), Body(base.ValueLiteral("pathod error: " + (body or reason))),
] ]
return PathodErrorResponse(tokens) return PathodErrorResponse(tokens)

View File

@ -17,15 +17,23 @@ class WF(base.CaselessLiteral):
TOK = "wf" TOK = "wf"
class Body(base.PreValue):
preamble = "b"
class WebsocketFrame(base._Message): class WebsocketFrame(base._Message):
comps = ( comps = (
base.Body, Body,
base.PauseAt, base.PauseAt,
base.DisconnectAt, base.DisconnectAt,
base.InjectAt base.InjectAt
) )
logattrs = ["body"] logattrs = ["body"]
@property
def body(self):
return self.tok(Body)
@classmethod @classmethod
def expr(klass): def expr(klass):
parts = [i.expr() for i in klass.comps] parts = [i.expr() for i in klass.comps]

View File

@ -183,24 +183,6 @@ class TestMisc:
s = v.spec() s = v.spec()
assert s == v.expr().parseString(s)[0].spec() assert s == v.expr().parseString(s)[0].spec()
def test_body(self):
e = base.Body.expr()
v = e.parseString("b'foo'")[0]
assert v.value.val == "foo"
v = e.parseString("b@100")[0]
assert str(v.value) == "@100"
v2 = v.freeze({})
v3 = v2.freeze({})
assert v2.value.val == v3.value.val
v = e.parseString("b@100g,digits", parseAll=True)[0]
assert v.value.datatype == "digits"
assert str(v.value) == "@100g,digits"
s = v.spec()
assert s == e.parseString(s)[0].spec()
def test_pathodspec(self): def test_pathodspec(self):
e = base.PathodSpec.expr() e = base.PathodSpec.expr()
v = e.parseString("s'200'")[0] v = e.parseString("s'200'")[0]
@ -227,16 +209,10 @@ class TestMisc:
assert e.freeze({}) assert e.freeze({})
assert e.values({}) assert e.values({})
def test_code(self): def test_value(self):
e = base.Code.expr() class TT(base.PreValue):
v = e.parseString("200")[0] preamble = "m"
assert v.string() == "200" e = TT.expr()
assert v.spec() == "200"
assert v.freeze({}).code == v.code
def test_reason(self):
e = base.Reason.expr()
v = e.parseString("m'msg'")[0] v = e.parseString("m'msg'")[0]
assert v.value.val == "msg" assert v.value.val == "msg"
@ -472,3 +448,12 @@ def test_options_or_value():
v2 = v.freeze({}) v2 = v.freeze({})
v3 = v2.freeze({}) v3 = v2.freeze({})
assert v2.value.val == v3.value.val assert v2.value.val == v3.value.val
def test_integer():
e = base.Integer.expr()
v = e.parseString("200")[0]
assert v.string() == "200"
assert v.spec() == "200"
assert v.freeze({}).value == v.value