アプリ制作、インストール、テスト

2023/10/29 追記:この記事は新しく書き直しました。 古い記事で使っていたGitHubのCalcが大幅にアップデートされたためです。 そこで、この記事に合うようなプログラムsimple_calcを新たに作りました。 このプログラムは本レポジトリ_example/simple_calcにあります。

ファイル名で起動する方法

Rubyプログラムは

$ ruby ファイル名

で起動できるのですが、「ruby」と入力するのは煩わしいものです。 アプリ作成中は仕方がないとしても、完成したアプリはファイル名だけで起動したいですね。 それを実現するには、次の3行をファイル名の先頭に付けます。 この方法はRubyのドキュメントで紹介されています。

#!/bin/sh
exec ruby -x "$0" "$@"
#!ruby

お呪いのようなものだと考えて、コピペしても構いません。 一応説明すると、まず1行目の#!はシバン(shebang)と呼ばれ、Unix系のOSではそのスクリプトを実行するプログラムを指定します。 この場合は「/bin/shによってこのファイルを実行する」のですから、シェルスクリプトとしての実行になります。 (/bin/bashではなく/bin/shとなっているのは、システムによってはbash以外のシェルが使われているかもしれないからです。 /bin/shはいろいろなシェル共通の呼び出しを提供します)。

2行目はシェルのコマンドで、execはそのシェルのプロセスで(新規プロセスを生成せずに)コマンドを実行する、というものです。 $0は起動されたファイル名(スクリプトファイルのファイル名)、$@は引数すべてを表します。 これから、もしこのスクリプトファイルのファイル名がabcでコマンドラインから次のように呼ばれたとすると、

abc file1 file2

まず、/bin/sh/が起動され、2行目が実行されます。 2行目は

ruby -x abc file1 file2

とコマンドラインから入力するのとほぼ同じことになります。

