9 people like it.
    Like the snippet!
  
  Count noise-lines in C# code
  This is the code I used to generate this pie chart:
http://pic.twitter.com/PgPEFByg56
Enough said?
  |  1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
 | open System
open System.IO
open System.Text.RegularExpressions
open MSDN.FSharp.Charting
open System.Windows.Forms
(SafeEnumerateFiles hidden for clarity)
/// Return all the lines in files matching the given wildcard starting at the given path.
let FileLines path wildcard =
    SafeEnumerateFiles path wildcard
    |> Seq.map (fun fileName -> File.ReadAllLines(fileName))
    |> Seq.concat
    
/// Break down the sequence giving counts of lines matching each regex pattern.
let CountByPattern patterns lines =
    seq { for pattern in patterns do
              yield lines
                    |> Seq.filter (fun line -> Regex.IsMatch(line, pattern))
                    |> Seq.length
    }
/// Break down the given lines into counts by pattern, associating each count with a label.
let Analyze patternsLabels lines =
    let patterns, labels =
        patternsLabels |> Array.map fst,
        patternsLabels |> Array.map snd
    lines
    |> CountByPattern patterns
    |> Seq.zip labels
// Example:
// > AnalyzeCSharp @"D:\MyCode";;
// val it : (string * int) [] =
//   [|("{ or }", 25128); ("Blank", 18261); ("Null checks", 877);
//     ("Comments", 27103); ("Useful lines", 61343)|]
// > 
/// Analyze C# files starting at the given path, showing various forms of noise.
let AnalyzeCSharp path = 
    let lines = FileLines path "*.cs" |> Seq.cache
    let patternCounts = 
        lines
        |> Analyze [|
                       "(^([ \t]*)([{}])([ \t]*)$)",  "{ or }"
                       "(^[ \t]*$)",                  "Blank"
                       "(\=[ \t]*null)",              "Null checks"
                       "(^[ \t]*//)",                 "Comments"
                   |]
    let otherCount =  ["Useful lines", (lines |> Seq.length) - (patternCounts |> Seq.sumBy snd)]
    Seq.append patternCounts otherCount
    |> Array.ofSeq
/// Show an FSharp chart in a Windows form.
let Show chart =
    let form = new Form(Visible=true, TopMost=true, Width=700, Height=700)
    let ctl = new ChartControl(chart, Dock=DockStyle.Fill)
    form.Controls.Add(ctl)
/// Show an array of strings and ints as a labelled pie chart.
let ToPie name (results : array<string*int>) =
    FSharpChart.Pie(results, Name = name)
    |> Show
 | 
namespace System
namespace System.IO
namespace System.Text
namespace System.Text.RegularExpressions
namespace Microsoft.FSharp
namespace System.Windows
namespace System.Windows.Forms
/// Enumerate files starting at a given path, having a given wildcard.
/// (Inaccessible directories are ignored.)
let SafeEnumerateFiles (path : string) (wildcard: string) =
    let safeEnumerate f path =
        try
            f(path)
        with
            | :? System.UnauthorizedAccessException -> Seq.empty
    let enumerateDirs = 
        safeEnumerate Directory.EnumerateDirectories
    let enumerateFiles =
        safeEnumerate (fun path -> Directory.EnumerateFiles(path, wildcard))
    let rec enumerate baseDir =
        seq {
            yield! enumerateFiles baseDir
        
            for dir in enumerateDirs baseDir do
                yield! enumerate dir
        }
    enumerate path
val FileLines : path:string -> wildcard:string -> seq<string>
Full name: Script.FileLines
 Return all the lines in files matching the given wildcard starting at the given path.
val path : string
val wildcard : string
val SafeEnumerateFiles : path:string -> wildcard:string -> seq<string>
Full name: Script.SafeEnumerateFiles
 Enumerate files starting at a given path, having a given wildcard.
 (Inaccessible directories are ignored.)
module Seq
from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
Full name: Microsoft.FSharp.Collections.Seq.map
val fileName : string
type File =
  static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
  static member AppendAllText : path:string * contents:string -> unit + 1 overload
  static member AppendText : path:string -> StreamWriter
  static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
  static member Create : path:string -> FileStream + 3 overloads
  static member CreateText : path:string -> StreamWriter
  static member Decrypt : path:string -> unit
  static member Delete : path:string -> unit
  static member Encrypt : path:string -> unit
  static member Exists : path:string -> bool
  ...
