diff --git a/FSharp.ProjectScaffold.sln b/FSharp.ProjectScaffold.sln index 756b267..079d6fe 100644 --- a/FSharp.ProjectScaffold.sln +++ b/FSharp.ProjectScaffold.sln @@ -1,8 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 -MinimumVisualStudioVersion = 10.0.40219.1 +# Visual Studio 2012 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1F1B4F0F-2998-4D74-865B-9122611C2B14}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config @@ -11,6 +9,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1F1B4F EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1}" + ProjectSection(SolutionItems) = preProject + docs\content\index.fsx = docs\content\index.fsx + EndProjectSection EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp.ProjectTemplate", "src\FSharp.ProjectTemplate\FSharp.ProjectTemplate.fsproj", "{7E90D6CE-A10B-4858-A5BC-41DF7250CBCA}" EndProject @@ -20,6 +21,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "project", "project", "{BF60 RELEASENOTES.md = RELEASENOTES.md EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{83F16175-43B1-4C90-A1EE-8E351C33435D}" + ProjectSection(SolutionItems) = preProject + docs\tools\generate.fsx = docs\tools\generate.fsx + docs\tools\template.html = docs\tools\template.html + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{8E6D5255-776D-4B61-85F9-73C37AA1FB9A}" + ProjectSection(SolutionItems) = preProject + docs\content\index.fsx = docs\content\index.fsx + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -34,4 +46,8 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {83F16175-43B1-4C90-A1EE-8E351C33435D} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1} + {8E6D5255-776D-4B61-85F9-73C37AA1FB9A} = {A6A6AF7D-D6E3-442D-9B1E-58CC91879BE1} + EndGlobalSection EndGlobal diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000..b72585b --- /dev/null +++ b/build.cmd @@ -0,0 +1,6 @@ +@echo off +if not exist packages\FAKE\tools\Fake.exe ( + .nuget\nuget.exe install FAKE -OutputDirectory packages -ExcludeVersion -Prerelease +) +packages\FAKE\tools\FAKE.exe build.fsx %* +pause diff --git a/build.fsx b/build.fsx new file mode 100644 index 0000000..cfabd85 --- /dev/null +++ b/build.fsx @@ -0,0 +1,188 @@ +// -------------------------------------------------------------------------------------- +// FAKE build script +// -------------------------------------------------------------------------------------- + +#r @"packages/FAKE/tools/FakeLib.dll" + +open System +open System.IO +open System.Text.RegularExpressions +open Fake +open Fake.AssemblyInfoFile +open Fake.Git + +Environment.CurrentDirectory <- __SOURCE_DIRECTORY__ + +let files includes = + { BaseDirectories = [__SOURCE_DIRECTORY__] + Includes = includes + Excludes = [] } |> Scan + +// Information about the project to be used at NuGet and in AssemblyInfo files +let project = "FSharp.DataFrame" +let authors = ["Blue Mountain Capital"] +let summary = "Easy to use F# library for data manipulation and scientific programming" +let description = """ + The F# DataFrame library (FSharp.DataFrame.dll) implements an efficient and robust + data frame and series structures for manipulating with structured data. It supports + handling of missing values, aggregations, grouping, joining, statistical functions and + more. For frames and series with ordered indices (such as time series), automatic + alignment is also available. """ + +let tags = "F# fsharp data frame series statistics science" + +// Read additional information from the release notes document +// Expected format: "0.9.0-beta - Foo bar." or just "0.9.0 - Foo bar." +// (We need to extract just the number for AssemblyInfo & all version for NuGet +let versionAsm, versionNuGet, releaseNotes = + let lastItem = File.ReadLines "RELEASE_NOTES.md" |> Seq.last + let firstDash = lastItem.IndexOf(" - ") + let notes = lastItem.Substring(firstDash + 2).Trim() + let version = lastItem.Substring(0, firstDash).Trim([|'*'|]).Trim() + // Get just numeric version, if it contains dash + let versionDash = version.IndexOf('-') + if versionDash = -1 then version, version, notes + else version.Substring(0, versionDash), version, notes + +// -------------------------------------------------------------------------------------- +// Generate assembly info files with the right version & up-to-date information + +Target "AssemblyInfo" (fun _ -> + let fileName = "src/Common/AssemblyInfo.fs" + CreateFSharpAssemblyInfo fileName + [ Attribute.Title project + Attribute.Product project + Attribute.Description summary + Attribute.Version versionAsm + Attribute.FileVersion versionAsm ] +) + +// -------------------------------------------------------------------------------------- +// Clean build results & restore NuGet packages + +Target "RestorePackages" (fun _ -> + !! "./**/packages.config" + |> Seq.iter (RestorePackage (fun p -> { p with ToolPath = "./.nuget/NuGet.exe" })) +) + +Target "Clean" (fun _ -> + CleanDirs ["bin"; "gh-pages"; "release" ] +) + +Target "CleanDocs" (fun _ -> +// CleanDirs ["docs"] + () +) + +// -------------------------------------------------------------------------------------- +// Build library & test project + +Target "Build" (fun _ -> + (files ["FSharp.DataFrame.sln"; "FSharp.DataFrame.Tests.sln"]) + |> MSBuildRelease "" "Rebuild" + |> ignore +) + +// -------------------------------------------------------------------------------------- +// Run the unit tests using test runner & kill test runner when complete + +Target "RunTests" (fun _ -> + let nunitVersion = GetPackageVersion "packages" "NUnit.Runners" + let nunitPath = sprintf "packages/NUnit.Runners.%s/Tools" nunitVersion + + ActivateFinalTarget "CloseTestRunner" + + (files ["tests/*/bin/Release/FSharp.DataFrame*Tests*.dll"]) + |> NUnit (fun p -> + { p with + ToolPath = nunitPath + DisableShadowCopy = true + TimeOut = TimeSpan.FromMinutes 20. + OutputFile = "TestResults.xml" }) +) + +FinalTarget "CloseTestRunner" (fun _ -> + ProcessHelper.killProcess "nunit-agent.exe" +) + +// -------------------------------------------------------------------------------------- +// Build a NuGet package + +Target "NuGet" (fun _ -> + // Format the description to fit on a single line (remove \r\n and double-spaces) + let description = description.Replace("\r", "").Replace("\n", "").Replace(" ", " ") + let nugetPath = ".nuget/nuget.exe" + NuGet (fun p -> + { p with + Authors = authors + Project = project + Summary = summary + Description = description + Version = versionNuGet + ReleaseNotes = releaseNotes + Tags = tags + OutputPath = "bin" + ToolPath = nugetPath + AccessKey = getBuildParamOrDefault "nugetkey" "" + Publish = hasBuildParam "nugetkey" + Dependencies = [] }) + "nuget/FSharp.DataFrame.nuspec" +) + +// -------------------------------------------------------------------------------------- +// Generate the documentation + +Target "JustGenerateDocs" (fun _ -> + executeFSI "tools" "build.fsx" ["define","RELEASE"] |> ignore +) + +Target "GenerateDocs" DoNothing +"CleanDocs" ==> "JustGenerateDocs" ==> "GenerateDocs" + +// -------------------------------------------------------------------------------------- +// Release Scripts + +let gitHome = "https://github.com/BlueMountainCapital" + +Target "ReleaseDocs" (fun _ -> + Repository.clone "" (gitHome + "/FSharp.DataFrame.git") "gh-pages" + Branches.checkoutBranch "gh-pages" "gh-pages" + CopyRecursive "docs" "gh-pages" true |> printfn "%A" + CommandHelper.runSimpleGitCommand "gh-pages" "add ." |> printfn "%s" + let cmd = sprintf """commit -a -m "Update generated documentation for version %s""" versionNuGet + CommandHelper.runSimpleGitCommand "gh-pages" cmd |> printfn "%s" + Branches.push "gh-pages" +) + +Target "ReleaseBinaries" (fun _ -> + Repository.clone "" (gitHome + "/FSharp.DataFrame.git") "release" + Branches.checkoutBranch "release" "release" + CopyRecursive "bin" "release/bin" true |> printfn "%A" + MoveFile "./release/" "./release/bin/FSharp.DataFrame.fsx" + let cmd = sprintf """commit -a -m "Update binaries for version %s""" versionNuGet + CommandHelper.runSimpleGitCommand "release" cmd |> printfn "%s" + Branches.push "release" +) + +Target "Release" DoNothing + +// -------------------------------------------------------------------------------------- +// Run all targets by default. Invoke 'build ' to override + +Target "All" DoNothing + +"Clean" + ==> "RestorePackages" + ==> "AssemblyInfo" + ==> "Build" + ==> "GenerateDocs" + ==> "RunTests" + ==> "All" + +"All" + ==> "ReleaseDocs" + ==> "ReleaseBinaries" + ==> "NuGet" + ==> "Release" + +RunTargetOrDefault "All" diff --git a/docs/content/index.fsx b/docs/content/index.fsx new file mode 100644 index 0000000..c3ad1df --- /dev/null +++ b/docs/content/index.fsx @@ -0,0 +1,68 @@ +(*** hide ***) +// This block of code is omitted in the generated HTML documentation. Use +// it to define helpers that you do not want to show in the documentation. +#I "../../bin" + +(** +F# Project Scaffold +=================== + +Documentation + +
+
+
+
+ The F# DataFrame library can be installed from NuGet: +
PM> Install-Package FSharp.ProjectTemplate
+
+
+
+
+ +Example +------- + +Assume we loaded [Titanic data set](http://www.kaggle.com/c/titanic-gettingStarted) +into a data frame called `titanic` (the data frame has numerous columns including string +`Sex` and Boolean `Survived`). Now we can calculate the survival rates for males and females: + +*) +#r "FSharp.ProjectTemplate.dll" +open FSharp.ProjectTemplate + +Library.hello 0 +(** +Some more info + +Samples & documentation +----------------------- + +The library comes with comprehensible documentation. The tutorials and articles are +automatically generated from `*.fsx` files in [the samples folder][samples]. The API +reference is automatically generated from Markdown comments in the library implementation. + + * [Stuff](stuff.html) has more stuff + + * [API Reference](reference/index.html) contains automatically generated documentation for all types, modules + and functions in the library. This includes additional brief samples on using most of the + functions. + +Contributing and copyright +-------------------------- + +The project is hosted on [GitHub][gh] where you can [report issues][issues], fork +the project and submit pull requests. If you're adding new public API, please also +consider adding [samples][samples] that can be turned into a documentation. You might +also want to read [library design notes](design.html) to understand how it works. + +The library is available under **INSERT** license, which allows modification and +redistribution for both commercial and non-commercial purposes. For more information see the +[License file][license] in the GitHub repository. + + [samples]: https://github.com/fsharp/FSharp.ProjectScaffold/tree/master/samples + [gh]: https://github.com/fsharp/FSharp.ProjectScaffold + [issues]: https://github.com/fsharp/FSharp.ProjectScaffold/issues + [readme]: https://github.com/fsharp/FSharp.ProjectScaffold/blob/master/README.md + [license]: https://github.com/fsharp/FSharp.ProjectScaffold/blob/master/LICENSE.md +*) \ No newline at end of file diff --git a/docs/files/img/logo.png b/docs/files/img/logo.png new file mode 100644 index 0000000..1b0dc98 Binary files /dev/null and b/docs/files/img/logo.png differ diff --git a/docs/tools/generate.fsx b/docs/tools/generate.fsx new file mode 100644 index 0000000..269045c --- /dev/null +++ b/docs/tools/generate.fsx @@ -0,0 +1,61 @@ +// -------------------------------------------------------------------------------------- +// Builds the documentation from `.fsx` and `.md` files in the 'docs/content' directory +// (the generated documentation is stored in the 'docs/output' directory) +// -------------------------------------------------------------------------------------- + +#I "../../packages/FSharp.Formatting.2.0.4/lib/net40" +#r "../../packages/FAKE/tools/FakeLib.dll" +#r "FSharp.Literate.dll" +#r "FSharp.CodeFormat.dll" +#r "FSharp.MetadataFormat.dll" +open Fake +open System.IO +open Fake.FileHelper +open FSharp.Literate +open FSharp.MetadataFormat +let (++) a b = Path.Combine(a, b) + +// Binaries that have XML documentation (in a corresponding generated XML file) +let referenceBinaries = [ "FSharp.ProjectScaffold.dll" ] +// Web site location for the generated documentation +let website = "http://tpetricek.github.io/FSharp.FSharp.ProjectScaffold" + +// -------------------------------------------------------------------------------------- +// For typical project, no changes are needed below +// -------------------------------------------------------------------------------------- + +// When called from 'build.fsx', use the public project URL as +// otherwise, use the current 'output' directory. +#if RELEASE +let root = website +#else +let root = "file://" + (__SOURCE_DIRECTORY__ ++ "../output") +#endif + +// Paths with template/source/output locations +let bin = __SOURCE_DIRECTORY__ ++ "../../bin" +let content = __SOURCE_DIRECTORY__ ++ "../content" +let output = __SOURCE_DIRECTORY__ ++ "../output" +let files = __SOURCE_DIRECTORY__ ++ "../files" +let template = __SOURCE_DIRECTORY__ ++ "template.html" +let referenceTemplate = __SOURCE_DIRECTORY__ ++ "reference" + +// Build API reference from XML comments +let buildReference () = + CleanDir (output ++ "reference") + for lib in referenceBinaries do + MetadataFormat.Generate(bin ++ lib, output ++ "reference", referenceTemplate) + +// Build documentation from `fsx` and `md` files in `docs/content` +let buildDocumentation () = + CopyRecursive files output true |> Log "Copying file: " + let subdirs = Directory.EnumerateDirectories(content, "*", SearchOption.AllDirectories) + for dir in Seq.append [content] subdirs do + let sub = if dir.Length > content.Length then dir.Substring(content.Length + 1) else "." + Literate.ProcessDirectory + ( dir, template, output ++ sub, + replacements = [ "root", root ] ) + +// Generate +buildDocumentation() +buildReference() \ No newline at end of file diff --git a/docs/tools/packages.config b/docs/tools/packages.config new file mode 100644 index 0000000..598a505 --- /dev/null +++ b/docs/tools/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs/tools/reference/default.cshtml b/docs/tools/reference/default.cshtml new file mode 100644 index 0000000..4e551c1 --- /dev/null +++ b/docs/tools/reference/default.cshtml @@ -0,0 +1,120 @@ + + + + + @Title + + + + + + + + + + + + + + Fork me on GitHub + + \ No newline at end of file diff --git a/docs/tools/reference/members.cshtml b/docs/tools/reference/members.cshtml new file mode 100644 index 0000000..d29040b --- /dev/null +++ b/docs/tools/reference/members.cshtml @@ -0,0 +1,31 @@ +@if (Enumerable.Count(Model.Members) > 0) { +

@Model.Header

+ + + + + + @foreach (var it in Model.Members) + { + + + + + } + +
@Model.TableHeaderDescription
+ @{ var id = Html.UniqueID().ToString(); } + + @Html.Encode(it.Details.FormatUsage(40)) + +
+ Signature:@Html.Encode(it.Details.Signature)
+ @if (!it.Details.Modifiers.IsEmpty) { + Modifiers: @it.Details.FormatModifiers
+ } + @if (!it.Details.TypeArguments.IsEmpty) { + Type parameters: @it.Details.FormatTypeArguments + } +
+
@it.Comment.FullText
+} \ No newline at end of file diff --git a/docs/tools/reference/module.cshtml b/docs/tools/reference/module.cshtml new file mode 100644 index 0000000..5978291 --- /dev/null +++ b/docs/tools/reference/module.cshtml @@ -0,0 +1,120 @@ +@using FSharp.MetadataFormat +@{ + Layout = "default"; + Title = "Module"; +} + +@{ + var nestModules = (IEnumerable)Model.Module.NestedModules; + var nestTypes = (IEnumerable)Model.Module.NestedTypes; + + var members = (IEnumerable)Model.Module.AllMembers; + var comment = (Comment)Model.Module.Comment; + var byCategory = + members.GroupBy(m => m.Category).OrderBy(g => String.IsNullOrEmpty(g.Key) ? "ZZZ" : g.Key) + .Select((g, n) => new { Index = n, GroupKey = g.Key, Members = g.OrderBy(m => m.Name), Name = String.IsNullOrEmpty(g.Key) ? "Other module members" : g.Key}); +} + +

