Featured image of post 第1回-簡易エディタを作ろう - テキストを編集する - Mooで作る簡易テキストエディタ

第1回-簡易エディタを作ろう - テキストを編集する - Mooで作る簡易テキストエディタ

PerlとMooでテキストを追加・削除できる簡易エディタを作成。Undo/Redo機能まで学ぶシリーズ第1回。

@nqounetです。

今回から、新シリーズ「Mooで作る簡易テキストエディタ」を始めます。

シリーズの紹介

このシリーズでは、PerlとMooを使ってUndo/Redo機能付きの簡易テキストエディタを作成します。全10回を通して、テキストエディタを段階的に機能拡張していきます。

最終的には、以下のような機能を持つエディタが完成します。

  • テキストの挿入・削除
  • 操作を元に戻す(Undo)
  • やり直し(Redo)
  • 複数の操作をまとめて実行(マクロ)

これらの機能を実装する過程で、オブジェクト指向設計の重要な考え方を自然に学んでいきます。

前提知識

このシリーズは、「Mooで覚えるオブジェクト指向プログラミング」シリーズ(全12回)を読了している方を対象としています。

具体的には、以下の知識を前提としています。

  • hasによる属性定義
  • is => 'ro' / is => 'rw'の使い分け
  • requireddefaultオプション
  • Moo::Roleによるロール定義
  • withによるロールの適用

まだ読んでいない方は、先に上記シリーズをご覧ください。

今回のゴール

今回は、シリーズの第1回として、テキストを追加・削除できる最小限のエディタを作成します。

まずは動くものを作ることを優先し、設計はシンプルに保ちます。今回作成するエディタには「元に戻す」機能はまだありません。それは次回以降で追加していきます。

Editorクラスを作る

まず、今回作成するEditorクラスの構造を確認しましょう。

	classDiagram
    class Editor {
        -text: String
        +insert(position, string)
        +delete(position, length)
    }
    note for Editor "テキストを保持し、
挿入・削除操作を提供する"

では、テキストを編集するためのEditorクラスを作成しましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Perl v5.36 以降
# 外部依存: Moo

package Editor {
    use Moo;
    use v5.36;

    has text => (
        is      => 'rw',
        default => '',
    );

    sub insert ($self, $position, $string) {
        my $current = $self->text;
        my $new_text = substr($current, 0, $position) 
                     . $string 
                     . substr($current, $position);
        $self->text($new_text);
    }

    sub delete ($self, $position, $length) {
        my $current = $self->text;
        my $new_text = substr($current, 0, $position) 
                     . substr($current, $position + $length);
        $self->text($new_text);
    }
};

このEditorクラスは、2つのメソッドを持っています。

  • insert($position, $string) — 指定した位置に文字列を挿入する
  • delete($position, $length) — 指定した位置から指定した長さの文字を削除する

text属性には、エディタで編集中のテキストが格納されます。初期値は空文字列です。

動作確認

以下のフローで、テキストの挿入と削除がどのように動作するか見てみましょう。

	flowchart LR
    subgraph 挿入操作
        A1["text: ''"] -->|"insert(0, 'Hello')"| A2["text: 'Hello'"]
        A2 -->|"insert(5, ' World')"| A3["text: 'Hello World'"]
    end
    subgraph 削除操作
        A3 -->|"delete(5, 6)"| A4["text: 'Hello'"]
    end

このEditorクラスを使って、実際にテキストを編集してみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Perl v5.36 以降
# 外部依存: Moo

use v5.36;

package Editor {
    use Moo;

    has text => (
        is      => 'rw',
        default => '',
    );

    sub insert ($self, $position, $string) {
        my $current = $self->text;
        my $new_text = substr($current, 0, $position) 
                     . $string 
                     . substr($current, $position);
        $self->text($new_text);
    }

    sub delete ($self, $position, $length) {
        my $current = $self->text;
        my $new_text = substr($current, 0, $position) 
                     . substr($current, $position + $length);
        $self->text($new_text);
    }
};

# メイン処理
my $editor = Editor->new;

# テキストを挿入
$editor->insert(0, 'Hello');
say "挿入後: " . $editor->text;  # Hello

# さらにテキストを追加
$editor->insert(5, ' World');
say "追加後: " . $editor->text;  # Hello World

# 一部を削除
$editor->delete(5, 6);  # ' World'を削除
say "削除後: " . $editor->text;  # Hello

実行結果は以下のようになります。

1
2
3
挿入後: Hello
追加後: Hello World
削除後: Hello

テキストの挿入と削除が正しく動作していることが確認できます。

今回作成した完成コード

以下が今回作成した完成コードです。1つのスクリプトファイルとして動作します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env perl
# Perl v5.36 以降
# 外部依存: Moo

use v5.36;

package Editor {
    use Moo;

    has text => (
        is      => 'rw',
        default => '',
    );

    sub insert ($self, $position, $string) {
        my $current = $self->text;
        my $new_text = substr($current, 0, $position) 
                     . $string 
                     . substr($current, $position);
        $self->text($new_text);
    }

    sub delete ($self, $position, $length) {
        my $current = $self->text;
        my $new_text = substr($current, 0, $position) 
                     . substr($current, $position + $length);
        $self->text($new_text);
    }
};

# 動作確認
my $editor = Editor->new;

$editor->insert(0, 'Hello');
say "挿入後: " . $editor->text;

$editor->insert(5, ' World');
say "追加後: " . $editor->text;

$editor->delete(5, 6);
say "削除後: " . $editor->text;

まとめ

  • Editorクラスを作成し、text属性でテキストを保持する
  • insertメソッドで指定位置に文字列を挿入できる
  • deleteメソッドで指定位置から文字を削除できる
  • まずは動くものを作り、段階的に機能を追加していく

次回予告

今回作成したエディタには、「元に戻す」機能がありません。

たとえば、「Hello World」から「 World」を誤って削除してしまった場合、どうすれば元に戻せるでしょうか?

次回は、この「元に戻したい!」という問題に取り組みます。単純な方法では難しいことに気づき、操作履歴の必要性を理解していきます。

お楽しみに。

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。