diff options
Diffstat (limited to 'doc/ref')
-rw-r--r-- | doc/ref/general.texi | 8 | ||||
-rw-r--r-- | doc/ref/general/data-formats.texi | 25 | ||||
-rw-r--r-- | doc/ref/general/data-stores.texi | 36 | ||||
-rw-r--r-- | doc/ref/general/lens.texi | 47 | ||||
-rw-r--r-- | doc/ref/general/sxml.texi | 100 | ||||
-rw-r--r-- | doc/ref/general/util-object.texi | 86 | ||||
-rw-r--r-- | doc/ref/general/util-path.texi | 8 | ||||
-rw-r--r-- | doc/ref/general/util-type.texi | 62 | ||||
-rw-r--r-- | doc/ref/general/util.texi | 16 | ||||
-rw-r--r-- | doc/ref/general/webdav.texi | 301 | ||||
-rw-r--r-- | doc/ref/vcomponent.texi | 41 |
11 files changed, 727 insertions, 3 deletions
diff --git a/doc/ref/general.texi b/doc/ref/general.texi index d33975ed..b97dece0 100644 --- a/doc/ref/general.texi +++ b/doc/ref/general.texi @@ -21,3 +21,11 @@ of these should be generally useful in any project. @include general/crypto.texi @include general/graph.texi @include general/options.texi + + +@include general/util-type.texi +@include general/util-object.texi +@include general/lens.texi +@include general/data-formats.texi +@include general/data-stores.texi +@include general/webdav.texi diff --git a/doc/ref/general/data-formats.texi b/doc/ref/general/data-formats.texi new file mode 100644 index 00000000..037d3ae7 --- /dev/null +++ b/doc/ref/general/data-formats.texi @@ -0,0 +1,25 @@ +@node Data Formats +@section Data Formats +A data format is some way that an individual event may get serialized +to disk. The default is iCalendar (TODO reference RFC 5545), but +others might be available (TODO footnote and reference xcal). + +Each available format should be included as +@code{(vcomponent formats @var{format-name})}. +Which module corresponds to what file type is currently defined out of band. + +Each module should expose the following procedures. + +@defun serialize component port +Write a serialized representation of @var{component} to @var{port}. +@end defun + +@defun deserialize port +Read a serialized representation of a component from @var{port}, and +return the deserialized instance of this object. +@end defun + +@subsection iCalendar +RFC 5545 + +@subsection xCal diff --git a/doc/ref/general/data-stores.texi b/doc/ref/general/data-stores.texi new file mode 100644 index 00000000..ec3962da --- /dev/null +++ b/doc/ref/general/data-stores.texi @@ -0,0 +1,36 @@ +@node Data Stores +@section Data Stores +Data stores are persistant stores for events, such as databases or the +file system. Each data store can support any number of data formats, +but which is an implementation detail of that format and shouldn't be +needed information from the high level view. +@footnote{It is however important for interoperability with other programs}. + +@c (make <calendar-store> #:path ``hello'') + +@defun path store +@end defun + +@deftp {GOOPS method} get-calendar this +Returns a vcomponent object of type @code{VCALENDAR}. Should contain +all @code{VEVENT} components of this calendar. +@end deftp + +@deftp {GOOPS method} get-by-uid this uid +Return the event object with UID equal to the string @var{uid}. +@end deftp + +@deftp {GOOPS method} queue-save this event +Queue a save event of @var{event} to the store. +@end deftp + +@deftp {GOOPS method} flush this +Force write of all queued actions. +@end deftp + +@subsection VDir +[VDIR]: http://vdirsyncer.pimutils.org/en/latest/vdir.html + +@subsection File + +@subsection SQLite diff --git a/doc/ref/general/lens.texi b/doc/ref/general/lens.texi new file mode 100644 index 00000000..eeddd6ca --- /dev/null +++ b/doc/ref/general/lens.texi @@ -0,0 +1,47 @@ +@node Lenses +@section Lenses + +Provided by the module @code{(hnh util lens)} + +@defun modify object lens f args ... +@end defun + +@defmac modify* object lens +@defmacx modify* object lens rest ... +@end defmac + +@defmac set object lenses ... value +@end defmac + +@defmac get object lenses ... +@end defmac + + +@defun make-lens getter setter +@end defun + +@defmac build-lens getter setter +Where any of getter or setter can either be a single symbol, or a list. +@end defmac + +@deftp {Scheme Lens} identity-lens +@end deftp + +@defun compose-lenses lenses ... +@defunx lens-compose lenses ... +Lenses composes left to right, so earlier lenses in @var{lenses} are +applied earlier. +@end defun + +@deftp {Scheme Lens} ref idx +Focuses the element at index @var{idx} in a list. +@end deftp + +@deftp {Scheme Lens} car* +@deftp {Scheme Lens} cdr* +Focuses the first or second element of a pair. +@end deftp + +@defun each object lens proc +@end defun + diff --git a/doc/ref/general/sxml.texi b/doc/ref/general/sxml.texi new file mode 100644 index 00000000..dd635b4c --- /dev/null +++ b/doc/ref/general/sxml.texi @@ -0,0 +1,100 @@ +@node sxml namespaced +@section Namespaced SXML + +Namespaces is a variant to ``regular'' SXML. Difference being that +instead of representing XML-tags as symbols, they are instead actual +objects. + +For example +@example +`(a (b "Content")) +@end example + +Would be represented as +@example +`(,(xml 'a) + (,(xml 'b) + "Content")) +@end example + +@defun namespaced-sxml->sxml tree [namespace-prefixes='()] +Takes a tree of namespaced-sxml, and optionally an assoc list from +namespace symbols, to prefered prefix. + +Returns a sxml tree, with xmlns:<prefix>=namespace attributes +@end defun + +@defun namespaced-sxml->xml tree [namespaces='()] [port='(current-output-port)] +Serializes the namespaced sxml tree to port. @var{namespaces} should +be an association list from namespace symbols, to prefered prefixes. +@end defun + +@defun namespaced-sxml->sxml/namespaces tree [namespace-prefixes='()] +Returns two values: +@itemize +@item An SXML tree (which doesn't have namespace attributes) +@item an association list from namespace symbols, to used prefixes. +@end itemize +@end defun + +@c xml->namespcaed-sxml and sxml->namespaced-sxml don't share +@c implementation, despite doing almost the same thing. This is since +@c xml->namespaced-sxml directly uses the ssax parser, giving us great +@c controll, while sxml->namespaced-sxml attempt to look at symbols. + +@defun xml->namespaced-sxml port-or-string +Reads xml from port, and return a namespaced SXML tree. +@end defun + +@defun sxml->namespaced-sxml tree namespaces +Converts a ``regular'' SXML tree into a namespaced sxml tree. +@var{namespaces} must be an association list which maps each prefix +used in @var{tree} onto a full XML namespace. + +The key @code{#f} can be used to map non-namespaced elements into a +namespace. +@end defun + +@defun xml tag +@defunx xml ns tag [attrs] +@anchor{xml-tag} + A single XML element, suitable to go as the car of a list to + create a full object. + + @var{xml} is a shorthand to @code{make-xml-element}, which + either takes just a tag (for non-namespaced elements), or a + namespace, a tag, and a list of attributes. + + @itemize + @item @var{tag} should be a symbol. + @item @var{ns} should be a symbol. + @item @var{attrs} should be a hash table. + @end itemize + + @defun make-xml-element tagname namespace attributes + @end defun + + @defun xml-element? x + @end defun + + @defun xml-element-tagname el + @end defun + + @defun xml-element-namespace el + @end defun + + @defun xml-element-attributes el + @end defun +@end defun + + +@defun make-pi-element tag body + @defun pi-element? x + @end defun + + @defun pi-tag pi + @end defun + + @defun pi-body pi + @end defun +@end defun diff --git a/doc/ref/general/util-object.texi b/doc/ref/general/util-object.texi new file mode 100644 index 00000000..ceac2f2a --- /dev/null +++ b/doc/ref/general/util-object.texi @@ -0,0 +1,86 @@ +@node define-type +@section Yet Another Object System + +@defmac define-type (name type-parameters ...) fields ... +Introduce a new type. + +Each field is either a symbol, or a list where the first element is a +symbol, and the remaining elements are alternating keywords and +values, as per @ref{Field Parameters}. All fields are optional by +default, but can be made non-optional through its type parameter. + +The example below creates a new type called @var{type}, with a custom +printer which always displays the string ``TYPE''. It has two fields, +@var{x}, which must be an integer, and @var{y}, which can have any +type, but gets the value ``Hello'' in none is given. +@example +(define-type (type #:printer (lambda (r p) (display "TYPE" p))) + (x #:type integer?) + (y #:default "Hello")) +@end example +@end defmac + +@subsection Type Parameters + +@deffn {Type Parameter} constructor (λ (primitive-constructor type-validator)) +Use a custom constructor for the type. The given procedure is called +with two values: +@itemize +@item the types primitive (and usually hidden) constructor, +which takes as many arguments as there are fields, in the order given +in define-type, and +@item the type validator procedure, which also takes all arguments, +but instead either returns an undefined value if everything is fine, +or throws @code{'wrong-type-arg} otherwise. +@end itemize +The procedure should then return a new procedure, which will be bound +as the constructor for the type. Note that default values are current +disregarded with custom constructors. + +A custom constructor for the type above might look like +@example +(lambda (primitive-constructor type-check) + (lambda* (#:key x y) + (type-check x y) + (primitive-constructor x y))) +@end example +@end deffn + +@deffn {Type Parameter} printer (λ (record port)) +Use a custom printer for the type. +@end deffn + +@subsection Field Parameters +@anchor{Field Parameters} + +@deffn {Field Parameter} default value +Value the field should get if not given. +@end deffn + +@deffn {Field Parameter} type type-clause +A type predicate that the field must obey. See @ref{type-clause} for details. +@end deffn + +@subsection Introduced Bindings + +Define type introduces a number procedures. (@var{<name>} should be +replaced with whatever was given as @var{name} to define-type. + +@defun @var{<name>} [kv-args ...] +Type constructor. Takes key-value arguments. Where the keys are the +names of the fields. +@end defun + +@defun @var{<name>}? x +Type predicate. +@end defun + +And for each field @var{<field>}: + +@defun @var{<field>} object [value] +Accessor for the given filed. +Returns the current value if called with only an object, and returns a +new object with @var{field} set to @var{value} if called with two values. + +The updating version checks the type if #:type was given on creation. +@end defun diff --git a/doc/ref/general/util-path.texi b/doc/ref/general/util-path.texi index 9c1da19b..ba78a828 100644 --- a/doc/ref/general/util-path.texi +++ b/doc/ref/general/util-path.texi @@ -41,7 +41,13 @@ The first component will be @code{""} if path is absolute. @defun filename-extension filename -Returns the extension of the filename, or the empty string if none exists. +Returns the extension of the filename without a leading period, or the +empty string if none exists. + +@example +(filename-extension "file.tar.gz") +⇒ "gz" +@end example @end defun @defun realpath path diff --git a/doc/ref/general/util-type.texi b/doc/ref/general/util-type.texi new file mode 100644 index 00000000..104b00b3 --- /dev/null +++ b/doc/ref/general/util-type.texi @@ -0,0 +1,62 @@ +@node Type utilities +@section Type utilities + +Provided by the module @code{(hnh util type)} + +@subsection Type Clauses +@anchor{type-clause} +@cindex type-clause + +Type clauses are an effective way of writing compound predicates +without explicitly mentioning the variable at all steps. + +The simplest type predicate is a single symbol, which is directly +called on the object: +@example +predicate? ⇒ (predicate? x) +@end example + +Otherwise, if the predicate is a list then the variable is spliced +into the argument list in the first position: +@example +(proc args ...) ⇒ (proc x args ...) +@end example + +The two primitives @code{and} and @code{or} are also available, which +both take an arbitrary number of predicates, and calls them in order, +with Scheme's usual short-circuiting rules. +@footnote{@code{and} and @code{or} doesn't have to be primitives, but +we would otherwise have one hell of a namespace conflict} + +@defmac list-of variable type-clause +Checks if @var{variable} is a list, and that every element satisfies type-clause. +@end defmac + +@defmac pair-of variable car-type-clause cdr-type-clause +Check if @var{variable} is a cons-pair, and that the car satisfies +@var{car-type-clause}, and that the cdr satisfies @var{cdr-type-clause}. +@end defmac + +@subsection Deffinitions + +@defmac build-validator-body variable type-clause +``Entry point'' of type clauses. Inserts variable into the +type-clause, returning something ready to be passed along the eval (or +rather, spliced into another macro). + +Also used if new ``primitives'' are to be added, such as list-of. +@end defmac + +@defmac typecheck variable type-clause [procedure-name=(current-procedure-name)] +Checks @var{variable} against @var{type-clause}, and raises +@code{'wrong-type-argument} if it fails. @var{procedure-name} is used +as the calling procedure for @code{scm-error}. + +Useful at the start of procedures. +@end defmac + + +@defmac current-procedure-name +Returns the current procedure name as a symbol, or @code{#f} if not found. +@end defmac + diff --git a/doc/ref/general/util.texi b/doc/ref/general/util.texi index a85ff661..1d6a4e7a 100644 --- a/doc/ref/general/util.texi +++ b/doc/ref/general/util.texi @@ -127,6 +127,11 @@ See @var{find-extreme} @end lisp @end defun +@defun init+last list +Returns two values: everything except the last element of @var{list}, +and the last element of @var{list}. +@end defun + @defun take-to lst n Equivalent to @var{take}, but return everything (instead of crash) if n > (length lst). @@ -235,7 +240,9 @@ list, whose indices matches the order of the inputs @end defun @defun string-flatten tree -@c TODO document me +Given an arbitary tree, do a pre-order traversal, appending all strings. + +Non-strings are converted to strings, and also appended. @end defun @defun intersperse item list @@ -243,7 +250,7 @@ Inserts @var{item} between each element in @var{list}. @end defun -@defun insert-ordered item collection [<=<] +@defun insert-ordered item collection [<] Inserts @var{item} into @var{collection}, such that collection remainins sorted if it was sorted beforehand. @end defun @@ -334,6 +341,11 @@ A variable can also be removed from the environment, by setting its value to @code{#f}. @end defmac +@defmac with-locale1 category locale thunk +Run @var{thunk} with the locale @var{category} temporarily set to +@var{locale}. +@end defmac + @defmac catch* thunk (symbol proc) ... Macro allowing multiple exception types to be caught. Each (symbol proc) pair expands to a regular @code{catch}, with the leftmost being diff --git a/doc/ref/general/webdav.texi b/doc/ref/general/webdav.texi new file mode 100644 index 00000000..a495c945 --- /dev/null +++ b/doc/ref/general/webdav.texi @@ -0,0 +1,301 @@ +@node WebDAV +@section WebDAV + +For a complete view of WebDAV, please see @cite{RFC4918 (HTTP +Extensions for Web Distributed Authoring and Versioning (WebDAV))}, +but in short, and specifc for this implementation. + +A DAV tree consists of resources, which are analogous to files and +directories. A resource is referenced by its href. + +Each resources is either a collection and have children, or have +content. Parts of this implementation allows a collection to also have +contents, while other does not. The standard doesn't seem to mind +either way. + +Each resource also has a set of properties, modelling metadata and +extra data about the resource. + +@emph{href}'s are internally represented as lists of strings, where the +root element ``/'' is an empty list, and all other cases are mapped +like: +@example +"/a/b" ⇒ '("a" "b") +@end example + +@emph{resources} are GOOPS objects, which the base class +@code{<resource>}. + +The user (of the library) is assumed to designate one resource +instance as the root of the resource tree. All other resources are +then added as (grand-)children to that resource. Each resource has a +field @var{name}, which is the normative name used when searching by +name in the tree@footnote{This means that one resource can't easily +exist at multiple points in the tree}. + +@emph{properties} are split into live and dead properties, where live +properties have extra handling by the server, while dead properties +are simply carried along after the end-user put them on a resource. + +Live properties are handled through GOOPS methods. + +Dead properties are (by default) stored directly inside each resource. + +@node WebDAV Properties +@subsection Properties + +@itemize +@item @code{(calp webdav property)} +@item @code{(calp webdav propfind)} +@end itemize + +@subsubsection Default Live Properties + +@deftp {GOOPS method} creationdate +@end deftp + +@deftp {GOOPS method} displayname +@end deftp + +@deftp {GOOPS method} getcontentlanguage +@end deftp + +@deftp {GOOPS method} getcontentlength +@end deftp + +@deftp {GOOPS method} getcontenttype +@end deftp + +@deftp {GOOPS method} getetag +@end deftp + +@deftp {GOOPS method} getlastmodified +@end deftp + +@deftp {GOOPS method} lockdiscovery +@end deftp + +@deftp {GOOPS method} resourcetype +@end deftp + +@deftp {GOOPS method} supportedlock +@end deftp + + +@node WebDAV Resources +@subsection Resources + +@deftp {GOOPS class} <resource> +Base type for all WebDAV resources. + +The base class shouldn't be directly instanciated. + + @defun resource? x + Is the given object a <resource>, or decendant? + @end defun +@end deftp + +@deftp {GOOPS method} name resource +The name of a resource is the local part of a href. +@end deftp + +@deftp {GOOPS method} children resource +All direct children of a resource, as a list. +@end deftp + +@defun add-child! parent child [#:overwrite?] [#:collection?=(is-collection? child)] +Adds a resource as a child of another resource. + +Before adding the resource to the parents child set, +@code{(setup-new-resource! child parent)} is called. If +@var{collection?} is true, then +@code{(setup-new-collection! child parent)} is also called. + +If @var{overwrite?} is present, then the parent will be checked for a +child which already has that name, and take action accordingly. +It will return one of: @code{'replaced} if a resource already existed +with that name, but it has been replaced, @code{'collision}, if the +old one was kept, and @code{'created} if the new resource was added +without collisions. + +If @var{overwrite?} is absent then the method always returns @var{'created}. +@end defun + +@defun add-resource! resource name content +Creates a new resource with the given name, and make it a child of +@var{self}. Setting its initial content to @var{content}. + +Calls @code{add-resource!}, so the same book-keeping procedures are called. +@c TODO Document throw +@c TODO Document return +@end defun + +@defun add-collection! resource name +Similar to @code{add-resource!} but the created resource is instead a collection. +@end defun + +@deftp {GOOPS method} setup-new-resource! (self <resource>) (parent <resource>) +Book-keeping procedure called by @code{add-resource!} on @emph{all} +added resources. + +Base implementation in a no-op. +@end deftp + +@deftp {GOOPS method} setup-new-collection! (self <resource>) (parent <resource>) +Book-keeping procedure called by @code{add-resource!} if +@var{collection?} is true. + +Base implementation is a no-op. +@end deftp + +@deftp {GOOPS method} is-collection? resource +Is the given resource a collection. + +The base implementation simply checks if the resource has any children. +@end deftp + +@deftp {GOOPS method} content resource +@deftpx {GOOPS method} set-content! resource content +Get and set the content of a given resource. @var{content}s type can +be anything that the given resource type accepts. Overrides of this +procedure should preferably save its contents properly. +@end deftp + +@c + +@defun get-property resource xml-tag +@defunx get-live-property resource xml-tag +@defunx get-dead-property resource xml-tag +@end defun + + +@defun set-property resource xml-el +@defunx set-property! resource xml-el +@defunx set-dead-property resource xml-el +@defunx set-dead-property! resource xml-el +@defunx set-live-property resource xml-el +@defunx set-live-property! resource xml-el +@end defun + + +@defun remove-property resource xml-tag +@defunx remove-property! resource xml-tag +@defunx remove-dead-property resource xml-tag +@defunx remove-dead-property! resource xml-tag +@defunx remove-live-property resource xml-tag +@defunx remove-live-property! resource xml-tag +@end defun + +@c + +@deftp {GOOPS method} copy-resource (resource <resource>) include-children? [name] +Create a new resource which looks as similar as possible to the given +resource. The new resource will have the same (GOOPS) class as the +source, displayname, contentlanguage and all dead properties are +transfered, other live properties are currently not explicitly +transfered (but probably still transfered implicitly). + +The new resources name is @var{name} if given, and the name of the +original resource otherwise. + +If @var{include-children?} is true then a deep copy is performed, +otherwise no children are copied, and the resulting resource will be a +leaf node. + +Content is copied verbatim. + +@b{NOTE} currently no helper method is called, which means that extra +resources held by the resource object can't be copied. +For example, FILE can't create a copy (but it also shouldn't do that +here, but rathen when the element is ``mounted'' into the tree). +@end deftp + +@c + +@defun lookup-resource root-resource path +@end defun + + +@defun all-resources-under resource [prefix='()] +Returns the given resource, and all its children in a flat list. + +Currently depth first, but that might change. +The root resource is however guaranteed to be first. +@end defun + +@c + +@c TODO + make-live-property + live-property? + property-getter + + property-setter-generator + property-remover-generator + + prepare-update-properties + + live-properties + dead-properties + + webdav-properties + + +@node WebDAV Resource Types +@subsection Resource Types + +@subsubsection @code{(calp webdav resource base)} + +Implementation of @code{(calp webdav resource)}. Exists to possibly +avoid dependency loops. + +@subsubsection @code{(calp webdav resource calendar)} +@subsubsection @code{(calp webdav resource file)} + +Resources backed by the file system. + +@defun file-resource? x +@end defun + +@deftp {GOOPS method} children <file-resource> +@end deftp + +@deftp {GOOPS method} is-collection? <file-resource> +@end deftp + +@deftp {GOOPS method} creationdate <file-resource> +Retrived directly from the file through @command{stat -c %W $@{filename@}}. +@end deftp + +@deftp {GOOPS method} content <file-resource> +@deftpx {GOOPS method} set-content! <file-resource> data +Directly interfaced with the file. + +Data can't be retrieved for collections, and will always be +returned as a bytevector for non-collections. + +Data can be set either as a string or a bytevector. When a string is +used Guile's current encoding will be used. +@end deftp + +@subsubsection @code{(calp webdav resource virtual)} + +@node WebDAV Utilities +@subsection Utilities +@defun xml-element-hash-key xml-tag +Given an xml tag object @ref{xml-tag}, return a suitable key for +@code{hash-ref} and family. + +These key objects should preferably not be carried around for +long. Prefer to keep the @emph{real} xml-tag object, and only call +this while directly referencing the hash table. +@end defun + +@defun href->string href +HREF's are represented as lists of strings. The root resource (``/'') +is the empty list. +@end defun + +@defun string->href string +Return a href list back into a string. A leading slash will always be added. +@end defun diff --git a/doc/ref/vcomponent.texi b/doc/ref/vcomponent.texi index dac47348..d0e032b3 100644 --- a/doc/ref/vcomponent.texi +++ b/doc/ref/vcomponent.texi @@ -113,6 +113,8 @@ Curried version of @var{prop}. @end deftp @defun copy-vcomponent vcomponent +Creates a shallow copy of @var{vcomponent}. If the source object has a +parent, then than parent adopts the new event also. @end defun @@ -122,3 +124,42 @@ Does symbol start with ``X-''? @defun internal-field? symb [prefix="-"] @end defun + +@node VComponent Create +@section (vcomponent create) + +Procedures for declarativly creating components (instead of the +primitive procedural API). + +@defun vcomponent type [key: prop] ... children +Creates a new vcomponent of @var{type}. Each kv-pair should contain a +keyword @var{key}, and a value which is either a direct value, or the +return value of @code{with-parameters} or +@code{as-list}. @var{children} should be a list of other vcomponent's. +@end defun + +@defun vcalendar +@defunx vevent +@defunx vtimezone +@defunx standard +@defunx daylight +Calls @code{vcomponent}, with type set to the procedure name (but +up-cased). +@end defun + +@defun with-parameters [key: param] ... value +Allows setting parameters for a property as created by @code{vcomponent}. + +@var{value} follows the same rules as in @code{vcomponent}. Multiple +@var{key}, @var{value} pairs can be given, where each key must be a keyword. +@end defun + +@defun as-list lst +Allows setting list values when using @code{vcomponent}. + +Without this a list value would be stored as a single value, while +with this a list of values is instead stored (as, for example, in EXDATE). + +A list of list types could be hard-coded, but even then this procedure +is needed since custom types might need it. +@end defun |