片栗粉とろみ

技術メモ

【typescript】interfaceやclassとmoduleは名前が被っていてもいい

こう書ける。

interface Name {
  firstName: string,
  lastName: string,
}

module Name {
  export const toFullName = (n: Name): string => n.firstName + " " + n.lastName
}

const myName: Name = {firstName: 'anjeri-na', lastName: 'jori-'}
console.log(Name.toFullName(myName)) // => anjeri-na jori-

「事情があってclassにはしたくないが、処理はまとめて記述したい」という場合に使えるかもしれない。
ML系の言語っぽくて少しかっこいい1

補足: classでも名前被りのmoduleを作れる

classの場合でも名前被りのmoduleを宣言できる

class NameClass {
    constructor(public firstName: string, public lastName: string){}
}

module NameClass {
    export const toFullName = (n: NameClass): string => n.firstName + " " + n.lastName
}

const myNameInstance = new NameClass('anjeri-na', 'jori-');
console.log(NameClass.toFullName(myNameInstance)) // => anjeri-na jori-

しかし、この使い方なら static 関数で十分だし、そのほうがシンプルだ。

static版

class NameClass {
  static toFullName = (n: NameClass): string => n.firstName + " " + n.lastName
  constructor(public firstName: string, public lastName: string){}
}

const myNameInstance = new NameClass('anjeri-na', 'jori-');
console.log(NameClass.toFullName(myNameInstance)) // => anjeri-na jori-

トランスパイル結果を見てもほとんど同じものが生成されているのがわかる。

// module版トランスパイル結果
class NameClass {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

(function (NameClass) 
    NameClass.toFullName = (n) => n.firstName + " " + n.lastName;
    // ^^^^^^^^^^^^^^^^^^ここで関数を追加してる^^^^^^^^^^^^^^^^^^^^^
})(NameClass || (NameClass = {}));

const myNameInstance = new NameClass('anjeri-na', 'jori-');
console.log(NameClass.toFullName(myNameInstance));
// static版トランスパイル結果
class NameClass {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
NameClass.toFullName = (n) => n.firstName + " " + n.lastName;
// ^^^^^^^^^^^^^^^^^^ここで関数を追加してる^^^^^^^^^^^^^^^^^^^^^
const myNameInstance = new NameClass('anjeri-na', 'jori-');
console.log(NameClass.toFullName(myNameInstance));

どちらもNameClassにメソッドを追加しているだけだ。

staticのほうがスコープをfunctionで表現していないぶん、多少効率的かもしれない(誤差だとは思う)。

補足2: interfaceと名前被りmoduleのトランスパイル結果

interfaceとmoduleを使った場合のトランスパイル結果

var Name;
(function (Name) {
    Name.toFullName = (n) => n.firstName + " " + n.lastName;
})(Name || (Name = {}));
const myName = { firstName: 'anjeri-na', lastName: 'jori-' };
console.log(Name.toFullName(myName));

moduleからexportした関数はObjectに対するメソッド追加として表現されており、interfaceの型情報は消去されていることがわかる。


  1. OcamlのListモジュールのlength関数にlistを渡すみたいなね let my_list = [1;2;3] in List.length my_list;;

Kitematicのログが出ない問題の解決

随分前にKitematicをアップデートして以来、コンテナのログを見ようとしても

0 No logs for this container.

という表示が出るのみでログが見られずにいた。

ターミナルから直接ログをみて誤魔化していたが、チームの人に「バージョン下げたらログ出ますよ」と言われてバージョンを下げたら本当にログが見えるようになった。

ありがたい。

v0.17.7でログが出ずに困っている人は、以下からv0.17.6をインストールし直せばOK github.com

Kitematic便利。

【Rails】カラム名が共通のインスタンスをつかってモデルを初期化する

まったく同じカラム名をもったモデルから値をまるまるコピーしてインスタンスを作成したい

Nekoと全く同じカラムを持つDuplicatedNekoというモデルがあるとき、

neko = Neko.find(1) # Nekoモデルのなにかしらのインスタンス
DuplicatedNeko.new neko.attributes

これでおk.

nekoをハッシュにしてDuplicatedNeko.newに渡しているだけ。

ActiveRecordのメソッドにto_hto_hashはないが、attributesでハッシュに出来る。

【Rails】ActiveAdminでselectメニューのラベルを変更する+公式ドキュメントに当たる

selectメニューの書き方

ActiveAdminでselectメニューを作りたいときは以下のように書く

form do |f|
  f.inputs do
    f.input :some_value, as: :select, collection: ['one', 'two', 'three']
  end
end

selectメニューのラベルを変更する

上記の場合画面上で選択した値がモデルにそのままセットされる。
しかし、画面上で選んだ値とは違う値をモデルにセットしたいという場合ががある。
たとえば、画面ではわかりやすいラベルで選択してもらって、モデルには区分値を設定したい場合などだ。

値とラベルを分けたいときは以下のようにハッシュで渡してやればいい

form do |f|
  f.inputs do
    f.input :some_value, as: :select, collection: { one: 1, two: 2, three: 3 }
  end
end

keyがラベルに、valueがセットされる値になる。

これで画面上は 'one', 'two', 'three' のなかから一つを選択することになるが、モデルにセットされる値は 1, 2, 3のいずれかになる。

公式のドキュメントから根拠をさがす。

上記の方法はQiitaでいろいろ調べれば出てくるが*1公式のドキュメントを読んで調べようと思っても意外に見つからない。

私の調べ方が悪いだけかもしれないが、このままだとActiveAdminのフォーム関連での困りごとを調べられないので、公式の情報の在り処を突き止めておく。

ActiveAdminの依存関係

リポジトリを見に行くと、ActiveAdminはその機能をいくつかのOSSに依存している*2

なかでも今回問題になったフォーム関連の機能はFormtasticに依存している。

Formtasticのselect機能

FormtasticのREADMEに使用例が列挙されていて、collection関連のコードだけでもズラッと以下のように書かれている

Many inputs provide a collection of options to choose from (like :select, :radio, :check_boxes, :boolean). In many cases, Formtastic can find choices through the model associations, but if you want to use your own set of choices, the :collection option is what you want. You can pass in an Array of objects, an array of Strings, a Hash... Throw almost anything at it!

