valid,invalid

関心を持てる事柄について

JetBrains Free Open Source Licenseを取得した

JetBrains Free Open Source Licenseを取得したのでやったことをメモしておく。このライセンスは1年ごとに更新が必要なため、来年も同じ手順を行うかもしれない。

Free Open Source Licenseとは

Open source projectでの開発に使用できるライセンスのこと。利用するにはJetBrainsが定める条項を満たす必要がある。その条項は以下から確認できる。

www.jetbrains.com

注意点があって、取得したライセンスは非商用開発にしか利用できない。商用・業務で利用する場合は別途ライセンスを取得しなければならない。

  • Licenses can be used for non-commercial OS development only. Please consider purchasing separate licenses to work on commercial projects.
  • Use of the software is restricted to the licensed user with no right to transfer the software to any third parties.

取得方法

上記サイトに書いてあるので省略する。基本的には「自分がどのプロジェクトのcore contributorであるのか」を示す情報でフォームを埋めていくだけ。

自分は特定の著名OSSのcore contributorというわけではないので、自身で開発しているgoofiというweb applicationで申請を行った。

github.com

OSS contributionを支援するOSSという若干メタな立ち位置なうえ、99%一人で開発しているので Your OS project's community is active. という条件を満たさないかもしれないとは思っていたが通ってよかった。

goofiについては以前に発表した内容があるので詳細は以下。

Node学園祭 #nodefest で『貢献できるOSSの見つけ方 -完結編-』という発表をしてきました - valid,invalid

申請内容

f:id:ohbarye:20190427145701p:plain
申請時の入力フォーム

上記画像で見切れてしまっているProject description欄には以下の文章を書いた。

Goofi is a simple web application to list issues labeled as "good first issue" in major repositories. With this app, developers who would like to contribute to anything can find issues or repositories to contribute.

What this app tries to solve is "contribution barrier": In my observation, most OSS projects want more contribution and there are quite many developers who would like to contribute to any OSS project but most of them don't know how to find issues or repositories. Therefore, unfortunately, nothing happens. It seems there is a barrier.

Acceptされるまで

2019-03-28 22:47 JST に申請し、2019-04-01 21:04 JST にAcceptされたとのメールが来た。

その後

ふだんはRubyMineを使っているのでこの機会にまったく普段さわらないやつを使ってみたいと思う。とりあえずCLionでC言語を(初めて)書いてみている。

また、複数の製品を管理するためのJetBrains Toolboxという製品があると知ったので試しているがなんだか挙動が安定しない気がする。

JetBrains Toolbox App: Manage Your Tools with Ease

macOSでirbのhistoryが使えなくなったときの対処法

