Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

RubyとCursesを使ったコンソールテキストエディタ

作って覚えるRuby再入門(第2回)

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/02/13 12:00

ダウンロード ソースコード (6.1 KB)

連載第二回目です。今回も引き続きRubyとCursesを使ったコンソールプログラムを作っていきます。例題としてテキストエディタを2回に渡って取り上げます。この例題を作っていくことで、引き続きRubyの勘所と親近感を養ってもらえるとうれしいです。

目次

対象読者

  1. Rubyの入門書を一読した方
  2. 練習用にRubyのプログラムを作りたいが良い課題が見つからない方

必要なもの

  • Ruby本体とお好きなエディタを用意してください。
  • 筆者は以下の環境で執筆しています。
  • ruby 1.8.6-p111 / SAKURAエディタ / WindowsXP SP2

今回作る物

 例題として作っていきたいのはテキストエディタです。

 テキストエディタといってもいろいろありますが、次のような感じのものを作りたいと思います。

  1. コンソールアプリケーション(もちろんですね)
  2. ごくごく基本的な機能のみを実装
  3. Viのようなモードを持つ

 モードというのはコマンドモードや追加モード、挿入モードなどの事で、それらを切り替えながらテキストファイルを編集していく事になります。昨今のUIデザインではこのようなモードを持つのはよくないデザインと考えられています。しかしモードを持つソフトウェアの代表ともいえるViは根強い人気を持ちますので、(慣れてしまえば)それほど悪くはないのかなと思います。

 完成時の画面イメージは次のようになります。

完成イメージ
完成イメージ
  • 編集エリアは、開いたテキストファイルを表示し編集するエリアです。
  • 情報表示エリアは、現在のモードなどを表示する(予定の)エリアです。
  • そのほかに現在開いているファイル名を画面中央に表示します。

 このテキストエディタの名前ですが、FileEditを略してFeとしましょう。名前を決めておくのは(主にモチベーションの面で)けっこう重要です。:)

クラス構成

 クラスの構成を下図のようにしようと思います。矢印は呼び出し関係を表します。

クラス構成
クラス構成

 メインクラスの名前は、そのままアプリケーションの名前でFeとします。それ以外のクラスは順次、この記事の中で説明していきます。

まずは見えるところから作る

 プログラムを作るときは、動いていることを視覚的に確認しながら進めるとモチベーションも上がりますし、進めている方向が正しい事が分かって安心もできます。まずは見えるところから作っていく事にしましょう。

 最初はメインクラスから作ります。

 Feは起動時に編集するファイル名を受け取ることにしたいので、コマンドラインから引数を一つ受け取ります。受け取れなかった場合は使用方法を表示してプログラムを終了します。

 お決まりのinit_screenを呼び出してコンソール画面を初期化しCursesを使えるようにします。続く2行は設定です。cbreakはキーボード入力のバッファリングを停止し、noechoで入力に対するエコー表示を停止します。コンソールアプリケーションを作成する場合は大抵はこの設定になると思います。

 あとは前述の画面構成となるようにサブウィンドウを二つとファイル名の表示を行い、テキストファイルを開いて最初の数十行(サブウィンドウの行数分)を表示します。

 後半はほとんど別クラスに処理を任せていますが流れだけ押さえておいてください。

fe.rb
require "curses"
require "editwind"
require "commandwind"
#ファイル名をコマンドライン引数として受け取る
if ARGV.size != 1
  #コマンドライン引数がない場合
  printf("usage: fe file_name\n");
  exit
else
  file_name = ARGV[0]
end
#コンソール画面を初期化し設定を行う
Curses.init_screen
Curses.cbreak
Curses.noecho
# デフォルトウィンドウを取得
defo_wind = Curses.stdscr
# 編集エリアウィンドウを作成
edit_wind = EditWind.new(defo_wind)
# 情報表示エリアウィンドウを作成
cmmd_wind = CommandWind.new(defo_wind,file_name)

# ファイルをオープンし内容を編集エリアに表示する
edit_wind.display(file_name)
# すぐ消えるのを防ぐために入力待ちとする
edit_wind.getch

#コンソール画面を終了
Curses.close_screen

 さて次は編集エリアウィンドウのクラスです。

 これはテキストファイルの内容を表示し編集するクラスですが、まだ表示(それも初期表示)しかしていません。一行ずつ読み込み、それを順次配列に追加しています。追加する際にはあらかじめ改行コードを取り除いてあります。これをしないと画面上の表示がくずれてしまいます。

editwind.rb
require "curses"

class EditWind
  def initialize(wind)
    # デフォルトウィンドウの高さを少し小さくしたサブウィンドウを作成
    @window = wind.subwin(wind.maxy-3,wind.maxx,0,0)
    # スクロール機能をONにする(後述します)
    @window.scrollok(true)
  end

  def display(file_name)
    @file_name = file_name
    begin
      # ファイルをオープンし、全内容を配列に読み込んでおく
      @file = open(@file_name, "a+")
      @data = []
      @file.each_line do |line|
        # 行末にある改行を取り除いた上で配列に入れる
        @data.push(line.chop)
      end
      # 初期表示として0行目からウィンドウの最大行数まで一行ずつ表示する
      @data[0..(@window.maxy-1)].each_with_index do |line, idx|
         @window.setpos(idx, 0)
         @window.addstr(line)
      end
    rescue
      # ファイルをオープンできない等、なにか例外が起きた場合
      raise IOError,"FILE OPEN ERROR: #{file_name}"
    end
    @window.setpos(0,0)
    @window.refresh
  end

  def getch
    return @window.getch
  end
end

 最後は情報表示エリアウィンドウのクラスです。

 サブウィンドウを作る事と、ファイル名を受け取りそれを反転表示の帯と共に表示することしかしていません。

commandwind.rb
require "curses"

class CommandWind
  def initialize(wind,file_name="")
    max_y   = wind.maxy
    max_x   = wind.maxx
    begin_y = wind.maxy - 3
    wind.setpos(begin_y,0)
    wind.standout             # 以後の文字表示を反転色にする
    wind.addstr(" " * max_x)  # 画面横サイズ分の空白で帯を表現
    wind.standend             # 反転色解除
    # 帯の真ん中にfile名を表示
    wind.setpos(begin_y,(max_x/2)-(file_name.length/2))
    wind.addstr(file_name)
    # 情報表示用のサブウィンドウを作成
    @window = wind.subwin((max_y-begin_y),max_x,begin_y,0)
    @window.refresh
  end
end

 一つだけパッと見、分かりにくい所を解説します。

(max_x/2)-(file_name.length/2)

 という計算は、テキストを画面の真ん中に表示するための描画開始位置を決めています。こういったプログラムを作る際には良く出てきますので定石として覚えておくといいかもしれません。説明のため図を書いてみました。

文字描画位置計算
文字描画位置計算

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 越智 理夫(オチ マサオ)

    株式会社カサレアル プロフェッショナルサービスセンター所属。エンジニア向けトレーニングコースの開発および講師を行う。専門はJava,Ruby,OOAD,DOA,テスト駆動開発など。最近二歳の娘にこき使われている。

バックナンバー

連載:作って覚えるRuby再入門
All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5