読者です 読者をやめる 読者になる 読者になる

へっぽこびんぼう野郎のnewbie日記

けろけーろ(´・ω・`)!

人に教える用にJavaScriptでExcelもどきもどきを作った

JavaScript

概要

「for文とか配列とか、なんのために使うの?」っていう
プログラミング初心者の人に教える用に、行・列追加とSUM関数(2個だけで1回限り…)だけのExcelの最低限の機能を作ってみた。
実用性は皆無です。

実用性とかではなくて
『for文とかいろいろ学習させられて、CSSで色とかも変えれるけど、具体的にどうすればそれっぽいアプリが作れるようになるかが見えない』人に
『for文とか配列とかはこんな感じで使われるよ』とか『関数分けてつくってね』っていうのを知ってもらうためにつくったやつ

人に教える用なのでフレームワークやライブラリは使ってないです。

こんなかんじ

f:id:haruharu1:20160922113902p:plainf:id:haruharu1:20160922113906p:plainf:id:haruharu1:20160922113909p:plainf:id:haruharu1:20160922120049p:plain

ソースについて

github.com

excel.js

本体。200行ちょっと(なんか嫌な感じがするので、ところどころ最適化できると思う)
(個人的に設計ミスした感があってあんまり好きじゃない)

意味ごとに関数を分割するとあとで拡張や修正がしやすい
f:id:haruharu1:20160922120852p:plain
f:id:haruharu1:20160922121130p:plain
f:id:haruharu1:20160922121453p:plain
f:id:haruharu1:20160922123238p:plain

excel.html

デフォルトの値が書いてある。
初期値を変えられる。増やしたり減らす場合は、js側のbodyArraysも変更する。

excel.css

雑につくったCSS。まだ最適化できる。

バグとか仕様とかに関して

バグはたぶんいっぱいありますがクリティカルな場所は大丈夫なので放置の方向で。

「行挿入や行削除はないの?」「AVERAGE関数は?」「色つける機能はよ」
「シートは?」「保存できないの?」「インポートはどうするの?」
「コピペしたいんだけど」
とか言うのはやめてほしいです。

pythonでdatetime.datetime型に、単にタイムゾーンを付与したいときにやること

Python

毎回忘れてStackoverflow見てるので(メソッドにするのもあれだな感)

タイムゾーンをくっつけるだけ

>>> import datetime
>>> import pytz
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2016, 9, 9, 11, 5, 34, 943737)
>>> now.replace(tzinfo=pytz.utc)
datetime.datetime(2016, 9, 9, 11, 5, 34, 943737, tzinfo=<UTC>)

タイムゾーン間の時差を計算してくれるやーつ

>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2016, 9, 9, 11, 8, 55, 33027)
>>> tokyo_now = now.replace(tzinfo=pytz.timezone('Asia/Tokyo'))
>>> tokyo_now
datetime.datetime(2016, 9, 9, 11, 8, 55, 33027, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
>>> tokyo_now.astimezone(pytz.utc)
datetime.datetime(2016, 9, 9, 2, 8, 55, 33027, tzinfo=<UTC>)
>>> tokyo_now.astimezone(pytz.timezone("US/Hawaii"))
datetime.datetime(2016, 9, 8, 16, 8, 55, 33027, tzinfo=<DstTzInfo 'US/Hawaii' HST-1 day, 14:00:00 STD>)

Chrome、version52のDeveloperコンソールからResourceタブがなくなるの巻

Chrome

Resourceタブがない!??!?

f:id:haruharu1:20160805194524p:plain


ブックマークのとこもダサくなってる

f:id:haruharu1:20160805194935p:plain


/(^o^)\

f:id:haruharu1:20160805194635p:plain


ResourceタブはApplicationタブに移動したみたいです

f:id:haruharu1:20160805194748p:plain



ダサい……(´;ω;`)

ゴミをゴミ捨て場へ捨てる方法

雑記

はじめに

ゴミを散らかす癖がついているのが僕です。

なぜ僕はゴミを散らかすのか。

それは「いっぱい集めてから捨てる方が効率的だから」です。
ゴミをそのへんにぽいぽいっとまとめて置いておき、「さすがにこれはやべぇな」ってなったときに、かき集めて捨てるというライフを送っていました。

課題

しかし

  • ゴミを見るたびに「捨てなきゃ」などという義務感によってつらい気持ちになり、生活の質が下がる。
  • 歩くときに邪魔になる。

こういう問題点が浮上してきました。部屋がせまいので、ゴミが障害物になり、自由に行動ができなくなっていたのです。
ぼくは自由意志で動いていたつもりなのに、ゴミがぼくの意思をカリー化している……!!!というわけです。
ゴミがメンヘラなのは困るので、ぼくはゴミのそのメンヘル性を管理下に置くことにしました。

そしてゴミは定期的に捨てるべきという結論に達しました。

ゴミ捨てコスト

ゴミを捨てるのは一苦労です。

ゴミが発生する
→ゴミ箱を探す
→ゴミをゴミ箱に捨てる
→ゴミ箱のゴミをまとめる
→ゴミ捨て場へ持っていく

なんというダルさ。

なんといってもゴミ箱を探す手間はありえない。
なので解決策云々の前にまず労力削減を考えました。

ゴミの発生源

ここでいうゴミとは「とりあえず人間が認識できる程度の大きさを持つ不愉快なもの」の総称です。

ゴミは大別すると次のように分けられそうです。

  • ほこり・髪の毛
  • 汚れ
  • 廃棄物

今回は汚れに関しては除外します。汚れに関しては、今回書く方法にDependency Injectionして解決しようと思いますが、後日暇な時に書きますん。

ほこり・髪の毛への対処法

とりあえず床に落としておけば、ルンバが勝手にやってくれるようになりました。
めっちゃほこりとってくれて4万だったので安い気がします。

ルンバがない? 買いましょう!

廃棄物への対処法

廃棄物は、大別して

  • 水回り
  • 消耗品を消耗した自分の位置

で発生します。
つまり、ゴミを捨てるのがめんどくさいのは、「ゴミになるようなものを使うときに自分がいる場所がゴミ箱から遠いから」というのが理由です。
だからゴミ箱の近くでゴミを出すようにすればゴミ箱をゴミを出すときの自分に近づければ解決しますね。

ゴミ箱にぼくをストーカーさせる能力を付与するのはめんどくさすぎるので技術的に厳しいので、
ここは単純明快に、ゴミ箱を増やすことにしました。

ぼくは小さなゴミ箱を複数買うことで対応しました。
これをサブゴミ箱と、もっとも大きなゴミ箱をメインゴミ箱と定義します。

(※ ただし「ゴミ箱を置くという行為」は、「その空間を『ゴミを捨てる機能』として固定する行為」にほかならないので、ゴミ箱が邪魔になるようなら問題です。
ゴミ箱ごときに自由意思を妨げられる人生は不幸なので、ちゃんと設置場所は考えた方がいいでしょう。)

こうすることで、ゴミが出たらゴミ箱に捨てることができます。
「この街、ゴミ箱ないからそのへんに捨てといたろ」を防ぐシステムと同じです。

こうすることで、ぼくはゴミ箱にゴミを捨てることができるようになりました。

ゴミを集積してゴミ捨て場へ

一見「ゴミを捨てるときに、ゴミを集積する」という作業が効率的っぽく見えますが、基本的に外出するときは忙しいものです。

  • 外出のときは忙しいからゴミ捨てはまた今度
  • ゴミがたまってるのにゴミ捨てが終わらない
  • 汚くなる!!

という悪循環が発生するのは誰の目にも明らかですね。

遅延評価も良いですが、遅延しすぎればコスト過剰であると考えられ、ゴミを集積することができません。

したがって「ゴミを集積するタスク」は、分離されるべきなのです。
ゴミを集積して玄関前に置いておきさえすれば、外出のとき「あ、ゴミ捨ててから行こ」となり、無事ゴミを捨てられます。

では、どのタイミングでゴミを集積するべきなのか。

もっとも効率的なのは、やはりメインゴミ箱が満タンになった状況です。
満タンになった瞬間ゴミ収集マンとなり、各地のゴミ箱からゴミを回収して、回収したゴミゴミは、玄関前に置いておくのが最高効率です。
このとき玄関前や、メインゴミ箱の設置箇所付近にレジ袋が置いてあれば、メインゴミ箱をカバーするレジ袋の補充もすぐ終わるので最高でしょう。

ゴミ捨てに関わるタスク一覧

ゴミが発生
→最も近くのゴミ箱に捨てる(近くにゴミ箱がなければゴミ箱設置を決意)

メインゴミ箱にゴミを捨てる
→メインゴミ箱の空き容量が基準を超える
→各地のゴミ箱からゴミを集積して玄関前に置く

単体で大きなゴミが発生
→玄関前への動線上にゴミを置く

玄関前付近へ移動する
→動線上にゴミがあれば玄関前に置く

外に出るときにゴミが玄関前に置いてある
→捨てる

まとめ

こうすることで、家の中にゴミがたまることがなくなるのです。
もっとも労力を使うのは「ゴミを集積するとき」ですが、数ヵ所を巡れば終わる話なので、めんどくさいですが、許容範囲のめんどくささです。

重要なのはゴミ箱の設置場所であり、少なければ少ないほどいいけど、捨てるときに不便ではない場所に設置するというのが難易度高いです。

また、ゴミ集積時はあくまで、「複数の特定の位置にあるゴミ箱からゴミを取り出して集積し、玄関前に置く」というのがタスクなので、
このタスクに何かべつのことを追加すると失敗します。

たかがゴミ捨てタスクですが
「ゴミが出たときにゴミ箱を探す」「ゴミ箱にわざわざ近づく」「レジ袋をとりにいく」というような作業を簡略化しているので、
圧倒的に楽ちんです。
また小さなタスクに分割したことで、他人にも依頼しやすくなり、図式化も可能です。

このようにして、ゴミをゴミ捨て場へ持っていくという作業は
「ゴミを集めて玄関前に置く(30秒)」と「外に出るついでにゴミを持ってゴミ捨て場へ行く(10秒)」に短縮され、
ぼくはゴミを40秒毎1ゴミ箱で処理でき、ゴミを支配下におくことができました。

また、ゴミ箱にゴミを集めるのではなく、買い物によって発生するようなゴミは、そのまま玄関前への動線上に置いた方がゴミをあつめなくて済むので楽です。
メインゴミ箱が満タンになる頻度が高いと「めんどくせぇな」と感じます。

人間は直感でコストをざっくり計算できるのですごいですね。
その直感が極めて優れているのがぼくたちめんどくさがり屋です。

というわけでした。

より効率的な方法があれば教えていただきたいです。

追記

これはぼくの家をもとにした最適化なので、十分一般化されていません。ご注意ください。

Reduxのソースを読んでみたので、Reactを使わずにReduxを説明してみた(Redux入門)

Redux React JavaScript ReactiveProgramming

Redux読んだ

会社の勉強会で発表したので共有も兼ねて。スライドはこれ↓


Reduxをざっくり読んでみた。

この記事の前提知識

EcmaScriptがあることは知っている
ES6を使うにはBabelがオススメ!
npmでインストールするのとかpackage.jsonとかは知ってる。

それがわからない場合は、たぶんやり方すらわからないはずなので、こっちを見てくれると嬉しいです↓
heppoko.hatenadiary.jp

要はこのソースのfilter関数の箇所を分離するのがReduxの役目

ソース
const playernames = ['nakada', 'tanaka', 'nakadayama', 'yamada', 'hamada'];
String.prototype.contains = function(string) { return this.indexOf(string) != -1 }

class View {
  // 動作も状態管理も状態変更後どうするかも全部ここに書かれちゃってる
  // このfilter関数が実行され終わったとき、誰もfilterNameを保持していない
  filter(filterName) {
    let playernamesForDisplay = null;
    if (filterName) {
      playernamesForDisplay = playernames.filter(
        playername => playername.contains(filterName)
      );
    } else {
      playernamesForDisplay = playernames;
    }
    console.log(playernamesForDisplay);
  }
}

let view = new View();
console.log(playernames);

