ChatGPT に Ruby など他のプログラミング言語も実行させたい

ChatGPT はたくさんの種類のプログラミング言語のコードを出力できますが、直接実行できるのは現状 Python のみとなっています。Ruby など他の言語も実行することはできないかと考えていました。

1つのアイデアとして思いついたのは ChatGPT に生成したコードを Ruby on Browser に渡す URL を生成してもらい、それをクリックするだけで実行できるようにするという方法です。これなら他の言語でも URL 経由で実行できる処理系なら応用できそうです。(現状は ChatGPT 4 でのみ実行可能な模様)

下準備

まず Ruby on Browser に URL 経由でコードを渡す方法を用意する必要があります。もともとクエリーパラメータ q= で渡せるのですが、文字数を短くするために lz-string という Javascript のライブラリを使っておりそのエンコーディングPython 標準では提供されていないためパラメータ文字列が生成できないためです。そのためにシンプルな URL エンコーディンでコードを渡すことができる q2= を新規に用意することにしました。

github.com

これで準備は完了です。

プロンプト

色々調整して ChatGPT に渡すプロンプトはこんな感じになりました。◯◯◯の箇所を生成して欲しいスクリプト種類に変更して使います。

◯◯◯ Rubyスクリプトを作成してください。
このRubyスクリプトをrubyonbrowser上で実行させたいです。

- URL は https://rubyonbrowser.ongaeshi.me/
- 後ろにクエリ文字列 ?q2=
- コードテキストを URLエンコーディングした文字列を q2 のパラメータに設定

コードと生成したURLへのリンクの順に一回で出力してください。

実行例1: 文字列を大文字に変換する

あなた

文字列を大文字に変換するRubyスクリプトを作成してください。 このRubyスクリプトをrubyonbrowser上で実行させたいです。

コードと生成したURLへのリンクの順に一回で出力してください。

ChatGPT

以下に、文字列を大文字に変換するRubyスクリプトと、それを実行するためのrubyonbrowserへのリンクを提供します。

Rubyスクリプト:

puts gets.chomp.upcase

生成したURL: https://rubyonbrowser.ongaeshi.me/?q2=puts+gets.chomp.upcase

感想

実際の実行はモバイル上から行っており、リンクを生成することで特にモバイルからだと確認しやすくなります。Ruby on Browser で実行することで、コードをちょっと修正できるのも嬉しいですね。


www.youtube.com

実行例2: Hash#dig のサンプルコードを出力させる

あなた

Hash#dig の使い方を初心者プログラマに説明するRubyスクリプトを作成してください。 このRubyスクリプトをrubyonbrowser上で実行させたいです。

コードと生成したURLへのリンクの順に一回で出力してください。

ChatGPT

RubyHash#digメソッドは、ネストされたハッシュから安全に値を取得するために使用されます。例えば、あるハッシュが複数の階層を持っている場合、digメソッドを使って特定のキーの経路に沿って値を取得できます。もし指定したキーのいずれかが存在しない場合、nilが返されます。

初心者の方に向けた説明用のRubyスクリプトを以下に示します。このスクリプトでは、簡単なハッシュを作成し、digメソッドを使用して値を取得します。

# ネストされたハッシュの例
user_data = {
  name: "Alice",
  contact: {
    email: "alice@example.com",
    phone: {
      home: "123-456-7890",
      mobile: "987-654-3210"
    }
  }
}

# 'dig' メソッドを使用して、モバイル電話番号を取得
mobile_phone = user_data.dig(:contact, :phone, :mobile)

# 結果を出力
puts "Mobile phone number: #{mobile_phone}"

このスクリプトをRubyOnBrowserで実行するためのURLは以下の通りです。

実行用URL

感想

実行すると "987-654-3210" が返ってきました。引数を (:contact, :phone, :home) に変更すると "123-456-7890" になりました。途中のパラメータ名が間違っていても例外にならず nil で返ってくるのが便利なのだと理解できました。サンプルデータも含めてコードを作成してくれるのがありがたいです。

