表参道.rb #27 での発表に一部誤りがあったので訂正と補足

発表から一週間以上経ってしまっているんですが、発表中の発言に一部誤りがあったので訂正と補足。
pattern-match を使っているコードを説明する時に

「pattern-match は using PatternMatch をすることで matchwith が使えるようになり〜」

と発言していたんですが、正しくは

「pattern-match は using PatternMatch をすることで match が使える」

でした。
pattern-match で使用している refinements では match のみが影響して with は関係ありませんでした。
では、なぜ with を使うことが出来るのかというと with を呼び出しているブロックは内部で #instance_eval されているためです。
#instance_eval を経由してブロックを呼び出すことで、評価するコンテキストが別になりブロック内で with を呼び出せるようになります。

class Env
    def with
        puts "with"
    end
end

def match &block
    # instance_eval で block を評価することで
    # block 内で Env のインスタンスメソッドを呼び出すことが出来る
    Env.new.instance_eval &block
end

match {
    with
    with
    with
}

# output:
# with
# with
# with

この辺りの内部実装はもう少し解説すべきでしたね…申し訳ありませんでした。

ちなみに個人的には #match メソッドだけなら『Object#match で refinements する』のではなくて『module_function と定義して PatternMatch.match みたいな呼び出し』でもいいかなーとは思います。
PatternMatch. の部分が煩わしければ include PatternMatch とでもしておけばいいですしね。
まあここら辺はどちらがよいのかを考えるのがむずかしいところ…作りての好みもありますし。

C++17 の構造化束縛を range-based for で使う

C++17 では構造化束縛という言語機能が追加されました。
これは std::tie のように std::tuple などを個別に変数で受け取る事が出来る機能です。

auto homu = std::make_tuple(1, "homu", 14);

// std::tuple の要素を個別に受け取る
auto [id, name, age] = homu;

std::tie とは違い変数定義で使用する事が出来ます。

range-based for で使う

これだけでも便利なのですが、range-based for と組み合わせることで更に便利になります。

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

int
main(){
    std::vector<std::tuple<int, std::string, int>> vc = {
        { 1, "homu", 14 },
        { 2, "mami", 15 },
        { 3, "mado", 14 }
    };
    for(auto&& [id, name, age] : vc){
        std::cout << "id:" << id << ", name:" << name << ", age:" << age << std::endl;
    }

    return 0;
}
/*
output:
id:1, name:homu, age:14
id:2, name:mami, age:15
id:3, name:mado, age:14
*/

https://wandbox.org/permlink/HwbLhRyBDCdQDsT8

こんな感じに range-based for の変数定義でも構造化束縛を使うことが出来ます。
ますます std::tuple が便利になりますね。

npm install で github のリポジトリからインストールする

npm installgithubリポジトリを指定してインストールする方法の覚書。

$ npm install osyo-manga/thomash-node-audio-metadata

また #{branch 名} を付けることで任意のブランチからインストールすることも出来ます。

$ npm install osyo-manga/thomash-node-audio-metadata#fix-fs_close

便利。

参照

Vim でシンタックスハイライトが突然オフになる現象の対処方法

覚書っていうか情報共有というか。

結構前からこの現象に悩まされていたんですが、わたしの場合は 'redrawtime' が原因だったのでその設定を見直すことで対処出来ました。
他にもこの現象に悩まされている人がいれば上記の手段を試してみてください。

追記

