Common Lisp Package: ACCESS

README:

Access

A Common Lisp library to unify access to the most common data structures and to allow you to operate on them as they are (ie as a bunch of dictionaries with slightly different apis)

access, accesses , (setf access), (setf accesses)

These functions allow unified access to these data structures:

  • accessor access to CLOS objects
  • slot access to CLOS objects if the key matches a slot name but not an accessor
  • plists
  • alists
  • hash-tables

They also opts to produce nil as opposed to signaling errors when they fail to access (eg (access nil 'anything) produces nil rather than signaling a missing method on nil (though if 'anything is specialized on nil it will call that method)). Slot unboundedness errors are not signaled.

This library will probably appeal most to new comers to the language as everyone else will probably be happy just calling each type of access according to its own api.

Limitations

  • Accessors should share slot names for this to work best. This is due to differences in "direct" class slots versus indirect slots (only direct slots have the reader value filed out).
  • While most structures use equalper to get around differnt key packages and strings vs symbols. Hash-tables do not currently support an equalper style interface. As such some small care needs to be taken. We try to support this by looking up values by symbol, then by symbol-name if symbol fails to produce a result.

A word on performance

This libary is meant to make writing the program easier. It does many runtime lookups and checks to make sure that funcations called can support the types they are called with. As such it should not be used in code where performance is important. It should however allow you to prototype more rapidly and change the backing data stores without having to change their access (ie I can switch from a plist to an alist and everything will continue to work)

Utilities

has-slot?, has-reader?, has-writer?

Given a function or symbol, see if the object has a slot named that or a reader/writer function associated with that name

class-slot-names, class-slot-readers, class-slot-writers

Returns the names associated with the classes slots. Readers and writers returns the functions used to access and set these slots, however these currently only support readers/writers with the same name as the slot.

call-if-applicable, call-applicable-fns Given an object and a function / funcation-name, this will call the function passing in the object if it seems like that will work

class-of-object A helper to find you the class of a given thing

(typecase o (symbol (find-class o)) (standard-class o) (standard-object (class-of o)))

equalper

A predicate to make comparing symbols in different packages easier, by comparing them case-insensitively based on symbol-name. In other respects it is equalp.

plist-val, rem-plist-val, set-plist-val

Functions to ease access to plist values (used by access when detecting a plist)

DOT syntax

DOT syntax is invoked with #D reader macro on a form or by wrapping that form in a with-dot call

