c4se記:さっちゃんですよ☆

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙☆)

.。oO(此のblogは、主に音樂考察Programming に分類されますよ。ヾ(〃l _ l)ノ゙♬♪♡)

音樂は SoundCloud に公開中です。

考察は現在は主に Scrapbox で公表中です。

Programming は GitHub で開發中です。

Monitoring Elixir Plug/Phoenix Web application easy. KomachiHeartbeat v0.1.0 ヾ(〃l _ l)ノ゙

Rails にはKomachiHeartbeatと云ふ何かと有り難い mountable engine が在り、Elixir/Phoenix にも欲しかったので移植した。

KomachiHeartbeat

github.com

Plug 若しくは Phoenix の application の、適当な path にぶら下げて使ふ。例では/opsにぶら下げてある。Phoenix だと router で、

defmodule ExampleWeb.Router do
  use ExampleWeb, :router

  forward("/ops", KomachiHeartbeat)
end

とすると、

  • GET /ops/heartbeat
  • GET /ops/stats

と云ふ二つの endpoint が出來る。heartbeat は 200 ok か 503 error を返す。application が新しい HTTP 接續を受けられるなら 200 ok が返ってくる。受けられないなら timeout するだらう。接續は受けられるが何か問題 (何を確認するかは plugin で擴張する) が在るなら 503 error を返すやうに出來る。

stats は application の統計情報を返せる。default では空っぽで、plugin で返す情報を増やす。

元の Rails のものとの違ひは、収集する情報は全てを plugin で作るやうにしてあり、入れ替へられるようにした。Elixir には Rails と違ひ、「標準の stack」の樣なものは Ecto 位いしか無く、application によって確認すべき事が全く異なるだらうからだ。とは言へ標準の plugin は幾つか作りたいと思ってゐる。

Git repository の名前は Ex-KomachiHeartbeat であるが、これは当然元としたものと區別出來なければならない事と、Max 新幹線の樣な語呂にする爲に suffix ではなく prefix にした。

はい?

こまち (列車) - Wikipedia

Max (鉄道車両) - Wikipedia

(〃l _ l)

Testable readonly ETS. Mnemonics.ExMachina v0.1.0 ヾ(〃l _ l)ノ゙

  • 讀み取り専用
  • on-memory で高速
  • 再起動せずに新しい ver.の data へ入れ替へられる
  • 古い ver.で處理してゐた計算はそのまま古い ver.を讀み出し續けられる
  • heap 領域に cache できる。讀み出した data を snapshot として system 外に持ち運べる
  • parallel

これらを滿たしたMnemonicsと云ふ Elixir の library を以前に作った。無停止 upgrade 出來るActiveHashの樣なものだ。

Mnemonics を使った code を test しやうとする。test で使ふ data は、實働環境から独立である必要が在る、即ち test で使ふ data はは test 内に書かれてあるのが好い。又 test で使ふ data は、他の test からも独立である必要が在る、即ち或る test が書き換へた data が他の test に影響しないのが好い。PostgreSQL 等の DB を使った code を test するには 2 つの方法が在る。ひとつには DB と遣り取りする函數を mock して了ふ。もうひとつは test 毎に一意な data を DB に書き込む。test 毎に一意であればその data は他のどこからも讀み出せない。RDB であれば通常は、一意な primary key を test の外で生成して 與へ、與へられた key の data 以外には手を触れないと取り決めてやる。所謂 test factory だ。Rails/ActiveRecord だとFactoryBotが有名だ。Elixir/Ecto だとExMachinaが有名である。例へばこう使ふ。

defmodule Factory do
  use ExMachina.Ecto

  def user_factory do
    id = sequence("")
    %User{id: String.to_integer(id), name: "user" <> id}
  end
end

defmodule UserTest do
  import Factory

  use ExUnit.Case

  test "authorized?" do
    user = insert(:user)
    assert User.authorized?(user)
  end
end

some_factoryと云ふ函數を定義してやりuse ExMachina.Ectoとしてやると、build(:some)insert(:some)と云ふ函數が使へる樣に成る。

さて Mnemonics ではこれが出來ない。test 毎に一意な data を生成してやるのだが、readonly なので環境に書き込めない。

出來なかった。mock する手も在っただらうとは思ふものの、ETS をまるごと mock するのはダルいので、Mnemonics 側に書き込み出來る穴を空けてやった。この穴は table 毎に 1 つの GenServer であり parallel ではないので本番では使ってはならないが、test で使ふには充分速い。

Mnemonics.ExMachina

github.com

こう使ふ。

defmodule Factory do
  use Mnemonics.ExMachina

  def item_factory do
    id = sequence("")
    %Item{id: String.to_integer(id), name: "user" <> id}
  end
end

defmodule UserTest do
  import Factory

  use ExUnit.Case

  test "drop?" do
    user = insert(:item)
    assert Item.drop?(item)
  end
end

use ExMachina.Ectouse Mnemonics.ExMachinaに變はっただけ。一つの factory に兩方を use する事は出來ないので、併用する時は 2 つ factory を作ってやり、尚且つ import せず full qualified に module 名附きで呼んでやれば好い。