Full name: System.IO.File
File.ReadAllLines(path: string) : string []
File.ReadAllLines(path: string, encoding: Text.Encoding) : string []
val concat : sources:seq<#seq<'T>> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.concat
val CountByPattern : patterns:seq<string> -> lines:seq<string> -> seq<int>
Full name: Script.CountByPattern
 Break down the sequence giving counts of lines matching each regex pattern.
val patterns : seq<string>
val lines : seq<string>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
val pattern : string
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.filter
val line : string
Multiple items
type Regex =
  new : pattern:string -> Regex + 1 overload
  member GetGroupNames : unit -> string[]
  member GetGroupNumbers : unit -> int[]
  member GroupNameFromNumber : i:int -> string
  member GroupNumberFromName : name:string -> int
  member IsMatch : input:string -> bool + 1 overload
  member Match : input:string -> Match + 2 overloads
  member Matches : input:string -> MatchCollection + 1 overload
  member Options : RegexOptions
  member Replace : input:string * replacement:string -> string + 5 overloads
  ...
Full name: System.Text.RegularExpressions.Regex
--------------------
Regex(pattern: string) : unit
Regex(pattern: string, options: RegexOptions) : unit
Regex.IsMatch(input: string, pattern: string) : bool
Regex.IsMatch(input: string, pattern: string, options: RegexOptions) : bool
val length : source:seq<'T> -> int
Full name: Microsoft.FSharp.Collections.Seq.length
val Analyze : patternsLabels:(string * 'a) [] -> lines:seq<string> -> seq<'a * int>
Full name: Script.Analyze
 Break down the given lines into counts by pattern, associating each count with a label.
val patternsLabels : (string * 'a) []
val patterns : string []
val labels : 'a []
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...
Full name: System.Array
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []
Full name: Microsoft.FSharp.Collections.Array.map
val fst : tuple:('T1 * 'T2) -> 'T1
Full name: Microsoft.FSharp.Core.Operators.fst
val snd : tuple:('T1 * 'T2) -> 'T2
Full name: Microsoft.FSharp.Core.Operators.snd
val zip : source1:seq<'T1> -> source2:seq<'T2> -> seq<'T1 * 'T2>
Full name: Microsoft.FSharp.Collections.Seq.zip
val AnalyzeCSharp : path:string -> (string * int) []
Full name: Script.AnalyzeCSharp
 Analyze C# files starting at the given path, showing various forms of noise.
val cache : source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.cache
val patternCounts : seq<string * int>
val otherCount : (string * int) list
val sumBy : projection:('T -> 'U) -> source:seq<'T> -> 'U (requires member ( + ) and member get_Zero)
Full name: Microsoft.FSharp.Collections.Seq.sumBy
val append : source1:seq<'T> -> source2:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.append
val ofSeq : source:seq<'T> -> 'T []
Full name: Microsoft.FSharp.Collections.Array.ofSeq
val Show : chart:'a -> unit
Full name: Script.Show
 Show an FSharp chart in a Windows form.
val chart : 'a
val form : Form
Multiple items
type Form =
  inherit ContainerControl
  new : unit -> Form
  member AcceptButton : IButtonControl with get, set
  member Activate : unit -> unit
  member ActiveMdiChild : Form
  member AddOwnedForm : ownedForm:Form -> unit
  member AllowTransparency : bool with get, set
  member AutoScale : bool with get, set
  member AutoScaleBaseSize : Size with get, set
  member AutoScroll : bool with get, set
  member AutoSize : bool with get, set
  ...
  nested type ControlCollection
Full name: System.Windows.Forms.Form
--------------------
Form() : unit
val ctl : Control
type DockStyle =
  | None = 0
  | Top = 1
  | Bottom = 2
  | Left = 3
  | Right = 4
  | Fill = 5
Full name: System.Windows.Forms.DockStyle
field DockStyle.Fill = 5
property Control.Controls: Control.ControlCollection
Control.ControlCollection.Add(value: Control) : unit
val ToPie : name:'a -> results:(string * int) array -> unit
Full name: Script.ToPie
 Show an array of strings and ints as a labelled pie chart.
val name : 'a
val results : (string * int) array
type 'T array = 'T []
Full name: Microsoft.FSharp.Core.array<_>
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.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<_>
  
  
  More information