Quantcast
Channel: もくもくブログ
Viewing all 216 articles
Browse latest View live

Neovimはじめました & 2016年vimrc大掃除

$
0
0

11月あたりからvim環境を見直して概ねまとまってきたのでメモとして残しておきます。

概要は

  • Neovim導入
  • プラグイン整理(neobundle => dein.vim)
  • Neovim/Vim/Nyaovim対応

になります。

設定ファイルはGitHubの.dotfilesにあるのでこちらを見ればこの記事は読まなくてもいいかもしれません。

embed.ly


Neovimはじめました

Home - Neovim

Neovimのterminal modeに感動してNeovimをはじめてみることにしました。

あとVimよりサクサク動いていて、思考の速度に近づいてる気がします。

Neovimのインストールはパッケージマネージャーから

OSXとUbuntuでの開発が多いのでパッケージマネージャーを使ってインストールすることにします。

しかもNeovimの場合パッケージマネージャーを使用して新しいNeovimをインストールすることが可能なので手元でビルドしなくていいのもメリットだと感じています。

あとPython拡張を使うのでインストールと一緒に有効にしておきます。

OSXの場合(homebrew-neovim/README.md at master · neovim/homebrew-neovim)

brew tap neovim/neovim
brew install --HEAD neovim
brew install python
brew install python3
pip2 install --user --upgrade neovim
pip3 install --user --upgrade neovim

Ubuntuの場合(Installing Neovim · neovim/neovim Wiki)

sudo apt-get install software-properties-common
sudo add-apt-repository ppa:neovim-ppa/unstable
sudo apt-get update
sudo apt-get install neovim
sudo apt-get install python-dev python-pip python3-dev python3-pip
sudo pip2 install --user --upgrade neovim
sudo pip3 install --user --upgrade neovim

手元でビルドする場合、CentOS6以前などではビルドに必要なツールをビルドする必要があったりするので、自分の場合は環境によってはNeovimは諦めてVimも併用で使うようにしています。

設定ファイルの場所

デフォルトでは"~/.config/nvim/init.vim"がVimで言う"~/.vimrc"になります。

環境変数"$XDG_CONFIG_HOME"を変更することで、デフォルトの"~/.config"部分を変更できます。

今後Neovimメインで使っていくような気がしているので、.vimrcへのシンボリックリンクを作成することでVimも同じ設定で使えるようにしています。

Nyaovimもはじめました

MiniBrowserプラグインを使って、Web開発のプレビューを横に出しながらプログラミングできて楽しいです。

Markdownプレビューも最高です。

設定ファイル(~/.config/nyaovim/nyaovimrc.html)

<dom-moduleid="nyaovim-app"><template><style>
      /* CSS configurations here */
      .horizontal {
         display: flex;
         width: 100%;
         height: 100%;
       }
       neovim-editor {
         width: 100%;
         height: 100%;
       }
    </style><!-- Component tags here --><divclass="horizontal"><neovim-editorid="nyaovim-editor"argv="[[argv]]"font-size="16"font="Meslo LG M DZ for Powerline"></neovim-editor><markdown-previeweditor="[[editor]]"></markdown-preview><mini-browserurl="https://google.com"editor="[[editor]]"></mini-browser></div><popup-tooltipeditor="[[editor]]"></popup-tooltip></template></dom-module>

Nyaovimプラグインもdein.vimで読み込むのですが、"if exists('g:nyaovim_version')"を使うことでNyaovim固有の設定を記述します。

プラグイン整理

今までの構成を大幅に変更してみました。dein.vimによる影響が大きいですが以下の点が今までと大きく変わりました。

  • cacheの利用
  • プラグイン遅延ロード
  • tomlファイルでプラグイン管理
  • NeovimとVimとNyaovimで設定を分ける
  • NeovimとVimとNyaovimで使用するプラグインも使い分かる

Neovimをメインに据えていくのでルートディレクトリは"~/.config/nvim"で、ディレクトリ構成は以下のようになっています。

~/.config/nvim
├── dein.toml
├── deinlazy.toml
├── init.vim
├── keymap.rc.vim
├── options.rc.vim
└── plugins
    ├── airline.rc.vim
    ├── anzu.rc.vim
    ├── deoplete.rc.vim
    ├── iceberg.rc.vim
    ├── neocomplete.rc.vim
    ├── neomake.rc.vim
    ├── neoterm.rc.vim
    ├── nerdcomenter.rc.vim
    ├── syntastic.rc.vim
    ├── vimfiler.rc.vim
    ├── vimshell.rc.vim
    └── yankround.rc.vim

dein.vim

Shougo氏がdein.vimという新しいプラグインマネージャを作っていたのでそちらに移行しました。

基本的にShougo氏のvimrcを参考にして作ってみました。

このあたりを参考にして以下のようなinit.vimになりました。

if&compatiblesetnocompatibleendif

augroup MyAutoCmd
  autocmd!
augroup END

if exists('g:nyaovim_version')let s:dein_cache_path = expand('~/.cache/nyaovim/dein')elseif has('nvim')let s:dein_cache_path = expand('~/.cache/nvim/dein')elselet s:dein_cache_path = expand('~/.cache/vim/dein')endiflet s:dein_dir = s:dein_cache_path
                 \ .'/repos/github.com/Shougo/dein.vim'if&runtimepath!~'/dein.vim'if!isdirectory(s:dein_dir)
    execute '!git clone https://github.com/Shougo/dein.vim' s:dein_dir
  endif
  execute 'set runtimepath+=' . fnamemodify(s:dein_dir,':p')endifif dein#load_state(s:dein_cache_path)call dein#begin(s:dein_cache_path)call dein#load_toml('~/.config/nvim/dein.toml', {'lazy' : 0})call dein#load_toml('~/.config/nvim/deinlazy.toml', {'lazy' : 1})if exists('g:nyaovim_version')call dein#add('rhysd/nyaovim-popup-tooltip')call dein#add('rhysd/nyaovim-markdown-preview')call dein#add('rhysd/nyaovim-mini-browser')endifcall dein#end()call dein#save_state()endifif dein#check_install()call dein#install()endiffiletype plugin indent onsyntax enable

runtime!options.rc.vim
runtime!keymap.rc.vim

ポイントは、Neovim/Vim/Nyaovimでcacheのパスを使い分けて各々のプラグインを使用できるようにしています。

Vim本体の設定とKeymapは別ファイルとして最後に読み込んでいます。

Neovimも開発中なので、プラグインに関しても日々更新されていくものが多いので、動作がおかしいときや数日に一度は":call dein#update()"してプラグインを更新すると良いです。

管理するプラグインについてはdein.toml(遅延ロードするプラグインはdeinlazy.toml)に書きます。

[[plugins]]repo='xxx/yyy'

基本的には上の書き方で、設定がある場合はhook_*を使って設定を読み込みます。

  • hook_addはプラグイン追加後
  • hook_sourceはプラグイン読み込み前
  • hook_post_sourceはプラグイン読み込み後

(ドキュメント => dein.vim/dein.txt at master · Shougo/dein.vim)

hookのスクリプトに"source .vim"と書いて外部のVim scriptを読み込むようにするとtomlファイルがすっきりするので、設定が長くなるプラグインなどはそうしています。

ifというキーを使ってNeovimやVimの切り替えができます。

以下はneocompleteとdeoplete.nvim、neotermとvimshellの例です。

[[plugins]]repo='Shougo/neocomplete.vim'depends='context_filetype.vim'if="has('lua')"on_i=1hook_source='''source~/.config/nvim/plugins/neocomplete.rc.vim'''[[plugins]]repo='Shougo/deoplete.nvim'depends='context_filetype.vim'if="has('nvim')"on_i=1hook_source='''source~/.config/nvim/plugins/deoplete.rc.vim'''[[plugins]]repo='kassio/neoterm'if="has('nvim')"hook_add='''source~/.config/nvim/plugins/neoterm.rc.vim'''[[plugins]]repo='Shougo/vimshell'if="!has('nvim')"hook_add='''source~/.config/nvim/plugins/vimshell.rc.vim'''

これを書くまでに参考にして勉強したりした情報集です、ありがとうございました。

Vimの文法はこちら


残りは気になった個別のプラグインについて書いていきます。

iceberg

Iceberg - dark color scheme for Vim

目に優しそうでカッコいいカラースキームです。

visual modeを結構多用するのですが、モニターのブルーライトカットが効きすぎているのか色が分かりづらかったのでオレンジ色に変えてあります。

au MyAutoCmd VimEnter * nested colorscheme iceberg
" Visual modeau MyAutoCmd VimEnter * highlight Visual ctermbg=216" backgroung transparency"au MyAutoCmd VimEnter * highlight Normal ctermbg=none"au MyAutoCmd VimEnter * highlight NonText ctermbg=none"au MyAutoCmd VimEnter * highlight TablineSel ctermbg=none"au MyAutoCmd VimEnter * highlight LineNr ctermbg=none"au MyAutoCmd VimEnter * highlight CursorLineNr ctermbg=none

カラースキームを使う場合、一行目の記述は必須のようです。

neoterm

neovimのterminal modeが便利すぎてやばいです。

とりあえずいつもどおりにノーマルモードを使用するために以下の設定をします。

if has('nvim')
  tnoremap <silent><ESC><C-\><C-n>endif

もっと便利に使うためにneotermを導入します。

kassio/neoterm: Wrapper of some neovim's :terminal functions.

neotermはneovimのterminalラッパープラグインです。手軽に分割ターミナルとかが使えます。

さらに、ファイルや行、選択範囲をreplに突っ込んでterminalで実行したりテスト連携があったりと便利機能満載です。

以下のように設定しました。

  • Quickrunの代用ぽい設定
  • toggleする設定
  • vimshellの代用ぽい設定
[[plugins]]repo='kassio/neoterm'if="has('nvim')"hook_add='''nnoremap<silent>,rc:TREPLSendFile<cr>nnoremap<silent>,rl:TREPLSendLine<cr>vnoremap<silent>,rl:TREPLSendSelection<cr>nnoremap<silent>vt:Ttoggle<cr>nnoremap<silent>vs:terminal<cr>'''

shellを指定している方を多く見ましたが、自分の環境では$SHELLが開いている感じがしたので設定していません。

embed.ly

とは言いましたが、Vimではterminal modeは使えないのでVimShellを使うように設定しています。

[[plugins]]repo='kassio/neoterm'if="has('nvim')"hook_add='''source~/.config/nvim/plugins/neoterm.rc.vim'''[[plugins]]repo='Shougo/vimshell'if="!has('nvim')"hook_add='''source~/.config/nvim/plugins/vimshell.rc.vim'''[[plugins]]repo='Shougo/vimproc.vim'if="!has('nvim')"build='make'

neomake

非同期でmakeやlintを実行するsyntasticの非同期版のようなプラグインです。

READMEは最低限の内容のみとなっているので、helpを読みながら設定していきます。

まず、見た目の設定です。

" color
autocmd!BufWritePost * Neomake
au MyAutoCmd ColorScheme * hi NeomakeErrorSign cterm=bold ctermfg=7 ctermbg=9au MyAutoCmd ColorScheme * hi NeomakeWarningSign cterm=bold ctermfg=8 ctermbg=216au MyAutoCmd ColorScheme * hi NeomakeMessageSign cterm=bold ctermfg=8 ctermbg=150au MyAutoCmd ColorScheme * hi NeomakeInfoSign cterm=bold ctermfg=8 ctermbg=110" textletg:neomake_error_sign = {'text': 'E✖','texthl': 'NeomakeErrorSign'}
letg:neomake_warning_sign = {
    \   'text': 'W➤',
    \   'texthl': 'NeomakeWarningSign',
    \ }
letg:neomake_message_sign = {
     \   'text': 'M➤',
     \   'texthl': 'NeomakeMessageSign',
     \ }
letg:neomake_info_sign = {'text': 'ℹ➤','texthl': 'NeomakeInfoSign'}

基本的にここにあるmakerは使えます。有効にする際は以下のように書きます。

let g:neomake_<lang>_enabled_makers = ['<maker>', '<maker>']

maker名は末尾の名前です、例えばneomake/cpp.vim at master · neomake/neomakeにある"function! neomake#makers#ft#cpp#gcc()"の場合は"gcc"になります。

複数指定すると複数個makerが動くことになるので動作が被ってる場合、同じメッセージが複数出ます。

makerは自作することもできるようです。

g:neomake_{filetype}_{makername}_maker

ディレクトリmakerという機能もあるようなので気になります。