ヾ(〃l _ l)ノ゙

Haskell is good for scripting language ヾ(〃l _ l)ノ゙

Clojure/Haskell の誓ひと云ふのを立ててゐる。個人的な programming を Clojure/Haskell 以外でしないと云ふ誓ひだ。大体の事は置き換へてゆける。Java を使ふところは Clojure に置き換へる。Lisp を使ひたかったし、SuperCollider (Overtone)と Processing (Quil)を同時に扱ふのが簡單であるので、Haskell-like (Eta)ではなく Clojure を使ってゐる。JavaScriptHaskell に置き換へられる。Web front-end 用 framework (Miso)すら在る。

一つ困ってゐて、shell script とその仲間を捨てられずにゐた。ClojureHaskell も shell script を置き換へるのは辛からうと思った。ClojureJVM を起動しなければならないし、又これは JVM に關はる事ではないからできれば Haskell でやりたい。しかし GHC の標準 library では全然足りないから幾つも library を入れ追從しなければならない。と思ってゐた。さういふ時には、Ruby を書いたり Perl を書いたり Crystal を書いたりしてゐた。誓ひは破られたのである。

この度に、少々無理にでも Haskell で軽く scripting できる手法を見附けておくべきだらうと思ひ決めた。GHC の標準 library は貧弱だと思ひ込んでゐたから、その貧弱な標準 library で苦心するか、Stack project を作る事無く Hackage の library を簡單に扱へる方法を組み立てやうと決め、もそもそと調べ出した。

しかし書けたのである。特に苦勞は無かった。runghc も GHC の標準 library も好い仕事をした。皆とりこし苦勞だった。

昔との違ひはDashを使ふ樣に成ってゐた事である。何をするにもその環境の標準 library を全文檢索する癖が附いてゐたから、そんな誤解もしなく成ってゐた。全文檢索は凄い。runghc も頗る速かった。この理由は知らない。

以下が shell script から移してきた短い Haskell script である。git-deployと名附け、git-deploy some_host_on_ssh_config /home/some_userの樣に使ふ。雜な内容から用途の雜さは推して知るべしである。

#!/usr/bin/env runghc

import System.Environment ( getArgs, getExecutablePath )
import System.FilePath ( takeBaseName )
import System.Posix.Directory ( getWorkingDirectory )
import System.Process ( readCreateProcess, shell )
import Text.Printf ( printf )

main :: IO ()
main = do
  args <- getArgs
  case args of
    host:remoteDir:_ -> deploy host remoteDir
    _ -> help

help :: IO ()
help = putStr $ unlines [ "Help: deploy HOST REMOTE_DIR" ]

deploy :: String -> String -> IO ()
deploy host remoteDir = do
  projectName <- fmap takeBaseName getWorkingDirectory
  sh $ printf "git archive -9 -o /tmp/%s.tar.gz --prefix %s/ HEAD" projectName projectName
  sh $ printf "scp /tmp/%s.tar.gz %s:%s/%s.tar.gz" projectName host remoteDir projectName
  sh $ unlines
    [ (printf "ssh %s -K 'bash -s' <<EOF" host)
    , (printf "cd %s" remoteDir)
    , (printf "tar xzf %s.tar.gz" projectName)
    , "EOF"
    ]

sh :: String -> IO ()
sh command = do
  putStrLn $ "+" ++ command
  out <- readCreateProcess (shell command) ""
  putStrLn out

-- vim:set ft=haskell:

今困ってゐるのは、Haskell の文件を開くと Emacs (Evil) が固まる事。kill するしか無くなってしまふ。代りに Vim を使ってゐるが…。

ヾ(〃l _ l)ノ゙

7 libraries I made by Elixir ヾ(〃l _ l)ノ゙

qiita.com

12/5

Elixir を使って製品を作ってゐると、release して此れ程の時が経ち此れ程の人が利用してゐるのに樣々のものが足りない。此の世では、必要なものは作る事に成ってゐるさうだ。なので一つづつ作ってきた。

みなさんも一つづつ作ってゆきませう。世界。

  • holiday_jp
  • inner_cotton
  • Mnemonics
  • PQueue2
  • stream_gzip
  • stream_hash
  • witha

holiday_jp

holiday_jp | Hex

Japanese holiday.

Ruby にはholiday_jpと云ふ便利な gem が在る。日本の休日を database にしたものだ。

休日と云ふのは規則的な樣だが、法律で決まるものであり、法律の改正によって變はるものだ。年に 20 日弱しか無い休日は數十年前から先迄樂に羅列できる。複雜な規則を法律の改正日で条件分岐しながら書き起こすより、羅列して引いてくるはうがずっと樂で bug を出しにくい。千年後はどうなるかわからないが当分は充分である。

此の Elixir のholiday_jpは、Ruby の holiday_jp と同じ data を使ってゐる。函數は三つ用意してある。between/2holiday?/1on/1だ。

iex> HolidayJp.between ~D[2016-03-01], ~D[2016-03-31]
[
  %HolidayJp.Holiday{date: ~D[2016-03-20], week: "", week_en: "Sunday", name: "春分の日", name_en: "Vernal Equinox Day"},
  %HolidayJp.Holiday{date: ~D[2016-03-21], week: "", week_en: "Monday", name: "振替休日", name_en: "Holiday in lieu"},
]