実行例3: 未知のアルゴリズムを教えてもらう

あなた

レーベンシュタイン距離を求めるRubyスクリプトを作成してください。 このRubyスクリプトをrubyonbrowser上で実行させたいです。

コードと生成したURLへのリンクの順に一回で出力してください。

ChatGPT

レーベンシュタイン距離を計算するためのRubyスクリプトと、そのスクリプトRuby on Browserで実行するためのURLを生成しました。

Rubyスクリプトは以下の通りです。

def levenshtein_distance(s, t)
  m = s.length
  n = t.length
  return m if n == 0
  return n if m == 0
  d = Array.new(m+1) {Array.new(n+1)}

  (0..m).each {|i| d[i][0] = i}
  (0..n).each {|j| d[0][j] = j}

  (1..n).each do |j|
    (1..m).each do |i|
      cost = (s[i-1] == t[j-1]) ? 0 : 1
      d[i][j] = [d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1] + cost].min
    end
  end
  d[m][n]
end

# 使用例
puts levenshtein_distance("kitten", "sitting")

このスクリプトRuby on Browserで実行するためのURLは以下のリンクからアクセスできます:Ruby on Browserでスクリプトを実行する.

感想

git のコマンドのスペルミスがあったときに近いコマンドを提示してくれるアルゴリズムが確かこんな名前だったという記憶だけで聞いてみました。ハルシネーションが怖いですが試した感じ正しく動いていそうな感じでした。実際に使いたいときはこれをベースに挙動を理解するとこから始めるもよさそうです。(そして調べたら git ではそれよりも少し複雑なダメラウ・レーベンシュタイン距離 を使っているそう)

実行例4: ゲームを作ってもらう

あなた

シンプルなゲームができるRubyスクリプトを作成してください。 このRubyスクリプトをrubyonbrowser上で実行させたいです。

ChatGPT

わかりました。シンプルなRubyスクリプトを作成して、それをrubyonbrowser上で実行するためのURLを生成します。ゲームの内容について、どのようなものを希望されますか?例えば、「数当てゲーム」や「じゃんけんゲーム」など、基本的なものであれば実装可能です。

あなた

数当てゲーム

ChatGPT

数当てゲームのRubyスクリプトを作成します。このゲームでは、コンピュータが1から100の間でランダムに数を選び、ユーザーがその数を当てるまで推測を続けます。ユーザーが数を入力すると、コンピュータはその数が正解より高いか低いかを教えます。正解を当てるとゲームが終了します。

数当てゲームのRubyスクリプトをURLエンコーディングしました。以下のURLを使用してrubyonbrowserでゲームを実行できます。

https://rubyonbrowser.ongaeshi.me/?q2=

リンクをクリックすると、ゲームが開始されます。楽しんでください!

あなた

gets が使えないのでコンピュータが自動で入力するような方式にできますか?

ChatGPT

了解しました。getsを使用しないで、コンピュータが自動で数を推測する方式に変更します。この場合、コンピュータは一定のルールに基づいて数を推測し、それに応じて次の推測を行います。

コンピュータが自動で数を推測する方式の数当てゲームのRubyスクリプトをURLエンコーディングしました。以下のURLを使用してrubyonbrowserでゲームを実行できます。

https://rubyonbrowser.ongaeshi.me/?q2=

リンクをクリックすると、ゲームが開始されます。楽しんでください!

感想

最後は簡単なゲームを作ってもらいました。答える側の AI 部分もこちらが要求すれば作ってくれるのはすごいですね。

まとめ

プロンプト側に URL も含めて生成させておくと後からチャットログを再確認するときや、今回のようにブログに貼り付けるときにすぐに確認できるので結構便利です。その場でコードを変更して確認できるのもよいです。是非みなさんも色々な Ruby コードを生成させて実行してみてください。

Obsidian で情報カードを作るための 5 ステップ

