Adds decorator to create properties
With properties it is possible to have expressions like $expr.foo handled by a function that trades $expr for 'foo' property value. This is done by 2 pieces: 1) #operator_. that handles $xpr.keyword expressions that could not be handled by other registered operator overloads and convert it to #property#keyword($expr) dynamically constructed function name 2) Decorator that transforms func(source) into a registered in context Because property name is part of a called function name there is no need to have separate #operator_. implementation for all possible combinations of (type, property_name) and makes property name be used in a context lookup thus speeding it up Change-Id: I8c39715d425d991cb2c1726e83c415f401cfd8fe
This commit is contained in:
parent
1218f07c5d
commit
86ca4124a5
@ -72,6 +72,8 @@ def create_context(data=utils.NO_VALUE, context=None, system=True,
|
||||
|
||||
context = _setup_context(data, context, finalizer, convention)
|
||||
if system:
|
||||
std_system.register_fallbacks(context)
|
||||
context = context.create_child_context()
|
||||
std_system.register(context, delegates)
|
||||
if common:
|
||||
std_common.register(context)
|
||||
|
@ -493,3 +493,13 @@ def meta(name, value):
|
||||
fd.meta[name] = value
|
||||
return func
|
||||
return wrapper
|
||||
|
||||
|
||||
def yaql_property(python_type):
|
||||
def decorator(func):
|
||||
@name('#property#{0}'.format(get_function_definition(func).name))
|
||||
@parameter('obj', yaqltypes.PythonType(python_type, False))
|
||||
def wrapper(obj):
|
||||
return func(obj)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
@ -302,11 +302,13 @@ class Context(HiddenParameterType, SmartType):
|
||||
|
||||
|
||||
class Delegate(HiddenParameterType, SmartType):
|
||||
def __init__(self, name=None, with_context=False, method=False):
|
||||
def __init__(self, name=None, with_context=False, method=False,
|
||||
use_convention=True):
|
||||
super(Delegate, self).__init__(False)
|
||||
self.name = name
|
||||
self.with_context = with_context
|
||||
self.method = method
|
||||
self.use_convention = use_convention
|
||||
|
||||
def convert(self, value, receiver, context, function_spec, engine,
|
||||
*convert_args, **convert_kwargs):
|
||||
@ -331,7 +333,7 @@ class Delegate(HiddenParameterType, SmartType):
|
||||
|
||||
return new_context(
|
||||
name, engine, new_receiver,
|
||||
use_convention=True)(*args, **kwargs)
|
||||
use_convention=self.use_convention)(*args, **kwargs)
|
||||
func.__unwrapped__ = value
|
||||
return func
|
||||
|
||||
|
@ -117,6 +117,14 @@ def lambda_(func):
|
||||
return func
|
||||
|
||||
|
||||
@specs.name('#operator_.')
|
||||
@specs.parameter('name', yaqltypes.Keyword())
|
||||
@specs.inject('func', yaqltypes.Delegate(use_convention=False))
|
||||
def get_property(func, obj, name):
|
||||
func_name = '#property#{0}'.format(name)
|
||||
return func(func_name, obj)
|
||||
|
||||
|
||||
def register(context, delegates=False):
|
||||
context.register_function(get_context_data)
|
||||
context.register_function(op_dot)
|
||||
@ -130,3 +138,7 @@ def register(context, delegates=False):
|
||||
if delegates:
|
||||
context.register_function(call)
|
||||
context.register_function(lambda_)
|
||||
|
||||
|
||||
def register_fallbacks(context):
|
||||
context.register_function(get_property)
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
from yaql.language import exceptions
|
||||
from yaql.language import specs
|
||||
import yaql.tests
|
||||
|
||||
|
||||
@ -141,3 +142,17 @@ class TestSystem(yaql.tests.TestCase):
|
||||
self.assertEqual([4, 5, 6], self.eval(
|
||||
'$.where(lambda($ > 3)())',
|
||||
data=data))
|
||||
|
||||
def test_properties(self):
|
||||
@specs.yaql_property(int)
|
||||
def neg_value(value):
|
||||
return -value
|
||||
|
||||
self.context.register_function(neg_value)
|
||||
self.assertEqual(-123, self.eval('123.negValue'))
|
||||
self.assertRaises(exceptions.NoMatchingFunctionException,
|
||||
self.eval, '"123".negValue')
|
||||
self.assertRaises(exceptions.NoMatchingFunctionException,
|
||||
self.eval, 'null.negValue')
|
||||
self.assertRaises(exceptions.NoFunctionRegisteredException,
|
||||
self.eval, '123.neg_value')
|
||||
|
Loading…
x
Reference in New Issue
Block a user