おんがえしの blog

作ったプログラムと調べた技術情報

blog new コマンドと blog commit コマンドの実装

自分用の blog コマンド を改善中。 git レポジトリへのコミットと blogsync を同期させる方向で実装してみた。

github.com

blog new

引数は --custom-path に渡すことで URL を直接指定できるようにする。 --draft--title はオプション。

class Main < Thor
  desc "new PATH", "Create a new blog post with PATH"
  method_option :title, type: :string
  method_option :draft, type: :boolean
  def new(path)
    Dir.chdir(BLOG_REPOSITORY_DIR) do
      opts = []
      opts << "--title=\"#{options[:title]}\"" if options[:title]
      opts << "--draft" if options[:draft]
      system("blogsync post --custom-path #{path } #{opts.join(" ")} ongaeshi.hatenablog.com")
      system("git add ongaeshi.hatenablog.com/entry/#{path}.md")
      system("git commit -m \"Add #{path}\"") 
    end
  end

blog commit

blog push してから変更内容をコミットする。

  desc "commit", "git commit and push blog changes"
  method_option :message, type: :string, aliases: '-m'
  def commit
    Dir.chdir(BLOG_REPOSITORY_DIR) do
      list = `git diff --name-only`.split("\n")
      list += `git diff --name-only origin/main..HEAD`.split("\n")
      list.each do |path|
        system("blogsync push #{path}")
      end

      system("git add .")
      message = options[:message] || "Commit blog changes"
      system("git commit -m \"#{message}\"") 
    end
  end

blogsync 20.0.1 への更新

blogsync の置き場所を確認

PowerShell の type は Get-Command (いつも忘れる)。

> Get-Command blogsync
C:\app\bin\blogsync.exe

ダウンロード

https://github.com/x-motemen/blogsync/releases から最新のバイナリをダウンロード。

https://github.com/x-motemen/blogsync/releases/download/v0.20.1/blogsync_v0.20.1_windows_amd64.zip

zip 展開してできたバイナリを C:\app\bin に放り込めば OK。(go で書かれたアプリは更新が簡単・・!)

0.20.1

この辺りが特に嬉しい。

  • blogsync remove が使えるようになった
  • custom-path パス未指定のドラフトを更新するたびに新しいファイルが降ってきてしまう問題が解決された
NAME:
   blogsync.exe - A new cli application

USAGE:
   blogsync.exe [global options] command [command options] [arguments...]

VERSION:
   0.20.1 (9760a4c)

COMMANDS:
   pull     Pull entries from remote
   fetch    Fetch entries from remote
   push     Push local entries to remote
   post     Post a new entry to remote
   list     List local blogs
   remove   Remove blog entries
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   -C PATH        Run as if blogsync was started in PATH instead of the current working directory. [%BLOGSYNC_WORKDIR%]
   --help, -h     show help
   --version, -v  print the version

補完の効く irb 環境を WSL 経由で Windows に導入するためのメモ

前回 で WSL に Ruby 3.3 が入ったので次は irb の設定をします。

最新の irb では型補完の追加、補完ダイアログの色変更API、デバッグに便利な機能、その他便利な機能追加などが入り、対話的なプロトタイピングやデバッグ、学習や実験の作業効率が大きく向上しています。また型情報を利用したより精度の高い補完アルゴリズムも使えるようになっています。目標は自分の書いているライブラリ内の sig/ に記述したメソッドが補完できるようにすることです。

json_canvas ライブラリを読み込んで補完入力

irb のセットアップ

bash(シェル)に以下を貼り付けて実行します。

# gem のインストール
gem install repl_type_completor

# .irbrc に設定追加
echo 'IRB.conf[:COMPLETOR] = :type' >> ~/.irbrc

# irb 起動。
irb

irb が起動したら irb_info で設定を確認します。Completion に ReplTypeCompletor が使われていたら成功です。

irb(main):001> irb_info
Ruby version: 3.3.1
IRB version: irb 1.13.1 (2024-05-05)
InputMethod: RelineInputMethod with Reline 0.5.8
Completion: Autocomplete, ReplTypeCompletor: 0.1.6, Prism: 0.29.0, RBS: 3.5.0.pre.2
.irbrc paths: /home/ongaeshi/.irbrc
RUBY_PLATFORM: x86_64-linux
LANG env: C.UTF-8
East Asian Ambiguous Width: 1
=> nil