Obsidian では普段デイリーノートを中心にメモを取っていますが、それらの情報を元に、より密度の高い情報カードを作りたくなることがあります。作成したカードを元にブログや SNS に記事を投稿します。

今日は私がどのように情報を整理しているかをシェアしたいと思います。これらの小さなテクニックを使えば、あなたの情報管理も簡単で効果的になるはずです。

1. 置き場所は1箇所にまとめる

情報カードはObsidian内の05_Cardフォルダに保存します(私はルートフォルダに数字を振っているためこうなっていますが具体的な名前はお好みで)。ここにカードを保管することで、全てが一箇所に整理されて、簡単にアクセスできます。パスが分かっていれば後から検索できるのでタグは付けません。

2. ファイル作成方法の統一

Obsidian のファイルエクスプローラーを使用して05_Cardフォルダ内で直接ファイルを作成します。最初は「無題のファイル」として作成し、内容が完成したらタイトルを付けます。大抵、文書の最初の行がそのまま適切なタイトルになります。

3. カードの書き方

各カードは、それ自体で理解可能な形式で書かれるべきです。これにより、カードは独立したメモとして、そのまま他の文脈にも使用できます。

4. 効果的な検索方法

次のクエリを使用して、05_Cardフォルダ内のカードを簡単に検索できます。

path:05_Card/ 検索ワード

5. 画像の管理

画像はGyazoにアップロードしてリンクを使うことをお勧めします。これにより、Obsidian レポジトリの肥大化とカードを他の場所に使用した際にリンクが切れることはありません。thumb/解像度.jpgを付けると画像サイズも簡単に変更できます。

