最近 Ruby の curses を使って遊ぶことがあり、その中で Curses::Window#refresh
と Curses::Window#noutrefresh
の違いがよくわからなかったので、ドキュメントを探していた。
日本語で探すと るりま が検索にかかるが、最新とは内容が離れているのでメモとして残しておく。
Ruby の curses のドキュメント
curses は Ruby 2.1.0 から標準ライブラリから切り出されて独立した gem になっている。see: https://github.com/ruby/curses#description
切り出されたことにより、curses のるりまは 1.8.7 の library curses でなくなって?おり、ruby/curses の README の Documentation にあるように www.rubydoc.info にあるものが最新を追随している公式ドキュメントになっている。
1.8.7 標準添付の curses から 現在の v1.3.2 までの間に API も増えているため、残念ながら 1.8.7 の情報では現在の curses を扱うのは難しい。
physical screen と virtual screen
Python の curses のドキュメント https://docs.python.org/3.5/library/curses.html はより詳細に説明が記載されており、physical screen と virtual screen という語を使って説明されていた。日本語版もあるが、単語が明確に分けて使われている英語のほうのドキュメントがおすすめである。
実際に私たちに見えるのは physical screen で、見えていないが変更内容を保持しているのが virtual screen である。virtual screen に対して変更したものを physical screen に同期するようなかたちで更新し、physical screen に反映して表示する仕組みとなっている模様だ。
尚、Curses.doupdate
というメソッドが用意されており、これにより強制的に physical screen を更新することができる。
Curses::Window#refresh と Curses::Window#noutrefresh の違い
さて、本題である。
https://www.rubydoc.info/gems/curses/Curses/Window をみると、どちらも Curses::Window
に設定した内容を更新するメソッドで、両メソッドの説明には Refresh the windows and lines.
とある。
Curses::Window#noutrefresh
は加えて、Curses::Window.noutrefresh allows multiple updates with more efficiency than Curses::Window.refresh alone.
と書いてあるので、複数 Window がある場合に効率的に処理できるらしい。
Curses::Window#refresh
Curses::Window#refresh
は、指定された Curses::Window
の設定内容を virtual screen、physical screen の両方に反映するようだ。つまり、実行されると更新されたものが私たちに見えるようになる。
Curses::Window#noutrefresh
一方で、Curses::Window#noutrefresh
は指定された Curses::Window
に設定した内容を virtual screen にのみ反映するようだ。この段階では私たちに変更は見えない。
これを physical screen に反映するには Curses.doupdate
を呼び出す必要がある。こうすることで、virtual screen の内容が physical screen に反映される。
先に書かれている “効率的” というのは、Curses.doupdate
が存在する Curses::Window
すべての virtual screen の内容を physical screen に反映するためだ。Curses::Window#refresh
は 1 つの Curses::Window
に対して Curses::Window#noutrefresh
と Curses.doupdate
を実行しているようなものなので、こちらを使ったほうが確かに効率的だ。
まとめ
Python のドキュメントのちからを借りつつ、Curses::Window#refresh
と Curses::Window#noutrefresh
の違いを確認した。
Curses::Window#refresh
- 1 つの
Curses::Window
に対して、virtual screen, physical screen 両方を更新する
Curses::Window#noutrefresh
- 1 つの
Curses::Window
に対して、virtual screen のみを更新する
- physical screen を更新するには
Curses.doupdate
を呼ぶ必要がある
Curses.doupdate
はすべての virtual screen を physical screen に反映するので複数 window がある場合はこちらを使うのが効率的である
ruby/curses のメンテをしている shugo さんの作っている Textbringer の window クラス が同様の使い方をしているので合っているはず。