Argu すごい
gmake のオプションを前半だけ書いてみた。
type Arguments = | [<AltCommandLine("-B")>] Always_Make | [<AltCommandLine("-C")>] Directory of dir : string | Debug of mode : DebugMode option | [<AltCommandLine("-e")>] Environment_Overrides | Eval of expr : string | [<AltCommandLine("-f")>] File of file : string | [<AltCommandLine("-i")>] Ignore_Errors | [<AltCommandLine("-I")>] Include_Dir of dir : string | [<AltCommandLine("-h")>] Jobs of n : int option | [<AltCommandLine("-k")>] Keep_Going with interface IArgParserTemplate with member this.Usage = match this with | Always_Make -> "Unconditionally make all targets." | Directory _ -> "Change to <dir> before doing anything." | Debug _ -> "Print various types of debugging information." | Environment_Overrides -> "Environment variables override makefiles." | Eval _ -> "Evaluate <expr> as a makefile statement." | File _ -> "Read <file> as a makefile." | Ignore_Errors -> "Ignore errors from recipes." | Include_Dir _ -> "Search <dir> for included makefiles." | Jobs _ -> "Allow <n> jobs at once; infinite jobs with no arg." | Keep_Going -> "Keep going when some targets can't be made."
DebugMode
に何を入れるのかわからなかったので、スキップ。
書くならこんな感じに:
type DebugMode = | A = 1 | B = 2 | C = 3
コマンドラインをパースする
コマンドラインをパースするにはパーサーを作成する:
open Argu let parser = ArgumentParser.Create<Arguments>( programName = "make.exe", errorHandler = ProcessExiter() )
第 2 引数の errorHandler = ProcessExiter()
を忘れると恐ろしいことが起こるので注意。
後は、argv
を引数に parser
の Parse()
メソッドか ParseCommandLine()
メソッドを呼び出すだけ:
let results = parser.ParseCommandLine argv
すると、Arguments []
が返ってくる。
ので、これをあれこれする。
らしい。
printfn とかで出力する時に
最近までこんな風にやってたんだけど:
let name = user.GetName() // printfn "Hello, %s!" user.GetName() はエラーになっちゃうので // 一旦、変数に束縛する。 printfn "Hello, %s!" name
別にそんなことをする必要はなかったらしい。
<|
を使うんだルーク!!
printfn "Hello, %s!" <| user.GetName()
ヽ(=´▽`=)ノ
よく考えると coke とか joke とかいい名前があるじゃまいか
よさげなビルドツールを作ることはよさげな開発人生に一条のいい感じの光を投げかける的ななんかアレなわけです。
以下の C 言語なソースコードをビルドすることを考えてみましょう:
// main.c #include <stdio.h> int main() { printf( "Hello, World!\n" ); return 0; }
このようなケースは実の所あんまりないんですが、えーっと考えるのが簡単だよねって思ったのでそーいうことにしています。
SCons 風のビルドツール
SCons さんは Python 製のビルドツールっていうかなんかそれです。
ごっごる神がお作りになった次世代ビルドツールである Bazel だって SCons さん風に*1ビルドスクリプトを書きます。
const joke = require( '../lib/' ); joke.program( 'main.c' );
こうして見ると、JavaScript にはもってこいのような気がしなくもないと云うか何と云うか………。
CMake 風のビルドツール
CMake さんは Makefile を生成するメタビルドツールだと云うこともできるかもしれません。
めんどくさい AutoTools よりは佳いと思われます。
const joke = require( 'joke' ); joke.project( 'hello-example' ); joke.addExecutable( 'main', 'main.c' );
っていうか、パッと見、SCons とあんまり変わってないですね………。
それで?
joke を SCons 風なビルドツールとして作ってみようかなと思ったり思わなかったり……………。
*1:ドキュメント見ただけだから、そんなことはないかもしれない
RequestPolicy じゃなくて RequestPolicy Continued にしたら捗った
いままで、RequestPolicy を愛用していたんだけど、全然更新されていないのに気がついたので、RequestPolicy Continued に切り替えた。
(๑´ڡ`๑) めっちゃ使いやすい
class が export キーワードで export できなくてちょっと悲しかった
node のバージョンはこんな感じ:
% node --version
v6.3.1
wasp を書いてたら、
// ↓ class は書けるのに、export ができない!!!>< /* export */ class Emitter { constructor() { this.events = []; } on(name, cb) { this.events = ( this.events || [] ); this.events[name] = cb; return this; } emit(name, that) { let self = this; let events = self.events[name] || []; events.forEach( anEvent => { anEvent.call( self, that ); } ); return self; } } // ↓ ので、従来通りの module.exports に Emitter を設定する。 module.exports = Emitter;
という感じだったので、悲しい。
ビルドツール Wasp とかどうかな
Fly を見ていたらこういう風に書けたって良いんじゃないかなと思った:
const gcc = require( 'wasp-gcc' ); const paths = { scripts: [ 'src/**/*.c' ], dist: 'obj' }; export default function () { this.ready( 'build' ); } export function compile() { this.from( paths.scripts ) .gcc() .to( paths.dist ); }
うん、source()
とか target()
じゃなくて、from()
とか to()
って書けた方が良いと思う。
モジュールが Fly オブジェクトのメソッドを使えるようにするのってどうするんだーーーー?
Nemerle やってみた
インストール
yaourt でインストールできる:
% yaourt -S nemerle
へろーわーるど
using System; Console.WriteLine( "Hello, World!" );
このファイルを hello.n とすると、ncc
を使ってこんな風にコンパイルできる:
% ncc ./hello.n -o hello.exe
関数
関数は def
から始まる:
def add(a : int, b : int) : int { a + b; }
FParsec のチュートリアル的な何か
さて、今日は FParsec 日本語チュートリアルを読んでやってみるよ。
nuget
はインストールしてるかな?
私は nuget3
をインストールしてみたよ:
% yaourt -S nuget3
勉強用のディレクトリを作成しよう:
% mkdir ./hello-fparsec
% cd ./hello-fparsec
FParsec
をインストールしてみよう:
% nuget install FParsec -outputDirectory ./packages
-outputDirectory ./packages
を付けない場合、カレントディレクトリに FParsec
がインストールされてしまうので注意だ。
なので、Visual Studio の慣習に習って ./packages/ にインストールしてみた。
さっそく使ってみる
run
関数に何らかのパーサー関数と文字列を渡すと結果が返ってくる模様。
ʕ•͡ω•ʔ pfloat は FParsec 浮動小数点数をパースして浮動小数点数を返す組み込みのパーサー関数だぞ
// demo000.fsx open FParsec let test p str = match run p str with | Success(result , _, _) -> printfn "Success: %A" result | Failure(errorMessage, _, _) -> printfn "Failure: %s" errorMessage test pfloat "1.25" test pfloat "1.25E" test pfloat "1.25E 3"
それで、こんな風に打ってみると:
% fsharpi -I ./packages/FParsec.1.0.2/lib/net40-client/ -r "FParsec.dll" ./demo000.fsx Success: 1.25 Failure: Error in Ln: 1 Col: 6 1.25E ^ Note: The error occurred at the end of the input stream. Expecting: decimal digit Failure: Error in Ln: 1 Col: 6 1.25E 3 ^ Expecting: decimal digit
最初の test pfloat "1.25"
だけパースされた。
ヽ(=´▽`=)ノ
OCaml の Test::Simple を目コピしてみた その 4
OCaml のソースコードに沿って TAPDocument.ml を test-document.fs にして、TAPBuilder.ml を test-builder.fs に書いてみた。
なんかクラスっぽいやつでやってみたんだけど、これでいいのかな…………(汗
module Test.Builder type Plan(?count : int) = let current_plan : option<int> = count type TestCaseBuilder () = let mutable running_tests : (int -> Test.Document.node) list = []; member this.BuildTestCase(todo : option<string>, diag : option<Test.Document.diagnostic>, test : bool, description : string) = let running_test = fun number -> match todo with | None -> Test.Document.TestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk), number, description, diag) | Some x -> Test.Document.TodoTestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk), number, description, Test.Document.Todo(x), diag) running_tests <- running_test :: running_tests running_test member this.BuildDiagnostic(line : string) = let running_test = fun (_ : int) -> Test.Document.DiagnosticNode (Test.Document.Diag( [ line ] )) running_tests <- running_test :: running_tests running_test
今ブログ記事を書いてる時に気がついたけど、これじゃダメだよねwwwwww
だって、Plan とか let plan = Plan(12)
とかってしないとわかんないじゃんwwwwww
ほげーーーーーーー!!!
あと、F# では、関数に省略した引数を使えないので、type
のコンストラクタ?の引数に使わなければならない………
(。・_・。) ………
TestCaseBuilder
を TestCaseResult
とかにして、そのリストをどこかに持ったほうが良いのかも?
こんな感じ:
type TestCase(?todo, ?diag, test, description) = let running_test = fun number -> match todo with | None -> Test.Document.TestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk), number, description, diag) | Some x -> Test.Document.TodoTestCaseNode((if test then Test.Document.Ok else Test.Document.NotOk), number, description, Test.Document.Todo(x), diag)