iex> HolidayJp.holiday? ~D[2017-01-02]
true

iex> HolidayJp.holiday? ~D[2016-01-02]
false

iex> HolidayJp.on ~D[2017-02-11]
[%HolidayJp.Holiday{date: ~D[2017-02-11], week: "", week_en: "Saturday", name: "建国記念の日", name_en: "National Foundation Day"}]

inner_cotton

inner_cotton | Hex

Collection of recommended Elixir check utilities.

幾つか application や library を作ってゐると幾度も同じ library を入れる事に成る。静的 check tool でいつも使ふものを集めた。私の作ったものには全て此のinner_cottonを入れてある。意味は「中綿」、Lint(糸屑)を集めたもの。

現状では以下のものが入る。

  • Credo : Lint, coding style enhancer.
  • Dialyxir : Type checker using Dialyzer. Erlang 附屬の型檢査 tool を實行する。
  • InchEx : Document (ExDoc) improver.

HEAD では更に次のものが入る。

  • stream_data : Property base testing like QuickCheck. 多數の random data を使って性質 test を書ける。性質が常に成り立つか檢査するかのやうな事に使ふ。
  • EyeDrops : Guardの樣に、file の變更を監視して command を實行する。

mix cotton.initで各 tool 用の設定 file を置き、mix cotton.lintで Credo と Dialyzer と Inch が走り、mix testでいつも通り test が走り、mix cotton.watchで file の變更に合はせて lint と test が走る(HEAD では)。今はExCoverallsを入れやうとしてゐる。

Mnemonics

mnemonics | Hex

Read only data store for Elixir: fast, concurrently, for large data & hot reloadable.

Mnesia に匹敵しさうな名前を考へたらMnemonicsに成った。皮肉は效いてゐないが……。

數十 MB 位いの readonly data を on memory に置いて讀み出す爲のものだ。RubyActiveHashが Elixir にも欲しくて作った。Read only な ETS table を管理する library として在る。同じ table 名の data を複數 version 管理できる。realtime に data を差し替へる爲だ。

version と data の cache 機能を附け終へた所だ。Mnemonicsを使った code が testable にならないのが一番の課題で、次は其れに取り組まうとしてゐる。ExMachinaの擴張を書く事に成ると思ふ。

PQueue2

pqueue2 | Hex

Priority queue that wraps pqueue2.

優先度附き queue。

優先度附き queue すら無かったのか何故作ったと思ふかもしれぬ。私もさう思った。然して調べてみると「優先度附き queue」と名乗る Elixir の library は幾つも在った。私は全て調べた。結果、優先度附き queue として動作する實裝は無かった。同じ優先度からは random に出てくるものも在ったし(此れはPSQで、但し map としても機能する好いものだ)、一番 unique な實裝は LIFO として動いた、即ち優先度附き「stack」であった。辛うじて動いた一つはとっくに開發が放棄されてゐた。

Elixir ではなく Erlang にはちゃんとした實裝が在った。pqueueだ。此れを Elixir から便利に呼び、Enumerable と Collectable を實裝したものがPQueue2である。今作ってゐる application の背骨に使ってゐる。

stream_gzip

stream_gzip | Hex

Gzip or gunzip a stream.

Elixir の Stream は遲くて嫌はれてゐるかもしれないが、pararell に處理する程ではない場面で少ない memory で大きな data を手軽に扱へる好いものだ。stream_gzipは data 全体を memory に載せずに gzip / gunzip できる Stream だ。

"x.js"
|> File.stream!
|> StreamGzip.gzip
|> Stream.into(File.stream! "x.js.gz")
|> Stream.run

gzip でき、

"x.js.gz"
|> File.stream!
|> StreamGzip.gunzip
|> Stream.into(File.stream! "x.js")
|> Stream.run

で gunzip できる。Web application で data を生成しつつ gzip で streaming下載downloadさせる所で使った。

stream_hash

stream_hash | Hex

Stream into md4, md5, ripemd160, sha, sha224, sha256, sha384, sha512 hash.

上記stream_gzipを test する爲に作ったが、どこかで使へる事も在るだらう。

witha

witha | Hex

With aspect: Monad chain, like Haskell's do or Clojure's cats.core/alet.

{:ok, value} | {:error, reason}を返す函數を連鎖したくて作った。Elixir 標準の with 式で似た事はできるが、より各構造に特化した連鎖を書ける。

witha Witha.Error,
      [x1 <- {:ok, 1},
       x2 <- {:ok, x1 + 1}],
  do: x1 + x2
# {:ok, 3}

nil | valueも連鎖できる。

witha Witha.Nilable,
      [x1 <- nil,
       x2 <- x1 + 1],
  do: x1 + x2
# nil

AST level (macro)で new (return) & flat_map (bind)する作りに成ってゐる。此れ丈だと with 式の亜種なので、もっと高度な抽象化を取り込みたい。

tokyo.ex #8

speakerdeck.com

ヾ(〃l _ l)ノ゙