-xはrubyのオプションで、「スクリプトを読み込む時に、`#!’で始まり, “ruby”という文字列を含む行までを読み飛ばす」というものです。 このことにより、最初の3行(#!/bin/sh〜#!ruby)が読み飛ばされ、4行目からrubyプログラムが実行されます。

Unix系OSのシバングは指定されたファイルを実行するので、

#!/usr/bin/ruby

でも良いように思われますが、これだとまずい場合もあります。 最もありそうなケースはrbenvでインストールしたrubyです。 rubyは$HOME/.rbenv以下に保存されるので、/usr/bin/rubyでは呼び出せません。 ($HOMEはユーザのホームディレクトリで、シェルからは~でも参照できます)。 このrubyはシェルから呼ぶことにより起動できるので、いったんシェルを起動してからrubyを起動する、という面倒なやり方が必要なのです。

以上の説明でたいていは良いのですが、Gem(Rubyのライブラリ)の実行プログラムでは上手く動かない場合があります。 その場合は次のようにします。

#!/usr/bin/env ruby

この方法が最も良いかもしれません。

コマンドへの引数の処理

Unix系OSではコマンドラインの構成が

コマンド 引数1 引数2 ・・・・

となっています。 Rubyでは、引数はARGVという配列に代入されます。 例えば

$ ruby_echo Hello world

とコマンドruby_echo(これはRubyスクリプトだとします)が呼ばれたとき、

  • ARGV[0]には文字列”Hello”が代入されている
  • ARGV[1]には文字列”world”が代入されている

となります。 コマンドラインでは半角空白が引数の区切り文字になります。 区切り文字はARGVの中には入りません。 もし、空白も入れたいというときには、シングルクォートを用います。

$ruby_echo 'Hello world'

この場合はARGV[0]に文字列”Hello world”が代入されます。 引数は1個ということになります。

引数が何個あるかは配列の要素の数を返すメソッドsizeを使います。 ARGV.sizeが引数の数です。

ruby_echoのプログラムは簡単です。

#!/usr/bin/env ruby

print ARGV.join(' '), "\n"

配列ARGVの各要素をjoinメソッドで繋げて文字列にします。 そのとき要素の区切りには、引数’ ‘(半角空白)が用いられます。

プログラム

コマンドの例として、電卓プログラムsimple_calc.rbを考えてみましょう。 このプログラムは引数に与えられた式を計算して答を表示します。 例えば1+2*3を引数に与えると7を表示します。

$ ruby simple_calc.rb 1+2*3
7.0
$

このとき、注意すべき点が3つあります。

  • 掛け算の記号(xの形の記号)がないので、アスタリスク*を使う
  • 式がスペースを含む場合は式全体をシングルクォートで囲む。なぜなら、空白はshellが引数の区切りと判断してしまうから
  • 数字をIntegerをFloatに変換してから計算し、答えもFloatで表示される。そのため、7ではなく7.0となる

このプログラムではs_calcというRubygemsのGemを使います。 事前にGemをインストールする必要があります。 それにはgemコマンドを使います。

$ gem install s_calc

プログラム中でこのGemをrequireするときはcalcです。 s_calcではないことに注意して下さい。

このGemの使い方はかんたんです。

  • Calcクラスのインスタンスを生成する
  • そのインスタンスのメソッドrunを引数付きで呼び出す。引数は評価したい数式の文字列。メソッドの返り値がその計算結果になる

プログラムは次のようになります。

#!/usr/bin/env ruby

require 'calc'

if ARGV.size != 1
  print "Usage: simple_calc expression\n"
  print "Example: simple_calc 1+2*3\n"
else
  c = Calc.new
  print "#{c.run(ARGV[0])}\n"
end
  • 1行目はこのスクリプトがその名前で直接shellから呼ばれたときに起動するアプリがRubyであることを示す。いわゆるシバン(Shebang)
  • 3行目でCalc名のGemを取り込む
  • if文以下は、引数が1つでなければ使い方を表示、1つならば引数を計算して答えを表示

インストーラ

このプログラムをコマンド名simple_calcでインストールしたいとします。 その場合はディレクトリ$HOME/.local/bin以下にファイルを置き、実行属性をつければよいのです。 もし$HOME/.local/binがない場合は、あらかじめ作成しておきます。 FileUtilsモジュールを使うのが便利です。

require 'fileutils'
include FileUtils

cp __dir__ + "/simple_calc.rb", "#{Dir.home}/.local/bin/simple_calc"
chmod 0755, "#{Dir.home}/.local/bin/simple_calc"
  • __dir__はそのファイル自身の置かれているディレクトリの絶対パスを返す
  • Dir.homeはユーザのホームディレクトリ($HOMEと同じ)を返すメソッド
  • cpFileUtilsモジュールのメソッドで、ファイルをコピーする。
  • chmodFileUtilsモジュールのメソッドでファイルの属性を指定する。 0755は8進整数を表す。このファイル属性は
    • 所有者は読み、書き、実行可
    • グループメンバーは読み、実行可で、書き込不可
    • その他ユーザは読み、実行可で、書き込不可 となる

実行属性をつけないと、ファイル名での起動はできません。 以上のようにインストールするとコマンドラインから

$ simple_calc

で起動できるようになります。

なお、ユーザ用のコマンドのディレクトリ名は$HOME/binでも大丈夫です。

アプリケーションを作るときには、インストーラも作っておきましょう。 また、アンインストーラ(インストーラに含め、オプションで切り替えても良い)も入れておくと良いです。 アンインストールは、単に$HOME/.local/bin/simple_calcを削除するだけなので、プログラムは簡単です。

File.delete("#{Dir.home}/.local/bin/simple_calc")

これまでのプログラムは、レポジトリ_exampleフォルダに次の名前で保存されています。

  • simple_calc.rb
  • simple_calc_installer.rb
  • simple_calc_uninstaller.rb

上記ではユーザ領域へのインストールでしたが、他のLinuxユーザにも使えるようにするには/usr/local/binにインストールします。 このときは管理者権限が必要なので、Ubuntuなどではsuコマンドを使います。 例えば

$ su ruby simple_calc_installer.rb

のように起動します。

しかし、Linuxを共用で使っておりかつそのプログラムが実用性の高いものでない限り、システム領域にインストールする必要はありません。

テスト

Rubyの標準のテスト・スートはminitestです。 名前はミニですが、結構大きいプログラムで、ドキュメントの量もあります。 minitestは別の記事で詳しく述べようと思いますが、ここではポイントを絞って書きたいと思います。

テストプログラムはRubyで書きます。 ここでは、テストプログラムはsimple_calcと同じフォルダにあるものとします。

simple_calcのテストは、例えば次のようになります。

require 'minitest/autorun'

class TestSimpleCalc < Minitest::Test
  def test_simple_calc
    assert_equal("100.0\n", `ruby simple_calc.rb 10*10`)
  end
end
  • minitesti/autorunをrequireで取り込む
  • テスト用のクラス(ここではTestSimpleCalcという名前になっている)をMinitest::Testのサブクラスとして定義する
  • テスト用のメソッドにはtest_というプレフィックスをつける
  • assert_equial A, B は「Aが正常に機能したときの結果のオブジェクト」「Bが実行結果のオブジェクト」で、それらが一致すればテストを通過したことになり、一致しないとメッセージが出力される。 前者をexpected(期待される結果)、後者をactual(実際に行った結果)としてメッセージに書き込まれる
  • `ruby simple_calc.rb 10*10`はKernelモジュールが定義するメソッドで、バックティック内の文字列を外部コマンドとして実行し、その結果を返す

今回は、カレントディレクトリをテストプログラムのディレクトリに移してから実行します。 テストを実行すると次のように出力されます。

$ ruby test_simple_calc.rb
Run options: --seed 3936

# Running:

.

Finished in 0.106165s, 9.4193 runs/s, 9.4193 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
$ 

ドットはテスト項目、つまりTestSimpleCalcの各テスト・メソッドを表しています。 上記はテストが成功したときの表示です。

テストが失敗するときは、例えば次のようなメッセージが出力されます。

$ ruby test_simple_calc.rb
Run options: --seed 37133

# Running:

F

Finished in 0.106931s, 9.3518 runs/s, 9.3518 assertions/s.

  1) Failure:
TestSimpleCalc#test_simple_calc [test_simple_calc.rb:5]:
--- expected
+++ actual
@@ -1,2 +1,2 @@
-"100.0
+"1000.0
 "


1 runs, 1 assertions, 1 failures, 0 errors, 0 skips

Failureはテストで失敗したことを示しています。 ここでは100.0を期待していたのに実際は1000.0が返されたという失敗です。

この他にErrorが出ることがありますが、それはプログラムを実行した時にエラーがあったことを意味しており、テストの結果ではありません。

すべての場合をテストするのは無理なので、典型的な例をテストすることになります。 プログラムのエラーは境界で起こりやすいです。 例えば正負が問題になるプログラムでは0が境界です。 「(変数)>= 0」を使わなければいけないのに「(変数)> 0」を使うといったバグは0以外ではフェイル(失敗)が起こりません。 ですから「境界をテストする」ことは非常に重要です。

minitestについては、別の記事がありますので、参考にしてください。

Readme.md

簡単なドキュメントは付けておくべきです。 仮に公開しなくても、将来自分自身が見直す時に役に立ちます。 2週間、別の仕事をすると、元の仕事内容を思い出すのに結構な時間がかかります。 そのときにドキュメントは役に立つでしょう。

GitHubに公開する場合はReadme.mdのようなファイル名をつけることになっています。 拡張子のmdはMarkdown形式を表します。 Markdownはhtmlと比べ格段に見やすく、書きやすいので勧められる形式です。 Markdownの説明は、次の記事を参考にしてください。

はてなブログのMarkdown徹底解説

ただし、はてな独自の記法(はてな記法など)はGitHubでは使えません(GitHubのMarkdownはGFM)。

GitとGitHub

プログラムを公開するならばGitHubは無料で、機能が充実していて、有力な選択肢です。 GitHubとGitについては「はじめてのJekyll+GitHub Pages」の中に書かれていますので、以下を参考にしてください。

はじめてのJekyll + GitHub Pages

  • 第3章 GitHub pagesクイックスタート
  • 第7章 Gitの使い方
  • 第10章 GitをSSHで使う方法

が参考になります。 このうち第10章のSSHで使う方法は知らなくても大丈夫です。

今回はアプリ開発の実際を見てきましたが、いかがだったでしょうか。 簡単なアプリで良いのでぜひ作ってGitHubにあげてみてください。 作れば作るほどプログラミングのレベルは上がります。

2023

単項マイナスと構文解析

1 minute read

単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合

Raccライブラリと構文解析

3 minute read

パーサ・ジェネレータとは 少し複雑な文法 四則(加減乗除)計算のBNF Racc で実装 クラス定義、BNFの記述部分 ヘッダー、インナー、フッター コンパイルと実行 演算子の優先順位と結合における左右の優先順位 まとめ

StrScanライブラリと字句解析

less than 1 minute read

StrScanライブラリのドキュメント 字句解析とは StrScanライブラリ StrScanライブラリを使った字句解析 実例

Gem

1 minute read

lbtというgemを作って公開してみた lbtはどんなgemか ファイルの配置 lbt.gemspec Rakefile gemのビルド RubyGems.orgへのアップロード 補足・・rake/gempackagetaskサブライブラリについて

Encoding

1 minute read

文字列のエンコーディングに頭を悩ませることはほとんどなくなりました。 なぜなら、どのアプリ、システムもUTF-8を使うようになったからです。 Rubyでもエンコーディングの問題が起こることはまず無いでしょう。 ですが、今回はエンコーディングの考え方を整理してみたいと思います。

Thread

less than 1 minute read

Fiberを書いたときから、次はスレッドを書こうと思っていましたが、時間がかかってしまいました。 その理由は、期待したとおりのスレッドの効果がなかったためです。 今回はそのことを書きますが、これはRubyのスレッドの抱えている問題なのか、自分のやり方が悪いのかははっきりしていません。

Fiber

1 minute read

Fiberは「ノンプリエンプティブな軽量スレッド」とRubyのマニュアルに記載されています。

RDoc

less than 1 minute read

今回はRubyプログラムから自動的にドキュメントを作成するRDocについて書きたいと思います。 私はこのことについて、エキスパートではありません。 この記事も、初心者の体験談だと考えてください。

Back to Top ↑

2022

Ruby/GTK4

5 minute read

Ruby/Gtkの記事を先日書いたときに、「これはかなり使える」という手応えを感じたので、WordBook(Railsで作った単語帳プログラム)のGTK 4版を作りました。 プログラムは「徒然なるままにRuby」のGitHubレポジトリに置いてあります。 レポジトリをダウンロードし、ディレクトリ_example/...

Shoes – Rubyとグラフィック

5 minute read

Rubyはグラフィックについて弱い印象があります。 しかし、グラフィックはデバイスに関することなので、言語そのものには直接の関係はないはずで、あるとすればライブラリです。 今後グラフィック関係のgemが開発されることに期待しましょう。

Rails7 テスト

5 minute read

前回作ったWordbook(リソースフル)のテストを書いてみます。 RailsのテストはminitestをRails用に拡張したものです。

Rails7 モデルとデータベース

2 minute read

今回はRailsにおけるデータの作成と保存、そして変更について説明します。 そのベースになるモデルとデータベースの話から始め、appendとchangeの動作について詳しく説明します。

Rails7とBootstrap

2 minute read

一般に、HTMLは文書の構造を表し、CSSはその体裁(見栄え)を表します。 Railsは最終的にCSSを含むHTML文書を出力するので、この2つについての理解が必須です。 この記事ではとくにCSSの人気ライブラリであるBootstrapを紹介します。 BootstrapはJavascriptも含んでいます。

Rails7のインストール

2 minute read

Rubyの最も人気のあるアプリケーションであるRuby on Railsを取り上げようと思い、書き始めました。 予想してはいましたが、相当な分量になってしまいました。 そのため、何回かに分けて記事にすることにします。 また、対象となる読者のレベルをどうしようかと考えましたが、「徒然Ruby」が基礎的な内容から始ま...

GemとBundler

1 minute read

Rubyのライブラリ管理システムのRubygemsとコマンドgemおよびbundlerについて説明します。

minitest(3)モックの詳細

2 minute read

minitestについて連続して2回書いてきました。 「minitestはドキュメントが少ない」という人がいますが、私も同感です。 例えば、モックとスタブの説明も少ないです。 そこで、今回はmock.rbのソースコードを参考に、モックの私的ドキュメントを書いてみました。 あくまで私個人の考えであり、minites...

minitest(1)テストとは

2 minute read

アプリ作成の記事でminitestを使いました。 今回はminitestについて、また一般にテストについて、私の考えを書こうと思います。

public、private、protected

2 minute read

今回はメソッドの呼び出し制限ついて説明します。 呼び出し制限にはpublic、private、protectedの3つがあります。

アプリ制作、インストール、テスト

1 minute read

2023/10/29 追記:この記事は新しく書き直しました。 古い記事で使っていたGitHubのCalcが大幅にアップデートされたためです。 そこで、この記事に合うようなプログラムsimple_calcを新たに作りました。 このプログラムは本レポジトリの_example/simple_calcにあります。

case文

2 minute read

if〜elsif〜・・・〜else〜endは皆さん良く使うでしょうか? これは場合分けで良く使われる方法です。 これと同様の制御構造にcase文があります。 Cのswitch文に似ていますが、より強力な機能を持っています。 if-else-endよりも高い能力があるといえます。

Lambda

2 minute read

Procオブジェクトを生成するメソッドlambdaについて説明します。

Proc オブジェクト

2 minute read

今回はブロックを一般化したオブジェクトProcを説明します。

モジュール

1 minute read

モジュールには名前空間とミックスイン(Mix-in)の2つの機能があります。 ここではミックスインについて説明します。

Kernelモジュール

less than 1 minute read

Kernelモジュールのメソッドはどこでも使うことができます。 そのメソッドの中には便利で有用なものが多いです。

便利なメソッド

1 minute read

ここでは私が便利だと思ったメソッドを紹介します。

文字列と正規表現

3 minute read

文字列は最も使うオブジェクトのひとつです。 特にウェブ・アプリケーションでは、コンテンツだけでなくHTMLのタグやCSSを含めすべてが文字列です。 Rubyは文字列オブジェクトのメソッドが充実しており、またパターンマッチのための正規表現も充実しています。

配列

2 minute read

配列は、どのプログラミング言語にもあると思います。 複数の要素を一括して扱うことができるのが配列です。 Rubyの配列はメソッドが充実しているので、プログラムを効率的、機能的に書くのに役立ちます。

トップレベルのメソッド

1 minute read

今回はメソッド定義です。 メソッド定義はRubyの核心ですが、今回はトップレベルに限って説明します。 この限定によって、内容はかなり易しくなっています。

ブロックとイテレータ

less than 1 minute read

ブロックはRubyの特長です。 ブロックのおかげで記述が非常にすっきりと分かりやすくなります。 今回はブロックをイテレータの本体として使う方法を説明します。

整数

less than 1 minute read

ここではRubyの最も基本的なオブジェクトである整数について説明します。

Hello world

less than 1 minute read

「徒然なるままに」をネットで調べてみると、「することもなく、手持無沙汰なのにまかせてという意味」とありました。 まさに、自分の現状を言い当てた言葉。 しかも、ブログに書くネタもなかなか思いつかない日々。

Back to Top ↑