Vim7.4.503からneomakeは使用可能ですが、syntasticに慣れていたのもありVimを使う時はsyntasticを使うようにしています。

[[plugins]]repo='neomake/neomake'if="has('nvim')"hook_add='''source~/.config/nvim/plugins/neomake.rc.vim'''[[plugins]]repo='vim-syntastic/syntastic'if="!has('nvim')"hook_add='''source~/.config/nvim/plugins/syntastic.rc.vim'''

ちなみにSyntasticもneomakeと同じような見た目になるように設定しています。

" ColorSchemeau MyAutoCmd VimEnter * highlight SignColumn ctermbg=237au MyAutoCmd VimEnter * highlight SyntasticErrorSign cterm=bold ctermfg=255 ctermbg=203au MyAutoCmd VimEnter * highlight SyntasticWarningSign cterm=bold ctermfg=233 ctermbg=150letg:syntastic_error_symbol ='E➤'letg:syntastic_warning_symbol ='W➤'" Basic settingletg:syntastic_always_populate_loc_list =1"let g:syntastic_auto_loc_list = 1letg:syntastic_check_on_open =1letg:syntastic_check_on_wq =0" for javascriptletg:syntastic_javascript_checkers = ['eslint']
" for c/cppletg:syntastic_cpp_compiler_options ='-Wall'

deoplete.nvim

neocompleteに次ぐ補完プラグインです。

deinlazyに追加します。

[[plugins]]repo='Shougo/deoplete.nvim'depends='context_filetype.vim'if="has('nvim')"on_i=1hook_source='''source~/.config/nvim/plugins/deoplete.rc.vim'''

deoplete.rc.vim

letg:deoplete#enable_at_startup =1" <TAB>: completion.inoremap<silent><expr><TAB>
      \ pumvisible() ? "\<C-n>" :
      \ <SID>check_back_space() ? "\<TAB>" :
      \ deoplete#manual_complete()function! s:check_back_space() abort "{{{letcol=col('.')-1return!col|| getline('.')[col-1]  =~'\s'endfunction"}}}

" <S-TAB>: completion back.inoremap<expr><S-TAB>  pumvisible() ? "\<C-p>" : "\<C-h>"" <BS>: close popup and delete backword char.inoremap<expr><BS> deoplete#smart_close_popup()."\<C-h>"" Use auto delimitercall deoplete#custom#set('_','converters', [
      \ 'converter_remove_paren',
      \ 'converter_remove_overlap',
      \ 'converter_truncate_abbr',
      \ 'converter_truncate_menu',
      \ 'converter_auto_delimiter',
\ ])letg:deoplete#enable_camel_case =1

deoplete.nvim/deoplete.txt at master · Shougo/deoplete.nvim

ドキュメントを見ると言語ごとにEXTERNAL SOURCESがあるので、開発する言語を中心にプラグインを適宜追加していけば良さそうです。

vim-airline

airlineは対応しているプラグインも多く設定も少なくて済むので、とても好きなpowerlineです。

dein.vimは依存関係を書けるので設定ファイルがわかりやすくなって良いです。

[[plugins]]repo='majutsushi/tagbar'[[plugins]]repo='tpope/vim-fugitive'[[plugins]]repo='vim-airline/vim-airline'depends=['tagbar', 'vim-fugitive']hook_add='''source~/.config/nvim/plugins/airline.rc.vim'''[[plugins]]repo='vim-airline/vim-airline-themes'depends='vim-airline'hook_add='''let g:airline_theme='luna''''

airline.rc.vim

if exists('g:nyaovim_version')letg:airline_powerline_fonts =0letg:airline_left_sep =''letg:airline_right_sep =''elseletg:airline_powerline_fonts =1endifletg:airline#extensions#tabline#enabled =1if!has('nvim')letg:airline#extensions#whitespace#mixed_indent_algo =2" see :help airline-whitespace@enendif

NyaovimでPowerlineFontが崩れてしまったのでNyaovimでは無効にしています。

mixed_indentがうざかったりしますがドキュメントを読むとアルゴリズムを変更できるので賢めのアルゴリズムに変更しています。

Vimfiler

Shougo/vimfiler.vim: Powerful file explorer implemented by Vim script

便利すぎて手放せないプラグインです。

[[plugins]]repo='Shougo/unite.vim'hook_add='''nnoremap<silent>fb:<C-u>Unitebuffer<CR>'''[[plugins]]repo='Shougo/vimfiler.vim'depends='unite.vim'hook_add='''source~/.config/nvim/plugins/vimfiler.rc.vim'''

vimfiler.rc.vim

call vimfiler#custom#profile('default','context', {
     \ 'safe' : 0,
     \ 'auto_expand' : 1,
     \ 'parent' : 0,
     \ })"default explore -> vimfilerletg:vimfiler_as_default_explorer =1"buffer directorynnoremap<silent> fe :<C-u>VimFilerBufferDir -quit<CR>" Nerdtree likennoremap<C-e> :<C-u>VimFilerBufferDir -split -winwidth=120-toggle -no-quit<CR>"key mapping
autocmd MyAutoCmd FileType vimfiler call s:vimfiler_my_settings()function! s:vimfiler_my_settings()nnoremap<silent><buffer><expr> s vimfiler#do_switch_action('vsplit')nnoremap<silent><buffer><expr>v vimfiler#do_switch_action('split')nnoremap<silent><buffer><expr>t vimfiler#do_action('tabopen')endfunction" Textmate iconsletg:vimfiler_tree_leaf_icon =' 'letg:vimfiler_tree_opened_icon ='▾'letg:vimfiler_tree_closed_icon ='▸'letg:vimfiler_file_icon ='-'letg:vimfiler_marked_file_icon ='*'

関数内検索

1000行くらいの長い関数がひしめき合ってるコードと向かい合うとき関数内検索があるとかなり便利なので下記の情報を元にできるようにしました。かなり便利です。

[[plugins]]repo='kana/vim-operator-user'[[plugins]]repo='kana/vim-textobj-user'[[plugins]]repo='kana/vim-textobj-function'[[plugins]]repo='osyo-manga/vim-operator-search'depends=['vim-operator-user', 'vim-textobj-function', 'vim-textobj-user']hook_add='''nmap<Space>/<Plug>(operator-search)if'''

/で検索できます。


deoplete.nvimが効かなくなった時の手元できる対処法

$
0
0

開発中なのもありよく動かなくなっているので試したことリストの備忘録です。

公式でもなく完全な対処方法であるかの確認もしてないので参考程度にして下さい。この方法で解決できない場合はIssueかなぁという判断基準にはなるかもしれません。

順番や番号に意味はありません。

1. プラグインのアップデート

:call dein#update()
:NeoBundleUpdate

など

2. :CheckHealth

:CheckHealth

このコマンドを実行して出てくる内容に応じて後述の対処をします。

3. has('python3')確認

:echo has('python3')

1ならok。

0の場合、状況に応じて他の方法を試す。

4. python3のインストール

macOS

brew install python3

ubuntu 14.04 later

apt-get install python3

など

5. neovimパッケージをインストールまたはアップデート

pip3 install --upgrade neovim

6. :UpdateRemotePlugins

Neovimをインストールまたはアップデートした後、deoplete.nvimを使うのに必要になります。

:UpdateRemotePlugins

7. Neovimが古い

macOS

brew update
brew upgrade neovim

または

brew install --HEAD neovim

アップデートできたら再度上記の内容を試します。

zsh -> fish 移行プロセス

$
0
0

込み入った設定をしないでスッと移行することを目的にしています。

.zshrcを投げ捨ててます。

自分の場合、zshrcの設定内容にコピー&ペーストが多かったので気持ち的に楽に投げ捨てられました。

fishのインストール

主要なOSのパッケージマネージャーでインストール可能なのでスッとインストールします。

fishermanを導入

fishのプラグインマネージャーです。oh-my-fishとも互換性があります。

日本語 · fisherman/fisherman Wikiを参考にインストールします。

$ curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs git.io/fisher

インストールできるプラグイン一覧は以下のコマンドで確認できます。

$ fisher ls-remote

手始めにthemeをインストールします。

$ fisher install omf/theme-bobthefish

設定

設定は~/.config/fish/config.fishに書きます。

欲しかったものはほとんどデフォルトとfishermanがやってくれるので環境変数の設定を主に書いていくことになります。

fishではexportはなくset -xで環境変数を設定します。

set -x XDG_CONFIG_HOME $HOME/.configset -x GOPATH $HOME/Documents/Goset -x PATH $HOME/.cargo/bin $PATHset -x RUST_SRC_PATH /usr/local/src/rust/srcset -g theme_color_scheme zenburn

現状config.fishはこの5行です、すっきり。

nvm

$ fisher install nvm

fishでもnvmを使ってnodejs開発できます。

bash互換のスクリプトを使ったツールが使えなくなることが多いですが有名所はプラグインで解決できそうです。

bassというbashスクリプト動かせるプラグインがあるので、困り果てたら自前で書いてしまっても良さそうです。

デフォルトシェル設定

/etc/shellsに"which fish"コマンドの結果を足してから、chshします。

ref

遊び感覚で手を出した Isomorphic Javascript 開発話

$
0
0

去年(2016年8月頃)、社内で使う電話帳blacklistアプリをIsomorphic Javascriptで作りながらWikiにまとめていた開発話が面白い感じになっていたのでその転載です。

GitLab上で開発していたのでJavascript以外にもGitLab CIの話もあります。

開発話

Reactを使用して楽をしたいので、開発言語はNode.jsを選択。

versionは新しいものを使っていこうと思うので、v6.3.0を使っていきます。

$ mkdir blacklist
$ cd blacklist
$ npm init
$ git init
$ vim .gitignore # https://gist.github.com/pmq20/2887714

全てESで書けるのでisomorphicということになる。

Node.jsの問題はここから使用するツールをいろいろ選択肢ないとなところ...

まずは、定番ぽいものを選択してboilerplateを作成していく。

  • サーバサイド => Koa
  • フロントエンド => React
  • コンパイラ => Babel
  • モジュール管理 => Webpack
  • ビルド => Gulp(この手のbuildツール使いたくない...)
  • テスト => Mocha

ウッ。。。。オオスギ。。。。。

Boilerplate

ES6で書くIsomorphicアプリ入門 - Part1: リソース - Qiita

このリンクからわかるように様々な人が色んなboilerplateを作成していて、しかも割りと複雑で控えめに言って地獄。

dozoisch/koa-react-full-example: Full example using Koa, React, Passport, Mongoose, Webpack, Mocha, Babel

今回は必要ないもの多すぎる気がするけど参考に眺めてみると...

  • npmコマンドで諸々のことができるようなのでgulpは死亡。
  • webpackが開発サーバ建てれるようなのでwebpackの調査
  • .babelrcという設定ファイルがあるようなのでbabelの調査
  • eslint使うの良さそう

いろいろ大変そうだが以下の記事が最高だと感じたので全面的に参考にしていく。

Building a boilerplate for a Koa, Redux, React application including Webpack, Mocha and SASS

setup server-side (koa)

$ npm install --save koa

とりあえず一番シンプルなKoaを書いてみます。

./server.js

varkoa=require('koa');varapp=koa();app.use(function*(){this.body='Hello from koajs';});app.listen(3000);

Koaはシンプルな機能のみを提供していて、必要な機能はmiddlewareを追加していくアーキテクチャになっているので、APIサーバを書く予定なのでまずはrouterを追加する。

$ npm install --save koa-route
($ npm install --save koa-cors)

Koa単体だと、Cross Origin Resource Sharing (CORS)の対策がないのでAPIサーバを実装する場合には入れたほうが良い。

テンプレートエンジンと静的ファイルも使いたいので、必要なパッケージを追加します。

(参考: koa入門 - from scratch)

$ npm install --save koa-static co-views

これらのmiddle wareを使ってserver.jsを書きなおします。

varkoa=require('koa');varroute=require('koa-route');varserve=require('koa-static');varviews=require('co-views');varapp=koa();// Viewvarrender=views(__dirname+'/views');app.use(route.get('/',function*(){this.body=yieldrender('index.html');}));// API// Staticapp.use(serve(__dirname+'/app/dist'));app.listen(3000);

setup front-end (babel/webpack/react)

ディレクトリ構成は以下のようにする方針で行きます。

.
├── app
│   ├── dist
│   │   └── bundle.js
│   └── src
│       └── main.js
├── package.json
├── server.js
├── views
│   └── index.html
└── webpack.config.js

