Open12

gleamを試す

jnuankjnuank

もうちょっと触りたいのでローカルで環境構築

環境構築

https://gleam.run/getting-started/installing/

ubuntu 22.04使っているので、それに合わせて入れる

asdf使っているので、asdfでgleam入れてみる

asdf plugin-add gleam
asdf install gleam latest
asdf global gleam latest
gleam --version         
結果
gleam 1.2.1

erlang

ベースはerlangで動くので、上記ドキュメントに従って入れる
ドキュメントだと、 esl-erlang を入れるよう書いてあるが、apt packageで検索しても無かったので、erlangで入れてみる

wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb
sudo dpkg -i erlang-solutions_2.0_all.deb
sudo apt update
sudo apt install erlang
バージョン確認
erl -version
結果
Erlang (SMP,ASYNC_THREADS) (BEAM) emulator version 12.2.1

Reber3

Erlangの標準のビルドツールらしいので、入れる

https://rebar3.org/docs/getting-started/

jnuankjnuank

チュートリアルプロジェクト

https://gleam.run/writing-gleam/

$ gleam new vars
Your Gleam project vars has been successfully created.
The project can be compiled and tested by running these commands:

	cd vars
	gleam test

せっかくなのでテスト動かす

gleam test
  Resolving versions
Downloading packages
 Downloaded 2 packages in 0.06s
  Compiling gleam_stdlib
  Compiling gleeunit
  Compiling vars
   Compiled in 1.13s
    Running vars_test.main
.
Finished in 0.006 seconds
1 tests, 0 failures

生成されているテストコードは以下

import gleeunit
import gleeunit/should

pub fn main() {
  gleeunit.main()
}

// gleeunit test functions end in `_test`
pub fn hello_world_test() {
  1
  |> should.equal(1)
}

コメントにあるとおり、最後に_testを入れないと判定されないそう

pub fn hello_world_test2() {
結果
$ gleam test
  Compiling vars
   Compiled in 0.20s
    Running vars_test.main

Finished in 0.002 seconds
0 tests

わざと壊してみる

  1
  |> should.equal(2)
結果
$  gleam test
   Compiled in 0.02s
    Running vars_test.main
F
Failures:

  1) vars_test.hello_world_test: module 'vars_test'
     Values were not equal
     expected: 2
          got: 1
     output: 

Finished in 0.005 seconds
1 tests, 1 failures

TourのPipelinesの説明を見る限り、以下のように他の言語でもよくあるような感じでassertできる。
(基本はパイプラインで渡す感じなんだとは思うけど)

  // 1
  // |> should.equal(2)
  should.equal(1, 2)

gleeunitのassertionは actual, expectedの順番なのか。
https://hexdocs.pm/gleeunit/gleeunit/should.html#equal

jnuankjnuank

依存関係の追加

gleam add envoy argv
gleam.toml
 [dependencies]
 gleam_stdlib = ">= 0.34.0 and < 2.0.0"
+envoy = ">= 1.0.1 and < 2.0.0"
+argv = ">= 1.0.2 and < 2.0.0"
 
 [dev-dependencies]
 gleeunit = ">= 1.0.0 and < 2.0.0"

lockファイルも変更がかかる

manifest.toml

 packages = [
+  { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
+  { name = "envoy", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "CFAACCCFC47654F7E8B75E614746ED924C65BD08B1DE21101548AC314A8B6A41" },
   { name = "gleam_stdlib", version = "0.38.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "663CF11861179AF415A625307447775C09404E752FF99A24E2057C835319F1BE" },
   { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
 ]
 
 [requirements]
+argv = { version = ">= 1.0.2 and < 2.0.0"}
+envoy = { version = ">= 1.0.1 and < 2.0.0"}
 gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
 gleeunit = { version = ">= 1.0.0 and < 2.0.0" }


jnuankjnuank

argv

argv使ったコード

pub fn main() {
  case argv.load().arguments {
    ["get", name] -> get(name)
    _ -> io.println("Hello from vars!")
  }
}

fn get(name: String) -> Nil {
  io.println("args")
}
gleam run get T
args
gleam run set T
Hello from vars!
vars.gleam
 pub fn main() {
+  io.debug(argv.load().arguments)
   case argv.load().arguments {
     ["get", name] -> get(name)
     _ -> io.println("Hello from vars!")
gleam run get T 
   Compiled in 0.02s
    Running vars.main
args
["get", "T"]

["get", "T"] と取ることができるので、Listのパターンマッチができるということぽい。

  case argv.load().arguments {
    // 1つ目が"get"で2つ目がなにかあれば、nameにバインドできるぽい
    ["get", name] -> get(name)
    _ -> io.println("Hello from vars!")
jnuankjnuank

パッケージ分け

To call the format_pair function from a module in the test/ directory we will need to make it public. We don’t want it to be part of the public API of the package, so we’ll move it to an internal module, which by default are modules named packagename/internal and packagename/internal/*.

internal という名前にすれば内部モジュールという扱いになるらしい。

src/vars.gleam
 import envoy
 import gleam/io
 import gleam/result
+import vars/internal
 
 pub fn main() {
   case argv.load().arguments {
 
 fn get(name: String) -> Nil {
   let value = envoy.get(name) |> result.unwrap("")
-  io.println(format_pair(name, value))
+  io.println(internal.format_pair(name, value))
 }
-
-fn format_pair(name: String, value: String) -> String {
-  name <> "=" <> value
-}

src/vars/internal.gleam
+pub fn format_pair(name: String, value: String) -> String {
+  name <> "=" <> value
+}

vars/internal.gleam とつくれば、 import vars/internal という形でimportができるらしい

jnuankjnuank

case文で _ のあとに書くと、 cannot be reached と怒られる

  case request.path_segments(req) {
    ["ws"] ->
      mist.websocket(
        request: req,
        on_init: fn(_con) { #(state, Some(selector)) },
        on_close: fn(_state) { io.println("goodbye!") },
        handler: handle_ws_message,
      )
    ["echo"] -> echo_body(req)
    _ -> echo_req(req)
    ["chunk"] -> serve_chunk(req)
  }
}

warning: Unreachable case clause
   ┌─ mist_handler.gleam:36:5
   │
36 │     ["chunk"] -> serve_chunk(req)
   │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This case clause cannot be reached as a previous clause matches
the same values.

Hint: It can be safely removed.