Thread: [Assorted-commits] SF.net SVN: assorted: [222] scala-commons/trunk/src/commons
Brought to you by:
yangzhang
From: <yan...@us...> - 2008-01-11 03:57:12
|
Revision: 222 http://assorted.svn.sourceforge.net/assorted/?rev=222&view=rev Author: yangzhang Date: 2008-01-10 19:57:11 -0800 (Thu, 10 Jan 2008) Log Message: ----------- - added frontends for javabib, jscrape, sun http server (for zdb) - added handle generator (aka symbol generator) - added single-node-type tree TreeNode - added google ajax search api...this is in java :) stuffing here for now (for zdb) - added optionize(), success() - added run() Modified Paths: -------------- scala-commons/trunk/src/commons/Collections.scala scala-commons/trunk/src/commons/Control.scala scala-commons/trunk/src/commons/Io.scala scala-commons/trunk/src/commons/Misc.scala Added Paths: ----------- scala-commons/trunk/src/commons/GoogleAJAXSearchAPI.java scala-commons/trunk/src/commons/extras/ scala-commons/trunk/src/commons/extras/JScrape.scala scala-commons/trunk/src/commons/extras/JavaBib.scala scala-commons/trunk/src/commons/extras/SunHttpServer.scala Modified: scala-commons/trunk/src/commons/Collections.scala =================================================================== --- scala-commons/trunk/src/commons/Collections.scala 2008-01-04 03:33:45 UTC (rev 221) +++ scala-commons/trunk/src/commons/Collections.scala 2008-01-11 03:57:11 UTC (rev 222) @@ -298,6 +298,19 @@ case class Leaf[a](x: a) extends Tree[a] } + case class TreeNode[a](value: a, children: Seq[TreeNode[a]]) { + def show = { + import Misc._ + def r(n: TreeNode[a], lvl: Int): Stream[String] = { + Stream cons ( + " " * lvl + n.value, + Stream concat (n.children map (n => r(n, lvl+1))) + ) + } + r(this,0) mkString "\n" + } + } + abstract class BoolTree[a] { def sat(f: a => Boolean): Boolean = this match { case And(ts) => ts forall (_ sat f) Modified: scala-commons/trunk/src/commons/Control.scala =================================================================== --- scala-commons/trunk/src/commons/Control.scala 2008-01-04 03:33:45 UTC (rev 221) +++ scala-commons/trunk/src/commons/Control.scala 2008-01-11 03:57:11 UTC (rev 222) @@ -21,6 +21,10 @@ val stop = System.currentTimeMillis stop - start } + def optionize[a](f: => a) = + try { Some(f) } catch { case _ => None } + def success(f: => Any) = + try { f; true } catch { case _ => false } def loop[a](f: => a) { loop(const(f)) } def loop[a](f: Int => a) = for (val x <- Stream from 0) f(x) def lazyLoop[a](f: => a): Stream[a] = lazyLoop(const(f)) Added: scala-commons/trunk/src/commons/GoogleAJAXSearchAPI.java =================================================================== --- scala-commons/trunk/src/commons/GoogleAJAXSearchAPI.java (rev 0) +++ scala-commons/trunk/src/commons/GoogleAJAXSearchAPI.java 2008-01-11 03:57:11 UTC (rev 222) @@ -0,0 +1,29 @@ +import java.io.*; +import java.net.*; + +public class GoogleAJAXSearchAPI { + private static String endpointURL = "http://www.google.com/uds/GwebSearch?"+ + "callback=GwebSearch.Raw" + + "Completion&context=0&lstkp=0&rsz=small&hl=en&" + + "sig=8656f49c146c5220e273d16b4b6978b2&q=Axis2&key=xxxxxxxxxxxxxxxxxx&v=1.0"; + + public static void main(String[] args) throws Exception { + URLConnection uc = new URL(endpointURL).openConnection(); + HttpURLConnection connection = (HttpURLConnection) uc; + connection.setDoOutput(true); + connection.setRequestMethod("GET"); + connection.connect(); + + String line; + InputStream inputStream = null; + try { + inputStream = connection.getInputStream(); + } catch (IOException e) { + inputStream = connection.getErrorStream(); + } + BufferedReader rd = new BufferedReader(new InputStreamReader(inputStream)); + while ((line = rd.readLine()) != null) { + System.out.println(line); + } + } +} Modified: scala-commons/trunk/src/commons/Io.scala =================================================================== --- scala-commons/trunk/src/commons/Io.scala 2008-01-04 03:33:45 UTC (rev 221) +++ scala-commons/trunk/src/commons/Io.scala 2008-01-11 03:57:11 UTC (rev 222) @@ -86,5 +86,17 @@ using (new ObjectOutputStream(bytes)) (_ writeObject x) using (BinaryWriter(fname)) (_ write bytes.toByteArray) } + + def run(cmd: String, input: String) = { + val proc = Runtime.getRuntime.exec(cmd) + using (TextWriter(proc.getOutputStream)) (_ println input) + if (proc.waitFor != 0) { + throw new Exception( + "command failed with exit status " + proc.exitValue + ": " + cmd + ) + } + using (TextReader(proc.getInputStream)) (_ read) + } + } import Io._ Modified: scala-commons/trunk/src/commons/Misc.scala =================================================================== --- scala-commons/trunk/src/commons/Misc.scala 2008-01-04 03:33:45 UTC (rev 221) +++ scala-commons/trunk/src/commons/Misc.scala 2008-01-11 03:57:11 UTC (rev 222) @@ -32,6 +32,13 @@ implicit def str2xstr(s: String): XString = XString(s) implicit def xstr2str(s: XString): String = s.s def id[a](x: a) = x + + // aka symbol generator + class HandleGenerator(base: String) extends Iterator[String] { + val i = Iterator from 0 + override def next = base + i.next + override def hasNext = i.hasNext + } // class OrderedPair[a <: Ordered[a], b](x:a,y:b) extends GPair[a,b](x,y) with Ordered[OrderedPair[a,b]] { // override def compare(o: OrderedPair[a,b]) = x compare o._1 // } Added: scala-commons/trunk/src/commons/extras/JScrape.scala =================================================================== --- scala-commons/trunk/src/commons/extras/JScrape.scala (rev 0) +++ scala-commons/trunk/src/commons/extras/JScrape.scala 2008-01-11 03:57:11 UTC (rev 222) @@ -0,0 +1,26 @@ +package commons.extras + +import com.apsquared.jscrape._ + +object JScraper { + def scrapeForString(url: String, query: String) = { + val q = + """declare namespace xhtml="http://www.w3.org/1999/xhtml";""" + new PageScraper scrapePageForString (url, q + query) + } +// +// def scrapeForList(url: String, query: String) = +// + + def main(args: Array[String]) { + if (args.length > 0) { + val url = args(0) + val query = args(1) + println(scrapeForString(url, query)) + } else { + val url = "http://citeseer.ist.psu.edu/desikan03lightweight.html" + val query = "//xhtml:pre" + println(scrapeForString(url, query)) + } + } +} Added: scala-commons/trunk/src/commons/extras/JavaBib.scala =================================================================== --- scala-commons/trunk/src/commons/extras/JavaBib.scala (rev 0) +++ scala-commons/trunk/src/commons/extras/JavaBib.scala 2008-01-11 03:57:11 UTC (rev 222) @@ -0,0 +1,36 @@ +package commons.extras + +import bibtex.dom._ +import bibtex.parser._ +import java.io._ +import scala.collection.jcl + +object JavaBib { + type Entry = Map[String, Seq[String]] + def list2buffer[a](xs: java.util.List) = new jcl.BufferWrapper[a] { + override def underlying = xs + } + def convert(entry: BibtexEntry): Entry = { + val map = new jcl.MapWrapper[String, BibtexAbstractValue] { + override def underlying = entry.getFields + } + val mappings = for ((k,uncasted) <- map.elements) yield { + val newV = uncasted match { + case v: BibtexPersonList => list2buffer(v getList) + case v: BibtexString => List(v getContent) + } + (k,newV) + } + Map(mappings toList:_*) + } + def parse(value: String): (Seq[Entry], Seq[Exception]) = + parse(new StringReader(value)) + def parse(reader: Reader) = { + val file = new BibtexFile + val parser = new BibtexParser(false) + parser parse (file, reader) + val entries = list2buffer[BibtexEntry](file getEntries) map convert + (entries, parser.getExceptions) + } +} + Added: scala-commons/trunk/src/commons/extras/SunHttpServer.scala =================================================================== --- scala-commons/trunk/src/commons/extras/SunHttpServer.scala (rev 0) +++ scala-commons/trunk/src/commons/extras/SunHttpServer.scala 2008-01-11 03:57:11 UTC (rev 222) @@ -0,0 +1,59 @@ +package commons.extras + +import com.sun.net.httpserver._ +import java.net._ +import commons.Control._ +import commons.Io._ +import scala.collection.{immutable => immut, jcl} +import com.Ostermiller.util._ + +/** + * Servlet-like wrapper around Sun's small HTTP server that comes with Java 6. + * + * Requires ostermillerutils, java 6 + */ +object SunHttpServer { + type HeaderMap = Map[String,Seq[String]] + type ParamMap = Map[String,String] + type Handler = (String, HeaderMap, URI, ParamMap, String) => String + def start(f: Handler) { + val server = HttpServer create (new InetSocketAddress(8888), 1) + server createContext ("/", new HttpHandler { + override def handle(t: HttpExchange) { + val headers = { + val hs = new jcl.MapWrapper[String,java.util.List] { + override def underlying = t.getRequestHeaders + } + Map(hs.elements map { case (k,v) => + val v2 = new jcl.BufferWrapper[String] { + override def underlying = v + } + (k, v2) + } toList: _*) + } + val body = using (TextReader(t getRequestBody)) (_ read) + val method = t getRequestMethod; + val uri = t getRequestURI; + // TODO note that this mapping is lossy (only uses one of multiple + // potential mappings for each key) + val paramMap = { + val params = new CGIParser(uri getQuery) getParameters; + val map = Map(params map { pair => (pair.getName, pair.getValue) }: _*) + map withDefaultValue "" + } + val response = try { + f(method, headers, uri, paramMap, body) + } catch { + case ex: Exception => { + ex.printStackTrace + throw ex + } + } + t sendResponseHeaders (200, response length) + using (t getResponseBody) (_ write response.getBytes) + } + }) + server setExecutor null + server start; + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yan...@us...> - 2008-02-02 09:09:07
|
Revision: 289 http://assorted.svn.sourceforge.net/assorted/?rev=289&view=rev Author: yangzhang Date: 2008-02-02 01:09:09 -0800 (Sat, 02 Feb 2008) Log Message: ----------- added median, sortStats; improved error handling for `run` Modified Paths: -------------- scala-commons/trunk/src/commons/Collections.scala scala-commons/trunk/src/commons/Io.scala Modified: scala-commons/trunk/src/commons/Collections.scala =================================================================== --- scala-commons/trunk/src/commons/Collections.scala 2008-02-02 09:08:15 UTC (rev 288) +++ scala-commons/trunk/src/commons/Collections.scala 2008-02-02 09:09:09 UTC (rev 289) @@ -89,6 +89,7 @@ def +(p: (Int, Int)) = Pair(x+p.x, y+p.y) } def sum(xs: Iterator[Int]) = xs.foldLeft(0)(_+_) + def mean(xs: Seq[Int]) = sum(xs.elements) / xs.size def not[a](pred: a => Boolean)(x: a) = !pred(x) // TODO make the following into rich iterator methods? // 3 [a,b,c,d,e] -> ([a,b,c],[d,e]) @@ -501,6 +502,14 @@ // implicit def force[a](lz: Lazy[a]) = lz.get def iterator2array[a](xs: Iterator[a]) = xs.toList.toArray def sum(xs: Seq[Double]) = xs reduceLeft ((x:Double,y:Double)=>x+y) + def median(xs: Seq[Long]) = xs(xs.length / 2) + def sortStats(xs: Array[Double]) = { + Sorting quickSort xs + val (mean, variance) = meanAndVariance(xs) + val (min, median, max) = (xs(xs.length / 2), xs(0), xs.last) + val sdev = Math sqrt variance + (mean, median, sdev, variance, min, max) + } def meanAndVariance(xs: Seq[Double]) = { val mean = sum(xs) / xs.length val variance = sum( xs map (x => Math pow (x - mean, 2)) ) / xs.length Modified: scala-commons/trunk/src/commons/Io.scala =================================================================== --- scala-commons/trunk/src/commons/Io.scala 2008-02-02 09:08:15 UTC (rev 288) +++ scala-commons/trunk/src/commons/Io.scala 2008-02-02 09:09:09 UTC (rev 289) @@ -90,12 +90,14 @@ def run(cmd: String, input: String) = { val proc = Runtime.getRuntime.exec(cmd) using (TextWriter(proc.getOutputStream)) (_ println input) + val out = using (TextReader(proc.getInputStream)) (_ read) + val err = using (TextReader(proc.getErrorStream)) (_ read) if (proc.waitFor != 0) { + Console.err println err throw new Exception( "command failed with exit status " + proc.exitValue + ": " + cmd ) } - using (TextReader(proc.getInputStream)) (_ read) } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <yan...@us...> - 2008-02-22 23:44:38
|
Revision: 478 http://assorted.svn.sourceforge.net/assorted/?rev=478&view=rev Author: yangzhang Date: 2008-02-22 15:44:36 -0800 (Fri, 22 Feb 2008) Log Message: ----------- added more documentation, some cleaning and reorganization Modified Paths: -------------- scala-commons/trunk/src/commons/Collections.scala scala-commons/trunk/src/commons/Control.scala scala-commons/trunk/src/commons/Debug.scala scala-commons/trunk/src/commons/Hash.scala scala-commons/trunk/src/commons/Io.scala scala-commons/trunk/src/commons/Misc.scala scala-commons/trunk/src/commons/Path.scala scala-commons/trunk/src/commons/Repl.scala Added Paths: ----------- scala-commons/trunk/src/commons/English.scala Removed Paths: ------------- scala-commons/trunk/src/commons/ExtractorObject.scala Modified: scala-commons/trunk/src/commons/Collections.scala =================================================================== --- scala-commons/trunk/src/commons/Collections.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Collections.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -11,6 +11,29 @@ object Collections { + // + // Tuples + // + + /** + * Swap the elements of a tuple. + */ + def swap[a,b](p: (a,b)) = (p._2, p._1) + + implicit def pair2xpair(p: (Int,Int)) = new XPair(p._1,p._2) + implicit def xpair2pair(p: XPair) = (p.x,p.y) + + case class XPair(x: Int, y: Int) { + /** + * Add a pair of Ints. + */ + def +(p: (Int, Int)) = Pair(x+p.x, y+p.y) + } + + // + // Strings + // + // TODO: Make faster. /** * Split a String into words. Use this when possible, since its @@ -19,8 +42,36 @@ */ def words(x: String) = x.trim.split("\\s+") + /** + * Convert camel case to lower case with the given inter-word glue string. + * <p> + * <code>camelToLower("helloWorld", "_") == "hello_world"</code> + * <p> + * <code>camelToLower("HelloWorld", "_") == "_hello_world"</code> + */ + def camelToLower(s: String, sep: String) = { + val xs = + for (c <- s) + yield if (c.isUpperCase) sep + c.toLowerCase else c + xs mkString "" + } + def camelToUnder(s: String) = camelToLower(s, "_") + def camelToHyphen(s: String) = camelToLower(s, "-") + def camelToSpaced(s: String) = camelToLower(s, " ") + + /** + * Convert a spaced word to a hyphenated word. + */ + def spacedToHyphen(s: String) = s replaceAll (" ", "-") + + /** + * Rot-n-encode a string, but where all characters are rotated, not just + * alphabetical characters. + */ + def rot(n: Int, s: String) = s map (_ + n toChar) mkString + // - // Views + // Views of sequences // // TODO: Is there a way to "chain" views? Then Iterable2FilterMap is @@ -61,16 +112,6 @@ } } - implicit def pair2xpair(p: (Int,Int)) = new XPair(p._1,p._2) - implicit def xpair2pair(p: XPair) = (p.x,p.y) - - case class XPair(x: Int, y: Int) { - /** - * Add a pair of Ints. - */ - def +(p: (Int, Int)) = Pair(x+p.x, y+p.y) - } - implicit def MapToRichMap[k,v](m: Map[k,v]) = new RichMap(m) implicit def RichMapToMap[k,v](m: RichMap[k,v]) = m.m @@ -119,8 +160,6 @@ // Simple statistics // - import scala.util.Sorting - def sum(xs: Iterator[Int]) = xs.foldLeft(0)(_+_) def sum(xs: Seq[Double]) = xs reduceLeft ((x:Double,y:Double)=>x+y) def sum(xs: Iterator[Double]) = xs reduceLeft ((_:Double)+(_:Double)) @@ -128,6 +167,8 @@ def mean(xs: Seq[Double]) = sum(xs.elements) / xs.size def median(xs: Seq[Long]) = xs(xs.length / 2) + import scala.util.Sorting + /** * Destructively sort the array, and returns a tuple of the (mean, median, * standard deviation, variance, minimum, and maximum) of a list. @@ -151,7 +192,7 @@ // TODO: Can I write functions that are generic over n-tuples? /** - * Returns the two smallest elements. + * Return the two smallest elements. */ def mins(xs: Iterable[Long]) = { var min1 = java.lang.Long.MAX_VALUE // smallest @@ -226,6 +267,100 @@ // /** + * Return pairs of elements. + * <p> + * <code> + * pairs([a,b,c,d]) == [(a,b),(c,d)] + * <p> + * pairs([a,b,c,d,e]) == [(a,b),(c,d)] + * </code> + */ + def pairs[a](xs: Seq[a]): Stream[(a,a)] = { + xs match { + case Seq() => Stream empty + case Seq(a, b, rest @ _*) => Stream cons ((a,b), pairs(rest)) + } + } + + /** + * Return an iterator that yields invocations of f until it returns null. + * Useful for, e.g., Java's IO stream abstractions. + */ + def untilNull[a](f: => a) = new Iterator[a] { + var upcoming = f + override def hasNext = upcoming != null + override def next = { + val emit = upcoming + upcoming = f + emit + } + } + + /** + * For each x in xs, if p(x), then x is a header, and it owns all the xs + * after it until the next x for which p(x) holds. The return value is the + * header and its body. + * <p> + * <code> + * groupByHeaders([1,2,3,4,5,6,7,8,9])(_%3==0) == [[3,4,5],[6,7,8],[9]] + * </code> + */ + def groupByHeaders[a](xs: Seq[a])(p: a => Boolean) = { + val ys = new mut.ArrayBuffer[mut.ArrayBuffer[a]] + for (x <- xs) { + if (p(x)) ys += new mut.ArrayBuffer[a] + if (!ys.isEmpty) ys.last += x + } + ys + } + + /** + * Given a list of sublists, return pairs of the first element of each + * sublist along with the remaining elements. Empty sublists are ignored. + * <p> + * <code> + * separateHeads([[a,b,c],[d,e,f,g],[],[h]]) + * == [(a,[b,c]),(d,[e,f,g]),(h,[])] + * </code> + */ + def separateHeads[a](xss: Seq[Seq[a]]) = + for (xs <- xss; if !xs.isEmpty; (Seq(a),b) = span(1)(xs)) yield (a,b) + + /** + * Construct a multimap out of the given key-value pairs; the result maps + * keys to sets of values. + */ + def multimap[a,b](xs: Iterable[(a,b)]) = { + val h = new mut.HashMap[a,mut.Set[b]] with mut.MultiMap[a,b] { + override def makeSet = new mut.HashSet[b] + } + for ((k,v) <- xs) { + h add (k,v) + } + h + } + + /** + * Construct a multimap out of xs, preserving the order of values as they + * were input. + */ + def orderedMultimap[a,b](xs: List[(a,b)]) = { + val h = new mut.HashMap[a, mut.ArrayBuffer[b]] { + override def default(k: a) = { + this(k) = new mut.ArrayBuffer[b] + this(k) + } + } + for ((k,v) <- xs) h(k) += v + h + } + + /** + * Convert an iterator to array. + */ + def iterator2array[a](xs: Iterator[a]) = xs.toList.toArray + + /** * A combination of take and drop. * <p> * <code>span(3)([a,b,c,d,e]) == ([a,b,c],[d,e])</code> @@ -235,7 +370,7 @@ /** * Same as span but for Strings, which are treated as an array of chars. * <p> - * <code>spanstr(3)("abcde") == ("abc","de") + * <code>spanstr(3)("abcde") == ("abc","de")</code> */ def spanstr[a](n: Int)(xs: String) = (xs take n mkString ("","",""), xs drop n mkString ("","","")) @@ -257,6 +392,10 @@ * <p> * <code> * splitBy([1..10], (_ % 4 < 2)) == [[2,3],[6,7],[8,9]] + * <p> + * [1,3,5,6,7,8] odd == ([1,3,5],[6,7,8]) + * <p> + * [] _ == ([],[]) * </code> */ def splitBy[a](xs: Seq[a])(pred: a => Boolean): Stream[Seq[a]] = { @@ -279,11 +418,11 @@ def groupBy[a](xs: Seq[a])(pred: a => Boolean): Stream[Seq[a]] = splitBy(xs)(not(pred)) - // TODO: these was renamed from slices. Make sure nothing was broken. + // TODO: this was renamed from slices. Make sure nothing was broken. /** * Return all length-n "chunks" of xs as a stream. * <p> - * <code>chunks([a..h], 3) == [[a,b,c],[d,e,f],[g,h]]</code> + * <code>chunks(3)([a..h]) == [[a,b,c],[d,e,f],[g,h]]</code> */ def chunks[a](n: Int)(xs: Seq[a]): Stream[Seq[a]] = { if (xs.length == 0) Stream.empty @@ -300,11 +439,13 @@ 0 to (xs.length - n) map { i => xs slice (i,i+n) } /** - * Same as slices(_,2) but yields tuples. + * Same as <code>slices(_,2)</code> but yields tuples. * <p> * <code> * pairwise([a,b,c]) == [(a,b),(c,d)] + * <p> * pairwise([a]) == [] + * <p> * pairwise([]) == [] * </code> */ @@ -338,10 +479,11 @@ /** * Return a stream of n elements, where each element is an evaluation of gen. - * Note that gen may be evaluated more than n times. See: - * + * <p> + * Note that gen may be evaluated more than n times. See + * <a href="http://homepages.inf.ed.ac.uk/wadler/papers/lazyinstrict/lazyinstrict.ps"> * "How to add laziness to a strict language, without even being odd" - * http://homepages.inf.ed.ac.uk/wadler/papers/lazyinstrict/lazyinstrict.ps + * </a> */ def replicate[a](n: Int, gen: => a): Stream[a] = repeat(gen) take n @@ -385,29 +527,51 @@ } /** - * Note that this operates by duplicating the iterator and traversing each - * copy. + * Given an Iterator of pairs, return two Iterators over the first and second + * elements of the pairs. Note that this operates by duplicating the + * iterator and traversing each copy. */ def unzip[a,b](pairs: Iterator[(a,b)]): (Iterator[a],Iterator[b]) = { val (i,j) = pairs.duplicate (i map (_._1), j map (_._2)) } + /** + * Given a Stream of pairs, return two Streams over the first and second + * elements of the pairs. + */ def unzip[a,b](pairs: Stream[(a,b)]): (Stream[a],Stream[b]) = (pairs map (_._1), pairs map (_._2)) /** * Indexes the result of groupBy. * <p> - // 0 1 2 3 4 5 6 7 8 9 - // [a,b,c,c,c,d,d,e,f,f] -> [[0],[1],[2,3,4],[5,6],[7],[8,9]] - // [] -> [] + * <code> + * <p> + * [0 1 2 3 4 5 6 7 8 9] + * <br> + * [a,b,c,c,c,d,d,e,f,f] == [[0],[1],[2,3,4],[5,6],[7],[8,9]] + * <p> + * [] == [] + * </code> */ def indexGroups[a,b](xs: Seq[a])(f: a => b) = { val i = Iterator from 0 Stream fromIterator xs.elements groupBy f map (_ map (x => i.next)) } + /** + * Zip or unzip some lists (the zip width is dynamic, so no tuples). The + * length of the resulting list is the length of the shortest input list. + * <p> + * <code> + * zipx([[a,b,c,d,e],[f,g,h,i,j],[k,l,m,n]]) + * == [[a,f,k],[b,g,l],[c,h,m],[d,i,n]] + * <p> + * unzipx([[a,f,k],[b,g,l],[c,h,m],[d,i,n]]) + * == [[a,b,c,d],[f,g,h,i],[k,l,m,n]] + * </code> + */ def zipx[a](xss: Seq[Iterable[a]]): Stream[Seq[a]] = { val is = xss map (_.elements) def rec: Stream[Seq[a]] = @@ -415,7 +579,12 @@ else Stream.empty rec } - def unzipx[a](xss: Iterable[Seq[a]]) = { + + /** + * Zip or unzip some lists (the zip width is dynamic, so no tuples). The + * length of the resulting list is the length of the shortest input list. + */ + def zipx[a](xss: Iterable[Seq[a]]) = { val width = xss.elements.next.length val iters = for (i <- 0 until width) @@ -423,6 +592,62 @@ List(iters: _*) } + /** + * Concatenate iterators. + */ + def concat[a](iters: Seq[Iterator[a]]) = + iters reduceLeft ((x: Iterator[a], y: Iterator[a]) => x ++ y) + + /** + * Eliminate consecutive duplicates. + */ + def uniq[a](xs: Seq[a]) = groupPairwiseBy(xs)(_==_) map (_.head) + + /** + * A specialization of argmin that uses the identity function as the + * comparison key. + * <p> + * <code> + * argminId([b,a,c]) == (a,1) + * <p> + * argminId([]) == error + * </code> + */ + def argminId[a <: Ordered[a]](xs: Iterator[a]) = argmin(xs)(x => x) + def argmin[a, b <: Ordered[b]](xs: Iterator[a])(f: a => b) = { + val i = Iterator from 0 + val first = xs.next + ((first, f(first), i.next) /: xs) { (p:(a,b,Int),y:a) => + val fy = f(y) + val iy = i.next + if (p._2 < fy) p else (y,fy,iy) + } + } + + /** + * Sort-merge streams. Assumes that the stream are each sorted already. + */ + def merge[a, b <: Ordered[b]](streams: Seq[BufferedIterator[a]])(f: a => b): Stream[a] = { + def loop: Stream[a] = { + val nonempty = streams filter (_ hasNext) + if (nonempty isEmpty) { + Stream empty + } else { + val (miniter,minvalue,minindex) = argmin( nonempty )( x => f(x head) ) + val p = miniter.head + nonempty(minindex).next + Stream cons (p, loop) + } + } + loop + } + + /** + * Get the i-th element of a flatten list of lists. + * <p> + * <code>coord(7, [[a,b],[],[c,d,e],[f],[g,h,i],[j,k]]) == h</code> + * @deprecated Use instead: <code>xss.flatMap(x=>x)(0)</code>. + */ def coord[a](i: Int, xss: Iterable[Seq[a]]): (Int, Int) = { var x = i var y = 0 @@ -435,35 +660,47 @@ /** * Convenience constructor for converting an Iterator into an ArrayBuffer. + * @deprecated Use instead: <code>xs.toElements</code>. */ def newArrayBuffer[a](xs: Iterator[a]) = { val buf = new mut.ArrayBuffer[a] buf ++= xs buf } + + // + // Trees + // + /** - * Swap the elements of a tuple. + * A simple tree class where each node (Tree) is a Leaf or a Branch, and each + * Branch contains a list of other Trees. */ - def swap[a,b](p: (a,b)) = (p._2, p._1) - object Tree { + /** + * A simple tree class where each node (Tree) is a Leaf or a Branch, and each + * Branch contains a list of other Trees. + */ abstract class Tree[a] { /** * Show the tree as a string. + * <code> + * <p> + * Leaf("a") -><p> + * a<p> + * <p> + * Branch(List(Leaf("a"), Leaf("b"))) -><p> + * a<p> + * b<p> + * <p> + * Branch(List(Leaf("a"), Branch(List(Leaf("b"), Leaf("c"))), Leaf("d")))<p> + * -><p> + * a<p> + * b<p> + * c<p> + * d<p> + * </code> */ - // Leaf("a") -> - // a - // - // Branch(List(Leaf("a"), Leaf("b"))) -> - // a - // b - // - // Branch(List(Leaf("a"), Branch(List(Leaf("b"), Leaf("c"))), Leaf("d"))) - // -> - // a - // b - // c - // d def show(showLeaf: a => String): String = { def r(t: Tree[a]): Stream[String] = t match { case Branch(ts) => Stream concat (ts map r) map (" " + _) @@ -514,6 +751,10 @@ } } + /** + * A boolean expression tree contains nodes corresponding to And, Or, Not, + * and Leaf. And, Or contain any number of children. + */ abstract class BoolTree[a] { def sat(f: a => Boolean): Boolean = this match { case And(ts) => ts forall (_ sat f) @@ -533,8 +774,10 @@ case Not(t) => t flatten f case Leaf(x) => Stream cons (f(x), Stream empty) } - // TODO this looks a candidate for some nicer monadic-style sum - // f returns false if the leaf is to be pruned out, and true otherwise + // TODO: this looks a candidate for some nicer monadic-style sum. + /** + * f returns false if the leaf is to be pruned out, and true otherwise. + */ def prune[b](f: a => Option[b]): Option[BoolTree[b]] = this match { case And(ts) => { @@ -560,51 +803,9 @@ case class Not[a](t: BoolTree[a]) extends BoolTree[a] case class Leaf[a](x: a) extends BoolTree[a] - def uniq[a](xs: Seq[a]) = groupPairwiseBy(xs)(_==_) map (_.head) - - // [b,a,c] -> (a,1) - // [] -> error - def argminId[a <: Ordered[a]](xs: Iterator[a]) = argmin(xs)(x => x) - def argmin[a, b <: Ordered[b]](xs: Iterator[a])(f: a => b) = { - val i = Iterator from 0 - val first = xs.next - ((first, f(first), i.next) /: xs) { (p:(a,b,Int),y:a) => - val fy = f(y) - val iy = i.next - if (p._2 < fy) p else (y,fy,iy) - } - } -// def merge[a, b <: Ordered[b]](streams: Seq[Stream[a]])(f: a => b): Stream[a] = { -// val nonempty = streams filter (!_.isEmpty) -// if (nonempty isEmpty) { -// Stream empty -// } else { -// val (minvalue,minindex) = argmin( nonempty map f(_ head) ) -// val remaining = for ((s,i) <- nonempty zipWithIndex) -// yield if (i == minindex) s.tail else s -// Stream cons (minvalue, merge(remaining)) -// } -// } -// def mergeId[a <: Ordered[a]](streams: Seq[Stream[a]]): Stream[a] = -// merge(streams)(x => x) - def concat[a](iters: Seq[Iterator[a]]) = - iters reduceLeft ((x: Iterator[a], y: Iterator[a]) => x ++ y) - def merge[a, b <: Ordered[b]](streams: Seq[BufferedIterator[a]])(f: a => b): Stream[a] = { - def loop: Stream[a] = { - val nonempty = streams filter (_ hasNext) - if (nonempty isEmpty) { - Stream empty - } else { - val (miniter,minvalue,minindex) = argmin( nonempty )( x => f(x head) ) - val p = miniter.head - nonempty(minindex).next - Stream cons (p, loop) - } - } - loop - } - + // // Performance work-arounds. + // /** * The standard library Iterator.dropWhile is inefficient and non-scalable, @@ -633,51 +834,12 @@ dst } - def orderedMultimap[a,b](xs: List[(a,b)]) = { - val h = new mut.HashMap[a, mut.ArrayBuffer[b]] { - override def default(k: a) = { - this(k) = new mut.ArrayBuffer[b] - this(k) - } - } - for ((k,v) <- xs) h(k) += v - h - } - def iterator2array[a](xs: Iterator[a]) = xs.toList.toArray - - // TODO where does this go??? // - // [1,3,5,6,7,8] odd -> ([1,3,5],[6,7,8]) - // [] _ -> ([],[]) + // Misc // - def camelToLower(s: String, sep: String) = { - val xs = - for (c <- s) - yield if (c.isUpperCase) sep + c.toLowerCase else c - xs mkString "" - } - def camelToUnder(s: String) = camelToLower(s, "_") - def camelToHyphen(s: String) = camelToLower(s, "-") - def camelToSpaced(s: String) = camelToLower(s, " ") - - def spacedToHyphen(s: String) = s replaceAll (" ", "-") - - // TODO: this isn't really rot encoding - def rot(n: Int, s: String) = s map (_ + n toChar) mkString - - def untilNull[a](f: => a) = new Iterator[a] { - var upcoming = f - override def hasNext = upcoming != null - override def next = { - val emit = upcoming - upcoming = f - emit - } - } - /** - * Returns the positive (unsigned int) modulo. + * Return the positive (unsigned int) modulo. */ def mod(n: Int, m: Int) = { val r = n % m @@ -685,23 +847,8 @@ } /** - * Returns pairs of elements. - * <p> - * <code> - * pairs([a,b,c,d]) == [(a,b),(c,d)] - * pairs([a,b,c,d,e]) == [(a,b),(c,d)] - * </code> + * Return a map that assigns unique IDs to distinct objects. */ - def pairs[a](xs: Seq[a]): Stream[(a,a)] = { - xs match { - case Seq() => Stream empty - case Seq(a, b, rest @ _*) => Stream cons ((a,b), pairs(rest)) - } - } - - /** - * Maps unique IDs to distinct objects. - */ class IdMapper[a] extends mut.HashMap[a,Int] { val i = Iterator from 0 override def default(k: a) = { @@ -721,56 +868,4 @@ (i >>> 16) & 0xff, (i >>> 24) & 0xff ).map(_.toChar).mkString - - /** - * For each x in xs, if p(x), then x is a header, and it owns all the xs - * after it until the next x for which p(x) holds. The return value is the - * header and its body. - * <p> - * <code> - * groupByHeaders([1,2,3,4,5,6,7,8,9])(_%3==0) == [[3,4,5],[6,7,8],[9]] - * </code> - */ - def groupByHeaders[a](xs: Seq[a])(p: a => Boolean) = { - val ys = new mut.ArrayBuffer[mut.ArrayBuffer[a]] - for (x <- xs) { - if (p(x)) ys += new mut.ArrayBuffer[a] - if (!ys.isEmpty) ys.last += x - } - ys - } -// def groupByHeaders[a](xs: Seq[a])(p: a => Boolean) = { -// def r(seq: Seq[a]): Stream[List[a]] = seq match { -// case Seq() => Stream.empty -// case Seq(y,ys@_*) => { -// val (as,bs) = spanBy(ys)(not(p)) -// Stream.cons(y :: as.toList, r(bs)) -// } -// } -// r(xs dropWhile (not(p))) -// } - - /** - * <code> - * separateHeads([[a,b,c],[d,e,f,g],[],[h]]) - * == [(a,[b,c]),(d,[e,f,g]),(h,[])] - * </code> - */ - def separateHeads[a](xss: Seq[Seq[a]]) = - for (xs <- xss; (Seq(a),b) = span(1)(xs)) yield (a,b) - - - /** - * Construct a multimap out of the given key-value pairs; the result maps - * keys to sets of values. - */ - def multimap[a,b](xs: Iterable[(a,b)]) = { - val h = new mut.HashMap[a,mut.Set[b]] with mut.MultiMap[a,b] { - override def makeSet = new mut.HashSet[b] - } - for ((k,v) <- xs) { - h add (k,v) - } - h - } } Modified: scala-commons/trunk/src/commons/Control.scala =================================================================== --- scala-commons/trunk/src/commons/Control.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Control.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -4,29 +4,57 @@ import Misc._ object Control { - /* - trait Disposeable { - def dispose: Unit; - } - def using[a <% Disposeable, b](x: a)(f: a => b) = - try { f(x) } - finally { x.dispose; } - */ + + /** + * Close streams. + */ def using[a <% Closeable, b](x: a)(f: a => b) = try { f(x) } finally { x.close } + + /** + * Time some code. + */ def time(f: =>Any): Long = { val start = System.currentTimeMillis f val stop = System.currentTimeMillis stop - start } + + /** + * Return Some(f) if the function succeeded, or None if there was an + * Exception. + */ def optionize[a](f: => a) = try { Some(f) } catch { case _ => None } + + /** + * Return true if the function succeeded, or false if there was an Exception. + */ def success(f: => Any) = try { f; true } catch { case _ => false } + + /** + * Invoke f forever. + */ def loop[a](f: => a) { loop(const(f)) } + + /** + * Invoke f(i) for all i from 0 on. + */ def loop[a](f: Int => a) = for (val x <- Stream from 0) f(x) + + /** + * Stream the repetition of f. + * + * @deprecated Use {@link commons.Collections.repeat} instead. + */ def lazyLoop[a](f: => a): Stream[a] = lazyLoop(const(f)) + + /** + * Stream f(i) for all i from 0 on. + */ def lazyLoop[a](f: Int => a): Stream[a] = Stream from 0 map f + } Modified: scala-commons/trunk/src/commons/Debug.scala =================================================================== --- scala-commons/trunk/src/commons/Debug.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Debug.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -5,7 +5,8 @@ import Misc._ import Io._ -// TODO use jakarta commons logging and/or log4j +// TODO Use jakarta commons logging and/or log4j. +// TODO Redo this whole forsaken thing. /* object Logger { @@ -26,10 +27,15 @@ */ object Debug { + + /** + * Output a labeled value, and return the value. Similar to Haskell's trace. + */ def trace[a](label: String, x: a) = { println(label + x) x } + val logFile = TextWriter("log") type Level = Int object Levels { @@ -126,6 +132,5 @@ // extends LogRoot(label + "." + label2, indent + 3) // } // class Log(label: String) extends LogRoot(label, 0) + } - -import Debug._ Added: scala-commons/trunk/src/commons/English.scala =================================================================== --- scala-commons/trunk/src/commons/English.scala (rev 0) +++ scala-commons/trunk/src/commons/English.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -0,0 +1,64 @@ +package commons + +import Collections._ +import Misc._ +import java.util.regex.Pattern + +object English { + val consonants = "bcdfghjklmnpqrstvwxz" + val singularizePattern = Pattern.compile("[%s]ies" % consonants) + implicit def str2english(s: String): EnglishText = EnglishText(s) + implicit def english2str(s: EnglishText): String = s.s + case class EnglishText(val s: String) { + /** + * Return the singular of s (if it's plural). + */ + def singularize = { + val lowered = s.toLowerCase + if (Array("ches", "shes", "sses") exists (lowered endsWith _)) { + s truncate 2 + } else if (singularizePattern matcher lowered find) { + (s truncate 3) + "y" + } else if (lowered endsWith "s") { + s truncate 1 + } else { + s + } + } + } + + /** + * Return true if and only if the target contains the query phrase, using + * search engine phrase search semantics. + */ + def phraseSearch(query: String, target: String) = { + val qs = tokenize(query) toArray; + val ts = tokenize(target) toArray; + // TODO this should really take an equalsWith (but I don't like the extra f) + slices(ts, qs.length) exists { slice => seqsEqual(slice,qs) } + } + + /** + * Shallow comparison of two sequences. + */ + def seqsEqual[a](xs: Seq[a], ys: Seq[a]) = + xs.length == ys.length && ( (xs zip ys) forall { case (x,y) => x == y }) + + /** + * The delimiters for the tokenizer. + */ + val delims = " \r\n\t,./;[]\\<>?:\"{}|`~!@#$%^&*()-=+'" + + /** + * Tokenize things, with special dropping of apostrophes/single-quotes. + */ + def tokenize( s: String ) = { + import java.util.StringTokenizer + val t = new StringTokenizer( s, delims, false ) + def recur: Stream[String] = + if ( ! t.hasMoreElements ) Stream.empty + else Stream.cons( t.nextToken, recur ) + recur + } + +} Deleted: scala-commons/trunk/src/commons/ExtractorObject.scala =================================================================== --- scala-commons/trunk/src/commons/ExtractorObject.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/ExtractorObject.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -1,67 +0,0 @@ -package commons - -/** - * From http://users.utu.fi/hvkhut/scalad/extractorobject.htm. - * Copyright Henrik Huttunen. - */ - -object ExtractorObject{ - // from http://users.utu.fi/hvkhut/scalad/extractorobject.htm - implicit def seqCharToString(seq: scala.Seq[Char]): String - = seq.foldLeft("")((b, a) => b + a) - private def rotateRight(char: Char, amount: Int) - = (char.toInt + amount).toChar - private def rotateLeft(char: Char, amount: Int) - = (char.toInt - amount).toChar - private def rotate(x: String, amount: Int, - rotateChar: (Char, Int) => Char): String - = x.map(char => rotateChar(char, amount)) - class FixedString(string: String) { - import collection.mutable.ArrayBuffer - def dropFixed(n: Int): Seq[Char] - = new ArrayBuffer[Char] ++ string.elements.drop(n) - } - implicit def string2FixedString(x: String): FixedString - = new FixedString(x) - object BinaryNumberWord{ - val Zero = "zero" - val One = "one" - def apply(x: Int) = x match { - case 0 => Zero - case 1 => One - case _ => error("Not legal number: " + x) - } - def unapply(x: String) = x match { - case Zero => Some(0) - case One => Some(1) - case _ => None - } - } - object EncodedString{ - private val times = 13 - private val header = "[rot]" - def apply(x: String) = header + rotate(x, times, rotateRight) - def unapply(x: String) = { - val front: String = x.take(header.length) - //val front = x.take(header.length) - if(front == header){ - val dropped = x.dropFixed(header.length) - Some(rotate(dropped, times, rotateLeft)) - } - else None - } - } - def test(x: String) = x match { - case EncodedString(decoded) => x + " is as decoded: " + decoded - case BinaryNumberWord(number) => x + " is as word: " + number - case _ => x + " is unknown" - } - def example = { - import Console.println - println(test(EncodedString("classified information"))) - println(test(BinaryNumberWord(0))) - println(test(BinaryNumberWord(1))) - } -} - -import ExtractorObject._ Modified: scala-commons/trunk/src/commons/Hash.scala =================================================================== --- scala-commons/trunk/src/commons/Hash.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Hash.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -1,5 +1,8 @@ package commons +/** + * Various hash functions. + */ object Hash { /** Modified: scala-commons/trunk/src/commons/Io.scala =================================================================== --- scala-commons/trunk/src/commons/Io.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Io.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -11,17 +11,33 @@ // TODO see also: Source // Source.fromInputStream(System.in).getLines.foreach { line => etc... } -// TODO fix the followin +object Io { -object Io { + // + // Views + // + implicit def InputStream2BinaryReader(is: InputStream) = BinaryReader(is) implicit def BinaryReader2InputStream(br: BinaryReader) = br.in implicit def Reader2TextReader(r: Reader) = TextReader(r) implicit def TextReader2Reader(tr: TextReader) = tr.in - //implicit def os2xos[os <: OutputStream](os: os) = new XOutputStream(os) - //implicit def xos2os[os <: OutputStream](xos: XOutputStream) = xos.stream + + // + // Files + // + + /** + * @deprecated + */ def fileExists(fname: String) = new File(fname).exists + // + // IO streams + // + + /** + * A reader for streams of binary data. + */ class BinaryReader(val in: InputStream) extends AnyRef with Closeable { def read = { val chunks = new ArrayBuffer[Array[Byte]]() @@ -36,11 +52,17 @@ def close = in.close } + /** + * Constructors. + */ object BinaryReader { def apply(in: InputStream) = new BinaryReader(in) def apply(fname: String) = new BinaryReader(new FileInputStream(fname)) } + /** + * A reader for text streams. + */ class TextReader(val in: BufferedReader) extends AnyRef with Closeable { def readLine = in.readLine def readLines: Stream[String] = { @@ -52,6 +74,9 @@ def close = in.close } + /** + * Constructors. + */ object TextReader { def apply(is: InputStream): TextReader = apply(new InputStreamReader(is)) @@ -61,15 +86,24 @@ apply(new FileReader(fname)) } + /** + * A writer for streams of binary data. + */ class BinaryWriter(out: OutputStream) extends Closeable { def write(x: Array[Byte]) = out.write(x) def close = out.close } + /** + * Constructors. + */ object BinaryWriter { def apply(fname: String) = new BinaryWriter(new FileOutputStream(fname)) } + /** + * Constructors. + */ object TextWriter { def apply(fname: String) = new PrintWriter(new FileOutputStream(fname), true) @@ -77,16 +111,35 @@ new PrintWriter(out) } + // + // Serialization + // + + /** + * Read a Java serialization object from a file. + */ def readObject(fname: String) = { val bytes = using (BinaryReader(fname)) (_ read) using (new ObjectInputStream(new ByteArrayInputStream(bytes))) (_ readObject) } + + /** + * Write an object to a file using Java serialization. + */ def writeObject(fname: String, x: AnyRef) { val bytes = new ByteArrayOutputStream using (new ObjectOutputStream(bytes)) (_ writeObject x) using (BinaryWriter(fname)) (_ write bytes.toByteArray) } + // + // Processes + // + + /** + * Run a command, providing the given input to stdin. On success, return + * stdout; on error, print stderr to stderr and raise an exception. + */ def run(cmd: String, input: String) = { val proc = Runtime.getRuntime.exec(cmd) using (TextWriter(proc.getOutputStream)) (_ println input) @@ -101,4 +154,3 @@ } } -import Io._ Modified: scala-commons/trunk/src/commons/Misc.scala =================================================================== --- scala-commons/trunk/src/commons/Misc.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Misc.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -1,10 +1,12 @@ package commons -import java.util.regex.Pattern - import Collections._ object Misc { + + /** + * @deprecated Use {@link Iterator.from} instead. + */ @serializable class Uniq(var x: Int) { def next = { @@ -12,112 +14,84 @@ x - 1 } } + + // TODO: Better name? + /** + * Funnel a value into the range [0,max]. + */ def bounds(max: Int, x: Int): Int = bounds(0, max, x) + + /** + * Funnel a value into the range [min,max]. + */ def bounds(min: Int, max: Int, x: Int) = Math.max(min, Math.min(max-1, x)) - def wrapMod(x: Int, mod: Int) = if (x < 0) mod + x % mod else x % mod + + // TODO: Better name? + /** + * Return the positive modulus x mod m. + */ + def wrapMod(x: Int, m: Int) = if (x < 0) m + x % m else x % m + def succ(x: Int) = x + 1 def pred(x: Int) = x - 1 def const[a](f: => a): Any => a = ((x: Any) => f) + + // TODO: move this to the same place as optionize and success in Control. + /** + * Return the result of f on success or null if there was an exception. + */ def nullifyExceptions[a >: Null](f: => a): a = try { f } catch { case e => null } + + /** + * "Simplify" a String by trimming and lower-casing it. + */ def simplify(s: String) = s.trim.toLowerCase + + /** + * Rich string view. + */ case class XString(val s: String) { + /** + * Case-insensitive comparator. + */ def ===(that: String) = s equalsIgnoreCase that + /** + * Case-insensitive comparator. + */ def !==(that: String) = !(===(that)) + /** + * Repeat the string n times. + */ def *(n: Int) = repeat(s) take n mkString ("", "", "") + /** + * Truncate a string to be of length n. + */ def truncate(n: Int) = s substring (0, s.length - n) + /** + * String interpolator. + */ def %[A](s: A*): String = format(s.map(_.asInstanceOf[AnyRef]).toArray) + /** + * String interpolator. + */ def format(a: Array[AnyRef]) = String.format(s, a) } implicit def str2xstr(s: String): XString = XString(s) implicit def xstr2str(s: XString): String = s.s + + /** + * Identity function. + */ def id[a](x: a) = x - // aka symbol generator + /** + * Generate Strings that are the given base string with a unique integer + * appended. + */ class HandleGenerator(base: String) extends Iterator[String] { val i = Iterator from 0 override def next = base + i.next override def hasNext = i.hasNext } -// class OrderedPair[a <: Ordered[a], b](x:a,y:b) extends GPair[a,b](x,y) with Ordered[OrderedPair[a,b]] { -// override def compare(o: OrderedPair[a,b]) = x compare o._1 -// } -// class OrderedPair[a <: Ordered[a], b](val x:a,val y:b) extends Ordered[Tuple2[a,b]] { -// override def compare(o: Tuple2[a,b]) = x compare o._1 -// } } - -import Misc._ - -object English { - val consonants = "bcdfghjklmnpqrstvwxz" - val singularizePattern = Pattern.compile("[%s]ies" % consonants) - implicit def str2english(s: String): EnglishText = EnglishText(s) - implicit def english2str(s: EnglishText): String = s.s - case class EnglishText(val s: String) { - // Returns the singular of s - def singularize = { - val lowered = s.toLowerCase - if (Array("ches", "shes", "sses") exists (lowered endsWith _)) { - s truncate 2 - } else if (singularizePattern matcher lowered find) { - (s truncate 3) + "y" - } else if (lowered endsWith "s") { - s truncate 1 - } else { - s - } -// if lowered in plurals: -// def matchCase(s1, s2): -// """Matches the case of s1 in s2""" -// if s1.isupper(): -// return s2.upper() -// else: -// L = list(s2) -// for (i, char) in enumerate(s1[:len(s2)]): -// if char.isupper(): -// L[i] = L[i].upper() -// return ''.join(L) -// return matchCase(s, plurals[lowered]) -// elif any(lowered.endswith, ['ches', 'shes', 'sses']): -// return s[:-2] -// elif re.search(depluralizeRegex, lowered): -// return s[:-3] + 'y' -// else: -// if lowered.endswith('s'): -// return s[:-1] # Chop off 's'. -// else: -// return s # Don't know what to do. - } - } - // similar to a search engine's phrase search semantics - // returns true iff we can the target contains the query phrase - // XXX 2.6.0 required -// def phraseSearch(query: String, target: String) = { -// val qs = List(tokenize(query):_*); -// val ts = List(tokenize(target):_*); -// // TODO this should really be an equalsWith (but I don't like the extra f) -// slices(ts, qs.length) exists (_ startsWith qs) -// } - def seqsEqual[a](xs: Seq[a], ys: Seq[a]) = - xs.length == ys.length && ( (xs zip ys) forall { case (x,y) => x == y }) - def phraseSearch(query: String, target: String) = { - val qs = tokenize(query) toArray; - val ts = tokenize(target) toArray; - // TODO this should really be an equalsWith (but I don't like the extra f) - slices(ts, qs.length) exists { slice => seqsEqual(slice,qs) } - } - // the delimiters for the tokenizer - val delims = " \r\n\t,./;[]\\<>?:\"{}|`~!@#$%^&*()-=+'" - // tokenize things, with special dropping of apostrophes/single-quotes - def tokenize( s: String ) = { - import java.util.StringTokenizer - val t = new StringTokenizer( s, delims, false ) - def recur: Stream[String] = - if ( ! t.hasMoreElements ) Stream.empty - else Stream.cons( t.nextToken, recur ) - recur - } -} - -import English._ Modified: scala-commons/trunk/src/commons/Path.scala =================================================================== --- scala-commons/trunk/src/commons/Path.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Path.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -1,14 +1,23 @@ package commons + import java.io.File + object Path { implicit def StringToPathString(s: String) = PathString(s) implicit def PathStringToString(p: PathString) = p.path val sep = File.separatorChar case class PathString(path: String) { + /** + * Join two paths without adding redundant path separators. + */ def /(relpath: String) = if (path.last == sep) path + relpath else path + sep + relpath } + + /** + * Return path if it's already an absolute path, and dir/path otherwise. + */ def rel2abs(dir: String, path: String) = if (path startsWith "/") path else dir / path } Modified: scala-commons/trunk/src/commons/Repl.scala =================================================================== --- scala-commons/trunk/src/commons/Repl.scala 2008-02-22 19:25:34 UTC (rev 477) +++ scala-commons/trunk/src/commons/Repl.scala 2008-02-22 23:44:36 UTC (rev 478) @@ -1,5 +1,8 @@ package commons +/** + * Things that may be helpful in a Scala REPL. + */ object Repl { case class Introspecter[a<:AnyRef](x:a) { def ? = m ++ f // p(x.getClass.getMethods.toList) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |