Ruby で内部クラスを private にする

Ruby で内部クラスを private にする場合どうするのがよいかと思っていたんですが private_constant を使うのがいいみたい。

class X
    class A
        
    end

    class B
        
    end
    private_constant :B

    def self.B_new
        B.new
    end
end

# OK
X::A.new

# Error: private constant X::B referenced (NameError)
# X::B

# OK
X.B_new

Ruby の hook メソッド一覧

Ruby から呼ばれる hook メソッドの一覧が欲しかったので Ruby 2.4 時点で定義されているメソッドをまとめてみました。
他にもあればコメント等で教えていただけると助かります。

Class クラス

  • #inherited
    • クラスのサブクラスが定義されたとき

Module クラス

  • #const_missing

    • 定義されていない定数を参照したとき
  • #extended

    • self が他のオブジェクト に Object#extend されたとき
  • #included

    • self が Module#include されたとき
  • #method_added

    • メソッド name が追加されたとき
  • #method_removed

    • メソッドが Module#remove_method により削除された時
  • #method_undefined

    • このモジュールのインスタンスメソッド name が Module#undef_method によって削除されるか、 undef 文により未定義にされるとき

BasicObject クラス

最新版の Vim で :terminal コマンドを使えるようにする

最近何かと話題の Vim:terminal ですが、使用する場合は最新版のソースコードからビルドする他にも configure 時に --enable-terminal を追加する必要があります。

$ ./configure --with-features=huge --enable-terminal

これで :terminal コマンドが使えるようになります。
細かいビルド方法などは以下のサイトを参考にしてください。

Scala でライフゲームを書いてみた

2〜3時間で軽く書いてみました。
初めて Scala をガッツリ書いたのであまり Scala らしさが感じられないコードですが…。

[コード]

import scala.sys.process._

object Lifegame {
    type Table = List[List[Boolean]]
    val o = false
    val x = true

    def width(table: Table) = {
        table(0).size
    }

    def height(table: Table) = {
        table.size
    }

    def at_cell(table: Table, x: Int, y: Int) = {
             if(x < 0 || width(table)  <= x) o
        else if(y < 0 || height(table) <= y) o
        else table(y)(x)
    }

    def dead_or_alive(table: Table, x: Int, y: Int) = {
        val cell  = at_cell(table, x, y)
        val count = List(
            at_cell(table, x - 1, y - 1),
            at_cell(table, x - 0, y - 1),
            at_cell(table, x + 1, y - 1),
            at_cell(table, x + 1, y - 0),
            at_cell(table, x + 1, y + 1),
            at_cell(table, x - 0, y + 1),
            at_cell(table, x - 1, y + 1),
            at_cell(table, x - 1, y - 0)
        ).count(x => x)
        if(cell) count == 3 || count == 2 else count == 3
    }

    def update(table: Table) = {
        table.zipWithIndex.map { case(row, y) =>
            row.zipWithIndex.map { case(cell, x) =>
                dead_or_alive(table, x, y)
            }
        }
    }

    def print(table: Table) = {
        Process("clear").run
        println(Range(0, width(table) + 2).map(x => "-").mkString)
        println(table.map(row => "|" + row.map(x => if(x) "*" else " " ).mkString).mkString("|\n") + "|")
        println(Range(0, width(table) + 2).map(x => "-").mkString)
        Console.flush()
    }

    def run(table: Table):Int = {
        print(table)
        Thread.sleep(500)
        run(update(table))
        return 0
    }

    def main(args: Array[String]) {
        val table = List(
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, x, o, x, x, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, x, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, x, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o),
            List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o)
        )

        run(table)
    }
}

[所感]