Many new-comers to the language long for their dot operator from other lanugages they know. This functionality is provided (when desired) by enable-dot-syntax (for #D) or wrapping a block in the with-dot macro. I wrote these for fun and much prefer just using the access functions directly (ie. I never actually use these syntax transformers). That said, when the dot syntax is enabled, symbols with a dot in them will be transformed to the appropriate accesses calls.

EX: #Dfoo.bar.bast => (accesses foo 'bar 'bast) EX: (with-dot () (setf ht.key.subkey new-val)) => (setf (accesses ht 'key 'subkey) new-val)

Authors

;; Copyright (c) 2011 Russ Tyndall , Acceleration.net http://www.acceleration.net ;; All rights reserved. ;; ;; Redistribution and use in source and binary forms, with or without ;; modification, are permitted provided that the following conditions are ;; met: ;; ;; - Redistributions of source code must retain the above copyright ;; notice, this list of conditions and the following disclaimer. ;; ;; - Redistributions in binary form must reproduce the above copyright ;; notice, this list of conditions and the following disclaimer in the ;; documentation and/or other materials provided with the distribution. ;; ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

FUNCTION

Public

ACCESS (O K &KEY TYPE (TEST #'EQUALPER) (KEY #'IDENTITY))

Access plists, alists, hashtables and clos objects all through the same interface

ACCESS-COPY (FROM TO KEYS)

Copy the values on 'from' to 'to' for all of the keys listed

ACCESSES (O &REST KEYS)

keep accessing keys on resulting objects eg: (accesses o k1 k2) => (access (access o k1) k2)

CALL-APPLICABLE-FNS (O &REST FNS)

For an object and a list of fn/fn names, call-if-applicable repeatedly

CALL-IF-APPLICABLE (O FN)

See if there is a method named fn specialized on o, or a function named fn and call it if so

EQUALPER (X Y)

compares symbols by equalp symbol-name

HAS-READER? (O READER-NAME)

For o, does a reader function exist for it

HAS-SLOT? (O SLOT-NAME &KEY (LAX? T))

Does o have a slot names slot-name if lax? we will ignore packages to find the slot we will always return a slot-name from the specified package if it exists, otherwise we return the slot-name we found if its in a different package

HAS-WRITER? (O WRITER-NAME)

For o, does a writer function exist for it?

MUTATE-ACCESS (O K FN)

Mutate the value stored in key k on object o, by passing it through fn

SET-ACCESS (NEW O K &KEY TYPE (TEST #'EQUALPER) (KEY #'IDENTITY))

set places in plists, alists, hashtables and clos objects all through the same interface

SET-ACCESSES (NEW O &REST KEYS)

keep accessing till you get to the end of keys , then store the result of setting that field back up the call tree returns the new value and the object that was stored there (so for a plist / alist you have a ref to the val and the full list)

Undocumented

CLASS-DIRECT-SLOT-NAMES (O)

CLASS-DIRECT-SLOT-READERS (O)

CLASS-DIRECT-SLOT-WRITERS (O)

CLASS-OF-OBJECT (O)

CLASS-SLOT-BY-NAME (O K &KEY (TEST #'EQUALPER))

CLASS-SLOT-DEFINITIONS (O)

CLASS-SLOT-NAMES (O)

CLASS-SLOT-READERS (O)

CLASS-SLOT-WRITERS (O)

SPLIT-DOT-SYM (SYM)

Private

%CREATE-ACCESSOR-SYMBOL-LIST (CLASS)

Gets the slots off a class an builds binding like (local::symbol orig::symbol) where local is the current *package* and orig is the original package of the symbol used in with-all-slot-accessors

%DISABLE-DOT-SYNTAX

Internal function used to restore previous readtable.

%ENABLE-DOT-SYNTAX

Internal function used to enable reader syntax and store current readtable on stack.

%REMOVE-QUOTE-&-OR (CLASS-NAME)

remove any quote / ors so that list type-specifications

%WITH-ALL-SLOT-HELPER (DATA CLASS-NAME BODY &KEY (WITH-NAME 'WITH-ACCESS) (ADD-IGNORABLES? NIL) &AUX (SDATA DATA))

A macro which binds (like with-access) all slot names of a class to a local symbolmacro let storing and retrieving using access class-name: a symbol or a list of class-names (symbols) to make this easier to call we ignore quote and or eg: 't1=>t1, (or 't1 't2 ...)=> (t1 t2 ...)

DOT-READER (-STREAM- CHAR ARG)

Reads a form and replaces dot calls

ENSURE-LIST (LIST)

If LIST is a list, it is returned. Otherwise returns the list designated by LIST.

SETF-IF-APPLICABLE (NEW O FN)

If we find a setf function named (setf fn) that can operate on o then call that with value new

Undocumented

%SLOT-READERS (SLOTS)

%SLOT-WRITERS (SLOTS)

ACCESS-WARN (MESSAGE &REST ARGS)

DOT-TRANSLATE-WALKER (FORM)

NAME-HAS-DOT? (N)

REPLACE-DOT-CALLS (FORMS)

TRANSLATE-DOT-SYM (SYM)

MACRO

Public

DISABLE-DOT-SYNTAX

Restore readtable which was active before last call to If there was no such call, the standard readtable is used.

ENABLE-DOT-SYNTAX

Enable reader syntax.

WITH-ACCESS ((&REST KEYS) VAL-FORM &BODY BODY)

Similar to with-accessors except using the access functions

WITH-ACCESS-VALUES (BINDINGS OBJ &BODY BODY)

A macro which binds local variables from accessed values on object according to bindings bindings: (local-symbol-and-access-key or (local-symbol access-key) ...) obj: the thing we are accessing data from

WITH-ALL-SLOT-ACCESS-VALUES ((OBJ CLASS) &BODY BODY)

A macro which binds local variables for each slot value in class as by access

WITH-ALL-SLOT-ACCESSORS ((DATA CLASS-NAME) &BODY BODY)

A macro which binds (like with-access) all slot names of a class to a local symbolmacro let storing and retrieving using access class-name: a symbol or a list of class-names (symbols) to make this easier to call we ignore quote and or eg: 't1=>t1, (or 't1 't2 ...)=> (t1 t2 ...)

Undocumented

ENSURE-ARG-LIST-KEY-VALUE! (DEFAULT IDS PLACE &KEY (TEST '#'EQUALPER) (KEY '#'IDENTITY))

REM-ARG-LIST-KEY-VALUE! (IDS PLACE &KEY (TEST '#'EQUALPER) (KEY '#'IDENTITY))

REM-PLIST-VAL! (ID PLACE &KEY (TEST '#'EQUALPER) (KEY '#'IDENTITY))

SET-ARG-LIST-KEY-VALUE! (NEW IDS PLACE &KEY (TEST '#'EQUALPER) (KEY '#'IDENTITY))

SET-PLIST-VAL! (NEW ID PLACE &KEY (TEST '#'EQUALPER) (KEY '#'IDENTITY))

WITH-DOT (NIL &BODY BODY)

Private

AIF (TEST THEN &OPTIONAL ELSE)

Like IF, except binds the result of the test to IT (via LET) for the scope of the then and else expressions.

AWHEN (TEST &BODY BODY)

Like WHEN, except binds the result of the test to IT (via LET) for the scope of the body.

GENERIC-FUNCTION

Public

ARG-LIST-KEY-VALUE (ID ARG-LIST &KEY TEST KEY (TEST #'EQUALPER) (KEY #'IDENTITY))

Given an &rest value that contains a (partial) lambda list with keys somewhere in it, find the specified value for a given key

ENSURE-ARG-LIST-KEY-VALUE (DEFAULT ID ARG-LIST &KEY TEST KEY (TEST #'EQUALPER) (KEY #'IDENTITY))

Ensure that a specific keyword has a value (or default) in an appliable arg list

PLIST-VAL (ID LIST &KEY TEST KEY (TEST #'EQUALPER) (KEY #'IDENTITY))

get a value out of a plist based on its key

REM-ARG-LIST-KEY-VALUE (ID ARG-LIST &KEY TEST KEY (TEST #'EQUALPER) (KEY #'IDENTITY))

Remove a specific keyword and value from the

REM-PLIST-VAL (ID LIST &KEY TEST KEY (TEST #'EQUALPER) (KEY #'IDENTITY))

removes key & its value from plist returning (values plist (list-of-values-removed))

SET-ARG-LIST-KEY-VALUE (NEW ID ARG-LIST &KEY TEST KEY ENSURE? (TEST #'EQUALPER) (KEY #'IDENTITY))

Set the keyword parameter id to the value new if ensure? then only set if it doesnt exist (in which case new acts as a default)

SET-PLIST-VAL (NEW ID LIST &KEY TEST KEY (TEST #'EQUALPER) (KEY #'IDENTITY))

If a key exists in the plist, set its value, otherwise add this key to the dictionary

Private

Undocumented

FORMAT-ARGS (CONDITION)

SETFFORMAT-ARGS (NEW-VALUE CONDITION)

FORMAT-CONTROL (CONDITION)

SETFFORMAT-CONTROL (NEW-VALUE CONDITION)

ORIGINAL-ERROR (CONDITION)

SETFORIGINAL-ERROR (NEW-VALUE CONDITION)

VARIABLE

Private

*DOT-PREVIOUS-READTABLES*

A stack which holds the previous readtables that have been pushed here by ENABLE-DOT-SYNTAX.

CONDITION

Public

Undocumented

ACCESS-WARNING

Private

Undocumented

ACCESS-CONDITION