![](https://gyazo.com/19240602e2eb34a3989f8040b26f7d9a/thumb/640.jpg)

これらの簡単なステップを実践することで、Obsidianを使った情報管理がぐっと楽になります。整理された情報は、より良いアイデアと生産性の向上につながります。ぜひ試してみてください!

ChatGPT Plus に入った

しばらく Waiting List に入っていたが使えるようになったと連絡が来た。 Apple Pay からも支払いができるのが便利。

Plus だと DALL·E 3 をアプリから実行できるのでプロンプトが試しやすい。アセット画像を自動生成するスクリプトの研究が捗る。

Use pixel art to represent the background in a 'christmas' themed game as 'Sea at night'. 16x9. Use larger pixel dots. Color scheme that does not interfere with game play. Since it is the background, lower the contrast.

楽しい。

英語のハノン初級が終わったら英語の本が読めるようになった

英語のハノン初級を終わらせた。評判通り大変だったが英語力の向上を大きく感じることができた。次は英語のハノン中級にチャレンジしてみようと思っているが、このタイミングでやり方のコツなどを一度メモしておく。

音声は PC から iTune 経由で iPhone のミュージックアプリに入れる。必ず入れる。面倒だけどリスニング&スピーキングをやらないと効果が半減するので頑張る。Unit 毎にプレイリストを作成して、1つの Unit をマスターするまで繰り返し再生できるようにする。プレイリスト作成は iPhone からできるので後からやればOK。

習慣付けしやすい時間帯を狙って毎日決まった時間に少しずつやる。1回にかける時間は5分〜15分位。長丁場になるので短くても毎日やれるようにした方がよい気がする。自分は会社に行く前、朝ご飯を食べた後でやってた。1つの Unit を1週間で1周できる位のペース。出勤前にやる習慣付けをすると土日はやらなくなるのがネックではある(それはそれで適度に休憩になってよかったのかもしれない)。

記録を付ける。Obsidian に日付とやった Unit をその日に印象に残ったことをメモ。 メモを読み返すと全部の Unit をやるのに半年位かかっていた。

気になるフレーズは暗記アプリに入れる。自分は reminDO というやつを使っていてその日の中で1番聞き取れなかった問題を追加していく。追加さえすれば記憶を固着させるタイミングで勝手に通知を出してくれるので便利。

効果について。自分はとにかくリーディングが1番必要で英語のハノンは基本ヒアリングとスピーキングなのだが、不思議なもので(そういうものなのだろうけど)継続することでリーディング力も向上していった。英語のツイートや Wikipedia を辿るのに抵抗感は大分無くなったし、長めの技術書を読むのも苦では無くなってきた。先日は Polished Ruby Programming (日本語版: 研鑽Rubyプログラミング) を読み終えることができ、今は Grokking Functional Programming (日本語版: なっとく!関数型プログラミング) を読んでいる。

まとめとしては、面倒だけどちゃんと音声をミュージックアプリに入れてプレイリストを作って毎日少しずつやりましょうという話になります。当初は PC 経由するのが面倒で iCloud に mp3 置いて直接再生でやってたりしていたけど、ある程度再生機能が充実していないとやりにくいので最初に頑張って iTune を PC にインストールしましょう。

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

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 を追加してみます。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" が可能になります。

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 からも直接実行できます。

デプロイしたアプリケーションの挙動を変更する

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

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

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

hello.rb を書き換えます。

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 を使ったゲームを runa で動かして終わりにします。

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

おわりに

私が自分用に作ったものはongaeshi/toolbox に置いてあります。src2urlとかお気に入りでよく使っています。

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

Polished Ruby Programming を読んでいる(2)

前回から継続してコツコツ読んでいる。 Chapter4 から先に読んだので、そこから逆戻りして Chapter 1, 2, 3, 5 ... の順に進めている。アラカルトに気になったところをメモ。

Chapter3: 変数

  • 変数名の長さはスコープの広さと反比例させる
    • メソッドの場合は呼び出し回数と反比例させる
    • Ruby に限らずどの言語でも有用な法則
  • 定数の内部実装は変数
    • 値の変更も禁止されていない
    • 警告が出るだけ
  • クラス変数は使ってはいけない。
    • 親子関係のあるクラスやモジュール間で簡単に上書きできてしまうため
    • 代用方法1: 定数を使う(値を変更したときに警告が出るのには目をつぶる)
    • 代用方法2: クラスインスタンス変数を defined?再帰的にルックアップする方法
    • 代用方法3: クラスインスタンス変数を inherited で生成時にサブクラスにコピーする方法
    • クラス変数微妙に使いにくくていつ使うんだろう?と思っていたので「使わないほうがよい」と書いてあってすっきりした
    • 代用方法がたくさんあるのが Ruby のメタ的な柔軟性の勉強になって面白い
  • グローバル変数も使わない方がよい
    • 代用方法1: 定数+instance_eval
    • 代用方法2: シングルトンクラスで置き換えられる
    • メソッドコールのコストをどうしても払いたくない限は代用方法で書くのがよさそう
    • シングルトンクラスの方法しか知らなかったけど、instance_eval はなんか恰好よいのでどこかで使ってみたい

Chapter5: 例外

※ まだ途中

  • hash#[] のキーが見つからないとき Ruby だと nil を返して Python は例外を返す
  • それぞれ逆をするために fetch(Rubyで例外出す) と get(Pythonでデフォルト値返す) が用意されている
  • この辺り言語の特徴を表していて大変面白い

おわり

第1部までは頑張って原著で読んで、その後は研鑽Rubyプログラミングの pdf で読む予定。

ruremai gem を Ruby3 でも動くようにした

ruremai は irb から簡単に日本語リファレンスマニュアル(るりま)を開く便利ツール。

$ gem install ruremai

こんな感じで使う。

irb> require "ruremai"
irb> "".method(:concat).rurema!    # String#<< のリファレンスを開く
irb> [].mean?.join                 # Array#join のリファレンスを開く

Ruby3 で動かなかったので手元で修正して PR を出した。

https://github.com/ongaeshi/ruremai/tree/feature/support-ruby3

取り込まれれば本体 gem でも使えるようになる。 それまでは Gemfile に

gem 'ruremai', github: "ongaeshi/ruremai", branch: "feature/support-ruby3"

と書けば使える。