@Model.Module.Name

+
+ @foreach (var sec in comment.Sections) { + if (!byCategory.Any(g => g.GroupKey == sec.Key)) { + if (sec.Key != "") { +

@sec.Key

+ } + @sec.Value + } + } +
+@if (byCategory.Count() > 1) +{ +

Table of contents

+
    + @foreach (var g in byCategory) + { +
  • @g.Name
  • + } +
+} + + + +@if (nestTypes.Count() + nestModules.Count() > 0) +{ +

Nested types and modules

+} + +@if (nestTypes.Count() > 0) +{ + + + + + + @foreach (var it in nestTypes) + { + + + + + } + +
TypeDescription
+ @it.Name + @it.Comment.Blurb
+} +@if (nestModules.Count() > 0) +{ + + + + + + @foreach (var it in nestModules) + { + + + + + } + +
ModuleDescription
+ @it.Name + @it.Comment.Blurb
+} + + + + + +@foreach (var g in byCategory) +{ + if (byCategory.Count() > 1) { +

@g.Name 

+ var info = comment.Sections.FirstOrDefault(kvp => kvp.Key == g.GroupKey); + if (info.Key != null) + { +
+ @info.Value +
+ } + } + + @RenderPart("members", new { + Header = "Functions and values", + TableHeader = "Function or value", + Members = g.Members.Where(m => m.Kind == MemberKind.ValueOrFunction) + }) + + @RenderPart("members", new { + Header = "Type extensions", + TableHeader = "Type extension", + Members = g.Members.Where(m => m.Kind == MemberKind.TypeExtension) + }) + + @RenderPart("members", new { + Header = "Active patterns", + TableHeader = "Active pattern", + Members = g.Members.Where(m => m.Kind == MemberKind.ActivePattern) + }) +} \ No newline at end of file diff --git a/docs/tools/reference/namespaces.cshtml b/docs/tools/reference/namespaces.cshtml new file mode 100644 index 0000000..e4f9023 --- /dev/null +++ b/docs/tools/reference/namespaces.cshtml @@ -0,0 +1,49 @@ +@{ + Layout = "default"; + Title = "Namespaces"; +} + +

