Runa: Ruby で中規模アプリケーションを書くためのフレームワーク

src: [ブログのおんがえし](https://ongaeshi.hatenablog.com/entry/2023/07/23/113420)

[Runa](https://github.com/ongaeshi/runa) という Ruby で Gem を使ったり複数ファイルで構成された中規模のアプリケーションを簡単に書くためのフレームワークを作っています。

# Runa を作った経緯
- Ruby は単独のスクリプトファイルとして実行するときは取り回しも簡単で大変使いやすい(小規模アプリケーション)
- が、特定の gem に依存したり複数ファイルで構成されるようなアプリケーションを作ろうとするとスタンダードな方法が用意されておらず(特に配布や共有のことを考えると)敷居が高くなってしまう(中規模アプリケーション)
- これが今まで余り問題にならなかったのは、Web アプリであれば Rails を使えばフレームワークがその辺りを内包してくれたり、コンソールアプリケーションなら gem で配布するみたいな方法でやりくりしてきた経緯がある。しかし gem で配布するには RubyGems のアカウントが必要だったり、昨今のセキュリティ問題などを考えると思いつきのアプリケーションを気軽に置くような感じではすでに無くなっている気がする(大規模アプリケーション)
- 私が普段作りたいのは個人的な問題を思い付きで解決したちょっとしたアプリケーションであり配布はレポジトリ作ったから使いたい人はどうぞ位にしたい

そこで普段使いのアプリケーションを気軽に作れるようにするために Runa を作りました。Ruby には Bundler という優れた依存関係管理ツールがすでに存在しており、実際のところ Runa は Bundler のラストワンマイルを埋める薄いラッパーです。

# Runa のインストール
gem でインストールします。`runa`コマンドが使えるようになるので以後はこれを使います。

```
$ gem install runa
```

`runa new アプリケーション名` でプロジェクトを作成します。ディレクトリができるので下に移動します。

```
$ runa new hello
Created 'hello' application.
$ cd hello
```

Gem の追加や複数ファイルのアプリケーション作成に必要なものが自動で追加されています。

```
$ ls
.bundle/
.runa/
lib/
.gitignore
Gemfile
hello.rb
```

`runa run スクリプト名`で実行します。`runa run`で実行すると追加した Gem や lib/ 以下へのパスが通った状態で実行されます。

```
$ runa run .\hello.rb
Hello, world!
```

[Launchy Gem](https://github.com/copiousfreetime/launchy) を追加してみます。Gem の追加には`runa gem_add Gem名`を使います。(`bundle install` した後に `runa install` でも OK)

```
$ runa gem_add launchy
.
.
Installing launchy 2.5.2
Generate '.runa/runa_load_path.rb'
```

これで hello.rb から `require "launchy"` が可能になります。

```ruby
require "hello"
require "launchy"

url = "https://www.ruby-lang.org"
Launchy.open(url)
puts "Hello, #{url}"
```

実行するとブラウザで https://www.ruby-lang.org/ が開けるようになります。

# Runa アプリケーションをデプロイする
ここまでは bundler だけでも頑張ればできると思います。

Runa を使うと作成したスクリプトを起動するための実行ファイル(シェルスクリプト、Windowsならバッチファイル)を簡単に作成することができます。これが一番の特徴です。私はこの起動スクリプトを PATH の通った場所に配置しています。

実行ファイルの作成には `runa deploy` コマンドを使います。(ここでは `../bin` にパスが通っていると仮定しています)

```
$ runa deploy hello.rb ../bin
Generate '.runa/runa_load_path.rb'
Deploy execution script to '../bin/hello.bat'.
```

デプロイしたバッチファイル(もしくはシェルスクリプト)は runa コマンドを経由せずにシェルから実行するができます。(つまり `.exe` と同じ)

```
$ ../bin/hello
$ hello                # (注) PATH が通っていれば
Hello, https://www.ruby-lang.org
(ブラウザ起動)
```

Win+R からも直接実行できます。

![GIF 2023-07-23 11-06-41.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885/a0dd32d4-6785-2091-bd38-3767916edb8e.gif)

# デプロイしたアプリケーションの挙動を変更する
実行用ファイルの実体は元々作った runa レポジトリなので、`hello.rb` を変更すればアプリケーションの挙動を変更することができます。このとき「再デプロイは不要」です。これは gem を追加したときも同様です。

例として hello アプリケーションに [clipboard gem](https://github.com/janlelis/clipboard) を追加して、特定のページを開きつつ URL をクリップボードにコピーしてみます。まずは clipboard gem をインストールします。

```
$ runa gem_add clipboard
.
.
Generate '.runa/runa_load_path.rb'
```

`hello.rb` を書き換えます。

```diff
require "hello"
require "launchy"
+ require "clipboard"

url = "https://www.ruby-lang.org"
Launchy.open(url)
puts "Hello, #{url}"
+ Clipboard.copy(url)
```

再デプロイは不要なのでそのままコマンドラインや Win+R から `hello` を実行します。

```
$ hello
Hello, https://www.ruby-lang.org
(ブラウザ起動＆クリップボードに https://www.ruby-lang.org がコピーされる)
```

再ビルド不要でアプリケーションの挙動を変更することができるのはかなり便利です。

# 他の人の使った Runa アプリケーションを使う
Runa で作られたアプリケーションは他の人の環境でも簡単に動かすことができます。ここでは先ほど作った hello アプリケーションを動かしてみます。

```
$ git clone https://github.com/ongaeshi/hello.git
cd hello
$ runa install
$ runa run hello.rb
```

とても簡単ですね。デプロイも簡単です。

```
$ runa deploy hello.rb /path/to/bin
```

最後に [gosu を使ったゲーム](https://github.com/ongaeshi/minesweeper)を runa で動かして終わりにします。

```
$ git clone https://github.com/ongaeshi/minesweeper.git
cd minesweeper
$ runa install
$ runa run hello.rb
```

![68747470733a2f2f692e6779617a6f2e636f6d2f31363236376164653365393266343464366432346134376330653162653436342e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3885/a7121a94-a819-1199-f9ea-10098a8756f6.png)

# おわりに
私が自分用に作ったものは[ongaeshi/toolbox](https://github.com/ongaeshi/toolbox) に置いてあります。[src2url](https://github.com/ongaeshi/toolbox/blob/master/src2url.rb)とかお気に入りでよく使っています。

みなさんもお気に入りのアプリケーションを runa で作って気軽に公開してください！