changeset 8:a4e5d053daed

Preparation for first release
author Adam Chlipala <adam@chlipala.net>
date Sat, 19 Mar 2011 14:35:11 -0400
parents 05a28a77f6fe
children f19beef42ceb
files LICENSE src/ur/feed.urs tests/mr.ur
diffstat 3 files changed, 70 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Sat Mar 19 14:35:11 2011 -0400
@@ -0,0 +1,25 @@
+Copyright (c) 2011, Adam Chlipala
+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.
+- The names of contributors may not be used to endorse or promote products
+  derived from this software without specific prior written permission.
+
+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.
--- a/src/ur/feed.urs	Thu Mar 10 18:36:50 2011 -0500
+++ b/src/ur/feed.urs	Sat Mar 19 14:35:11 2011 -0400
@@ -1,36 +1,69 @@
+(* This module implements imperative processing of XML feeds.
+ *
+ * Module author: Adam Chlipala
+ *)
+
 con pattern :: Type -> Type -> Type
+(* A pattern describes a set of XML subtrees, mapping each element of the set to
+ * a data value.  A value of type [pattern internal result] uses values of type
+ * [internal] internally, but this API exposes no details of that usage.  The
+ * type [result] gives the type used in mappings of matched subtrees. *)
+
+val null : pattern unit (variant [])
+(* A null pattern matches nothing, returning a value of the impossible empty
+ * type if it ever does match. *)
 
 con tagInternal :: {Unit} -> Type
 
-val null : pattern unit (variant [])
-
 val tag : attrs ::: {Unit} -> folder attrs -> string -> $(mapU string attrs)
           -> pattern (tagInternal attrs) {Attrs : $(mapU string attrs), Cdata : option string}
+(* A basic [tag] pattern matches a single tag with a number of required
+ * attributes.  A result value gives the attribute values and an optional
+ * CDATA value for the text content of the tag.  The [string] argument is the
+ * tag name, and the following argument gives attribute names. *)
 
 val tagA : attrs ::: {Unit} -> folder attrs -> string -> $(mapU string attrs)
           -> pattern (tagInternal attrs) $(mapU string attrs)
+(* A version of [tag] that ignores CDATA *)
+
 val tagAO : attrs ::: {Unit} -> folder attrs -> string -> $(mapU string attrs)
             -> pattern (tagInternal attrs) $(mapU (option string) attrs)
+(* A version of [tagA] that makes each attribute optional *)
 
 val tagC : string -> pattern (tagInternal []) string
+(* A version of [tag] that only matches tags with nonempty CDATA and returns
+ * only that text *)
 
 con childrenInternal :: Type -> {Type} -> Type
 
 val children : parentI ::: Type -> parent ::: Type -> children ::: {(Type * Type)}
                -> pattern parentI parent -> $(map (fn (i, d) => pattern i d) children) -> folder children
                -> pattern (childrenInternal parentI (map fst children)) (parent * $(map snd children))
+(* A combinator that takes in a pattern for a parent node and a set of patterns
+ * that must be matched against children of the parent.  This combinator will
+ * find at most one match per matching parent node. *)
+
 val childrenO : parentI ::: Type -> parent ::: Type -> children ::: {(Type * Type)}
                 -> pattern parentI parent -> $(map (fn (i, d) => pattern i d) children) -> folder children
                 -> pattern (childrenInternal parentI (map fst children)) (parent * $(map (fn (i, d) => option d) children))
+(* A version of [children] where each child pattern need not be matched *)
 
 con treeInternal :: Type -> Type -> Type
 
 val tree : parentI ::: Type -> parent ::: Type -> childI ::: Type -> child ::: Type
            -> pattern parentI parent -> pattern childI child
            -> pattern (treeInternal parentI childI) (parent * child)
+(* A combinator that takes in a pattern for a parent node and another pattern to
+ * be matched at any depth within the parent's subtree.  Unlike [children],
+ * [tree] finds as many subtree matches per parent node as possible. *)
 
 type document
 val show_document : show document
+(* Type of uninterpreted XML documents *)
 
-val fetch : string (* url *) -> transaction document
+val fetch : string -> transaction document
+(* Retrieve a document by URL. *)
+
 val app : internal ::: Type -> data ::: Type -> pattern internal data -> (data -> transaction {}) -> document -> transaction {}
+(* Find all matches of a pattern in a document, running an imperative function
+ * on the data returned by each match. *)
--- a/tests/mr.ur	Thu Mar 10 18:36:50 2011 -0500
+++ b/tests/mr.ur	Sat Mar 19 14:35:11 2011 -0400
@@ -1,12 +1,14 @@
 fun main () =
+    doc <- Feed.fetch "http://marginalrevolution.com/feed";
+
     Feed.app (Feed.children
-                  (Feed.tagA "item" {1 = "rdf:about"})
-                  (Feed.tagC "title", Feed.tagC "content:encoded"))
-             (fn (item, props) =>
-                 debug ("URL: " ^ item.1);
-                 debug ("Title: " ^ props.1);
-                 debug ("Content: " ^ props.2))
-             "http://feeds.feedburner.com/marginalrevolution/hCQh";
+                  (Feed.tagA "item" ())
+                  (Feed.tagC "link", Feed.tagC "title", Feed.tagC "content:encoded"))
+             (fn ((), (link, title, content)) =>
+                 debug ("URL: " ^ link);
+                 debug ("Title: " ^ title);
+                 debug ("Content: " ^ content))
+             doc;
     return <xml>
       See stdout.
     </xml>