juan_gandhi: (VP)
  def dropConstraint(table: String, constraint: String): Unit =
    update(s"alter table $table drop constraint if exists $constraint")

  def dropAllFkeys(): Unit = {
    val found =
      select("constraint_name, table_name from information_schema.table_constraints where constraint_schema='public' and constraint_type = 'FOREIGN KEY'") strings
    for ((k::t::_) <- found) dropConstraint(t, k)
juan_gandhi: (VP)
Now two versions:

1. With tail recursion, via [livejournal.com profile] lomeo
  def groupByRelationship[T](xs: List[T])(p: (T,T) => Boolean) = {
    def go(xs: List[T], accum: List[List[T]]): List[List[T]] = (xs, accum) match {
      case (Nil, _) => accum.reverse map (_.reverse)
      case (x::xs, Nil) => go(xs, List(List(x)))
      case (x::xs, ((ys@(y::_))::rest)) => go(xs, if (p(y, x)) (x::ys)::rest else
    go(xs, Nil)

2. With fold (corrected thrice)
  def groupByRelationship[T](p: (T,T) => Boolean)(xs: List[T]) = {
    val (seg,acc) = ((List[T](),List[List[T]]()) /: xs) {
      case ((y::ys, a), x) if p(y,x) => (x ::y ::ys, a)
      case (   (ys, a), x)           => (x::Nil, ys.reverse::a)
    (seg.reverse::acc).reverse drop 1

More critique?
juan_gandhi: (VP)
  def groupByRelationship[T](p: ((T,T) => Boolean)) = {
    new (List[T] => List[List[T]]) { group =>

      def apply(xs: List[T]): List[List[T]] =
        xs match {
          case Nil => Nil
          case x::Nil => (x::Nil)::Nil
          case x::y::tail if x == y || p(x,y) =>
            val (h::t) = group(y::tail)
          case x::ys => (x::Nil)::group(ys)

or, alternatively,
  def groupByRelationship[T](p: ((T,T) => Boolean)) = {
    new (List[T] => List[List[T]]) { group =>

      def apply(xs: List[T]): List[List[T]] =
        xs match {
          case Nil    => Nil
          case x::Nil => (x::Nil)::Nil
          case x::ys  =>
            val tail = group(ys)
            if (x == ys.head || p(x, ys.head)) (x::tail.head)::tail.tail
            else                               (x::Nil)::tail

Like in Haskell.
Thanks [livejournal.com profile] lomeo, [livejournal.com profile] huzhepidarasa, [livejournal.com profile] cousin_it, [livejournal.com profile] sassa_nf for their critique.
juan_gandhi: (VP)
       Good("huilo") filter ((s:String) => s.startsWith("he"), "oi vei") must_== Result.error("oi vei")
juan_gandhi: (VP)
  override def getEOBs: Outcome = {
    import JavaScript._
    val outcome =
    for (_ ← clickElementHavingText("a", "My Stuff") onError suspiciousError;
         _ ← waitSelector("input#continue");
         _ ← clickElementHavingText("input[name=dateRangeSelection]", "past year");
         _ ← findElement("input[name=selectedMembers]");
         _ ← js(s"$foundElement.checked = true");
         _ ← clickElementHavingText("input#continue", "");
         _ ← clickElementHavingText("a", "INTERNET.com");
         _ ← findElementContainingText("*", "Processed");
         _ ← clickElementHavingText("a", "More");
         _ ← clickElementHavingText("input", "View All");
         (contents, source) <- pageContents.toResultKeepingSource) yield {
    debug(s"Got $outcome"); OK

What happens here: we do these operations, monadically, since each one depends on the success of the previous one; errors are stored in negative result. If everything went well, I grab page contents and convert it to Result[Props], so the props contain all the information I managed to extract from the page.

On failure the error is logged; what can we do, it requires human interference.

All this amounts to flatMap on my Result class.
Yes, it does remind checked exception handling, but well, we are not in denial here; and we could do applicative join if needed.
juan_gandhi: (VP)
val List(_, median, _) = List(a,b,c).sorted

(c) Naftoli Gugenheim
juan_gandhi: (VP)

// I dedicate all this code, all my work,
// to my wife, Darlene, who will
// have to support me and our three
// children and the dog once it gets
// released into the public.

// Magic. Do not touch.

// this comment included for the benefit of
// anyone grepping for swearwords: shit.

// I am not responsible of this code.
// They made me write it, against my will.

// no comments for you
// it was hard to write
// so it should be hard to read

/* Be a real daemon: fork myself and kill my parent */

// I don't understand how the following bit works,
// but it worked in the program I stole it from.

// Dear maintainer:
// Once you are done trying to 'optimize' this routine,
// and have realized what a terrible mistake that was,
// please increment the following counter as a warning
// to the next guy:
// total_hours_wasted_here = 42

code sample

May. 4th, 2014 05:55 pm
juan_gandhi: (VP)
I have to log in to a server, send a file, then log out.
What do people do in this case? Log in, check the result, keep the session id, use it to send a file, use the session id to log out in a finally block. I mean, that's what I did all my life.
Tired of it.

So I want to log in, create a session, then, inside the session, do my operation, and then "automatically" close it. So I log in, and then call "execute". But wait, what if I don't call it? The resource will hang around.

So what I did, I inverse it. I say client execute {operation} inSession(username, password). That's how it should be.
client.execute { 
  session => {
    val response = session.send(fileInfo)
    info(s"Attachment - $fileInfo sent: $response")
} inSession(username, password)

How does it work? Pretty easy:

  def execute[T](op:ApiSession => Result[T]) = new {
    def inSession(name:String, password:String): Result[T] = {
      login(name, password) flatMap { s =>
        try op(s) finally s.close

case class ApiSession(private val id: String, private val client: APIclient) {
  def close() = client.get(s"logout?session=$id")
  def send(fileInfo: FileInfo) = fileInfo.send(client)(id)

Client here is an http client that does all this multipart paraphernalia.
What I wanted to say is: the order of parameters is meaningful, is not it?
And pretty neat, too.
juan_gandhi: (VP)
... is passing parameters via "common variables", imitating "environment", which they are on most occasions not.

This is unavoidable if you have functions 100 lines long; you have those variables keeping this and that... then you split the code, but you have to keep those "shared variables", so there.

They are just parameters, you know. If you think of them this way, your architecture becomes clean and clear.
juan_gandhi: (VP)
Just wrote a prototype for the tests I'm going to write
class EobHandling_Test extends Specification with MoreExpectations {
  val handler = new EobHandling with MockDB {
    override def pat_ins: Patient_ins = new MockPatientIns(42, Some(2))

  "existsInDB" should {
    "say 'no' if eob id is missing" in {
    "say 'no' if eob is not in db" in {
    "say 'yes' if one such eob is in db" in {
    "say 'yes' if more than one such eob is in db" in {
juan_gandhi: (VP)
It's recursive. An array inside a map inside a map, etc. You need a context-free grammar to parse it.
But this can be fixed. See how.

1. You can convert array into a map, right? s"[[$i]]" -> arrayValue(i)

So, generally speaking, can have just maps.

2. If we ban (or escape) dots ('.') inside keys, we can "flatten" the map of maps of maps, just by merging keys.

{"a" -> {
  "key1" -> {
    "[[0]]" -> "value at a.key1[0]"

will be
{"a.key1.[[0]]" -> "value at a.key1[0]"

3. We ban or escape quotes in keys, and html-escape quotes in values, s/"\""/"&quot;"/g, we can get rid of quotes in keys and have only delimiting quotes in values.

What does it give us? We get Regular Language. That easy.

What's the point of having a regular language? Tons of them.

- You can keep it in SQL and match using regular SQL statements.
- You can check or extract data in shell scripts.
- You can parse it efficiently in your code, no need for parsers/combinators.

P.S. And fuck Crockford, he's an ignorant asshole anyway.
juan_gandhi: (VP)

type NoResult = Result[Nothing]

case object Empty extends NoResult with NoGood[Nothing] {

As a side-effect, have to use this famous type, (_:_)

.onError((_:_) => savePage())
juan_gandhi: (VP)

  def using[T](file:File)(f: FileInputStream => T): Try[T] = Try {
    val in = new FileInputStream(file)
    (Try(f(in)), Try(in.close))._1

  def startsWith(prefix: Array[Byte])(file: File):Boolean =
    using (file) (in => prefix forall (in.read ==)) filter identity isSuccess

What happens here. I want to check if a file starts with these bytes (usually, "%PDF".getBytes).

I have function using that takes a file, then takes a function that converts a stream into something, opens the file, feeds the stream to the function, then always closes the file, returning a failure something went wrong.

In startsWith I get a prefix and a file; on this file I call the function that reads the stream and compares its bytes with the bytes of prefix; the result will be Try[Boolean]; I filter it, so that Success(false) will turn into Failure; then I check if it's still a success.

Obvious and funny; and yes, we use Java io library here, unfortunately.
juan_gandhi: (VP)

type Outcome = Result[Any]

val OK:Outcome = Good("OK")

Turned out, have tons of it everywhere. Weird actually.

And no, I'm not saying it's good. I'm just seeing a pattern that worries me a little bit, but I don't know why.

  def executeJS(js: String): Result[Unit] = runJS(js) map asScala filter
    ("OK"==, wrong => s"Wrong response from browser: <<$wrong>>")
juan_gandhi: (VP)
presentation: http://2013.flatmap.no/blakstad.html
unfiltered library: https://github.com/unfiltered/unfiltered/blob/master/directives/README.markdown

So, the idea is, have all this http run monadic; that includes checking conditions and throwing back all those 404s, 451, 500...
juan_gandhi: (VP)

In short, these two Norwegians found a readable and monadic way to write http stuff.
Check out how they convert booleans to rich booleans with explanations what went wrong, and use them in monadic context.


juan_gandhi: (Default)

October 2017

1 2 3 45 6 7
8 910 11 12 13 14
15 16 17 18192021


RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Oct. 18th, 2017 08:31 pm
Powered by Dreamwidth Studios