エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

diff を清書する、加えて gem にする

気がつけば。diff を実装してから7年も経っていました。

案の定、考え方がかなり頭から抜けて行ってしまっているのですが、当時 diff について詳しい記事を書かれていた方がいらっしゃって、加えてこの記事にリンクを貼ってくださっていたおかげでそれを辿って当該記事にたどり着くことができて、どうにか再実装にこぎつけることができました。感謝です。

C++ で再実装

少々思うところがあって。C++の実装を書き直してみました。

職業プログラマに転向してからは主に Ruby を使っていて、C++ の方はすっかり進歩が止まってしまっていたものと思っていたのですが、それでも7年前のコードを見ると粗が目に付きます。


利用例。

#include <iostream>
#include <vector>
#include <string>

#include "myers.h"

int main(int, char* [])
{
    using namespace emattsan::myers;

    std::string fooBarBaz = "fooBarBaz";
    std::string FooBazBar = "FooBazBarfoz";

    std::vector<EditType> ses = diff(fooBarBaz, FooBazBar);

    std::string::const_iterator i1 = fooBarBaz.begin();
    std::string::const_iterator i2 = FooBazBar.begin();
    std::for_each(ses.begin(), ses.end(), [&](EditType edit_type) {
        switch(edit_type)
        {
        case DELETE:
            std::cout << "- " << *i1 << std::endl;
            ++i1;
            break;
        case ADD:
            std::cout << "+ " << *i2 << std::endl;
            ++i2;
            break;
        default:
            std::cout << "  " << *i1 << std::endl;
            ++i1;
            ++i2;
            break;
        }
    });

    return 0;
}


ビルド & 実行。

$ g++ --std=c++11 -o sample sample.cpp 
$ ./sample
- f
+ F
  o
  o
  B
  a
- r
+ z
  B
  a
+ r
+ f
+ o
  z

Ruby で再実装

gem 作りの練習をしているので勢いで Ruby で実装してみた。


利用例。

Gemfile 。

gem 'myers_diff', github: 'mattsan/ruby_myers_diff'


サンプル。

require 'myers_diff'

FooBarBaz = "fooBarBaz";
FooBazBar = "FooBazBarfoz";

ses = MyersDiff.diff(FooBarBaz, FooBazBar)

i1 = FooBarBaz.chars.each
i2 = FooBazBar.chars.each

ses.each do |edit_type|
  case edit_type
  when :DELETE
    puts "- #{i1.next}"
  when :ADD
    puts "+ #{i2.next}"
  else
    puts "  #{i1.next}"
    i2.next
  end
end


インストール。

$ bundle install --path vendor/bundle


実行。

$ bundle exec ruby sample.rb 
- f
+ F
  o
  o
  B
  a
- r
+ z
  B
  a
+ r
+ f
+ o
  z