  f.input :authors, :as => :check_boxes, :collection => User.order("last_name ASC").all
  f.input :authors, :as => :check_boxes, :collection => current_user.company.users.active
  f.input :authors, :as => :check_boxes, :collection => [@justin, @kate]
  f.input :authors, :as => :check_boxes, :collection => ["Justin", "Kate", "Amelia", "Gus", "Meg"]
  f.input :author,  :as => :select,      :collection => Author.all
  f.input :author,  :as => :select,      :collection => Author.pluck(:first_name, :id)
  f.input :author,  :as => :select,      :collection => Author.pluck(Arel.sql("CONCAT(`first_name`, ' ', `last_name`)"), :id)
  f.input :author,  :as => :select,      :collection => Author.your_custom_scope_or_class_method
  f.input :author,  :as => :select,      :collection => { @justin.name => @justin.id, @kate.name => @kate.id }
  f.input :author,  :as => :select,      :collection => ["Justin", "Kate", "Amelia", "Gus", "Meg"]
  f.input :author,  :as => :radio,       :collection => User.all
  f.input :author,  :as => :radio,       :collection => [@justin, @kate]
  f.input :author,  :as => :radio,       :collection => { @justin.name => @justin.id, @kate.name => @kate.id }
  f.input :author,  :as => :radio,       :collection => ["Justin", "Kate", "Amelia", "Gus", "Meg"]
  f.input :admin,   :as => :radio,       :collection => ["Yes!", "No"]
  f.input :book_id, :as => :select,      :collection => Hash[Book.all.map{|b| [b.name,b.id]}]
  f.input :fav_book,:as => :datalist   , :collection => Book.pluck(:name)

Throw almost anything at it!と言っているようにほとんどなんでも渡せるようだ。

今回のQiitaで調べたケースだとハッシュを渡しているから、ドキュメント上では

 f.input :book_id, :as => :select,      :collection => Hash[Book.all.map{|b| [b.name,b.id]}]

が根拠になるだろうか。書いてみて動いている以上の根拠はないのだが。

また、これ以上の意味はあまりないがソースコード中のドキュメントでも直接ハッシュを渡している例を見つけた。