基本的な使い方

テキストを入力すると自動で補完候補が表示されます。補完候補が表示されているときは以下のホットキーが使えます。

操作 ホットキー
次の補完候補に移動 TAB
1つ前の補完候補に移動 Shift+TAB
補完対象のドキュメントを表示 Alt+D

また補完中に関わらずテキスト入力中は以下のホットキーが使えます。

操作 ホットキー
入力中のテキストをすべてクリア Ctrl+U
直前のドットまでテキストをクリア Alt+Backspace

開発中のライブラリや sig を読み込んだ状態で irb を起動したい

bundler に repl_type_completor と irb を追加します。

※ 注: 2024-06-16 現在、irb には repl_type_completor の依存が含まれていないので手動でインストールする必要があります。

$ cd /path/to/project
$ bundle add repl_type_completor irb --group development

bundle exec 経由で irb を起動するとライブラリが require できるようになります。

$ bundle exec irb

これでライブラリに sig を書いていれば補完も効くようになります。

WSL に rbenv 経由で Ruby 3.3 をインストールする

Windows 環境で Ruby 3.3 の補完が強化された irbrbs-inline などの最新の機能を試したいたいときは RubyInstaller を使わずに WSL 経由で入れた方が挙動が安定していておすすめです。

また Ubuntu で snap を使って Ruby をインストールすると標準ライブラリのドキュメントがインストールされず irb の補完時にドキュメントが表示されないため、 rbenv 経由でインストールしています。

動作確認環境は

です。

WSL のインストール(新規)

> wsl --install

https://learn.microsoft.com/ja-jp/windows/wsl/install

これで Ubuntu の安定版がインストールされるはずです。そのまま rbenv のインストールに進んでください。

WSL のインストール(追加)

Ubuntu 22.04 LTS を入れてそこに rbenv 経由で Ruby 3.3 を入れます。

一度 wsl update して最新にしておきます。

> wsl --update
更新プログラムを確認しています。
Linux 用 Windows サブシステムの最新バージョンは既にインストールされています。

wsl -l -v で今何が入っているか確認します。(私の環境では古い Ubuntu 20.04 が入っていました)

> wsl -l -v 
  NAME            STATE           VERSION
  Ubuntu-20.04    Running         2

wsl -l --online でインストールできるディストリビューションを確認します。

> wsl -l --online
インストールできる有効なディストリビューションの一覧を次に示します。
'wsl.exe --install <Distro>' を使用してインストールします。

NAME                                   FRIENDLY NAME
Ubuntu                                 Ubuntu
Debian                                 Debian GNU/Linux
kali-linux                             Kali Linux Rolling
Ubuntu-18.04                           Ubuntu 18.04 LTS
Ubuntu-20.04                           Ubuntu 20.04 LTS
Ubuntu-22.04                           Ubuntu 22.04 LTS
Ubuntu-24.04                           Ubuntu 24.04 LTS
.
.

wsl --install -d Ubuntu-22.04Ubuntu 22.04 LTS をインストールします。 Ubuntu のユーザー名とパスワードを入力すればインストール完了です。

> wsl --install -d Ubuntu-22.04
.
.
Enter new UNIX username: username
New password:password
Retype new password:password
passwd: password updated successfully
この操作を正しく終了しました。
Installation successful!

lsb_release -a でインストールされたバージョンを確認します。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.3 LTS
Release:        22.04
Codename:       jammy

rbenv 経由で Ruby 3.3 を入れる

1. apt install

まず、rbenv と Rubyコンパイルするために必要な依存関係をインストールします。

sudo apt update
sudo apt install -y build-essential libssl-dev libreadline-dev zlib1g-dev libffi-dev libyaml-dev

https://github.com/rbenv/ruby-build/wiki#ubuntudebianmint で推奨を全部入れてもいいかもしれない。

2. rbenvのインストール

次に、 rbenv と ruby-build をインストールします。

# rbenv のクローン
git clone https://github.com/rbenv/rbenv.git ~/.rbenv