あるmacOSでいつの間にか、irbhistoryが使えなくなっていた。使えないとは、irbで矢印キーの↑を押すと制御文字 ^[[A が表示され、ENTERを押すとirbプロセスが終了するような状態。

$ irb
irb(main):001:0> RUBY_VERSION
=> "2.6.0"
irb(main):002:0> ^[[A

$ 

Ruby versionは異なるが、macos - IRB history not working with Ruby 2.3.0 - Stack Overflowに従って再インストール(再ビルド)することで解消した。

rbenv automatically detects homebrew and looks in it for readline, so, if you're using Homebrew and irb history doesn't work, you either haven't installed readline or you built your Ruby before you installed readline.

  • brew install readline if it isn't installed already
  • rbenv uninstall 2.3.0
  • rbenv install 2.3.0

なぜこれで直るのか?

StackOverflowの解説を読んでへーと思ったのでメモ。

OS X's command-line editing is based on the libedit library. OS X has a version of the readline library which is a wrapper around libedit, but it does not behave completely like GNU readline. irb history works in Ruby built with OS X's wrapper up to Ruby 2.1, but Ruby 2.2 and later need to be built with GNU readline for irb history to work.

  • OS Xコマンドライン編集ではlibeditのラッパーを使っているがGNU readlineとの完全な互換性はない
  • Ruby2.1まではそれで動いていたが、2.2以降はGNU readlineとともにビルドする必要がある
  • Rubyのビルド時にhomebrewでインストールされたreadlineを検出して使用するようになった ref

readlineとは?

以下の記事に詳しい。

readline は、CUI アプリケーションにおいてユーザが行を入力する際に便利な「行頭・行末移動」「ヒストリ機能」などを提供するライブラリである。readline というコマンドがあるわけではない。

readlineコマンドの使い方: UNIX/Linuxの部屋より引用)

そもそもlibeditとは?

知らなかったのでググった。

readline のライセンスが GPL であることを嫌い、NetBSD 界隈で readline 互換の libedit というライブラリが開発された。editline と表記することもある。

libedit は GPL ではなく BSD ライセンスとなっている。readline との互換性 100% が目標だが、libedit 独自の機能拡張もある。

readlineコマンドの使い方: UNIX/Linuxの部屋 より引用)

とのこと。ややこしい。

macOSのlibeditに関する問題点は他にもいろいろあるようだ。

環境

対人関係のリスクを取っている

今日職場で↑のツイートに言及して「ohbaryeさんは対人関係のリスクを取っているんですか?」と聞かれた。

どう見えますか?と質問を質問で返すと「取っていると思いますよ」とのこと。(なるほど?)

なぜリスクを取るか…いろんな思惑はあるが一つはやはり健康な職場を目指したい気持ちがある。この文脈でいう健康はハイコンテクストなのだが二段階あり:

  1. 対人関係のリスクを取れる状態(過渡期)
  2. リスクを取るのが常態化してきて、もはやリスクと感じない状態(理想形)

2を目指すためにはまず自分が率先してリスクを取っていき、それが当たり前な状態にしたいからリスクを取っていきましょう、という話をした。

俺が日和ってたら殴ってくれ!


余談だが、リスクを取っているが周囲にはそのように思わせないスキルを持っている人もいて凄みがある。

2018年に読んで心が動いた漫画 (1)

2019年1月も終わっていますが2018年に読んで心が動いた漫画の一覧を紹介します。対象は以下。

  • 2018年に買った・読んだ漫画
  • 2018年より前から読んでいて続刊を買った・読んだもの
  • 2018年以前に完結しているが初めて読んだもの

おすすめ順に並べるとかカテゴリ順に並べるとか考えたのですが終わらなさそうなのでやめました。コメント量が多いものがおすすめです(たぶん)。

また、一記事に収まらなかったのでとりあえず20作品だけ。

続きを読む

GatsbyjsがContributorにグッズを配布したりする取り組み

Static site generator の GatsbyJS が掲題の取り組みを始めたようす。


朝起きたらだいぶ前にめっちゃ小さくコントリビュートしたときの pull request にコメントが付いていた。

f:id:ohbarye:20190217181458p:plain

Gatsby community の OSS に貢献した人への感謝の気持ちとして

  1. Gatsby Swag Store*1 でグッズと引き換えられるクーポンをあげる
  2. GitHubGatsby organization に招待する

とのことだった。早速グッズを注文*2して org にも join してみた。

f:id:ohbarye:20190217182223p:plain
Tシャツと迷ったのだがテック系イベント等で入手したTシャツが棚に溢れているのを思い出してキャップを選択


sustainable な OSS community をどのように成立させるか?という問については昨年のNode festivalで発表する程度には関心があるので、この取り組みは非常に面白いと思った一方、グッズのデザイン・製造・販売、これはもはや事業だよな〜と思っていたら2018年5月にすでに会社が設立されていたことをいまさら知る。


興味が湧いた方はぜひ Contribution をどうぞ。

github.com

*1:Shopify製

*2:到着には 6 weeks or more かかるらしい

ReactのContextとHooksで日本語のふりがな入力を支援するコンポーネント書いた

(2019-09-22追記) この記事の内容と公開したライブラリはdeprecatedとしました。詳しくは ReactのuseStateで日本語のふりがな入力を支援するhook書いた - valid,invalid 参照

漢字を入力したときにふりがなを自動入力する機能をサポートするためのReact componentを書いてみました。日本語のフォームでよくあるやつです。

demo

github.com

www.npmjs.com

最近は仕事でReactをあまり書いておらず16以降のContextとか16.8のHooksとか新し目の機能のことがわかっていなかったので、その辺で遊びたかったのがモチベーションです。

Hooks と言っていますが目玉ぽい useState の話でなく useReducer, useContext がメインです。

実装

使いかたはREADMEに書いたのでさらっと流します。以下のような感じで Kana(Provider|Dispatcher|Consumer)react-kana-provider が提供します。provider, consumer という名前からわかるとおり React Context を使っています。

import * as React from "react";
import * as ReactDOM from "react-dom";
import {
  KanaProvider,
  KanaDispatcher,
  KanaConsumer,
  KanaDispatcherProps,
  KanaConsumerProps
} from "react-kana-provider";

const App = () => (
  <KanaProvider fieldNames={["last_name"]}>
    <KanaDispatcher>
      {({ setKana }: KanaDispatcherProps) => (
        <input
          type="text"
          onChange={e => setKana("last_name", e.target.value)}
        />
      )}
    </KanaDispatcher>
    <KanaConsumer>
      {({ kana }: KanaConsumerProps) => (
        <input
          type="text"
          value={kana.last_name}
         />
      )}
    </KanaConsumer>
  </KanaProvider>
  );
);

ReactDOM.render(<App />, document.getElementById("root"));

実践: React Hooks - mizchi's blogに書かれている「useReducerとcontextを組み合わせてReduxのようにstateを管理する」というのを内部ではやっています。provider、consumerだけでなくdispatcherという名前のcomponentを提供しているのはそのためです。(実態はdispatcherもconsumerです)

漢字を入力するフィールド側(KanaDispatcher)で「漢字を入力する」イベントをdispatchし、内部のstateが更新され、ふりがなを入力するフィールド(KanaConsumer)側でそれを参照する流れです。

入力された文字列からひらがなを抽出するロジックはhistorykanaに丸投げです。

また、ふりがなフィールド側に値をどういう条件で・どのタイミングでセットするかは完全に利用者に委ねています。(ふりがなフィールドが入力済かどうかを検知したりはしない)

原形: context のみで書く

最初はuseReducerなどは使わずcontextだけでなんとかしようと、providerをラップした React.Component をがりがり書いていました。

import * as React from "react";
import historykana from "historykana";

const KanaContext = React.createContext("");

export class KanaProvider extends React.Component {
  constructor(props) {
    // 省略
  }

  setKana(fieldName, inputtedValue) {
    this.setState((state, props) => {
      const history = inputtedValue
        ? [...state.history[fieldName], inputtedValue]
        : [];

      return {
        ...state,
        history: {
          ...state.history,
          [fieldName]: history
        },
        kana: {
          ...state.kana,
          [fieldName]: historykana(history)
        }
      };
    });
  }

  render() {
    return (
      <KanaContext.Provider value={this.state.kana}>
        {this.props.children({
          setKana: this.setKana,
          kana: this.state.kana
        })}
      </KanaContext.Provider>
    );
  }
}

export const KanaConsumer = ({ children }) => (
  <KanaContext.Consumer>{kana => children({ kana })}</KanaContext.Consumer>
);

これはこれで動くのですが遊び足りない React.Component を使わなくなっていく流れに沿ってないなーと思ったり、ライブラリ利用者側では consumer は 切り離せるのに state を更新する setKana 関数は利用する component まで props で渡していくのが不均衡だなと思ったりしました。

現状: useReducer + context で書く

現在の react-kana-provider の実装を一部省略しつつ貼ります。(上記実装との間にミッシングリンクがあり、突然 TypeScript になります)

import * as React from 'react';
import historykana from 'historykana';

function reducer(state: KanaProviderState, action: any) {
  switch (action.type) {
    case 'SET_KANA': {
      const { inputtedValue, fieldName } = action;
      const history = inputtedValue
        ? [...state.history[fieldName], inputtedValue]
        : [];

      return {
        ...state,
        history: {
          ...state.history,
          [fieldName]: history,
        },
        kana: {
          ...state.kana,
          [fieldName]: historykana(history),
        },
      };
    }
    default: {
      return state;
    }
  }
}

const KanaContext = React.createContext<KanaProviderState>(null as any);
const DispatchContext = React.createContext<React.Dispatch<any>>(null as any);

export const KanaProvider: React.FunctionComponent<{
  fieldNames: string[];
}> = ({ fieldNames, children }) => {
  const [state, dispatch] = React.useReducer(
    reducer,
    getInitialState(fieldNames),
  );
  return (
    <KanaContext.Provider value={state}>
      <DispatchContext.Provider value={dispatch}>
        {children}
      </DispatchContext.Provider>
    </KanaContext.Provider>
  );
};

export const KanaDispatcher: React.FunctionComponent = ({ children }) => {
  const dispatch = React.useContext(DispatchContext);
  const setKana = (fieldName: string, inputtedValue: string) =>
    dispatch({ type: 'SET_KANA', fieldName, inputtedValue });
  return typeof children === 'function' ? children({ setKana }) : null;
};

export const KanaConsumer: React.FunctionComponent = ({ children }) => {
  const { kana } = React.useContext(KanaContext);
  return typeof children === 'function' ? children({ kana }) : null;
};

すっきりしています。記述量はさほど変わっていないので一見これ本当にすっきりしてんのかという感じですが、state を更新する責務が reducer にまとめられたりしているため、Redux 利用者ならさらっと読み下せるようになったのではと感じます。 export している component がすべて React.FunctionComponent に置き換えられているのも良さそうです。

dispatcher を提供しているので prop drilling 問題も解消してます。

CodeSandbox

これまで使っていなかったのですがアイデアを試したいときに超絶便利ですね。自分はフロントエンドの環境構築能力がダメダメなので一瞬で立ち上げてもらえて非常に助かりました。

f:id:ohbarye:20190210112250p:plain

CodeSandbox上で「ライブラリ側」と「利用者側」のコードを同時に編集できるのも実験がしやすくて最高です。ライブラリが提供するAPIについてインタラクティブに試行錯誤したりできます。

今回は「よーしライブラリ書くぞ!」と意気込んで始めたというより、CodeSandbox上で「こんなことできるかな」といろいろ試してたらなんかできたので面白かった、公開しておくか、という流れでした。

所感

久々に触ったらいろいろ学びがあってよかったですが、逆にまだまだわからないことがいっぱいあるなと思いました。React + TypeScript にまだ身体が順応しきってなくてけっこう手が止まる。

また、npm publish したものの hooks 使っているので16.8以上じゃないと使えない、おまえ使ってもらう気あるのかという感じですが一旦は自分のためのコードということで。

余談

実はけっこう前にこういうのを書こうとしたけど完全に記憶から消えていた、というのを思い出した。以前に jquery.autokana というライブラリを使っていて、その repository の issue で「オレもいつか React で書いてみるわ!」とか宣言していた…!

(1年以上かけて伏線を回収した感がある)

わかっていないこと

このあと調べたり詳しい人に聞いたりしたい

そもそもこのやりかたでよいのか

わざわざ context とか hooks 使わなくても render props とか HOC でも書けるので、解決したい問題に対してベストなアプローチなのかわかってない

実験の仕方

CodeSandboxでごりごり書いて実装したけど、世の中で React の component ライブラリ書いている人はどうやって開発・実験・テストしているのか

hooks の polyfill

React context には create-react-context という polyfill があるが、hooksにもあるのかな?もしあれば対応する React の version を下げられる