  <%= f.input :status,     :collection => {"Draft" => 0, "Published" => 1} %>

https://github.com/justinfrench/formtastic/blob/master/lib/formtastic/helpers/input_helper.rb#L187

これだけ読んでcollectionにHashを渡せばラベルを変更できるんだなと思える気はしないが、列挙されているcollectionの渡し方に目を通しておいて損はないとおもう。

*1:たとえば https://qiita.com/murata0705/items/6dccb5467233816808f7

*2:activeadmin/activeadmin: The administration framework for Ruby on Rails applications.: https://github.com/activeadmin/activeadmin#dependencies

全射と単射/エピ射とモニック射のイメージについてのメモ

www.youtube.com

英語の勉強も兼ねてBartosz Milewski先生の講義を観て圏論に入門しようとしている。そのメモ。

エピ射とモニック射のイメージ

エピ射(epimorphism)

始域の像が終域の上に覆いかぶさるようなイメージ。「epi-」の意味はupon
集合の圏だと全射(surjective / onto function)。

「upon(上に)」も「onto(上に)」も「sur-(上に)」というイメージ。

f:id:sushi__melody:20190417133341p:plain

全射

fの終域がYをすっぽり覆う感じ。

モニック射(monomorphism)

始域の像が終域にポコっと入るイメージ。
集合の圏だと単射(injection / injective function)。

「inject(注入)」というイメージ。「mono-(単一)」はたぶん一対一対応のイメージ

f:id:sushi__melody:20190417133336p:plain

単射

fの始域と終域が一対一対応を保ったままYのなかにスッポリ収まる感じ。

 

さいごに

間違っているところが多々ありそうなので指摘していただけるとありがたいです

心理的安全性を取りに行く + ACTの話

心理的安全性

チームの生産性をあげるために心理的安全性の大切さが叫ばれて久しい。

bizhint.jp

チームメンバーが心理的安全性を確保できるように配慮するのは当然のこととして、ぼくのように新卒1年目でもっともジュニアなメンバーとしては"心理的安全性を取りに行く"のが大事ではないかと思った。

心理的安全性を取りに行く

ぼくはもともと内向的で人の顔色を伺うタイプなので、すこし油断すると「話して悪く思われないか不安 => しゃべる機会が減る => 機会が減ることで反応が予想ができなくなり、より不安になる」という負のループに陥ってしまう。

しかし一方で、ぼくは一度心を許してしまえば何でも率直に言えるタイプだ(これはみんなそうかもしれない)。

だから、少し勇気をだして雑談に入っていったり、少し勇気を出して1on1をセッティングするなど、自分が積極的に意見を言うための足場を整えることが大事だ。

べつに雑談を盛り上げたり笑わせたりなど成果を出す必要はなくて、いざ自分の意見が必要な場面になったときのために足場を整えておく。

行動療法ACTとの関連性

心理的安全性のために勇気をだすのは、チームと自分の生産性のためだ。

この"勇気"というのは決して「不安に打ち克つ」のようなニュアンスではなく、「不安を受け入れる」に近い。

生産性という価値のために、コミュニケーションへの不安を受け入れ、行動する。

書いていて気づいたが、これはまさに行動療法ACTの不安のアクセプタンスと価値へのコミットメントだ。

www.psychological-skils.com

nlpvoice.com

少し前にビジネスマンのあいだで流行ったマインドフルネスについて

ACTはその治療体系にマインドフルネスを組み込みんでいることで有名だ。ACTではマインドフルネスを、感情から距離を取り、受け入れ、価値に基づいた行動につなげるためのツールとして用いる。

『SOFT SKILLS』では瞑想を"プラスの感情を経験しやすくなる"のような文脈で捉えているが*1、もう少しテンションを下げて"勇気を出すためのツール"くらいのものとしてマインドフルネスを使っていって良いのだと思う。

ということでこれから一週間マインドフルネスに取り組んでみようかな。

*1:SOFT SLILLS 第66章

Javascriptでfor文を使わずにpythonっぽくn回ループする

pythonのループ

n回ループしたいだけなのに i++とか書きたくないですよね?pythonっぽくループ回したくないですか?

for i in range(5):
  print(i)

うんうん!いいね!こんな感じで回したい!回したいよね!ね?同意してください!

方法

Arrayとfor-of文を使う

5回ループしたいときは

for (const i of Array(5).keys()) {
  console.log(i);
}

ループの中で繰り返し回数を使わないならもっと簡単に書けます。

for (const _ of Array(5)) {
  // なんかする
}

使いどころ

ほとんどの場合mapを使って書けるので必要ありませんが、強いて言えば非同期処理を直列に行いたい場合に使えます。

const f = async (n) => {
    for(const i of Array(n).keys()) {
        await someAsyncFunction()
    }
}

Generator式で複数直列にyieldしたい場合にも使えます。以下の例は自作のなんちゃってrange関数。

function* range(stop) {
  for(const i of Array(stop).keys()) {
    yield i   
  }
}

なんでこうなるか

ドキュメントにはArrayのコンストラクタに整数を渡すと、渡した数だけ空の要素をもったリストが生成されると書いてあります*1

じっさい、中身を表示してみると

for (const value of Array(5)) {
  console.log(value) // => undefined
}

undifinedが表示されます。

(実際に配列の中にundefinedが入っているわけではなく、長さのみもった空の配列が生成されるようです)

さらに、Arrayのkeys()を呼ぶと、キーを順番に返却するイテレータが返却されます*2。試しにイテレータと、イテレータのnext()を呼んでプリントしてみます。

const iter = Array(5).keys()

console.log(iter) // => {} 
// 配列が返ってくるわけではない。

console.log(iter.next()) // => { value: 0, done: false }
console.log(iter.next()) // => { value: 1, done: false }
console.log(iter.next()) // => { value: 2, done: false }
console.log(iter.next()) // => { value: 3, done: false }
console.log(iter.next()) // => { value: 4, done: false }
console.log(iter.next()) // => { value: undefined, done: true }
console.log(iter.next()) // => { value: undefined, done: true }

for-of文はof以下にイテレータが渡されると、イテレータがdoneになるまでnextを呼び続けてvalueを渡すので*3

const iter = Array(5).keys()

for (const i of iter) {
  console.log(i);
  // => 1
  // => 2
  // => 3
  // => 4
  // => 5
}

となり回数指定ループが実現できます。