view.filter('nakada');
view.filter('ma');
view.filter('');
実行結果
$ node reduxtesttest.bundle.js
[ 'nakada', 'tanaka', 'nakadayama', 'yamada', 'hamada' ]
[ 'nakada', 'nakadayama' ]
[ 'nakadayama', 'yamada', 'hamada' ]
[ 'nakada', 'tanaka', 'nakadayama', 'yamada', 'hamada' ]

スライドの中身を含めてReduxを使って作ったソース(要Babel, Redux)

スライド見てからの方がわかりやすいと思います。
※印に関しては、このソースの下に説明が書いてあります。

ソース
import { createStore } from 'redux';

// Helper function
String.prototype.contains = function(string) { return this.indexOf(string) != -1 }

// Action Creator
function filterPlayer(filterPlayername) {
  // Action
  return {
    type: 'FILTER_PLAYER_NAME',
    filterPlayername: filterPlayername
  };
}

// Reducer
// ※default parameters
// ※Object.assign
function playerData(state = { playernames: ['nakada', 'tanaka', 'nakadayama', 'yamada', 'hamada'] }, action) {
  switch(action.type) {
    case 'FILTER_PLAYER_NAME':
      return Object.assign({}, state, {
        filterName: action.filterPlayername
      });
    default:
      return state;
  }
}

let store = createStore(playerData);

// View
class View {
    // filterするのと、displayPlayerNameをそれぞれ独立して書ける。
    filter(name) {
      store.dispatch(filterPlayer(name))
    }

    displayPlayerName(state) {
      // ※Destructuring
      const { playernames, filterName } = state;

      let playernamesForDisplay = null;
      if (filterName) {
        playernamesForDisplay = playernames.filter(
          playername => playername.contains(filterName)
        );
      } else {
        playernamesForDisplay = playernames;
      }
      console.log(playernamesForDisplay);
    }
}

let view = new View();

// Redux observes state and if state is changed, `view` displays PlayerName;
let currentValue;
function handleChange() {
  console.log('----- handleChange() Called -----');
  let previousValue = currentValue;
  currentValue = store.getState();

  if (previousValue !== currentValue) {
    view.displayPlayerName(currentValue);
  }
}

let unsubscribe = store.subscribe(handleChange);
// Initialize handler (as if `do {} while {}`)
handleChange();
console.log("========== INITIALIZED ===========");

view.filter("nakada");
view.filter("ma");
view.filter("");
実行結果
$ node reduxtest.bundle.js
----- handleChange() Called -----
[ 'nakada', 'tanaka', 'nakadayama', 'yamada', 'hamada' ]
========== INITIALIZED ===========
----- handleChange() Called -----
[ 'nakada', 'nakadayama' ]
----- handleChange() Called -----
[ 'nakadayama', 'yamada', 'hamada' ]
----- handleChange() Called -----
[ 'nakada', 'tanaka', 'nakadayama', 'yamada', 'hamada' ]

ES6の説明のためのソース

ソース
console.log('----- default parameters ------');
function f(x = { a: 2 }) {
    console.log(x.a);
}


console.log('--- no arguments')
f();
console.log('--- argument one')
f({ a: 'xxx', b: 'yyy'});

console.log('----- Object assign ------');
// ※Object assign
let assigned = Object.assign({}, {p: 3}, {q: 4}, {r: 'aa', s: {}});
console.log(assigned);

console.log('----- destructuring ------');
let coodinate = {
    x: 1,
    y: 2,
}

const { x, y } = coodinate;
console.log("x's value:", x);
console.log("y's value:", y);

console.log('----- arrow function ------');

console.log('--- printXXX')
let printXXX = () => console.log('XXX');
printXXX();

console.log('--- plus3')
let plus3 = x => x + 3;
console.log(plus3(5));

console.log('--- reduce')
console.log([1, 5, 8, 10, 7].reduce((p, n) => p + n));
実行結果
$ node reduxtest-explain.bundle.js
----- default parameters ------
--- no arguments
2
--- argument one
xxx
----- Object assign ------
{ p: 3, q: 4, r: 'aa', s: {} }
----- destructuring ------
x's value: 1
y's value: 2
----- arrow function ------
--- printXXX
XXX
--- plus3
8
--- reduce
31

