На работе (Erlang/C#-разработка) подозрительно часто приходится писать небольшие скрипты для кодогенерации. Пишу я их, конечно, на F# — и он успел зарекомендовать себя как отличный инструмент для этого (кто бы сомневался!). Сейчас же я немного покодогенерировал не на работе, а делая новую версию моего шаблона проекта DataAnalysisApp.
Задача: сделать кодогенерацию директив компилятора F# для подключения .dll-библиотек из пакетов NuGet'a.
Эти библиотеки расположены в подпапках \lib директории с пакетами, а иногда — в подпапках этих подпапок с названиями вида \Net45 или \40.
Решение:
Довольно красивое сочетание pipe-lining'a, композиции и вычислительного выражения. Ну и регэкспы, конечно!
Легко заметить, что в решении используется одна из новых возможностей F#: triple-quoted strings. Кстати, скоро будет пост с анализом этих самых новых возможностей))
Ну и да — на самом деле можно сделать проще, воспользовавшись методом
... но эта версия не показывает всю няшность того, насколько просто записать сложные сценарии с помощью функциональных возможностей F#))
Задача: сделать кодогенерацию директив компилятора F# для подключения .dll-библиотек из пакетов NuGet'a.
Эти библиотеки расположены в подпапках \lib директории с пакетами, а иногда — в подпапках этих подпапок с названиями вида \Net45 или \40.
Решение:
let printInterpreterRDirectives dir = let formDirective path = sprintf """#r @"..%s" """ <| Regex.Match(path, @"(?i:\\packages\\.*\\lib\\.*)").Value Directory.EnumerateDirectories dir |> Seq.map (Directory.EnumerateDirectories >> Seq.find (fun y -> Regex.IsMatch(y, @"(?i:\\lib$)"))) |> Seq.collect (fun dir -> seq { for subdir in Directory.EnumerateDirectories dir do if Regex.IsMatch(subdir, @"(?i:\\(net)?4(0|5)$)") then yield subdir yield dir }) |> Seq.collect (Directory.EnumerateFiles >> Seq.filter (fun file -> FileInfo(file).Extension = ".dll")) |> Seq.map formDirective |> Seq.iter (printfn "%s") printInterpreterRDirectives @"C:\...\Visual Studio 2012\Projects\Data Analysis App 2012\packages"Получается портянка из вот такого:
#r @"..\packages\FSPowerPack.Community.2.1.3.1\Lib\Net40\FSharp.PowerPack.Parallel.Seq.dll"
#r @"..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll"
#r @"..\packages\MathNet.Numerics.2.2.1\lib\Net40\MathNet.Numerics.dll"
...
Довольно красивое сочетание pipe-lining'a, композиции и вычислительного выражения. Ну и регэкспы, конечно!
Легко заметить, что в решении используется одна из новых возможностей F#: triple-quoted strings. Кстати, скоро будет пост с анализом этих самых новых возможностей))
Ну и да — на самом деле можно сделать проще, воспользовавшись методом
EnumerateDirectories
с другой арностью:
let printInterpreterRDirectives' dir = let formDirective path = sprintf """#r @"..%s" """ <| Regex.Match(path, @"(?i:\\packages\\.*\\lib\\.*)").Value let enumSubdirs pattern = Directory.EnumerateDirectories(dir, pattern, SearchOption.AllDirectories) List.fold (fun acc pattern -> Seq.append acc <| enumSubdirs pattern) Seq.empty ["lib"; "net40"; "net45"; "40"; "45"] |> Seq.collect (Directory.EnumerateFiles >> Seq.filter (fun file -> FileInfo(file).Extension = ".dll")) |> Seq.map formDirective |> Seq.iter (printfn "%s")
... но эта версия не показывает всю няшность того, насколько просто записать сложные сценарии с помощью функциональных возможностей F#))
Комментариев нет:
Отправить комментарий