Lines of code and other metrics in F#
Asked Answered
G

3

9

How to get some nice statistics about my F# code?

I could imagine things like

  • number of lines of my code
  • number of files
  • number of characters?
  • number of functions, classes, modules etc
Gratitude answered 2/5, 2012 at 6:6 Comment(0)
A
10

Why not use some simple shell utilities?

Answers in order

wc -l *.fs
ls -l *.fs | wc -l
wc -c *.fs
grep module *.fs | wc -l
grep type *.fs | wc -l
grep "^let\|member" *.fs | wc -l

Update: Some examples for recursive folders - I hope the pattern is obvious

wc -l `find . -name "*.fs" `
find . -name "*.fs" | wc -l
wc -c `find . -name "*.fs" `
grep module `find . -name "*.fs" ` | wc -l
Applicative answered 2/5, 2012 at 6:21 Comment(3)
Nice! How do I run it? I use Windows 7 + VS 2010Gratitude
These are all standard unix command line tools. They are all included in cygwin at cygwin.com.Applicative
Thanks. One last question. Is there a way how to recursively call the commands on all sub-folders?Gratitude
P
4

Here is an F# version which counts both fs and fsx files recursively (assuming you have F# runtime installed):

open System.IO
open System.Text.RegularExpressions

let rec allFiles dir =
    seq { yield! Directory.GetFiles dir
          yield! Seq.collect allFiles (Directory.GetDirectories dir) }

let rgType = new Regex(@"type", RegexOptions.Compiled)
let rgModule = new Regex(@"module", RegexOptions.Compiled)
let rgFunction = new Regex(@"^let|member", RegexOptions.Compiled)

let count (rg: Regex) s =
    s |> rg.Matches |> fun x -> x.Count

type Statistics = {
        NumOfLines: int; NumOfFiles: int;
        NumOfChars: int; NumOfTypes: int;
        NumOfModules: int; NumOfFunctions: int;
    } 

let getStats =
    allFiles 
    >> Seq.filter (fun f -> f.EndsWith ".fs" || f.EndsWith ".fsx")
    >> Seq.fold (fun acc f -> 
                    let contents = f |> File.ReadLines
                    { NumOfLines = acc.NumOfLines + Seq.length contents; 
                      NumOfFiles = acc.NumOfFiles + 1;
                      NumOfChars = acc.NumOfChars + Seq.sumBy String.length contents;
                      NumOfTypes = acc.NumOfTypes + Seq.sumBy (count rgType) contents;
                      NumOfModules = acc.NumOfModules + Seq.sumBy (count rgModule) contents;
                      NumOfFunctions = acc.NumOfFunctions + Seq.sumBy (count rgFunction) contents; } 
                        ) { NumOfLines = 0; NumOfFiles = 0; 
                            NumOfChars = 0; NumOfTypes = 0; 
                            NumOfModules = 0; NumOfFunctions = 0 }
Pict answered 2/5, 2012 at 7:8 Comment(2)
I think your let regex won't be correct. I think it is more correct if you anchor it so that the let must be at the start of a line.Applicative
Thanks. The regex isn't exhaustive since it doesn't recognize static let or differentiate between functions and values.Pict
H
-2

Because F# compile to IL code and Common Type System (CTS) and PDB files, F# assemblies can be analyzed by the tool NDepend and you'll get 82 code metrics about your code (+ all others features of the tool). A free trial version is available here.

Disclaimer, I am a member of the NDepend Team.

Holbein answered 3/5, 2012 at 7:33 Comment(1)
well, nice idea to recur to IL code analysis, but due to the way the F# compiler produces code, most code metrics based on IL will be meaningless.Insessorial

© 2022 - 2024 — McMap. All rights reserved.