# rbenv をパスに追加
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

# シェルの再読み込み
source ~/.bashrc

# ruby-build プラグインのクローン
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

3. Ruby 3.3 のインストール

rbenvを使ってRuby 3.3をインストールします。

# rbenv を使って Ruby 3.3 をインストール
rbenv install 3.3.2

# グローバルで使用する Ruby のバージョンを設定
rbenv global 3.3.2

# シェルの再読み込み
exec $SHELL

インストールの確認コマンドruby -vを実行して、正しくインストールされたかを確認してください。

$ ruby -v
ruby 3.3.1 (2024-04-23 revision c56cd86388) [x86_64-linux]

まとめ

WSL に Ubuntu 22.04 LTS を入れて rbenv 経由で Ruby 3.3 を入れました。これで強力に補完の効いた irb が使えるようになります。代入したローカル変数にもちゃんと補完が効くのがいいですね。

irb-repl-type-completor

irb の TypeCompletor を Windows で試してみる

RubyKaigi 2024 のWriting Weird Code @tompngExploring Reline @ima1zumi で紹介されている新しい irb の補完機能がよさそうなので手元でもインストールしてみた。

Ruby 3.3 のインストール

3.2 でも gem update irb とかすれば動くらしいけどせっかくなので Ruby 3.3 を入れる。

https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.3.1-1/rubyinstaller-devkit-3.3.1-1-x64.exe をダウンロード&インストール。 Ruby 本体は普通のインストーラが起動するので普通に C:\Ruby33-x64 に入れる。

次に MSYS2 と DevKit も入れる。

Image from Gyazo

Which components be shall be installed? If unsure press ENTER [1,3] が出たら 1, 3 を入力してインストール。

Image from Gyazo

まで来たら成功なので ENTER を押して終了。

ReplTypeCompletor gem のインストール

Windows版だと? Ruby 3.3 でも ReplTypeCompletor は標準でインストールされていないようなので事前にインストールしておく。

PS> gem install repl_type_completor

.irbrc の設定

.irbrc に以下の設定を追加。(設定しない場合は irb --type-completor で起動すれば OK)

IRB.conf[:COMPLETOR] = :type

irb を起動&設定の確認

irb を起動する。

PS> irb

irb_info を入力して設定が Completion が ReplTypeCompletor になっていることを確認する。

irb(main):025> irb_info
Ruby version: 3.3.1
IRB version: irb 1.11.0 (2023-12-19)
InputMethod: RelineInputMethod with Reline 0.4.1
Completion: Autocomplete, ReplTypeCompletor: 0.1.6, Prism: 0.19.0, RBS: 3.4.0
.irbrc path: C:/Users/ongaeshi/.irbrc
RUBY_PLATFORM: x64-mingw-ucrt
East Asian Ambiguous Width: 1
Code page: 932
=> nil

ReplTypeCompletor による補完を試す

配列の中身が String であることを認識して、ブロック引数の型も理解してくれるのが便利。(l を入力すると Sting のメソッド群がちゃんと出てくる)

Image from Gyazo

配列内に数値と文字列を混合すると Integet と String のメソッド群が両方表示される。(つまり Array<Integer|String> が解析できている?すごい!)

Image from Gyazo

もう一度 TAB を押すとドキュメントも閲覧できる。TAB を押す度に次の候補に移動する。Shift + TAB で前の候補に戻る。

Image from Gyazo

バグ

WindowsPowerShellコマンドプロンプト環境だと Alt+d でドキュメントを拡大したときに操作ができなくなるバグがあるようなのでそこは押さないように注意。

自分が書いたライブラリを読み込む

require のパスも補完される。

Image from Gyazo

ドキュメントや RBS が無くてもメソッド一覧は表示してくれる。

Image from Gyazo

生成したオブジェクトの型もちゃんと追跡できている。

Image from Gyazo

jc.nodes の戻り値は Array<JsonCanvas::Node> なんだけどさすがにここまでは追跡できない模様。(pu を入力したのに push が候補に出ない。) これも RBS 書けば取得できるようになりそう。(rbs-inline)を使って書くのがいいかしら。

Image from Gyazo

まとめ