@Model.Name.Name

+ +@foreach (var ns in Model.Namespaces) +{ +

@ns.Name

+
+ @if (ns.Types.Length > 0) { + + + + + + @foreach (var it in ns.Types) + { + + + + + } + +
TypeDescription
+ @it.Name + @it.Comment.Blurb
+ } + @if (ns.Modules.Length > 0) { + + + + + + @foreach (var it in ns.Modules) + { + + + + + } + +
ModuleDescription
+ @it.Name + @it.Comment.Blurb
+ } +
+} diff --git a/docs/tools/reference/type.cshtml b/docs/tools/reference/type.cshtml new file mode 100644 index 0000000..31d61f3 --- /dev/null +++ b/docs/tools/reference/type.cshtml @@ -0,0 +1,64 @@ +@using FSharp.MetadataFormat +@{ + Layout = "default"; + Title = "Module"; +} + +@{ + var members = (IEnumerable)Model.Type.AllMembers; + var comment = (Comment)Model.Type.Comment; + var byCategory = + members.GroupBy(m => m.Category).OrderBy(g => String.IsNullOrEmpty(g.Key) ? "ZZZ" : g.Key) + .Select((g, n) => new { Index = n, GroupKey = g.Key, Members = g.OrderBy(m => m.Name), Name = String.IsNullOrEmpty(g.Key) ? "Other type members" : g.Key }); +} + +

