This page looks best with JavaScript enabled

memfs-ファイル操作をメモリ上で完結する

 ·  ☕ 2 min read

個人的にいいなと思ったgemの紹介です。
今後もいいgemを見つけたら記事にしていきたいと思います。

ファイル操作のテストは面倒

やったことがある人はわかるとは思いますがファイルやディレクトリを作成、削除したり、パーミッションを変更したりのテストは意外と気を使います。
例を挙げると

  • 作成したファイルの後片付け
  • テスト対象のコードのバグによる想定しない場所へのファイル作成、削除

などです。
特にファイルの削除を間違ってしてしまと取り返しがつかなくなってしまう場合もあります。

memfs

memfsはファイル操作をメモリ上で完結してくれるライブラリです。ハードドライブを操作することがないので余計なファイルが生まれたり消してはいけないファイルを消してしまうことがありません。

実現方法は以下のようになっています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  # https://github.com/simonc/memfs/blob/master/lib/memfs.rb#L86
  def activate!(clear: true)
    Object.class_eval do
      remove_const :Dir
      remove_const :File
      remove_const :IO

      const_set :Dir, MemFs::Dir
      const_set :IO, MemFs::IO
      const_set :File, MemFs::File
    end

    MemFs::FileSystem.instance.clear! if clear
  end

至って単純でRubyの標準ライブラリを置き換えています。

使用例

学習テストを書いたのでそこからいくつか抜粋します。

 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
44
45
46
47
48
49
50
51
52
53
  def test_pwd
    MemFs.activate do
      assert_equal('/', Dir.pwd)
    end
  end

  def test_ls
    MemFs.activate do
      assert_equal([], Dir.glob('*'))
    end
  end

  def test_system
    MemFs.activate do
      assert_not_equal('', `ls`)
    end
  end

  def test_list_mkdir
    dirs = %w[/test1 /test2]
    MemFs.activate do
      FileUtils.mkdir(dirs)
      dirs.each do |dir|
        assert_true(File.directory?(dir))
      end
    end
    dirs.each do |dir|
      assert_false(File.directory?(dir))
    end
  end

  def test_ln_s
    MemFs.activate do
      dir = '/tmp/test1'
      link = '/tmp/test1_link'
      FileUtils.mkdir(dir)
      FileUtils.ln_s(dir, link)
      assert_true(File.symlink?(link))
    end
  end

  def test_chmod
    MemFs.activate do
      dir = '/tmp/test1'
      FileUtils.mkdir(dir, mode: 0o755)
      stat = File.stat(dir)
      assert_equal(0o100755, stat.mode)

      FileUtils.chmod(0o644, dir)
      stat = File.stat(dir)
      assert_equal(0o100644, stat.mode)
    end
  end

ディレクトリの作成、削除や、シンボリックリンク、パーミッション系もカバーしているようです。
もっと複雑な場面になるとわかりませんが、単純な操作はこれを使って安全にテストできそうです。

注意点

  • test_pwdtest_ls からわかりますが、 MemFs.activate のブロック内はなんのファイルも存在しない / がpwdになるので、必要なファイル、ディレクトリはブロック内で作成する必要があります
  • test_system の通り、rubyの FileDirIO を介していないsystem系のコマンドでは当然ハードディスクをいじれるので、そういったコマンドを使用している場合は注意しましょう

まとめ

ファイル操作がある時に使ってみようと思います。
他の言語でも似たようなライブラリ欲しいですが、割とゴリ押しなので同じような方法を使うのは柔軟な言語でないと厳しそうですね。

Share on

ippachi
WRITTEN BY
ippachi
Software Developer