Reduxは何が嬉しいのか??

結構冗長にはなってしまうが、「何をするか、どうなるか、こういうときどうするか」を分離して考えることができる。

  • 「彼をトイレに移動させる」
  • 「彼はトイレに行くとおしっこを出せる状態になる」
  • 「おしっこを出せる状態になれば彼はズボンを下げる」

とそれぞれ分離できるので、状態が混ざらない。あるいは、状態が複雑に絡まっても気にしなくていい。

こういうパターンを考えないと、

  • 「彼をトイレに移動させると彼はズボンを下げる」

みたいな書き方になって、
おしっこを出す出さないに関わらずズボン下げっぱなしだったりして、デバッグが大変。

まとめ

このサンプルでは、アクションが1つ、stateも1つしかないので、イメージがつきにくいが、複数になってくると、問題が分離できてらくちん。

Functional Reactive Programmingが発想元なので、こっちを読むとイメージつきやすいかもしれない。
Reduxの中でrxjsを使っているもよう。
github.com

Reactive Programmingのおまけ( rxjs, rxjs-esが必要)

import Rx from 'rxjs/Rx';
import 'rxjs/add/operator/map';

function listen(element, eventName) {
    return Rx.Observable.create(observer => {
        // Create an event handler which sends data to the sink
        let handler = event => observer.next(event);

        // Attach the event handler
        element.addEventListener(eventName, handler, true);

        // Return a function which will cancel the event stream
        return () => {
            // Detach the event handler from the element
            element.removeEventListener(eventName, handler, true);
        };
    });
}

// Return an observable of special key down commands
function commandKeys(element) {
    let keyCommands = { "38": "up", "40": "down" };

    return listen(element, "keydown")
        .filter(event => event.keyCode in keyCommands)
        .map(event => keyCommands[event.keyCode])
}

let subscription = commandKeys(document).subscribe({
    next(val) { console.log("Received key command: " + val) },
    error(err) { console.log("Received an error: " + err) },
    complete() { console.log("Stream complete") },
});

f:id:haruharu1:20160708181323p:plain

Big "Babel" Is Watching Another ".babelrc" in Your Home Directory, Root Directory, And So On :)

babel ES6 JavaScript

f:id:haruharu1:20160704091104p:plain

ERROR in ./foo.js
Module build failed: Error: Couldn't find preset "react" relative to directory "/Users"
    at /Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:395:17
    at Array.map (native)
    at OptionManager.resolvePresets (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:387:20)
    at OptionManager.mergePresets (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:370:10)
    at OptionManager.mergeOptions (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:330:14)
    at OptionManager.addConfig (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/o

preset "react"?
I never wrote this!!
I don't want to use preset react. just only preset "es2015"!!
Here is the evidence.
f:id:haruharu1:20160704092738p:plain

I don't want you to use preset 'react'. Thank you :)

However babel still cause an error.

ERROR in ./foo.js
Module build failed: Error: Couldn't find preset "react" relative to directory "/Users"
    at /Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:395:17
    at Array.map (native)
    at OptionManager.resolvePresets (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:387:20)
    at OptionManager.mergePresets (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:370:10)
    at OptionManager.mergeOptions (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/option-manager.js:330:14)
    at OptionManager.addConfig (/Users/usrNeko/es6teset/node_modules/babel-core/lib/transformation/file/options/o

Because Google does not teach me how to fix this, I read sources.

./node_modules/babel-core/lib/transformation/file/options/option-manager.js
f:id:haruharu1:20160704091543p:plain

Babel is going to find .babelrc my home directory :)
f:id:haruharu1:20160704091753p:plain

Oh, some time ago, certainly I wrote this here. fuck me.
f:id:haruharu1:20160704091957p:plain
then remove this.
f:id:haruharu1:20160704092112p:plain

Gotcha.
f:id:haruharu1:20160704092150p:plain

追記:
キャッシュせんのかーい

$ ssh [host]で接続したときは、.bashrcとか.zshrcとか呼ばれないので自分で読みこめよって話

Shell Scripting

例:

$ ssh default 'source ~/.bashrc; [.bashrcの中にあるスクリプトを実行する]'

知らなんだ