ReplTypeCompletor による補完を使うと割といいところまで補完してくれることが分かりました。

TAB 押したときに閲覧できるミニドキュメントは閲覧できるし、他の操作はサクサク動いて快適です。irb 内で require したライブラリのメソッド一覧やドキュメントがさっとみられるのも便利。

Image from Gyazo

自分が書いている gem もちゃんと型を記述すれば irb でサクサク補完できるようになりそうなので RBS を書くメリットが分かりやすくなるのがよかったです。(特に各メソッドの戻り値の型だけでも明示しておくとメソッドチェインが途切れなくなってよさそう)。

次は rbs-inline を試してみようと思います。

Ruby で JSONCanvas 形式を読み書きできるライブラリを作りました

json_canvasJSONCanvasは形式のファイルを Ruby で簡単に読み書きできるライブラリです。すでにいくつかの言語のライブラリはあったのですが Ruby 用が無かったので作りました。

インストール方法

json_canvas を使い始めるには、まずアプリケーションのGemfileに以下の行を追加してください。

gem 'json_canvas'

その後、ターミナルで以下のコマンドを実行します。

$ bundle install

もしくは、直接以下のコマンドを使ってインストールすることも可能です。

$ gem install json_canvas

基本的な使い方

JsonCanvasを使用するには、Rubyスクリプト内で以下のようにgemを読み込んでください。

require 'json_canvas'

キャンバスの作成

新しいキャンバスを作成するには、次のコードを使用します。

jc = JsonCanvas.create

テキストノードの追加

キャンバスにテキストノードを追加する方法は以下の通りです。

text_node = jc.add_text(text: "Hi")

テキストノードには、id, 位置, サイズ, 内容, 色などのパラメータをカスタマイズして設定することができます。

custom_text = jc.add_text(id: "unique_id", x: 50, y: 100, width: 200, height: 50, text: "Hello World!", color: "2")

このテキストを後述の save メソッドを使ってファイルに保存してから Obsidian などの対応するアプリケーションで開くと以下のように表示されます。

その他のノードタイプ

ファイルノードやリンクノード、グループノードを特定の属性で追加することもできます。

file_node = jc.add_file(file: "path/to/file")
link_node = jc.add_link(url: "https://example.com")
group_node = jc.add_group(label: "Test Group")

エッジの追加

ノード間をエッジで接続することができます。

jc = JsonCanvas.create
start = jc.add_text(id: "START", text: "start")
goal = jc.add_text(id: "GOAL", x: 400, text: "goal")
jc.add_edge(id: "edge1", fromNode: start.id, toNode: goal.id)
jc.add_edge(id: "edge2", fromNode: start.id, fromSide: "top", fromEnd: "arrow", toNode: goal.id, toSide: "bottom", toEnd: "arrow", color: "2", label: "HELLO")

JSON文字列への変換

作成したキャンバスインスタンスJSON文字列に変換する場合は、to_jsonメソッドを使用します。

jc.to_json  #=> '{"nodes":[{"id":"START","x":0,"y":0,"width":250,"height":60,"type":"text","text":"start"},{"id":"GOAL","x":400,"y":0,"width":250,"height":60,"type":"text","text":"goal"}],"edges":[{"id":"edge1","fromNode":"START","toNode":"GOAL","fromSide":"right","toSide":"left"},{"id":"edge2","fromNode":"START","toNode":"GOAL","fromSide":"top","fromEnd":"arrow","toSide":"bottom","toEnd":"arrow","color":"2","label":"HELLO"}]}'

保存と読み込み

キャンバスをファイルに保存することや、ファイルからキャンバスオブジェクトを読み込むことができます。

# "sample.canvas"ファイルに保存。
jc.save("sample.canvas")

# キャンバスオブジェクトを読み込み。
loaded_canvas = JsonCanvas.parse(File.read("sample.canvas"))

まとめ

Ruby コードからクラス構造を出力したり、複雑なルールに沿ったグラフを自動生成したいときなどはスクリプトから作るのが便利かもしれません。もしくは Obsidian で生成したグラフを読み込んで特定のルールに沿ってノードを整形するなどもよさそうです。是非色々な使い方を考えてみてください。