Barb


Introducing Barb

The first thing you need to know about Barb is how to generate a function. This is done by calling the buildExpr function with the types you expect as well as your expected result.

1: 
2: 
3: 
4: 
5: 
6: 
#r "Barb.dll"
open Barb.Compiler

let func = buildExpr<unit, string>("'Hello World'")
let result = func ()
printfn "%s" result // "Hello World"

Barb was originally designed for queries on DOM-like data trees. Let's start with a simple example.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
open System

type MyRecord = 
    {
        Name: string
        Countries: string []
    }

let testRecords = 
    [ { Name = "Rick Minerich";      Countries = [|"US"; "MX"|] }
      { Name = "Isabella Mapletree"; Countries = [|"CA"; "GR"|] } 
      { Name = "Jose Luis";          Countries = [|"MX"; "CA"|] } ]

You can easily query this simple record for various information. To do this efficiently first generate the function and then call it as you'd like over each record. Members of the input type are automatically put into scope as variables to make this easy.

1: 
2: 
3: 
let rickFun = buildExpr<MyRecord, bool> "Name.ToUpper().Contains('RICK')"

testRecords |> List.filter rickFun

This is where set operators come into play, as they allow you to do simple contains/overlap queries easily. In this example we're using the has-intersection operator.

1: 
2: 
3: 
let countryFun = buildExpr<MyRecord, bool> "Countries /?\ [|'CA'; 'GR'|]"

testRecords |> List.filter countryFun

Sometimes you may want to map a method call over a collection of items. This can be done with the .. syntax (one dot per level of collection).

1: 
2: 
3: 
let dotFun = buildExpr<MyRecord, bool> "Countries..ToLower() /?\ 'us'"

testRecords |> List.filter dotFun

When a Barb fails it tries its best gives you the offset where something went wrong. Here we're going to access a variable that doesn't exist. This makes it easy to report what went wrong to the user, even when they have a long function string.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
open Barb.Representation

let failFunStr = "Cntry /?\ 'Hello'"
try 
    let failFun = buildExpr<MyRecord, bool> failFunStr
    testRecords |> List.map failFun |> ignore
with | :? BarbException as ex -> 
    let failedPart = failFunStr.Substring(int ex.Offset, int ex.Length)
    printfn "Failed on: '%s' with '%s'" failedPart ex.Message
namespace Barb
module Compiler

from Barb
val func : (unit -> string)

Full name: Tutorial.func
val buildExpr : predicate:string -> ('I -> 'O)

Full name: Barb.Compiler.buildExpr
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
val result : string

Full name: Tutorial.result
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
namespace System
type MyRecord =
  {Name: string;
   Countries: string [];}

Full name: Tutorial.MyRecord
MyRecord.Name: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
MyRecord.Countries: string []
val testRecords : MyRecord list

Full name: Tutorial.testRecords
val rickFun : (MyRecord -> bool)

Full name: Tutorial.rickFun
type bool = Boolean

Full name: Microsoft.FSharp.Core.bool
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member GetSlice : startIndex:int option * endIndex:int option -> 'T list
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val countryFun : (MyRecord -> bool)

Full name: Tutorial.countryFun
val dotFun : (MyRecord -> bool)

Full name: Tutorial.dotFun
module Representation

from Barb
val failFunStr : string

Full name: Tutorial.failFunStr
val failFun : (MyRecord -> bool)
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
Multiple items
type BarbException =
  inherit Exception
  new : message:string * offset:uint32 * length:uint32 -> BarbException
  member Length : uint32
  member Offset : uint32

Full name: Barb.Representation.BarbException

--------------------
new : message:string * offset:uint32 * length:uint32 -> BarbException
val ex : BarbException
val failedPart : string
String.Substring(startIndex: int) : string
String.Substring(startIndex: int, length: int) : string
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
property BarbException.Offset: uint32
property BarbException.Length: uint32
property Exception.Message: string
Fork me on GitHub