@Model.Type.Name

+
+ @foreach (var sec in comment.Sections) { + if (!byCategory.Any(g => g.GroupKey == sec.Key)) { + if (sec.Key != "") { +

@sec.Key

+ } + @sec.Value + } + } +
+@if (byCategory.Count() > 1) +{ +

Table of contents

+
    + @foreach (var g in byCategory) + { +
  • @g.Name
  • + } +
+} +@foreach (var g in byCategory) { + if (byCategory.Count() > 1) { +

@g.Name 

+ var info = comment.Sections.FirstOrDefault(kvp => kvp.Key == g.GroupKey); + if (info.Key != null) { +
+ @info.Value +
+ } + } + + @RenderPart("members", new { + Header = "Constructors", + TableHeader = "Constructor", + Members = g.Members.Where(m => m.Kind == MemberKind.Constructor) + }) + + @RenderPart("members", new { + Header = "Instance members", + TableHeader = "Instance member", + Members = g.Members.Where(m => m.Kind == MemberKind.InstanceMember) + }) + + @RenderPart("members", new { + Header = "Static members", + TableHeader = "Static member", + Members = g.Members.Where(m => m.Kind == MemberKind.StaticMember) + }) +} diff --git a/docs/tools/template.html b/docs/tools/template.html new file mode 100644 index 0000000..5794c9b --- /dev/null +++ b/docs/tools/template.html @@ -0,0 +1,98 @@ + + + + + {page-title} + + + + + + + + + + + + + + + + + Fork me on GitHub + + \ No newline at end of file diff --git a/src/FSharp.ProjectTemplate/Library.fs b/src/FSharp.ProjectTemplate/Library.fs index 30eae7d..b6924e4 100644 --- a/src/FSharp.ProjectTemplate/Library.fs +++ b/src/FSharp.ProjectTemplate/Library.fs @@ -1 +1,16 @@ -namespace fsharp_project_template +namespace FSharp.ProjectTemplate + +/// Documentation for my library +/// +/// ## Example +/// +/// let h = Library.hello 1 +/// printfn "%d" h +/// +module Library = + + /// Returns 42 + /// + /// ## Parameters + /// - `num` - whatever + let hello num = 42