まずWebpackの準備をします。

$ npm install --save webpack
$ npm install --save-dev webpack-dev-server 

最初のwebpack.config.jsを書いてみます。

module.exports={entry:['./app/src/main.js'],output:{path:__dirname+'/app/dist',publicPath:'/',filename:'bundle.js'},devServer:{contentBase:'./app/dist'}};

publicPathは、この記事によると、

publicPath は webpack-dev-server で自動コンパイルするために必要(URLにおけるJSファイルへのパスを書く)

ということなので、index.htmlから参照するbundle.jsのディレクトリを指定します。

Webpackを実行してみます。

$ ./node_modules/.bin/webpack
Hash: 448a36d28f029188e4ee
Version: webpack 1.13.1
Time: 51ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.51 kB       0[emitted]  main
   [0] multi main 28 bytes {0}[built][1] ./app/src/main.js 0 bytes {0}[built]

bundle.jsが誕生しました。package.jsonのscriptsにwebpackビルドのコマンドを追加します。

"scripts": {
    "webserver": "node server.js",
    "build": "./node_modules/.bin/webpack",
    "dev": "./node_modules/.bin/webpack-dev-server"
  },

これで、"npm run build"や"npm run dev"でwebpackビルドやdev-serverの起動ができます。

さぁ、ここからが本番です。Let's yak shaving!

Webpackにbabelビルドを追加します。ついでにdevServerにHotRoadも追加します。

varwebpack=require('webpack');module.exports={entry:['./app/src/main.js'],module:{loaders:[{test:/\.jsx?$/,exclude:/node_modules/,loader:'babel'}]},resolve:{extensions:['','.js','.jsx']},output:{path:__dirname+'/app/dist',publicPath:'/',filename:'bundle.js'},devServer:{contentBase:'./app/dist',historyApiFallback:true,hot:true,inline:true,progress:true},plugins:[newwebpack.HotModuleReplacementPlugin()]};

babelビルドのためにbabel-loaderをインストールします。

$ npm install --save babel-loader

Webpack固有の記法がじゃんじゃんでてきてウッってなりますが、webpack.config.jsの読み方、書き方 - dackdive's blogなどの有用な日本語記事を呼んで気を安らげると良いです。