要所要所でつまずいたものの、全体的にみればそこまで難しくなかったかなーという感じです。
まあ元々 C++ の実装をそのまま Scala で書きなおしただけですしね(なので Scala らしさがあまりないとも言える
型に関しては C++ よりも厳しいという印象を受けました。
本当は List[List[Boolean]] という型に依存したくなかったんですが、上手く消すことが出来なかった…。
ダックタイピングするだけでも結構いろいろと記述必要があるぽいのがちょっと厳しい…(良し悪しは別として。
Scala は他にはパターンマッチや trait、Structural Subtyping、implicit あたりなど面白い機能があるぽいので、次 Scala を書くときはそのあたりを少し意識してかいてみたい。

[気になったところ]

  • 条件演算子がない
  • List[List[Boolean]] 型に依存してしまっている
  • table の多次元配列をもっとすっきり記述したい
  • 型に対して厳しいのでつらい
    • val is_even = x => x % 2 == 0 みたいな事がやりたかった。
  • どのあたりが Scala らしいのかわからなかった

C++ でライフゲームを書いてみた

特に意味はないんですが、C++ライフゲームを書いてみました。
C++14 で動作します(Windows での動作は未確認。

[コード]

#include <cstdlib>
#include <thread>
#include <string>
#include <iostream>
#include <vector>


int
main(){
    using table_t = std::vector<std::vector<bool>>;
    table_t table = {
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
    };

    auto width = [](auto const& table){
        return table[0].size();
    };

    auto height = [](auto const& table){
        return table.size();
    };

    auto at_cell = [&](auto const& table, auto x, auto y){
        return x < 0 || width(table)  <= x ? false
             : y < 0 || height(table) <= y ? false
             : table[y][x];
    };

    auto dead_or_alive = [&](auto table, auto x, auto y){
        auto cell  = at_cell(table, x, y);
        auto count = at_cell(table, x - 1, y - 1)
                   + at_cell(table, x - 0, y - 1)
                   + at_cell(table, x + 1, y - 1)
                   + at_cell(table, x + 1, y - 0)
                   + at_cell(table, x + 1, y + 1)
                   + at_cell(table, x - 0, y + 1)
                   + at_cell(table, x - 1, y + 1)
                   + at_cell(table, x - 1, y - 0);
        return cell ? count == 3 || count == 2 : count == 3;
    };

    auto update = [&](auto const& table){
        table_t result = table;
        for(int y = 0 ; y < table.size() ; ++y){
            for(int x = 0 ; x < table[y].size() ; ++x){
                result[y][x] = dead_or_alive(table, x, y);
            }
        }
        return result;
    };
    
    auto print = [&](auto const& table){
        std::system("clear");
        // or
//      std::system("cls");
        
        std::cout << std::string(width(table) + 2, '-') << "\n";
        for(auto&& row : table){
            std::cout << "|";
            for(auto&& cell : row){
                std::cout << (cell ? "*" : " ");
            }
            std::cout << "|\n";
        }
        std::cout << std::string(width(table) + 2, '-') << "\n";
        std::cout << std::endl;
    };

    while(1){
        print(table);
        table = update(table);
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }

    return 0;
}

[動作]

lifegame

C++ だと実装するのが難しいと思いましたが、実際に書いてみるとそこまで複雑なコードにはならなかった。
上のコードだと100行もありませんし、短くしようと思えばもっと短くできそう。
鬼門なのは『接するセル』をどうやって走査するかですかね。
今回は愚直に実装しましたが、もっとスマートなやり方はありそう。
とりあえず、標準ライブラリに Range がほしい。

Ruby の (1..5) と (1...5) の違い

前者は使っていたけど、後者は知らなかかったので覚書。
範囲演算子 .. を使用した場合は終端を含み... を使用した場合は終端を含みません

p (1..5).to_a  # => [1, 2, 3, 4, 5]
p (1...5).to_a # => [1, 2, 3, 4]

C++14(17) で zip 書いてみた

現状の C++ で zip を書いたらどうなるんだろう、と思って書いてみました。

[コード]

#include <iostream>
#include <algorithm>
#include <vector>
#include <tuple>

template<typename T, typename U>
constexpr auto
zip_impl(T v1, U v2){
    auto vi1 = std::begin(v1);
    auto vi2 = std::begin(v2);

    using value_t = decltype(std::make_tuple(*vi1, *vi2));
    std::vector<value_t> result{};

    while(vi1 != std::end(v1) && vi2 != std::end(v2)){
        result.emplace_back(*vi1, *vi2);
        vi1++;
        vi2++;
    }
    return result;
}

template<typename T, typename U>
constexpr auto
zip(T v1, U v2){
    return zip_impl(v1, v2);
}

template<typename T, typename U>
constexpr auto
zip(std::initializer_list<T> v1, std::initializer_list<U> v2){
    return zip_impl(v1, v2);
}


int
main(){
    for(auto [x, y] : zip({1, 2, 3, 4, 5}, {'a', 'b', 'c', 'd', 'e'})){
        std::cout << x << ":" << y << std::endl;
    }
    return 0;
}

[出力]

1:a
2:b
3:c
4:d
5:e

https://wandbox.org/permlink/qQEvmwNMjgVt3GHJ

手癖で constexpr をつけているけど特に constexpr ではない(std::vector に依存してるので constexpr には出来ない…。
使う側では C++17 の『構造化束縛』を使っているけど、実装側は C++14 でも動作すると思う。
っていうか、range based-for で構造化束縛使うのかなり強力なのではないだろうか???
実装は単純に2つのコンテナを iterator で回しながらタプルで保持するようにしてるだけですね。
特に複雑なことはしていないと思う。
最適解かどうかは別としてこういうコードが C++ でも雑に書けるようになったのはだいぶよさがあるなあ。