unite.vim を使っている方は内部で 'redrawtime' が書き換えられる可能性があるので、unite.vim を更新すると対処出来るかもしれません(最新版の unite.vim では 'redrawtime' 自体の変更が削除されました。

追記2 : 'redrawtime' について

'redrawtime' は、

  • Vim が再描画を行う際に『'redrawtime' に設定された以上の時間がかかる場合』にハイライトを無効にする

というような機能になります。
なので 'redrawtime' で低い値(ミリ秒)が設定されていたり、描画に時間がかかるような場合にハイライトが無効化されます。
また、『Vim が再描画を行う際』というのも様々で、

  • hlsearch がオンの場合のパターン検索
  • :match
  • syntax on
  • matchadd() を行った時

などなど、いろいろなタイミングがあります。
もし、突然ハイライトが消えてしまった場合は 'redrawtime' の値が低くなっていないか(既定値は 2000)、描画が遅くなかったか、などを確認してみるとよいと思います。

element-ui の tree コンポーネントでノードのレンダリングをカスタマイズする

かなりマイナーなネタですが、element-ui の tree コンポーネントで表示されるノードをカスタマイズしてみたいと思います。

環境

  • Vue.js : v2.4.4
  • element-ui : v1.4.6

コード

HTML

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui@1.4.6/lib/theme-default/index.css">
</head>
<body>
  <div id="app">
    <el-tree
      node-key="id"
      default-expand-all
      :data="table"
      :render-content="renderContent"
      :props="defaultProps">
    </el-tree>
  </div>
</body>
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue@2.4.4/dist/vue.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui@1.4.6/lib/index.js"></script>
  <script src="./script.js"></script>
  <script>
  </script>
</html>

JavaScript

new Vue({
  el: '#app',
  data: function() {
    return {
      table : [
        {
          id: 1,
          label: "Level one 1",
          children: [
            {
              id: 2,
              label: "Level two 1"
            },
            {
              id: 3,
              label: "Level two 2",
              children: [
                {
                  id: 5,
                  label: "Level three 1"
                },
                {
                  id: 6,
                  label: "Level three 2"
                },
                {
                  id: 7,
                  label: "Level three 3"
                },
              ]
            },
            {
              id: 4,
              label: "Level two 3"
            },
          ]
        },
      ],
      defaultProps: {
        children: "children",
        label: "label"
      },
      renderContent(h, { node, data, store }){
        console.log(h);
        return h("span", [
          h("span", node.label),
          h("span", { attrs: { style: "float: right; margin-right: 20px;" } }, [
            h("el-button", { attrs: { type: "primary", size: "mini" } }, "button")
          ])
        ]);
      }
    }
  }
})

https://jsfiddle.net/jxc0m2n6/1/

el-tree:render-content で各ノードのレンダリングを行う関数(renderContent)を指定することが出来ます。
element-ui のサンプルコードでは renderContent 内で JSX っぽい記述を行っていたのですが、上記のコードでは生JSで記述しています。
書き方とかはまあこんな感じになりますよ、と(生 JS だと hyperscript っぽい記述?よくわかってない…

参照

ES2015(ES6)以降 の JavaScript でオブジェクトのキーに変数を使う

次のように JavaScript でオブジェクトのキーに変数を使おうとしても当然ですが変数は展開はされません。

const key   = "age";
const value = 14;

const obj = { key : value };
console.log(obj);
// => { key: 14 }

通常このような場合は obj[key] = value みたいにする必要がありました。

const key   = "age";
const value = 14;

const obj = {};
obj[key] = value;
console.log(obj);
// => { age: 14 }

ES2015(ES6)以降

ES2015(ES6)以降ではオブジェクトのキーを定義する時に [key] とすることで変数が展開されるようになります。

const key   = "age";
const value = 14;

const obj = { [key] : value };
console.log(obj);
// => { age: 14 }

これは便利そう。
最近の JavaScript はよく知らないので便利な文法は覚えていきたい。

Ruby の #class_eval と #module_eval の違い

Ruby#class_eval はクラスオブジェクト専用、#module_eval はモジュールオブジェクト専用のメソッドだと思っていたのですが、実は名前が違うだけで同等のメソッドだったみたい。

検証コード

class C
end

C.class_eval {
    def homu
    end
}

# クラスオブジェクトに対しても #module_eval が使える
C.module_eval {
    def mami
    end
}

p C.instance_methods false
# => [:homu, :mami]


module M
end

# モジュールオブジェクトに対しても #class_eval が使える
M.class_eval {
    def homu
    end
}

M.module_eval {
    def mami
    end
}

p M.instance_methods false
# => [:homu, :mami]

結論

#class_eval#module_eval の違いは名前だけなのでケースによってよしなに使い分けましょう。

参照