dev-serverでhotリロードするにはdistにhtmlが配置されてる必要があるようです(参考: webpack-dev-serverの基本的な使い方とポイント - dackdive's blog)

Koaのテンプレートとしてhtmlを扱っていたので、Koa+Webpack+Hotという構成を取る...?という流れになります。

そしてさっと探すだけでそういうものが見つかります。

glenjamin/webpack-hot-middleware: Webpack hot reloading you can attach to your own server

見てみると、serverサイドのコードにhotリロードのためだけに手を入れる必要がでてきます。

デプロイするときは無効にするようにwebpackでやったりするのかなぁ...

ウッ...オ、、、オッ、、、オゥエェェェェ

危険を察知したなので使うのをやめます。

KoaとWebpackを組み合わせるのはisomorphicとは言え面倒さがある気がします。

サーバサイドとフロントエンドで同じ言語を使えますが、その壁を綺麗さっぱりぶち壊すことはできません。

あらためて方針を決めていきます。

  • hotリロードは便利なので使う
  • htmlはSPA的(KoaのAPIを叩く)に使うことにして開発時はwebpack-dev-serverを使う
  • Koaで作るAPIも動かす必要があるので、開発時はKoaサーバとwebpack-dev-serverの両方を起動した状態で開発
  • デプロイ時は、Koaでapp/dist/index.htmlをViewとして使うがテンプレートとしては全く使用しない(ただ表示するのみ)

開発中に2つサーバを動かすことを妥協点としてやっていくことにします。

(正直この辺の選択は難しいのと個人差がありそうなので、皆さんがどうしてるか知りたいところ...)

ここで今までのことの60,70%くらいが水の泡と化したので改めて検討し直します。

方針を決める

フロントエンドのほうはそのままwebpackで行きます。

サーバサイドはAPIサーバとindex.htmlを単に表示して、jsとcssをstaticファイルとして配信することができればokです。

本番環境ではフロントエンドをWebpackでビルドして通ったらKoaサーバを動かして完了。

開発環境ではwebpack-dev-serverでフロントエンド開発、KoaサーバでAPI開発をします。(一応Koaサーバのindex.htmlで本番環境と同等の状態で動かせますがHotリロードはない)

setup server-side (Koa)

koa-staticとkoa-routeを使ってSPAとAPIを同じプロジェクト内に作ります。

varkoa=require('koa');varroute=require('koa-route');varserve=require('koa-static');varapp=koa();// Viewapp.use(serve(__dirname+'/app/dist'));// API// app.use(route.get('/api/xxx', function *(next) {// }));app.listen(3000);

setup front-end (webpack, babel, react)

reactを使う方向でディレクトリ構成を改めて決めていきます。

.
├── app
│   ├── dist
│   │   ├── bundle.js
│   │   └── index.html
│   └── src
│       ├── components
│       │   └── App.jsx
│       └── index.jsx
├── package.json
├── server.js
└── webpack.config.js

webpackを改めて書き直します。

varwebpack=require('webpack');module.exports={entry:['./app/src/index'],module:{loaders:[{test:/\.jsx?$/,exclude:/node_modules/,loaders:['babel']}]},resolve:{extensions:['','.js','.jsx']},output:{path:__dirname+'/app/dist',publicPath:'/',filename:'bundle.js'},devServer:{contentBase:'./app/dist',historyApiFallback:true,hot:true,inline:true,progress:true},plugins:[newwebpack.HotModuleReplacementPlugin()]};

reactを使っていくので必要なものをインストールします。

$ npm install --save react react-dom

babelでコンパイルするのですが、babelをreactとimportに対応させるためにパッケージと.babelrcが必要です(しばらくハマった...)

$ npm install --save-dev babel-preset-es2015 babel-preset-react

.babelrc

{
  "presets": ["react", "es2015"]
}

これで"npm run dev"でhot-reloadなwebpack-dev-server(:8080)でフロントエンド開発ができます。

最後に、ブラウザでのdebug用にsource-mapの追加と、pathが相対パスなのを修正します。

varpath=require('path');varwebpack=require('webpack');module.exports={devtool:'source-map',entry:[path.resolve(__dirname,'app/src/index')],module:{loaders:[{test:/\.jsx?$/,exclude:/node_modules/,loaders:['babel']}]},resolve:{extensions:['','.js','.jsx']},output:{path:path.resolve(__dirname,'app/dist'),publicPath:'/',filename:'bundle.js'},devServer:{contentBase:path.resolve(__dirname,'app/dist'),historyApiFallback:true,hot:true,inline:true,progress:true},plugins:[newwebpack.HotModuleReplacementPlugin()]};

setup test/lint

mochaとeslintのセットアップをしていきます。

eslint

eslintをdevにインストールして、initします。

$npminstall--save-deveslint$./node_modules/.bin/eslint--init?HowwouldyouliketoconfigureESLint?Answerquestionsaboutyourstyle?AreyouusingECMAScript6features?Yes?AreyouusingES6modules?Yes?Wherewillyourcoderun?Browser?DoyouuseCommonJS?No?DoyouuseJSX?Yes?DoyouuseReactYes?Whatstyleofindentationdoyouuse?Spaces?Whatquotesdoyouuseforstrings?Single?Whatlineendingsdoyouuse?Unix?Doyourequiresemicolons?Yes?Whatformatdoyouwantyourconfigfiletobein?JavaScriptInstallingeslint-plugin-reactblacklist@1.0.0└─┬eslint-plugin-react@6.1.2└──jsx-ast-utils@1.3.1

Vimのsyntasticにeslintを使うように書いておくと、

letg:syntastic_javascript_checkers = ['eslint']

今いるディレクトリのeslint.jsを読み込んでくれます。

実はinitで吐いたeslint設定では、jsx内で使ってるはずの変数に対して

error 'App' is defined but never used (no-unused-vars)

になります、これに困ってる方がたくさんいます

というわけで、initで生成したeslintの設定を少し変えてあげる必要があります。

eslint-plugin-reactのREADMEにあるように、rulesを追加します。

yannickcr/eslint-plugin-react: React specific linting rules for ESLint

"rules": {
    "react/jsx-uses-react": "error",
    "react/jsx-uses-vars": "error",
  }

おすすめルールを全て有効にするようにしてもいいなら

"extends": ["eslint:recommended", "plugin:react/recommended"],

のようにしても良さそうです。なんとなくこっちのほうが良さそうなのでextendsのほうを採用します。

npm run lintで実行できるようにします。

"lint": "./node_modules/.bin/eslint server.js app/src/* --ext .js --ext .jsx",

mocha

babelを噛ましてテストをするのでbabel-coreもインストールします。

$ npm install --save-dev babel-core mocha

assertにはchaiを使っているケースが多いですが、せっかく日本人なのでpower-assertを使おうと思います。

mocha + power-assert環境の構築 - Qiitaを参考にインストール。

npm install --save-dev intelli-espower-loader power-assert

npm run testでテストをするためにpackage.jsonのscriptsにコマンドを作成します。

test: "./node_modules/mocha/bin/mocha --require intelli-espower-loader --recursive"

testディレクトリにserver-test.jsを作成してテストを書いてみます。

mochaはざっと調べると、describeで大枠を作ってその中にitで実際に行うテストを複数定義していく流れぽいです。

mochaでKoaのテストをする方法を調べてみると、APIのテストはsupertestを使うのが良さそうです。

今回はViewは最低限のものを返しているだけなのでテストの必要はない感じです。しかもkoaでのテスト - QiitaによるとViewのテストが大変そうなのでやりたくない感じもあります。

Koajsのexmapleプロジェクトを参考にすると良い感じあります。

examples/test.js at master · koajs/examples

varassert=require('power-assert');varapp=require('../server');varrequest=require('supertest').agent(app.listen());describe('api',()=>{it('hello',(done)=>{request.get('/api/hello').expect(200).expect('hello',done);});});

サーバサイドのテストはこれでokです。

フロントエンドのテストはbabelでコンパイルする必要があるのでちょっと変わってきます。しかもサーバサイド(nodejs)のコードをbabelコンパイルするとKoaのGenerator周りのコードが盛大にエラーを吐くので別々のテストコマンドでテストするほうが良さそうです。 => Node.js & webpack & babel で「 regeneratorRuntime is not defined」が発生する場合の対処 - Qiita

...

......

.........

いよいよisomorphicが幻想だとわかってきました。というより自分の想像していたisomorphicが大きすぎる解釈だったと気付きました。サーバサイドとフロントエンドは別物です、全てESで書けるとはいえjavascriptとnodejsは違います、しっかり線引して扱うと良いということがわかりました。

boilerplate完成

ゼェ...ゼェ...

やっと記念すべき最初のコミットが完成しました。

最終的なディレクトリ構成

.
├── .babelrc
├── .eslintrc.js
├── .gitignore
├── app
│   ├── dist
│   │   ├── bundle.js
│   │   └── index.html
│   ├── src
│   │   ├── components
│   │   └── index.jsx
│   ├── test
│   │   └── model-test.js
│   └── webpack.config.js
├── package.json
├── server.js
└── test
    └── server-test.js
  • webpackはフロントエンドしか関係していないのでappに配置
  • app内はbabelでコンパイルされるのでimportで依存解決
  • serverはnodejsなのでrequireで依存解決

npm runコマンド

"scripts": {
    "lint": "./node_modules/.bin/eslint server.js app/src/* --ext .js --ext .jsx",
    "build:front": "cd app && ../node_modules/.bin/webpack",
    "dev:front": "cd app && ../node_modules/.bin/webpack-dev-server",
    "dev:server": "node server.js",
    "test:front": "./node_modules/mocha/bin/mocha --compilers js:babel-core/register --require intelli-espower-loader app/test/*.js",
    "test:server": "./node_modules/mocha/bin/mocha --require intelli-espower-loader test/*.js"
  },

というわけで、本番のアプリ開発にとりかかります。

GitLab CI

dockerビルドを試してみます。

まずはRunnerの設置です。

docs/install/docker.md · master · GitLab.org / gitlab-ci-multi-runner · GitLab

dockerビルドするためにはdockerコマンドを叩く必要があるのでhostの/var/run/docker.sockをマウントする必要があります。

$ docker run -d \
--name blacklist-runner \
--restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /srv/blacklist-runner/config:/etc/gitlab-runner \
gitlab/gitlab-runner:latest
$ docker exec -it blacklist-runner gitlab-runner register

executerにdockerを選択して、imageにnode:6.3を指定します。

プロジェクトのほうに.gitlab-ci.ymlを追加します。

image:node:6.3before_script:-npminstallstages:-testeslint:stage:testscript:-npmrunlintmocha-test:stage:testscript:-npmruntest:server-npmruntest:front

将来的にdokkuへの自動デプロイをしたいのですが、なかなか大変そうです。とりあえずアイデアを書いておきます。

  • dokkuへのデプロイのためにはSSH鍵ペアが必要なのでどうにかしないとな感じ
  • ssh鍵ペアをrunnerにマウントしてpush
  • deployタスクだけimage使わないので工夫必要そう
  • masterへのpushのときだけdeploy(only: master)
  • stagingもあるとよさ(only: staging)

Koaサーバをコード変更でリロード

node.js - automatically reloading Koa server - Stack Overflow

nodemonで動かす。

server-side (redismongo)

stagingブランチを作成して作っていきます。

redisかなと思っていましたが、やっぱりmongodbを使ってみます。mongo採用の理由は

  • 使ったことないから気になっていた
  • mongooseを使えばschemaを使えるので可読性良さそう&バリデーションを自分で書かなくて良い
  • nodeと組み合わせる情報が多い
  • redisのset/getを同期処理させたいけど勉強不足で辛い
  • 同期処理(generator)のmongo+koaの例があった => Write "Synchronous" Node.js Code with ES6 Generators

早速書いてみます。

const mongoose = require('mongoose');

const mongoUrl = process.env.MONGO_URL ? process.env.MONGO_URL
                                     : 'localhost/blacklist';

mongoose.connect(mongoUrl);
mongoose.connection.on('error', (err) => {
  console.log(err);
});

const Blacklist = mongoose.model( 'blacklist', new mongoose.Schema({
  company: { type: String, required: true },
  sender:  String,
  target:  String,
  date:    { type: Date, default: Date.now() },
  comment: String,
  black:   { type: Boolean, default: true }
}));

良い感じします。server.jsにそのまま追記していく方針で行きますので、このままapiも書いてみます。

app.use(route.get('/api/set',function*(){constparams=querystring.parse(this.request.querystring);letblacklist=newBlacklist();blacklist.company=params.company?params.company:null;blacklist.sender=params.sender?params.sender:null;blacklist.target=params.target?params.target:null;blacklist.comment=params.comment?params.comment:null;blacklist.black=params.black?params.black:true;try{yieldblacklist.save();}catch(e){this.body={ok:false,response:e.message};return;}this.body={ok:true,response:JSON.stringify(blacklist)};}));app.use(route.get('/api/get',function*(){constparams=querystring.parse(this.request.querystring);this.body=yieldBlacklist.find(params);}));app.use(route.get('/api/update',function*(){letparams=querystring.parse(this.request.querystring);if(!('_id'inparams)){this.body={ok:false};return;}constquery={_id:params._id};deleteparams._id;params.date=Date.now();letblacklist=null;try{blacklist=yieldBlacklist.findOneAndUpdate(query,params);}catch(e){this.body={ok:false,response:e.message};return;}this.body={ok:true,response:JSON.stringify(blacklist)};}));app.use(route.get('/api/delete',function*(){constparams=querystring.parse(this.request.querystring);constquery={_id:params._id};constres=yieldBlacklist.remove(query);this.body={ok:Boolean(res.result.ok),response:res.result.n};// res.result.nは消えた数}));

あと普通にmongooseを使っていると

(node:52888) DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html

というエラーが出ます。mongoose標準のPromiseが古いので比較的新しいNodejsを使っている場合はNodejsのPromiseに置き換えてやります。(Mongoose Promises v4.5.9)

mongoose.Promise=global.Promise;

そんなこんなで、テストも一通り書いて実装が完成しました。

.gitlab-ciの改善

サーバサイド実装のコミットでCIが死にました。mongoがないのが原因です。

デプロイをしたいのもあるのでもう少し凝ったCIに書き直します。

GitLab Documentationによると、docker image/serviceはjobごとに設定できます。デプロイはdocker containerではなくrunner上でやるほうが良さそうなので明示的にcontainerとrunnerでのjobを分けます。

.........

試してみましたが、imageを一度指定してしまうと全てのjobに対してimageが適用される模様...

front-end開発

Prerequisites - Material-UI

Getting Startsする。

$ npm install --save react-tap-event-plugin material-ui

そろそろまとめるのが面倒になってきたのでリンクと何を勉強したかとまとめていきます。

Material UI関連

ここにはComponentの全てが詰まっています。

iconはこちら。namespaceは小文字、空白は"-"で繋いでsvg形式でimportできます。

(例)

importPhoneMissedfrom'material-ui/svg-icons/notification/phone-missed';

type=inputをMaterial UIで扱う方法が謎なのと、そもそもFile APIなんて使ったことなかったのでその情報です。

結果的に以下のようなコードになりました。

handleCsvUpload(){letfileUploadDom=ReactDOM.findDOMNode(this.refs.fileUpload);fileUploadDom.click();}handleVirtualClickCsvUpload(e){varreader=newFileReader();reader.onload=()=>{constcsv=reader.result;// TODO: Server: web api未実装};reader.readAsText(e.target.files[0],'UTF-8');}// ...<FlatButtonlabel='CSV import'labelPosition='after'icon={<ImportExport/>}onTouchTap={this.handleCsvUpload}/><inputref='fileUpload'type='file'style={{'display':'none'}}accept={'text/csv'}onChange={this.handleChange}/>

GUI設計

フレームワークは使いませんが参考にはしました。

ErgoDoxを混合軸にした話

$
0
0

もともとGREETECH赤軸だったのですが、GATERONの緑軸を購入してまぜまぜしました。

経緯

MX軸は初めてというのもあって、はじめはこんなもんかーと思って使っていたのですが、半年くらい使うと不満が出てきました。

底打ちがつらい

ErgoDox購入前は軽いほうが疲れないと思っていたのですが、MX軸のキーストロークは(キーキャップやO-ringである程度調整できますが)割と深いので意外と疲れることに気づきました。

あとは、軽くて深く押し込んでしまうのでキーが戻るときの音が大きくなります。せっかくO-ringをつけて底打ち時の音は軽減しても戻るときに音が出てしまうのでどんまいな感じがしました。


実際に使ってみた結果、黒軸+O-ringがかなり静音なので静音好きな方におすすめです。赤軸よりO-ring効果がある感じがします。

しかし重いので底打ちする勢いでタイピングしてると指の疲弊を感じます、なぞるようにタイピングしないとな感じですが、テンションの上がったときとかはつい強めに打ち込んでしまうので謎に疲れます。慣れが必要そうです。

親指Enterが雑

セパレートしてないキーボード使っていると親指はSpaceバーを強打する用途が多いのであまり繊細な入力を要求されていませんが、Enterは割りと繊細に使われることが多いので、親指Enterをするとなかなかつらい誤爆してしまうことが多かったです、例えば

  • 意図しないコマンドの発火
  • IME変換確定Enterのつもりが勢い余って改行
  • 上記の現象でslackに誤投稿

などで、チャタってるわけではないのに二度打ちしてしまっていることが多くてツラミが溜まっていました。

というわけで、親指には重くてフィードバックのある軸のほうが向いてそうという結論になりました。


実際に緑軸親指Enterを試した結果ですが、

  • カチッとなるので確実に1回クリックしたという感触がある安心感
  • 実際に入力されるカチッの前に一番重いところがあるので思い留まれる(軸の特性)

と良い感じです、青軸だと軽すぎるので雑な親指の持ち主は思い留まれないこともありそうなので緑軸がおすすめです。

緑軸はうるさいというデメリットがありますが、実際うるさいです。O-ring付けたので底打ち時の音は軽減されていますがカチッ音はなります。

音はどうしようもないので緑軸の数をできるだけ減らす方向で軸を交換しました。

軸交換

ErgoDoxのはんだを取らないで軸だけを交換する話は、以前参加したErgoDox users meet upで聞いていて、ErgoDox の壊れたキースイッチを交換する - Okapies' Archiveでもさらに詳しい情報があったのでとても心強かったです。

今回はGREETECH⇔GATERONをしましたが、GREETECH,GATERON,CHERRYは相互に交換できるみたいです。

GATERON緑軸購入

緑軸なんて手に入れるのめんどいんだろうなぁ、、とMassdrop待ちを覚悟していたのですがなんと国内で手に入りました。(20170118現在、緑軸80個があと1つあります)

embed.ly

yahooポイントを駆使して80個1500円で手に入れました。最高です。

この方、ErgoDoxのBamboo Caseなどを安く出店しててすごい欲しくなりましたが売り切れていました。

今回は使わなかったMassdropですが、バネのみとかも売られているという情報もあるのでMassdrop漁りすると面白そうです。

緑軸と赤軸の混合

緑軸のバネを赤軸につければ、黒軸のような重みのある軸が作れます(疑似黒軸)

反対に赤軸のバネを緑軸につければ、青軸のような軽い軸が作れます(疑似青軸)

というわけで緑軸を買うと、赤軸、緑軸、疑似黒軸、疑似青軸が使えるようになります。

個人的に緑軸は気に入っていて、簡単には入力ポイントまで押せないので誤入力が防げてる感じがあります、疑似青軸も試してみましたが割りとスッと入力ポイントまで押せてしまうので緑買って良かったです。

作業の様子

embed.ly

ほとんどのキーを置き換えましたが、この記事のおかげか3時間程度で終わりました。

クリップがこんな形で役に立つとは思わなかったです。

ちなみに道具は

  • キーキャップ引き抜き工具
  • ペンチ*2
  • 小さめのクリップ

で十分でした。

結果

緑は緑軸、疑似青軸、黒っぽいところは疑似黒軸、赤は赤軸(変更なし)。

基本的にキーストロークを浅く+静音にする目的でO-ringを2つ付けていますが、印字してある白のキーキャップはプロファイルが高低差のあるDCSなので、黒が濃い部分(数字のキー)は背が高いのでO-ringを3つ、黒が薄い部分(数字の下の列)は背が低いのでO-ringを1つにしています。

キープロファイル(キーの高さ)ですが、DSA(全部同じ高さ)を良いと思っていたのですが、リストレスト(GRIFITI)を使い始めてからはDCS(高低差がある)のほうがタイピングがしやすいので、以前のカラフルなDSAのキーキャップから変更しました。

親指で押すところの黒軸周辺が全部クリッキーな軸にしてあるのは、誤って黒軸部分以外をクリックしたときに即気づけるようにそうしてあります。


買えてみて1週間位使っていますが結構快適でだいたい思惑通りな感じです。

緑軸のクリッキーな打キー感最高だなぁと思いながら親指を使えてて楽しいです。

またしばらく使ってみて改善欲求が出るかもしれないですが、当面これで楽しくプログラミングができそうです。

Vimで始める型付きPython3開発

$
0
0

型付きPythonは静的型解析ツールであるmypyによる検査と、jediによる補完が効くという開発に役立つ便利な恩恵があります。

実行時には(まだ)型の恩恵はないですが始めるには十分な恩恵だと感じたので始めてみました。


venvとmypyを使うので、Python3と言ってもPython3.5(現在の最新版)を使います。

スタイルチェックにはflake8を使用します。

Vim(Neovim)の準備

:echo has('python')
:echo has('python3')

コマンドが1を返すことを確認します。もし0の場合は、Pythonを有効にします(有効にする方法は"vim python 有効"で検索)。

Python3.5のインストール

※Python3.6も出るみたいなので適宜その時の最新版をインストールしてください

パッケージマネージャーでインストールするとPython3.5が入って便利かつ簡単です。

macOS

$ brew install python3
$ python3 --version
3.5.2

ubuntu16.04

% sudo apt-get install python3% python3 --version

Windows

パッケージマネージャがあるのかもしれませんが詳しくないので、インストーラからPython3.5をインストールします。

必要なパッケージのインストール

UbuntuとWindowsでは管理者権限が必要になるので、それぞれsudoをつける、管理者権限でcmdを起動してください。

$ pip3 install -U flake8 mypy-lang jedi

それぞれ

  • flake8はスタイルチェッカー
  • mypyは静的型解析
  • jediは補完エンジン

です。

mypyは型付きPythonに必須のツールです。

python/mypy: Optional static typing for Python 2 and 3 (PEP484)

後述するsyntasticやneomakeと組み合わせて使うとファイル編集時に型チェックができてとても良いです。

typeshedにてライブラリや3rd-partyパッケージの型にも対応しようとしていて今後の発展に注目です。

(たとえばFlaskは現在対応中のようです(help wanted by Guido...) => Stub for flask · Issue #28 · python/typeshed)

次にflake8ですが、スタイルチェッカーにはpylintやhackingなどがありますがflake8を選びました。理由は、

  • flake8で十分と感じた
  • flake8だけでも割りと遅いので併用したくない

ということでflake8単体で使っています。

しかもsyntasticを使用した場合、非同期に実行されないのでスタイルチェッカーが重いと結構なストレスになりそうです。

環境構築(venv)

デフォルトでvenvが同梱されているのでそちらを使います。

$ mkdir progect
$ pyvenv project
$ cd project
$ source bin/activate

Warning

activateファイルにfishスクリプトも用意されているのですが、"$(var)"を使っていてエラーになるので該当部分を"(var)"に修正すれば動きます。

pyvenvコマンドをすると色々ファイルが作られるのでgitignoreしたくなります。

GitHub公式のgitignoreを使うと良いです。

この2つを組み合わせればPythonのgitignoreは多くのケースで十分そうです。

後者の方はGlobalのgitignoreに入れると良いようです。

Neovim/Vimの設定

flake8とmypyのスタイルチェックをSyntasticまたはNeomakeで行い、jediで補完します。

型チェック & スタイルチェック

syntasticまたはneomakeを使って、ファイル保存時にチェックします。

インストール方法は各プラグインマネージャなどに従って下さい。

Python用の設定は以下のように書きます。

syntastic↓

let g:syntastic_python_checkers = ['python', 'flake8', 'mypy']

neomake↓

let g:neomake_python_enabled_makers = ['python', 'flake8', 'mypy']

参考までに私の設定です。プラグインマネージャにはdein.vimを使ってtomlファイルでプラグインを管理しています、Neovimのときはneomake、Vimのときはsyntasticを使っています。

(neomakeはNeovim専用ではなくVim8.0.0027以降であれば使えます)

[[plugins]]repo='neomake/neomake'if="has('nvim')"hook_add='''autocmd!BufEnter,BufWritePost*Neomakelet g:neomake_python_enabled_makers=['python', 'flake8', 'mypy']'''[[plugins]]repo='vim-syntastic/syntastic'if="!has('nvim')"hook_add='''let g:syntastic_always_populate_loc_list=1let g:syntastic_check_on_open=1let g:syntastic_check_on_wq=0"forPythonlet g:syntastic_python_checkers=['python', 'flake8', 'mypy']'''

補完

jediをneocomplete.vimとdeoplete.nvimから利用する方法を紹介します。

jediはType Hintsがついてると型に応じてメソッド名などを補完するのでかなり便利です。

neocomplete.vimとdeoplete.nvimのインストール方法については省略します。

neocomplete.vim

davidhalter/jedi-vim: Using the jedi autocompletion library for VIM.をプラグインを追加して以下の設定をします。

autocmdFileTypepythonsetlocalomnifunc=jedi#completionsletg:jedi#completions_enabled = 0letg:jedi#auto_vim_configuration = 0letg:neocomplete#force_omni_input_patterns.python = '\%([^. \t]\.\|^\s*@\|^\s*from\s.\+import \|^\s*from \|^\s*import \)\w*'

参考: jedi-vimとneocomplete.vimを併用する際に行っておきたい設定 - kozo2's blog

deoplete.nvim

zchee/deoplete-jedi: deoplete.nvim source for Pythonをプラグインに追加します。

venvを使うのでグローバルにインストールされているPythonへのパスの設定が必要です。

let g:python_host_prog = '/full/path/to/neovim2/bin/python'
let g:python3_host_prog = '/full/path/to/neovim3/bin/python'

Previewが邪魔な人向け

jediを使っているとPreviewがでてきて邪魔という方が多く見受けられます、Vimの機能なのでVim側の設定で変えられます。

Previewを出さない

set completeopt-=preview

補完終了時に自動で閉じる

autocmd InsertLeave,CompleteDone * if pumvisible() == 0 | pclose | endif

など良い感じに設定すると良いです。

まとめ

型の恩恵は実行時には(まだ)ないですが、静的型チェッカー(mypy)、jediによる補完と開発に置ける恩恵はなかなかのものだと思うのでおすすめです。

紹介した方法は新しいPython1つしかインストールしてないので、古いバージョンでのデバック作業などが必要になった場合に困りそうですがそれはまた必要になってから考えようかと思ってます。とりあえず現状はCIするときにtoxで各バージョンのテストを走らせることで確認しています。

艦これ2017冬イベE-1甲 伊26 Mマス掘り

$
0
0

伊26ほしいです。伊26がほしいです。

Iマスでも掘れますがIマスまで行くのに時間かかるのでMマスで掘ることにしてみました。

401やUが欲しい場合はIマスに行きましょう。

編成

A勝利時は何も落ちない場合がほとんどなので、S勝利じゃないとドロップしない気がします。

戦艦は含めることができないので、ヲ級改flagshipを倒すために雷巡の開幕魚雷と夜戦を使います。

編成

後述する基地航空隊とこの編成でS勝利安定しています。制空値は盛り気味なのでもう少し少なくても良いかもしれません。

3回に1回くらいバケツを使う程度の被害です。

ダメージよりも疲労がたまりやすいので軽空母と秋月型、雷巡の替えがいると快適に回せそうです。

資材消費

ボーキサイトは40程度です。

基地航空隊

いろいろ試しましたが以下の隊をIマス集中が一番安定して資材消費が割と少ないです。

基地航空隊

基地航空隊資材消費

基地航空隊も疲労がたまるので、疲労がたまったら休息にし、第二航空隊を出すようにします。

掘り中

伊19ちゃんがいっぱい出て19祭りになっています。

Vue.jsで縦横拡張可変グリッド

$
0
0

CodePenエディタのような可変グリッドで、拡張可能なグリッドがほしかったので作ってみました。

embed.ly

demo

詳しい話

templateでは可変グリッドのCSS書くのが大変になったのでrenderを使ったりして色々勉強になりました。という話です。

可変グリッド

ロジックは、sparklinlabs/resize-handle: Robust resize handles / splitters for your HTML5 apps and websitesをまるっと参考にしました。

CSSはflexboxを使っていて、リサイズイベントはJavaScriptで以下のような感じで制御してます

  1. リサイズバーのmousedownイベント発火
  2. サイズを変える要素を特定、初期値記録
  3. キャプチャーを制限 or イベントの対象をwindowオブジェクトに
  4. mousemoveとmouseupイベントを追加
  5. mousemoveでサイズ変更
  6. mouseupでmousemoveとmouseupイベント削除

本家のソースコードは上下左右に対応した汎用的なコードなのですが、今回作ったものは決め打ちのハードコードになっています。

CSS(flexbox)

縦横グリッドなので、flex(column)>flex(row)の入れ子になってます。

実際にはグリッド内の要素にも適用しているので、flex(column)>flex(folumn)>flex(row)>flex(row)になっています。

今回やって思ったのは、flexboxはネストして使うと便利ということでした。

普段からCSSをもりもり書いているわけではないのでflexboxはトップレベルに近いところで使うと勝手に思っていたのですが、ネストするとスッキリするケースもあるので複雑になりすぎない程度にはネストさせると良いと思いました。

レイアウト

参考にした可変グリッドがグリッド要素とリサイズバーが同レベルに並んでいる構成になっているのですが、v-forを使うとどうしてもroot要素が必要になるので同じDOM構成にならないという問題がありました。

どういうことかというと、こうしたい

<divclass="grid">...<div><divclass="resizer"><div><divclass="grid">...<div><divclass="resizer"><div>

けど、v-forでやるとこうなります。

<div><!-- v-forで増える要素 --><divclass="grid">...<div><divclass="resizer"><div></div><div><!-- v-forで増える要素 --><divclass="grid">...<div><divclass="resizer"><div></div>

DOMの描画をもっと細かく制御したいと思ってたら、Vue.jsにはrender関数という便利機能があるので

問題点ぽいところ

要素を追加するときは良い感じのサイズで追加されてほしいのでflexboxで追加してるのですが、リサイズするときはflexから外して固定サイズにしてるので、リサイズ前とリサイズ後で挙動が変わってしまいますが今のところ解決策を思いついてないのでそのままです。


もくもくブログを作りました

$
0
0

定期的な更新ができそうなブログができました。

自動

自動的な様子

自動的な様子

このブログ自体はPelicanというPythonの静的サイドジェネレータで作られていて、MemoMemoというアプリを通して自動生成されています。

MemoMemoは、かねてからドックフーディングで作っていたWebアプリで、個人的なメモを残すアプリだったのですが、公開指定したメモをPelicanを使ってBlogにできるようにしました。

このアプリはもともとHerokuで動かしていましたが、Herokuがちょっと厳しさを提示してきたので、IDCFクラウドにDokkuをのせてこのアプリを動かしています。

ブログジェネレートの仕組みはMemoMemo内に実装されていて、GitHubからPelicanの情報をpullして、公開用のメモをgh-pagesにpushする仕組みになっています。

材料

良さ

  • 愛着があるドックフーディングアプリからジェネレートされているので最高の気持ちでブログが書ける
  • Pelicanの良さ
  • reStructuredTextもMarkdownも使える便利
  • プラグインの機構があるのでカスタマイズできる
  • プラグインによりGFMも使える
  • ドキュメントが丁寧
  • Dokkuの良さ
  • 完全にHeroku

まとめ

とても快適なブログライフが送れる気持ちです。

ひとまず、PelicanとDokku on IDCFクラウドのこととか書く予定です。

IDCFクラウド借りました

$
0
0

経緯

今までGehirnを使っていたけど、Gehirnの料金体制の変更に伴い、VPSを変更することにしました。

自分の場合、個人用途なのでアクセスも主に自分くらいしかないようなサービスしか動かさないのでとにかく安いVPSを探して使っています。

旧Gehirnは300円(税抜) per monthという遠足のお菓子くらいの価格なので選択していましたが、料金体制が40円 per dayになるのでもっと安いのにしたいので乗り換えることにしました。

とりあえず、安いVPSを探すと

  • Digital Ocean
  • IDCFクラウド

が500円くらい。

DigitalOceanがあるが為替が安定しないので辞めて、IDCFクラウドにしました。

IDCFクラウドは、2015/7/31までに申し込めば使える3000円クーポンがあったのが決め手。

申し込み

IDCFクラウド -使いやすく、パワフル|IDCフロンティア

  1. 「無料で始める」からユーザーの登録をします
  2. 名前、ユーザー名、メールアドレス、パスワードを入力して、電話又はSNS認証をします
  3. メールが届くので承認して、登録完了です

管理コンソールに初めてアクセスすると、基本情報と支払情報の入力をしないといけないのでします。

初期費用もなくサーバもすぐに立ち上がります。すごい良さ。

管理画面もわかりやすくて、すごい良さです。

IDCFクラウド、良いです。

サーバを立てる

light.S1の追加ストレージなしをUbuntu14.04LTSで立てました。

このとき、あとでSSHするのでSSH keyも登録しておきます。

SSHの設定

サーバを立てましたが、プライベートネットワークで構成されているので、グローバルIPでサーバの必要なポートにアクセスできるように設定します。

IDCFクラウドのイメージ

こんな感じのイメージ(イメージなので正しくないかもしれません)なので、FirewallとPort forwardingの設定をします。

管理コンソールのIPアドレスにある、もらってるIPのところで設定ができます。

FirewallとPort forwardの設定ボタン

ポートフォワードでプレイベートポートにSSH(22番ポート)、パブリックポートに22ポートを指定します。

次にFirewallで、さきほどパブリックポートに指定したポートに対して、ソースCIDRにMy IP、タイプにCustom TCPを設定します。

(セキュリティ的に、ポートフォワードのパブリックのSSHのポートを変えたほうがいいですが、ここでは、FirewallのソースCIDRでIPを制限することにしています。)

コメントは両者ともSSHとしました。

SSHの公開鍵を登録したPCからSSHします。

$ ssh root@XXX.XXX.XXX.XXX

Ubuntuの場合、ログインできたら以下のようになりました。

swap領域の設定

デフォルトでswap領域は作られていないので作っておきます。(Docker使うのでswapを作っておいたほうが良さそうでした)

このあたりを参考にしました。

RAM1Gなので、上記の記事によると2Gのswapを確保することになるが、あんまり大きくてもディスクを圧迫しかねないので1Gにしておきます。

dd if=/dev/zero of=swap用ファイルのパス名 bs=単位 count=サイズ

1Gにするなら、bs=1024 count=1024kで1G、bs=1M count=1024で1G。

/.swapfileに作る。

$ sudo dd if=/dev/zero of=/.swapfile bs=1M count=1024$ sudo mkswap /.swapfile$ sudo swapon /.swapfile$ sudo vi /etc/fstab
/.swapfile       none    swap    sw      0       0$ sudo chown root:root /.swapfile$ sudo chmod 0600 /.swapfile

userの追加

rootユーザーしかいないので、セキュリティ的にrootでSSH出来ないようにして、root権限を持つユーザーで操作するように設定します。

$ adduser $USER$ visudo$USERALL=(ALL:ALL) ALL

sshできるようにして、rootのssh接続をできないようにします。

$ su $USER$ mkdir ~/.ssh$ chmod 0700 ~/.ssh$ vi ~/.ssh/authorized_keys(接続するPCのSSHの公開鍵を記載)$ chmod 0600 ~/.ssh/authorized_keys$ sudo vi /etc/ssh/sshd_config#PermitRootLogin without-password
PermitRootLogin no

sshd_configは以下の項目も確認。

PubkeyAuthentication yes
PasswordAuthentication no

Mackerelを使う

IDCFクラウドは、サーバの状態を見たりするUIがなさそうなので、Mackarelで監視してみました。

IDCFクラウドはMackerel対応していて、OAuthしてMackarel使えるみたいでしたが、同じメールアドレスでMackerelのユーザー持ってたので、もったいないですが既存のユーザーで行いました。

Ubuntuにしたので、debパッケージでのインストール方法を参考にインストール、追加でサービスの設定等はしていませんが、Mackerelでの監視はさくっとできました。

今後

Dokkuを動かしたいなぁという感じです。

IDCFクラウドの一番安いのでDokkuを使う

$
0
0

(Dokku v0.3.26の話)

Herokuで1日6時間止めたくないし、30分でスリーブしたくないアプリがあるとき、VPS on Dokkuは最高のソリューションかもしれないです。

プロダクションには無理がありそうですが、社内とか個人用途には良さそうですね、nginxとかのセットアップをやってくれますし、Herokuのbuildpackを使えるので便利便利です。

VPSにはIDCFクラウドの一番安いのを使います。Dokkuを入れる前に、

IDCFクラウド借りました

にあるようなセットアップが済んでいるものとします。

Dokkuのインストール

$ wget https://raw.github.com/progrium/dokku/v0.3.26/bootstrap.sh$ sudo DOKKU_TAG=v0.3.26 bash bootstrap.sh

続いてサーバにログインしている状態で、ホスト名の設定。(root権限で実行)

VHOSTとHOSTNAMEに、持っているDNSの名前を設定する。(サブドメインでも良い)

(仮に、foo.barを設定したとする。)

# echo "foo.bar" > /home/dokku/VHOST
# echo "foo.bar" > /home/dokku/HOSTNAME

("http://foo.bar"にアクセスしてもdokkuの初期設定画面が出てきたので、そちらで設定できるみたい)

次に、git pushできるようにするために、SSHの公開鍵を設定する。公開鍵のある場所で以下のコマンドを実行する。

(ローカル) $ cat ~/.ssh/id_rsa.pub | ssh root@<your_ip> "sudo sshcommand acl-add dokku <name>"
(サーバ内) $ cat ~/.ssh/id_rsa.pub | sudo sshcommand acl-add dokku <name>

Dokkuの下準備はこれだけ、次にドメインの設定する。

ドメインの設定(お名前.com)

Dokkuはnginxを使ってサブドメインにデプロイしてくれるので、ワイルドカードを設定してみる。

お名前.comでは、サブドメインにワイルドカードが使えないので、*.とするしかないみたいです。

しょうがないので、DNSレコード設定で以下のようにAレコードを設定する。

A recordIPTTL
foo.bar3600
*.foo.bar3600

これで、例えば"dokku@foo.bar:sample"にpushしたとき、"http://sample.foo.bar"にデプロイされる。

Dokkuにサンプルアプリをデプロイ

Pythonのサンプルをデプロイしてみる。

heroku/python-sample

ローカル環境にgit cloneして、remoteにdokkuを追加。

$gitclonehttps://github.com/heroku/python-sample.git$cdpython-sample$gitremoteadddokkudokku@foo.bar:python-sample$gitpushdokkumasterCountingobjects:21,done.Deltacompressionusingupto8threads.Compressingobjects:100%(17/17),done.Writingobjects:100%(21/21),1.81KiB|0bytes/s,done.Total21(delta6),reused0(delta0)----->Cleaningup...----->Buildingpython-samplefromherokuish...remote:Unabletofindimage'gliderlabs/herokuish:latest'locallyremote:latest:Pullingfromgliderlabs/herokuishremote:835c565d00e2:Pullingfslayerremote:c5c659229e15:Pullingfslayer(中略)remote:359e311e765f:Pullcompleteremote:359e311e765f:Alreadyexistsremote:Digest:sha256:7aaa5dd65a7f90a47f2bb1266375b27d4f273ff94495527949536c9e944a871aremote:Status:Downloadednewerimageforgliderlabs/herokuish:latest----->AddingBUILD_ENVtobuildenvironment...----->Pythonappdetected----->Installingruntime(python-2.7.10)----->InstallingdependencieswithpipCollectingFlask==0.9(from-rrequirements.txt(line1))DownloadingFlask-0.9.tar.gz(481kB)CollectingJinja2==2.6(from-rrequirements.txt(line2))DownloadingJinja2-2.6.tar.gz(389kB)CollectingWerkzeug==0.8.3(from-rrequirements.txt(line3))DownloadingWerkzeug-0.8.3.tar.gz(1.1MB)Installingcollectedpackages:Werkzeug,Jinja2,FlaskRunningsetup.pyinstallforWerkzeugRunningsetup.pyinstallforJinja2Runningsetup.pyinstallforFlaskSuccessfullyinstalledFlask-0.9Jinja2-2.6Werkzeug-0.8.3remote:Youareusingpipversion7.0.3,howeverversion7.1.2isavailable.remote:Youshouldconsiderupgradingviathe'pipinstall--upgradepip'command.----->DiscoveringprocesstypesProcfiledeclarestypes->web----->Releasingpython-sample...----->Deployingpython-sample...----->DOKKU_SCALEfilenotfoundinappimage.Defaultingtoasinglewebprocess----->NewDOKKU_SCALEfilegenerated----->Runningpre-flightchecksFormoreefficientzerodowntimedeployments,createafileCHECKS.Seehttp://progrium.viewdocs.io/dokku/checks-examples.md for examplesCHECKSfilenotfoundincontainer:Runningsimplecontainercheck...----->Waitingfor10seconds...----->Defaultcontainerchecksuccessful!=====>python-samplecontaineroutput:*Runningonhttp://0.0.0.0:5000/=====>endpython-samplecontaineroutput----->Runningpost-deploy----->Creatingnew/home/dokku/python-sample/VHOST...----->Configuringpython-sample.muuny-blue.info...----->Creatinghttpnginx.conf----->Runningnginx-pre-reloadReloadingnginx=====>Applicationdeployed:http://python-sample.foo.barTodokku@foo.bar:python-sample*[newbranch]master->master

初回はDockerのイメージとかを色々落としてくるので時間がかかるが、いい感じにデプロイされている様子を見れる。

Aレコードがちゃんと設定されていれば、ブラウザでも見れます。

Hello Dokku

Dokkuの様子を、サーバにSSHして確認。

$ dokku apps=====> My Apps
python-sample$ dokku ps python-sample
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1   60641632 ?        Ssl  00:11   0:00 /start web
root        10  0.0  0.0   1484920 ?        S    00:11   0:00 /root/.basher/bash -c main 'web'
u3135      136  0.0  1.4 17952014716 ?        S    00:11   0:00 python app.py
root       137  0.0  0.0   4440652 ?        Ss+  00:21   0:00 /bin/sh -c ps auxwww
root       143  0.0  0.1  155641156 ?        R+   00:21   0:00 ps auxwww$ ls -la /home/dokku | grep python-sample
drwxrwxr-x  8 dokku dokku 4096 XXX XX XX:XX python-sample

Dockerの様子も確認。

$ sudo docker ps
CONTAINER ID        IMAGE                        COMMAND             CREATED             STATUS              PORTS               NAMES
a63daf76bcb3        dokku/python-sample:latest   "/start web"4 minutes ago       Up 4 minutes                            insane_leakey$ sudo docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
dokku/python-sample    latest              d8025105f0c0        4 minutes ago       1.421 GB
gliderlabs/herokuish   latest              359e311e765f        6 weeks ago         1.263 GB

okぽい。

アプリに対して、操作するときはdokkuコマンドから操作する。詳しくはdokku --help。

まとめ

IDCFフロンティアの一番安いのにもDokkuちゃんとのせられたし、ちゃんと動いた。個人用途には申し分なさそう。

メモリ使用量の様子。

メモリ使用量

アプリ1つしかデブロイしてないけど、あまり無茶させなければ大丈夫そうな気配。

入れたあとにDokkuAlternativeってのがあることを知った、こっちは、メジャーどころのDB連携がデフォルトでついていたりWebコンソールがあるみたい、こっちのほうがなにかとよさそう。

dokku-altに関しては日本語で丁寧にまとまってる記事があったのでそちらを見るといいかもしれない。

Dokku Alternative触ってみる。

(今のところ不便はないので素のdokkuを運用しいています)

参考資料

埋め込み機能がほしい

$
0
0

作りました(2015/11/11)

PelicanとPython-MarkdownでEmbedlyが使える便利なExtensionを作った

Twiterは以下のようになります。

embed.ly

Embedlyを使用しているのであらゆるURLがそれっぽくなります。便利です。


ブログに埋め込み機能がほしい。

埋め込めている様子

こういった機能が、このブログにも欲しい。

embed機能

つまるところ、はてなブログなどにあるembed機能がほしい。

リンクの挿入とコンテンツの埋め込み - はてなブログ ヘルプ

"[:embed]"

とすると、いい感じに埋め込まれるようにしたい。

PelicanはMarkdownもreStructuredTextもプラグインがあるので存在するかもしれないし自分で作れるかもしれない。

reStructuredTextの場合、rawディレクティブを使って".. raw:: html"としてembeddedなHtmlを書けば出来ないこともないがめんどくさい。

embedディレクティブとかほしい。

.. embed::

埋め込みたいものリスト

  • Twitter
  • Youtube
  • ニコニコ動画
  • SlideShare
  • SpeakerDeck
  • hatena blog
  • GitHub
  • Amazon

まとめ

既存のものがあれば使いたいけど、なかったら作ろうと思います。

あったら誰かおしえてほしい。

日記でした。

出産後あって良かったものリスト

$
0
0

この間、子どもが生まれました。

かわいい

かわいいですが、育児は大変です。

夫目線ですが出産後あってよかった物リストをまとめてみました。(現在一ヶ月半)

らでぃっしゅぼーや

宅配野菜です。

宅配野菜はらでぃっしゅぼーやに限らないので、何でもいいと思いますが宅配野菜は便利です。

便利な点

  • 買い物しなくてもいい(回数が減る)
  • 割と偏りなくいろんな野菜が食べれる
  • 献立が勝手に決まる

割と偏りなくいろんな野菜が食べれるので、母乳育児をするときにいろんな栄養をとれていいんじゃないかと思っています。

自分で買い物行くとつい同じような野菜ばかり買っているような気がするので個人的に一番いいポイントだと思っています。

らでぃっしゅぼーやにはいくつかコースがありますが、「ぱれっと」の7種+果物を頼んでいます。

契約選択(ぱれっと) | らでぃっしゅぼーや 有機野菜・無添加食材の宅配ネットスーパー

野菜と果物はそのとき旬のものが届きます。

金曜日までに追加の注文も受け付けているので、野菜以外になにかほしい物があったら頼めます。湯葉とか鶏肉とか卵とかも頼んだりしています。

スリング

北極しろくま堂のキュットミーを使っています。

キュットミー | 北極しろくま堂オリジナル商品。数十万人のママが愛用。

自分は使っていませんがママが使っていて調子良さそうです。

密着する感じがいいのか、抱っこ紐より落ち着いている感じがします。

赤ちゃんを入れるのが少しコツがいるそうですが、両手が空くので便利だそうです。

このキュットミー色や記事の種類が豊富なのですがこの色です。

キュットミーの色(みるく)

ウォッシュレット

出産後のママにあると良さそうです。

出産前に設置していたのですが、かなりのありがたみを感じていました。

賃貸でも、便座のみを交換できるので問題なかったです。

ちなみに自分は、新宿のビックロで購入しました。ウォッシュレットのところの店員さんがとても良い方でしっかり検討できました。取り付けサービスもやっているので便利でした。

スケール

母乳で育てる場合、ちゃんと飲んだのかがすごく気になります。

不安は少しでもないほうがいいのでスケールがあるととても良いと思います。

スケールはいつまでも必要なわけではないのでレンタルにしました。

3ヶ月で3700円の5g単位のスケールをレンタルしました。

スケール

2g単位のもありましたが、5gで十分測れています。

バランスボール

抱っこしても歩いてないとブーブー言うことがあるので、そういうときにバランスボールが便利です。

同時にダイエットもできるので一石二鳥です。

酸素系漂白剤

もらった昔の洋服の黄ばみ落としや、排泄物の汚れ落としなどに役に立っています。

なんとかく洗濯の回数も増えるかと思い、出産前に洗濯機の槽洗浄にも活躍しました。

過炭酸ナトリウム100%の酸素系漂白剤が良いと言われたので過炭酸ナトリウムを購入しました。

Amazon.co.jp: 過炭酸ナトリウム(酸素系漂白剤) 1kg: ヘルス&ビューティー

過炭酸ナトリウム

ハンディクリーナー

今後、子どもがいるとさっと掃除機かけたい機会が増えるんじゃないかということで、ハンディクリーナーを買いました。

コードとか刺さなくていいし、すぐに使えて実際便利です。

マキタのハンディクリーナー使っています。

Amazon.co.jp: マキタ 充電式ハンディクリーナー CL182FDRFW: ホーム&キッチン

マキタのハンディクリーナー

充電時間が短く、使用時間が長めなので良いです。吸引力も割と強いです。結構軽いのでさっと出してさっと掃除機をかけられます。

マキタのハンディクリーナーは、V(ボルト)数や、ボタン式or自動式などいくつか種類があるのでちゃんと選ぶといいです。

ダイソンなどと比べるとヘッドがクルクル回るのとかがついていないので、拭き掃除と併用すると良さそうです。実際にそうしています。

有給

里帰りをしない選択をしたので有給が必須でした。

ママだけでは出産後すぐに一人でひたすら面倒と見るのには限界があるので、平日の中日などに有給をとるようにしました。

自分も赤ちゃんかわいいし、会社休めるし、ママも楽ができるのでいいことしかなかったです。

一ヶ月検診などに付き合いとなるとその時も有給が必要なので計画的に使うと良いです。

Youtubeの動画URLを取得するSwiftコードを書いた

$
0
0

Objective-Cだと以下のプロジェクトで、YoutubeからiOSで再生可能な形式の動画を取得して再生している。その中身の必要そうな部分をSwiftで書き直して使う話。

hellozimi/HCYoutubeParser

http://www.youtube.com/get_video_info?video_id=<video_id>

で取得できるデータから再生可能な動画のURLを引っ張り出すことができるので、video_idさえわかればYoutubeから動画を引っ張ってきてiOSアプリ内で再生できるようだ。

データがURLのQuery形式になっていて、そのパーサが必要なので作る。

動画データは、url_encoded_fmt_stream_mapに入っている。

データの取得(GET)

非同期でGETする。

leturl="http://www.youtube.com/get_video_info?video_id=<ID>"varreq=NSMutableURLRequest(URL:NSURL(string:url)!)req.HTTPMethod="GET"vartask=NSURLSession.sharedSession().dataTaskWithRequest(req,completionHandler:{data,response,errorinif(error==nil){varresult=NSString(data:data,encoding:NSUTF8StringEncoding)!println(result)}else{println(error)}})task.resume()

GETしたレスポンスをパース

URLクエリ文字列をパースしてDictionaryに入れる。パースしたあとのデータはstringByRemovingPercentEncodingでデコードする必要があるので注意。

varparameters:Dictionary=[String:String]()forkey_valinsplit(result,{$0=="&"}){letkey_val_array=split(key_val,{$0=="="})letkey=key_val_array[0]letval=key_val_array[1].stringByRemovingPercentEncodingparameters[key]=val;}returnparameters

GETのコールバック内にこのコードを仕込めば完成。

得られるデータ内の必要そうなパラメータ

thumbnail_url, length_seconds, iurl, title, iurlmq, url_encoded_fmt_stream_map, iurlmaxres, iv_module(swfのリンクになってる、iOSで再生できるかは確認してない), vid, iurlsd

あとは、url_encoded_fmt_stream_mapのURLをAVPlayerなりに入れれば再生できます。

プログラミング言語を作る前知識

$
0
0

まったく何の知識もない状態で、プログラミング言語を作ることになったのでネット上をあさって前知識をまとめてみました。

歴史から始まり最近のプログラミング言語の作り方、C言語で作る場合どうするのかまで書いてあります。

(大体Wikipediaをまとめただけである)

むかしむかし

1940年に今でいうところのコンピュータが作られ、機械語→アセンブリ言語→アセンブリ言語のマクロというように発展しました。(低水準言語)

低水準言語に対して

  • 低水準言語は人間には難しい
  • アーキテクチャの異なるマシンで動かしたい

という思いがあり、コンパイラ(高水準言語を機械語に変換する)の開発がなされた。

1952年のA-0 Systemが最初のコンパイラとされるが、一般的認知度的には、1957年のFORTRANが最初のコンパイラと呼ばれることが多い。

その後、1960年、複数のアーキテクチャ上でコンパイルが可能できるCOBOLができた。

これらは、アセンブリ言語で書かれている。この先の多くのコンパイラは、アセンブリでコンパイラを作らず、セルフホスティングして作られる、セルフホスティングでの問題点は、ブートストラップ問題といって、「鶏が先か、卵が先か」的な問題を解決している言語である。

Pascalの初期のコンパイラはFORTRANで書かれていたりするらしい。

ブートストラップ問題でLISPは興味深い話を持っている。

LISPが出来た初期は、LISPはコンパイルされていたが、スティーブ・ラッセルがevalを実装したことによりLISPインタプリタが実現され、インタプリタ上でLISPコンパイラが作られた。

LISPのインタプリタが世界初のインタプリタであるようだ。

1950年代に、FORTRAN, COBOL, LISPの3つの高水準言語が開発され、1950年末にALGOLが登場しのちの言語に影響を与える。

1960年代から1970年代末ごろまでに、現在使われている主な言語パラダイムが開発された。

  • APL, PL/I, Simula, C, Prolog, ML

今後出てくる言語は、いづれかの系統であるものが大半である。

プログラミング言語の処理系

プログラミング言語の処理系には、コンパイラとインタプリタがある。

コンパイラは、コードを解釈して機械語を吐く。

インタプリタは、コードを逐次解釈しながら実行する。

インタプリタでも、JITなどコンパイルを実行時に行うものや、Javaのように中間表現をコンパイラで生成してインタプリタで実行するものもあるので、コンパイラとインタプリタの垣根をはっきりさせることもなくなってきている感がある。

プログラミング言語の設計

大雑把に言うと、ソースコードから抽象構文木を作成してコード(機械語)やデータを得るという流れになる。

コンパイルは機械語、インタプリタはデータ(機械語かもしれない)を生成するという分類ができそう。

コンパイラの場合

コンパイラ設計手法についてPQCCで使われ、割と一般的な分類となっている。

大きくフロントエンドとバックエンドに分かれていて

  • フロントエンド : 行再構築、字句解析、プリプロセッサ、構文解析、意味解析など
  • バックエンド : 解析、最適化、コード生成など

となっている。

フロントエンドで吐かれた一般的なデータ構造である中間表現(抽象構文木やシンボルテーブル)を、バックエンドが解析、実行可能なコードを生成するという流れである。

インタプリタの場合

  • バイトコードインタプリタ
  • 抽象構文木(AST)インタプリタ
  • 実行時コンパイル(JIT)

(コンパイルする気満々である)

これらは組み合わせて使われたりすることが多いようだ、ASTにしてからJIT(Javascriptなど)、ASTにしてからバイトコード生成(Javaや.Net Framework)など。

Emacs Lispのように、LISPを高度に圧縮して最適化したコードを生成して、バイトコードインタプリタ(C言語で作られている)に読ませるようなことをしているものもある。

抽象構文木を作るタイプの話しかしていませんが、世の中のプログラミング言語が全てそうではないです。

プログラミング言語をつくるには?

今までの流れ的に、プログラミング言語を作るには大雑把に言って

  1. 字句解析
  2. 構文解析
  3. 解析結果の評価

という流れで作れそうです。

字句解析と構文解析は必要。

解析結果の評価の部分は、速度や機械語でないといけないという理由がない限り、ASTを解析して実行するインタプリタ、つまりその言語のVMを作るということになりそうです。

思い描いた文法を字句解析・構文解析でASTにして、ASTをVMで実行するというのがベースでプログラミング言語を作っていくことになりそう。

字句解析・構文解析の部分をParserと一般的には呼ぶそうです。

C言語でプログラミング言語を作るとき

全て手作りで設計してもいいと思いますが、字句解析と構文解析に関して、C言語には有名なツールがあります。

字句解析 lex/flex

flexはlexのGNU実装です。

構文解析 yacc/bison

bisonはyaccのGNU実装です。

lexとyaccはセットで扱われることがほとんどです。

yaccはC言語以外にも実装があり、 OCaml, ML, Ada, Pascal, Java, Python, Ruby, Go, Common Lispなどで使えます。

まとめ

ほとんどWikipediaの情報ですが、プログラミング言語作りにとりかかれそうな気がしてきました。

参考資料


lexとyaccで計算機

$
0
0

前の記事(プログラミング言語を作る前知識)でプログラミング言語少し作れる気がしてきたので、lexとyaccに軽く触れてみた。

実際はflexとbisonを使っている。

lexの書き方

lexのファイルには3つのブロックがあって、%%で区切って記述します。

 -------------------------------------------------------
| 定義部
| オプションやincludeや変数宣言、マクロなどを記述します。
| includeや変数宣言は%{...%}で囲って書きます。
| yaccと組み合わせて使う場合、生成されるCソースを
| インクルードすることがあるので、ここに記載します。
| オプションは%ではじめます。
| %noyywrap
| これは入力が1ファイルであることを示していて、よく使われます。
| マクロは、「マクロ名  正規表現」で書きます。
 -------------------------------------------------------
%%
 -------------------------------------------------------
| ルール部
| 「正規表現  対応するCコード」という記述方法でルールを書きます。
| +や*などは正規表現の特殊文字なので、文字として使いたい場合は
| \でエスケープしたり、""で囲んで明示的に文字列として書きます。
| 定義部で宣言したマクロは{}で囲うことで使えます。
 -------------------------------------------------------
%%
 -------------------------------------------------------
| ユーザーサブルーチン部
| C言語のmain関数などを書きます。
| yaccと組み合わせて使う場合は、main関数はyacc側に書くため
| この部分はあまり書かないかもしれません。
 -------------------------------------------------------

lexで使える正規表現情報です。

Lex(flex)の使い方(簡略版)

lexのファイルは*.lという名前で作成し、lex(flex)コマンドでCソースを生成します。

// lexの場合
$ lex sample.l
// flexの場合
$ flex sample.l

lex.yy.cというファイルが出力されていればok。

yaccの書き方

基本構造はlexと同じです。

 -------------------------------------------------------
| 定義部
| includeや%union, %token, %typeなどを定義します。
| includeはlexと同様に%{...%}で記述します。
| %unionは、型定義に使います。
| %tokenは、単にトークンを定義します。
| %typeは、ルール部で使用する変数名を定義します。
| <>で囲んでuniconの変数名を参照して記述することもできます。
 -------------------------------------------------------
%%
 -------------------------------------------------------
| ルール部
| ルール定義のブロックは以下のよな構成になります。
| 変換結果: 構成要素1 構成要素2 ...
|         | (他の構成内容)
|         { (マッチした際に実行されるCコード) }
|         ;
| ;は省略可能で、{}は構成内容につきそれぞれ定義できます。
 -------------------------------------------------------
%%
 -------------------------------------------------------
| ユーザーサブルーチン部
| C言語のmain関数などを書きます。
| 実際に入力を解析したりするのに使います。
| 構文解析関数はyyparseです。
| yyparse関数を使う際、yacc単体で利用するときは
| 字句解析器としてyylex関数の実装が必要になります。
 -------------------------------------------------------

yaccファイルは、*.yという名前で作成し、yacc(bison)コマンドでCソースを生成します。

// yaccの場合
$ yacc -d sample.y
// bisonの場合
$ bison -d sample.y

sample.tab.hとsample.tab.cというファイルが出力されていればok。

lexとyaccを組み合わせて使う

yyparseが、yylexを必要としているように、lexとyaccは組み合わせ使うと便利です。

大域変数の利用パターン(変数)

intやdoubleなどの変数を扱う場合に、lexとyaccの間で大域変数を使用して、lexの正規表現にマッチした変数を、yaccのunionと紐付けておくことができます。

yaccでuniconで定義した変数は、lexで、yylval.変数名で参照できます。

double型の足し算をするだけの単純な例です。

lexファイル(sample.l)

%{#include <stdio.h>#include <stdlib.h>#include "sample.tab.h"%}%%[0-9]+\.[0-9]*{yylval.double_value=atof(yytext);returnDOUBLE;}"+"  {returnADD;}%%

yaccファイル(sample.y)

%{#include <stdio.h>#include <stdlib.h>%}%union{doubledouble_value;}%token<double_value>DOUBLE%type<double_value>factorexpr%leftADD%%input:|inputlineline:CR|exprCR{printf(">> %f\n",$1);}expr:factor{$$=$1;}|exprADDexpr{$$=$1+$3;}factor:DOUBLE%%intyyerror(charconst*str){fprintf(stderr,"%s\n",str);return0;}intmain(void){yyparse();return0;}

double_valをいうyaccで定義した型を、lexファイルでyylvalを介して参照しています。

yaccファイルでは、%tokenを使ってDOUBLEとunionの変数を紐付けることで、自動的に型をつけるように指定しています。

簡単な計算機を作る

計算機なので計算順序を正しく定義してあげるのが大事だと思います。計算順序を決めるのに、yaccの%left、%rightが役に立ちそうです。

%leftは左結合規則を定義、%rightは右結合規則を定義できます。

身近なところだと、足し算などは左結合、代入などは右結合です。

%left,%rightは定義した順番(上から下)に優先順位がつきます。

"+-*/%^()"と数字(小数点)をlexで定義します。

%optionnoyywrap%{#include <stdio.h>#include <stdlib.h>#include "cal.tab.h"%}%%[0-9][0-9]*{yylval.value=atof(yytext);returnVALUE;}[0-9]+\.[0-9]*{yylval.value=atof(yytext);returnVALUE;}"+"{returnADD;}"-"{returnSUB;}"*"{returnMUL;}"/"{returnDIV;}"%"{returnREM;}"^"{returnPOW;}"\n"{returnCR;}"("{returnLP;}")"{returnRP;}%%

yaccで構文規則を書いていきます、今から作る計算機は"^"だけ右結合です。

%{#include <stdio.h>#include <stdlib.h>#include <math.h>%}%union{doublevalue;}%token<value>VALUE%tokenADDSUBMULDIVREMPOWCRLPRP%type<value>factorexpr%leftADDSUB%leftMULDIVREM%leftNEGPOS%rightPOW%%input:|inputlineline:CR|exprCR{printf(">> %f\n",$1);}|errorCR{yyerrok;yyclearin;}expr:factor|ADDexpr%precPOS{$$=$2;}|SUBexpr%precNEG{$$=-$2;}|exprADDexpr{$$=$1+$3;}|exprSUBexpr{$$=$1-$3;}|exprMULexpr{$$=$1*$3;}|exprDIVexpr{$$=$1/$3;}|exprREMexpr{$$=fmod($1,$3);}|exprPOWexpr{$$=pow($1,$3);}|LPexprRP{$$=$2;}factor:VALUE%%intyyerror(charconst*str){externchar*yytext;fprintf(stderr,"%s\n--> %s\n",str,yytext);return0;}intmain(void){yyparse();}

コンパイルして実行します。

$ flex cal.l$ bison -d cal.y$ gcc cal.tab.c lex.yy.c -lm -o cal$ ./cal
2+4*4>> 18.000000(2+4)*4>> 24.000000
60/5*2>> 24.000000(9-2*3)^3>> 27.000000

おぉ、ちゃんと動いてる風だ。

計算機の例が書いてあって参考にした記事

まとめ

lexとyaccの記法について、わかってくれば計算機作れた。

実際に言語を作るときは、yaccで即時評価するのでなく、ASTを作成することになるので、ややこしくなってくる。。

参考記事

一人アサカツ!しよう

$
0
0

一人朝活。

経緯

最近朝9:00くらいに出社するようになったのだけど、出社してから一時間くらい進捗してないことに気づいた。

仕事しても進捗がないので出社してから一時間くらい朝活をしてみようと思ったのです。

自分ルール

  • 出社後1時間くらい(長くても11時くらいまで)だけ
  • 内容をブログにpost
  • 毎日じゃなくてもいい(進捗する日もある、進捗する気配のない日にする)

プログラミングするときは、書き捨てていくもののためにGitHubのオーガニゼーションを作ったのでそこにコミットすることにしよう。

Kakisute


個人的に時間を限定してなんかするっていうとブログを更新することは苦手だったので挑戦的な試みである。

インターネット上に情報を公開するという行為にまだあまり慣れていないのでそれになれていく目的もあるかもしれない。

今日から始めてみたい。3日坊主にならないように頑張ろう。

Haskellをはじめたい

$
0
0

朝活#1

積読

おもしろそうだなーと思ってつい本を買う

目次を読む

へぇー

何かが起こる

本棚にしまう

関数プログラミング 珠玉のアルゴリズムデザイン

Amazon.co.jp: 関数プログラミング 珠玉のアルゴリズムデザイン: Richard bird, 山下 伸夫: 本

この本の場合、Haskellが読めなくて本棚にinされた。

Haskellに入門したい

この本を読みたいのでHaskellを書けるようになりたい。

"Haskell 入門"でGoogle検索すると、上のほうに「怖くないHaskell」が出てきてこわい。関数プログラミングには怖いイメージあるの良くないことだと思う。

実行したいので処理系を調べると、GHCというのがデファクトぽい。

GHCにふれる

Mac OS X環境では、brew経由でインストールできるようだ。

$ brew install ghc

自分のMacには何故かHaskellがインストールされていた。

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.8.3

これは、2014年のバージョンみたいだ。

以前も始めようとしていた痕跡があった。

律儀にパッケージマネージャのcabalもインストールされていた。

$ cabal --version
cabal-install version 1.20.0.3
using version 1.20.0.2 of the Cabal library

どういうコマンドでインストールされていたのかわからないのでこわい。

Haskellを書いてみる

ひとまずこのバージョンのHaskellで書いてみる。

main=doputStrLn"Hello Haskell!"

はじめてのHaskellはこのコードで、vim-quickrunで実行されたので実行コマンドを知らなくても実行された、quickrunとても便利。

少し調べてFizzBuzz関数を書くと下のようになりました。

fizzbuzzn|n`mod`3==0="Fizz"|n`mod`5==0="Buzz"|n`mod`15==0="FizzBuzz"|otherwise=shownmain=doletl=1print(mapfizzbuzz[1..10])

"|"で書いているのはガードと呼ばれるものみたいです。

なんとなく書いている気になれた。

参考記事

結果として

Haskellのスペルが曖昧になる程度のハスケェル力しかないので、まず文法を覚えようと思った。

すごいH本などを読むといいのだと思うけど、あの手の分厚い本を頑張って読むのは自分には合ってないことがわかっているので、辞書代わりに使うのがちょうどいいと思っている。

文法をひとさらいしたら先の本をよみながらHaskellを勉強していく予定。

Goでnet/httpな簡単なJSON API

$
0
0

朝活#2

code

localhost:8080/jsonに向けてJSONをPOSTするとJSONが返ってきます。

packagemainimport("fmt""net/http""encoding/json""io/ioutil")typeInputstruct{Instring}typeOutputstruct{Outstring}funcjsonHandleFunc(rwhttp.ResponseWriter,req*http.Request){output:=Output{"返ってくる"}deferfunc(){outjson,e:=json.Marshal(output)ife!=nil{fmt.Println(e)}rw.Header().Set("Content-Type","application/json")fmt.Fprint(rw,string(outjson))}()ifreq.Method!="POST"{output.Out="Not post..."return}body,e:=ioutil.ReadAll(req.Body)ife!=nil{output.Out=e.Error()fmt.Println(e.Error())return}input:=Input{}e=json.Unmarshal(body,&input)ife!=nil{output.Out=e.Error()fmt.Println(e.Error())return}fmt.Printf("%#v\n",input)}funcmain(){fs:=http.FileServer(http.Dir("static"))http.Handle("/",fs)http.HandleFunc("/json",jsonHandleFunc)http.ListenAndServe(":8080",nil)}

動作している様子

POSTしている様子

$ curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"In": "イィイィィィンッ"}' http://localhost:8080/json# curlの表示(長いので省略){"Out":"返ってくる"}%

Serverの様子

$ go run server.go
main.Input{In:"イィイィィィンッ"}

staticディレクトリを掘ると、そこのファイルがルートで見れるようにしているので、そこからJSON APIに向けてPOSTして良しなにする感じのSPAを作る予定。

まとめ

調べるのと理解に時間がかかった(2時間くらい)、発明された車輪を使用するほうがいいかもしれないと何度も思った。

参考資料

Node.jsでささっとSPA始める個人的なメモ

$
0
0

朝活#3

※個人的なメモです、簡単なアプリしか想定していません。

gulp, browserify, reactjs, coffee-script, sass(scss), hamlで始めます。

ディレクトリ構成

srcにあるcoffee-script, haml, scssを編集して、そこをgulpでwatchします。

dest/, *.htmlはgulpが勝手に作ります。libにはダウンロードしたCSS及びJSライブラリを入れる構成です。

.
├── package.json
├── gulpfile.coffee
├── *.html
├── dest
│   ├── css
│   └── js
├── lib
│   ├── css
│   └── js
└── src
    ├── coffee
    ├── haml
    └── scss

Bootstrapping

$ npm install gulp -g$ npm init$ npm install gulp browserify gulp-sass gulp-haml gulp-watch glob vinyl-source-stream react coffee-script coffee-reactify superagent sanitize.css -save

CSSで困らないために、sanitize.cssを使います。

-> src/scss/style.scss

@import'sanitize.scss';

-> src/haml/index/haml

!!!%html{lang:"ja"}%head%meta{charset:"utf-8"}%title Title%link{rel:"stylesheet",type:"text/css",href:"dest/css/style.css"}/%link{rel: "stylesheet", type: "text/css", href: "lib/css/xxx.css"}%body%script{src:"dest/js/app.js"}/%script{src: "lib/js/xxx.js"}

エントリポイントです、Reactを使う場合、bodyをReactで扱えばこれ以上書かなくても良いかもしれないです。libに追加したCSS/JSがあればロードします。

gulpfile

watchしていますが、コンパイルエラーでgulpのプロセスが落ちるという欠陥がありますが、個人用途ですぐに捨てゆくのもなので気にせず使っています。

gulp       = require'gulp'browserify = require'browserify'sass       = require'gulp-sass'haml       = require'gulp-haml'watchify   = require'gulp-watch'source     = require'vinyl-source-stream'glob       = require'glob'gulp.task'default',['build']gulp.task'build',['build:coffee''build:scss''build:haml']gulp.task'build:coffee',->srcFiles = glob.sync('./src/coffee/*.coffee')returnbrowserifyentries: srcFilestransform: ['coffee-reactify'].bundle().pipesource('app.js').pipegulp.dest('dest/js')gulp.task'build:scss',->gulp.src('src/scss/*.scss').pipe(sass()).pipe(gulp.dest('dest/css'))gulp.task'build:haml',->gulp.src('src/haml/*.haml').pipe(haml()).pipe(gulp.dest('.'))gulp.task'watch',['build'],->gulp.watch'src/coffee/*.coffee',['build:coffee']gulp.watch'src/scss/*.scss',['build:scss']gulp.watch'src/haml/*.haml',['build:haml']
$ gulp watch

で開発スタートです。

Viewing all 216 articles
Browse latest View live