Next: Introduction, Previous: (dir), Up: (dir) [Contents][Index]
This is the descriptions Reference Manual, generated automatically by Declt version 4.0 beta 2 "William Riker" on Mon Aug 15 04:26:27 2022 GMT+0.
Next: Systems, Previous: The descriptions Reference Manual, Up: The descriptions Reference Manual [Contents][Index]
{} descriptions is a meta level descriptions library for Common Lisp.
It is inspired by Smalltalk Maggrite, as well as Lisp On Lines.
Download the source code from https://github.com/mmontone/descriptions and point .asd
system definition files from ./sbcl/system (ln -s <system definition file path>)
and then evaluate:
(require :descriptions)
from your lisp listener.
You will also need to satisfy these system dependencies:
alexandria
anaphora
sheeple
cxml
and cl-json
for the serialization modulecl-ppcre
for the validation moduleThe easiest way of installing those packages is via Quicklisp.
This library is under the MIT licence.
{} descriptions is a very dynamic meta-description library similar to Smalltalk Maggrite and Lisp On Lines. Meta description of the application's domain model is done defining descriptions for the different aspects is desired to represent. This helps automate the generation of different views, editors, serialization schemas, validation procedures for the domain model objects and to avoid very repetitive and error-prone work when those objects change its shape.
Domain model meta descriptions consist of the definition of description objects for its different aspects (viewing, editing, validation, persistence, serialization, etc). Description objects are a collections of attributes, can inherit from each other, and are composable.
Let's go through an example to see how this works.
Say we have a person model object:
(defclass person ()
((id :accessor id)
(username :initarg :username
:accessor username)
(fullname :initarg :fullname
:accessor fullname)
(email :initarg :email
:accessor email)
(password :initarg :password
:accessor password)))
We would like to print instances of that model on the screen. So first we define a {person} description that just describes which attributes person model objecs possess and their "types".
(define-description {person} ()
((username =>string
:reader #'username
:writer #'(setf username))
(email =>email
:reader #'email
:writer #'(setf email))
(fullname =>string
:reader #'fullname
:writer #'(setf fullname))
(password =>password
:reader #'password
:writer #'(setf password)))
:documentation "A person description")
Descriptions names are enclosed between brackets {
}
as a naming convention. Also, notice that the attribute types (=>string
, =>email
, =>password
), begin with =>
. Attributes types begin with =>
as a naming convention.
Now we can use the information on the attributes of a person, and its types, to print a description of a person on the screen. To do that we define a new description that indicates which person slots we would like to print, and in which order.
(define-description {person-view} ({person})
((fullname =>view :label "Full name")
(username =>view)
(email =>view :label "E-mail")
(password =>view :view nil)))
We can see that the password is disabled for viewing, that "Full name" and "E-mail" are used for labels, and that fullname, username, email and password are to be displayed in that order.
We can see that in action:
(display-object (make-instance 'person :username "mmontone"
:email "mariano@copyleft.no"
:password "lalala"
:fullname "Mariano Montone")
{person-view})
prints:
Full name: "Mariano Montone"
Username: "mmontone"
E-mail: "mariano@copyleft.no"
Descriptions can be composed using inheritance. Multiple inheritance is supported and they are implemented on top of a prototype based object system, so they can be composed in run time on the fly.
When inheriting from other descriptions, attributes with the same name are collapsed into one containing all the attribute properties.
For example, consider the basic {person} description we had before. We can ask for an attribute name and type, but asking if that attribute is going to be displayed throws an error, because that attribute property does not belong to the {person} description, but the {person-view} description we saw before.
{}> (attribute-name (get-attribute {person} 'fullname))
FULLNAME
{}> (attribute-type (get-attribute {person} 'fullname))
#<Object =>STRING {1005A0A0A3}>
{}> (attribute-view (get-attribute {person} 'fullname))
;; Error
But if we ask the same to the {person-view} description, we can access to all the attributes properties.
{}> (attribute-name (get-attribute {person-view} 'fullname))
FULLNAME
{}> (attribute-type (get-attribute {person-view} 'fullname))
#<Object =>STRING {1005A0A0A3}>
{}> (attribute-view (get-attribute {person-view} 'fullname))
T
This makes the approach layered, with each description describing different aspects of the same model and extending other more basic descriptions.
As we mentioned before, descriptions can be composed on the fly thanks to the prototype object system the library is implemented in.
For example, we can create new descriptions with the make-description function, passing the descriptions we want to compose as parents:
(let ((description (make-description :parents
(list {person-validation} {person-repl-editing}))))
(let ((person (make-instance 'person)))
(edit-object person description)
(validate-object person description)
(describe person)))
A prettier way of doing it is using the description name as a function:
(let ((description ({person-validation} {person-repl-editing})))
(let ((person (make-instance 'person)))
(edit-object person description)
(validate-object person description)
(describe person)))
We can also choose not to compose descriptions, but work with them separately on the different aspects of the model objects:
(let ((person (make-instance 'person)))
(edit-object person {person-repl-editing})
(validate-object person {person-validation})
(describe person)
(print
(with-output-to-string (s)
(serialize-object person {person-serialization} s))))
{} descriptions is implemented as a thin layer over Sheeple prototypes. As a consequence, descriptions and its attributes can be easily be combined in run time.
It is not possible to achieve quite the same with metaclasses. They do not allow to keep the metamodel independent of the actual implementation of the class. It should be possible to exchange descriptions on the fly, and even use multiple descriptions at the same time for the same underlying domain object.
Metaclasses have their own specific power though, and may be good to use them in combination with descriptions.
Next: Modules, Previous: Introduction, Up: The descriptions Reference Manual [Contents][Index]
The main system appears first, followed by any subsystem dependency.
Next: Files, Previous: Systems, Up: The descriptions Reference Manual [Contents][Index]
Modules are listed depth-first from the system components tree.
descriptions (system).
Next: Packages, Previous: Modules, Up: The descriptions Reference Manual [Contents][Index]
Files are sorted by type and then listed depth-first from the systems components trees.
Next: descriptions/src/package.lisp, Previous: Lisp, Up: Lisp [Contents][Index]
descriptions (system).
Next: descriptions/src/descriptions.lisp, Previous: descriptions/descriptions.asd, Up: Lisp [Contents][Index]
src (module).
Next: descriptions/src/mop.lisp, Previous: descriptions/src/package.lisp, Up: Lisp [Contents][Index]
package.lisp (file).
src (module).
Previous: descriptions/src/descriptions.lisp, Up: Lisp [Contents][Index]
descriptions.lisp (file).
src (module).
Next: Definitions, Previous: Files, Up: The descriptions Reference Manual [Contents][Index]
Packages are listed by definition order.
Next: Indexes, Previous: Packages, Up: The descriptions Reference Manual [Contents][Index]
Definitions are sorted by export status, category, package, and then by lexicographic order.
Next: Internals, Previous: Definitions, Up: Definitions [Contents][Index]
Next: Macros, Previous: Public Interface, Up: Public Interface [Contents][Index]
Boolean attribute
Email attribute
Integer attribute
Keyword attribute
Password attribute
String attribute
Symbol attribute
Next: Ordinary functions, Previous: Special variables, Up: Public Interface [Contents][Index]
Attribute builder macro
Define an attribute type
:param name: the attribute type name.
:param parents: the attribute type parents.
:param properties: list of properties.
:param options: options, like :documentation, etc
Define a new description
Run body with description attributes bound
Next: Generic functions, Previous: Macros, Up: Public Interface [Contents][Index]
Create a =>BOOLEAN attribute. Takes a plist of property values for the created attribute
Create a =>EMAIL attribute. Takes a plist of property values for the created attribute
Create a =>INTEGER attribute. Takes a plist of property values for the created attribute
Create a =>KEYWORD attribute. Takes a plist of property values for the created attribute
Create a =>MULTIPLE-OPTION attribute. Takes a plist of property values for the created attribute
Create a =>PASSWORD attribute. Takes a plist of property values for the created attribute
Create a =>SINGLE-OPTION attribute. Takes a plist of property values for the created attribute
Create a =>STRING attribute. Takes a plist of property values for the created attribute
Create a =>SYMBOL attribute. Takes a plist of property values for the created attribute
Create a =>TO-MANY-RELATION attribute. Takes a plist of property values for the created attribute
Create a =>TO-ONE-RELATION attribute. Takes a plist of property values for the created attribute
Create a =>VALUED attribute. Takes a plist of property values for the created attribute
Create a =>VIEW attribute. Takes a plist of property values for the created attribute
Obtain a description attributes. :param description: the description.
Create an attribute.
:param attribute-type: The attribute type :property-values: A plist of attribute properties values
Next: Standalone methods, Previous: Ordinary functions, Up: Public Interface [Contents][Index]
automatically generated reader method
automatically generated reader method
automatically generated writer method
automatically generated writer method
Next: Classes, Previous: Generic functions, Up: Public Interface [Contents][Index]
sb-mop.
sb-mop.
sb-mop.
Initialize the default object description
Ensures we inherit from described-object.
sb-mop.
Previous: Standalone methods, Up: Public Interface [Contents][Index]
:default-description
(list descriptions:{description})
:parent-descriptions
:default-description-name
standard-class.
:default-description
Previous: Public Interface, Up: Definitions [Contents][Index]
Next: Symbol macros, Previous: Internals, Up: Internals [Contents][Index]
Next: Ordinary functions, Previous: Special variables, Up: Internals [Contents][Index]
Next: Generic functions, Previous: Symbol macros, Up: Internals [Contents][Index]
Create a =>OPTION attribute. Takes a plist of property values for the created attribute
Create a =>REFERENCE attribute. Takes a plist of property values for the created attribute
Create a =>RELATION attribute. Takes a plist of property values for the created attribute
Next: Structures, Previous: Ordinary functions, Up: Internals [Contents][Index]
automatically generated reader method
automatically generated writer method
automatically generated reader method
automatically generated writer method
automatically generated reader method
automatically generated writer method
automatically generated reader method
automatically generated writer method
Next: Classes, Previous: Generic functions, Up: Internals [Contents][Index]
structure-object.
Previous: Structures, Up: Internals [Contents][Index]
Previous: Definitions, Up: The descriptions Reference Manual [Contents][Index]
Jump to: | (
=
A C D E F G M P S U V W |
---|
Jump to: | (
=
A C D E F G M P S U V W |
---|
Next: Data types, Previous: Functions, Up: Indexes [Contents][Index]
Jump to: | %
+
=
{
A D P S |
---|
Jump to: | %
+
=
{
A D P S |
---|
Jump to: | C D F M P S U |
---|
Jump to: | C D F M P S U |
---|