Merge pull request #1656 from Kodiologist/keyword-call
Make HyKeyword callable
This commit is contained in:
commit
5bfd4592f6
6
NEWS.rst
6
NEWS.rst
@ -7,6 +7,12 @@ Removals
|
|||||||
------------------------------
|
------------------------------
|
||||||
* Empty expressions (`()`) are no longer legal at the top level.
|
* Empty expressions (`()`) are no longer legal at the top level.
|
||||||
|
|
||||||
|
New Features
|
||||||
|
------------------------------
|
||||||
|
* Keyword objects (not just literal keywords) can be called, as
|
||||||
|
shorthand for `(get obj :key)`, and they accept a default value
|
||||||
|
as a second argument.
|
||||||
|
|
||||||
0.15.0
|
0.15.0
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
@ -83,6 +83,11 @@ the error ``Keyword argument :foo needs a value``. To avoid this, you can quote
|
|||||||
the keyword, as in ``(f ':foo)``, or use it as the value of another keyword
|
the keyword, as in ``(f ':foo)``, or use it as the value of another keyword
|
||||||
argument, as in ``(f :arg :foo)``.
|
argument, as in ``(f :arg :foo)``.
|
||||||
|
|
||||||
|
Keywords can be called like functions as shorthand for ``get``. ``(:foo obj)``
|
||||||
|
is equivalent to ``(get obj :foo)``. An optional ``default`` argument is also
|
||||||
|
allowed: ``(:foo obj 2)`` or ``(:foo obj :default 2)`` returns ``2`` if ``(get
|
||||||
|
obj :foo)`` raises a ``KeyError``.
|
||||||
|
|
||||||
.. _mangling:
|
.. _mangling:
|
||||||
|
|
||||||
symbols
|
symbols
|
||||||
|
@ -1552,13 +1552,6 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
fn = expression[0]
|
fn = expression[0]
|
||||||
func = None
|
func = None
|
||||||
if isinstance(fn, HyKeyword):
|
|
||||||
if len(expression) > 2:
|
|
||||||
raise HyTypeError(
|
|
||||||
expression, "keyword calls take only 1 argument")
|
|
||||||
expression.append(expression.pop(0))
|
|
||||||
expression.insert(0, HySymbol("get"))
|
|
||||||
return self.compile(expression)
|
|
||||||
|
|
||||||
if isinstance(fn, HySymbol):
|
if isinstance(fn, HySymbol):
|
||||||
|
|
||||||
|
10
hy/models.py
10
hy/models.py
@ -146,6 +146,16 @@ class HyKeyword(HyObject):
|
|||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
return bool(self.name)
|
return bool(self.name)
|
||||||
|
|
||||||
|
_sentinel = object()
|
||||||
|
|
||||||
|
def __call__(self, data, default=_sentinel):
|
||||||
|
try:
|
||||||
|
return data[self]
|
||||||
|
except KeyError:
|
||||||
|
if default is HyKeyword._sentinel:
|
||||||
|
raise
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
def strip_digit_separators(number):
|
def strip_digit_separators(number):
|
||||||
# Don't strip a _ or , if it's the first character, as _42 and
|
# Don't strip a _ or , if it's the first character, as _42 and
|
||||||
|
@ -1380,9 +1380,24 @@
|
|||||||
(assert (= (len "ℵℵℵ♥♥♥\t♥♥\r\n") 11)))
|
(assert (= (len "ℵℵℵ♥♥♥\t♥♥\r\n") 11)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-keyword-dict-access []
|
(defn test-keyword-get []
|
||||||
"NATIVE: test keyword dict access"
|
|
||||||
(assert (= "test" (:foo {:foo "test"}))))
|
(assert (= (:foo {:foo "test"}) "test"))
|
||||||
|
(setv f :foo)
|
||||||
|
(assert (= (f {:foo "test"}) "test"))
|
||||||
|
|
||||||
|
(with [(pytest.raises KeyError)] (:foo {:a 1 :b 2}))
|
||||||
|
(assert (= (:foo {:a 1 :b 2} 3) 3))
|
||||||
|
(assert (= (:foo {:a 1 :b 2 :foo 5} 3) 5))
|
||||||
|
|
||||||
|
(with [(pytest.raises TypeError)] (:foo "Hello World"))
|
||||||
|
(with [(pytest.raises TypeError)] (:foo (object)))
|
||||||
|
|
||||||
|
; The default argument should work regardless of the collection type.
|
||||||
|
(defclass G [object]
|
||||||
|
(defn __getitem__ [self k]
|
||||||
|
(raise KeyError)))
|
||||||
|
(assert (= (:foo (G) 15) 15)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-break-breaking []
|
(defn test-break-breaking []
|
||||||
|
Loading…
Reference in New Issue
Block a user