3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

F# Interactive(fsi)で新しいパッケージマネジメントの記法を使う。ついでにCanopyで遊ぶ。

Last updated at Posted at 2020-09-03

はじめに

今までfsiではパッケージ管理にpaketを使う必要があったり、DLLへのパスを明記しないといけなかったり面倒だった。

head.fsx
// ↓パッケージはpaket.dependenciesで別途落としてきてもらわないとけない
# r "packages/FSharp.Data/lib/netstandard2.0/FSharp.Data.dll"
open FSharp.Data

dotnet 3.1.300+からは--langversion:previewオプションで、ドラフトだったfsiでのパッケージマネジメント記法が使えます。
https://docs.microsoft.com/en-us/dotnet/fsharp/tutorials/fsharp-interactive/#package-management-in-f-interactive

head.fsx
// DLと参照をよしなにやってくれる
# r "nuget: FSharp.Data"
open FSharp.Data

というわけで早速試しましょう!!

Canopyで試す

What's Canopy? →https://lefthandedgoat.github.io/canopy/
公式を参考にしつつ、Googleでボーダーコリーを検索するテストコードを書きます。
ボーダーコリー、賢いし可愛いので。

search-collie.fs
# r "nuget: Selenium.WebDriver"
# r "nuget: canopy"
# r "nuget: Selenium.WebDriver.ChromeDriver, 83.0.0"

open canopy
open canopy.runner.classic
open canopy.configuration
open canopy.classic
open canopy.reporters
open System

let driverDir = System.Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\.nuget\\packages\\selenium.chrome.webdriver\\83.0.0\\driver"
canopy.configuration.chromeDir <- driverDir
//せっかくなのでレポートも出力する
reporter <- new JUnitReporter("./TestResults.xml")


//start remote
start chrome

"Google検索でボーダーコリーを検索" &&& fun _ ->
    //検索ページのURLを開く
    url "https://www.google.co.jp/"
    //検索ボックスに文字を入力
    "input[name='q']" << "ボーダーコリー"
    //検索ボタンをクリック
    click "Google 検索"

run()
quit()

注意点として、
公式ではchromeDirにSystem.AppContext.BaseDirectoryを使っていますが、このスクリプトはfsiが実行するため、
System.AppContext.BaseDirectory = fsi実行ファイルがあるディレクトリになってしまいます。
※公式はdotnet CLIがビルド時にchromedrive.exeを実行ファイルと同じとこに置いてくれるので動く

真っ先に思いついたのはスクリプトと同じディレクトリにchromedriver.exeを置いて、
ビルトイン変数の__SOURCE_DIRECTORY__を使うことですが、それだとコード上でバージョン管理ができません。

いろいろ調べてみると、
#r "nuget: ~"の記法で書くとF#5.x(もしくはdotnet)はパッケージを~/.nuget/packagesに展開するようなので、
$env:USERPROFILE\\.nuget\\packages\\selenium.chrome.webdriver\\{version}\\driver"を直書きして
ドライバーを参照させています。

他にいいやり方を知っている人がいたら、ぜひ教えて下さい。
ちなみに、previewなのでこのあたりの挙動は正式リリースで変わるかもしれません。

話を戻して、先程書いたプログラムを動かします。

dotnet fsi --langversion:preview ./search-collie.fs

動きました!!(スクショ取り忘れ)(君の目で確かめてくれ)
もうこれで.fsxファイル単体を配布するだけでみんな幸せです。
さよならpaketくん…君のことは忘れないよ…

ちなみに--langversion:previewは.NET5でF#5.xが正式リリースされたら不要になるらしいです。
.NET5が待ち遠しいですね。

余談

その他の注意点として、
csv.Load等で相対的にファイルパスを書いた場合、作業用に作られるテンポラリディレクトリから探そうとします。
$HOME\AppData\Local\Temp\nuget\<なんかよくわからないハッシュ値>\

> #r "nuget: FSharp.Data";;
> open FSharp.Data;;
[読み込み中 C:\Users\iranika\AppData\Local\Temp\nuget\24068--45e63f04-34e0-4cb9-aafd-4ba346693aff\Project.fsproj.fsx]
namespace FSI_0002.Project

> type csv = CsvProvider<"params.csv">;;
type csv = CsvProvider<...>

> let data = csv.Load("params.csv");;
セッションを 'C:\Users\iranika\.nuget\packages\fsharp.data\3.3.3\lib\netstandard2.0\FSharp.Data.dll' にバインドしています...
System.IO.FileNotFoundException: Could not find file 'C:\Users\iranika\AppData\Local\Temp\nuget\24068--45e63f04-34e0-4cb9-aafd-4ba346693aff\params.csv'.
File name: 'C:\Users\iranika\AppData\Local\Temp\nuget\24068--45e63f04-34e0-4cb9-aafd-4ba346693aff\params.csv'
   at System.IO.FileStream.ValidateFileHandle(SafeFileHandle fileHandle)
   at System.IO.FileStream.CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
   at FSharp.Data.Runtime.IO.asyncRead@219-5.Invoke(Unit unitVar) in C:\GitHub\dsyme\FSharp.Data\src\CommonRuntime\IO.fs:line 220
   at Microsoft.FSharp.Control.AsyncPrimitives.CallThenInvoke[T,TResult](AsyncActivation`1 ctxt, TResult result1, FSharpFunc`2 part2) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 386
   at Microsoft.FSharp.Control.Trampoline.Execute(FSharpFunc`2 firstAction) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 105
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.FSharp.Control.AsyncResult`1.Commit() in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 338
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronouslyInCurrentThread[a](CancellationToken cancellationToken, FSharpAsync`1 computation) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 858
   at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 878
   at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in F:\workspace\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1142
   at <StartupCode$FSI_0005>.$FSI_0005.main@()
エラーのため停止しました
>

今のところは__SOURCE_DIRECTORY__を使って相対参照を回避していますが、
なんかいい感じの解決方法がほしいです。

let [<Literal>] paramsCsv = __SOURCE_DIRECTORY__ + "\\params.csv"
type csv = CsvProvider<paramsCsv>
3
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?