もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

退屈なことはPythonにやらせようを読んでpython勉強した(パート1 python基礎編)

こんにちは。絶賛風邪ひき中の僕です。

熱があって、気分が悪いので、毎日続いてた運動も今回はやめています。。

早めに治してまたいつものスタイルに持っていきたいです。

ただ、週2回のブログ記事だけは頑張ろうと思っています。

今回は、去年の本なのですが以下の本を読んでます。

pythonは簡単なツールを何個か作るくらいのスキルしか持ち合わあせていません。

ツールづくりも、ググりながらコピりながらやっているので、この際キチンと勉強しようと多い、購入しました。

いつもどおり自分のために、自分が勉強になったなぁと思うところを記録していきます。

事前準備

本ではanacondaをインストールしよう的なことを書いてましたが、pyenv でインストールできるようだったので、落としてみます。

# インストール
$ pyenv install anaconda3-4.3.1
Downloading Anaconda3-4.3.1-MacOSX-x86_64.sh...
-> https://repo.continuum.io/archive/Anaconda3-4.3.1-MacOSX-x86_64.sh
Installing Anaconda3-4.3.1-MacOSX-x86_64...
Installed Anaconda3-4.3.1-MacOSX-x86_64 to /Users/アカウント/.anyenv/envs/pyenv/versions/anaconda3-4.3.1

# globalへセット
$ pyenv global anaconda3-4.3.1

# spyder起動
$ spyder 

起動しました。 かっこいい。。。 pythonの開発環境はこれで行こう。sublime卒業できそうです。

f:id:kojirooooocks:20180210031918p:plain

勉強になったところまとめ

not演算子

否定を表す場合、php!= とは違い、pythonでは not と表現するみたいです。

a = 'abc'
if not a == 'def':
    print('defじゃないよ')
else:
    print('defだよ')
    
>>> defじゃないよ

sys.exit()

phpdie()exit() のようなもので、プログラムを終了させるものです。

個人的には主にデバッグで使えるなと思いました。

ステップ実行出来るIDEあればローカル開発は問題ないでしょうけど、サーバに入って直接デバッグする場面とか来たら、重宝しそうです。

使用するには、 import sysでsysモジュールをimportする必要があります。

None値

phpのnullと同義ということです。

def test():
    print('testだよ')
    
result = test()
print(result == None)

>>> testだよ
>>> True

printのオプション引数(end, sep)

end

通常 print() は渡された文字列の末尾に改行を付けちゃうのですが、それを制御できるのがendオプションです。

print('はじめまして', end='。')
print('よろしく')

>>> はじめまして。よろしく

sep

複数の文字列を引数に渡した時、printが各文字の間に半角スペースを入れるのですが、そレを制御するのが sepオプションです。

print('こんにちは', 'はじめまして', 'よろしくおねがいします', sep='☆')
>>> こんにちは☆はじめまして☆よろしくおねがいします

2つ組み合わせると可愛い文章も作れます。

print('こんにちは', 'はじめまして', 'よろしくおねがいします', sep='♡', end='♡')

>>> こんにちは♡はじめまして♡よろしくおねがいします♡

地味に使えそうですね。

例外処理

try catchのような形で例外処理は書けるようです。

これが一番知りたかったw

import sys
def sum_func(a, b):
    try:
        return a + b
    except TypeError:
        print("引数のどちらかが、数値型ではありません。")
        sys.exit();

result = sum_func(1, 'aa')
print(result)

>>> 引数のどちらかが、数値型ではありません。

phpのexceptionとかとはやはり違いますが、記述方法とかが大幅に違うという訳でもないので、覚えたら問題なく使える感じです。

リスト型

phpの配列のようにどんな型でも入れられますが、配列のkeyの指定は0, 1, 2といった添字になります。

items = ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']
print(items)
print(items[1]);

>>> ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']
>>> のび太くん

リスト型はいろいろおもしろい機能があって、勉強になりました!

負のインデックス

細かいツールを作ってた時に、これがかなり使えるなー!と思ったものでした。

phpでもsubstrとかの引数で負の位置を設定すれば、後ろから判断してるようになりますが、それと同じく、負のkeyの値を入れると、後ろから判断して要素を取り出してくれます。

items = ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']
print(items[-2]);

>>> ドラミちゃん

スライス

keyの指定で : を用いて取得場所の範囲指定して新たなリストとして取得できます。

:を挟んで左側が開始位置、右側は終了位置です。

ただ、終了位置に関しては、以下の通り、indexを指しているようには見えません。

items = ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']
print(items[2:4]);

>> ['しずかちゃん', 'ジャイアン']

# ['しずかちゃん', 'ジャイアン', 'スネ夫']になると思ってた。

どうやら指定した数値のインデックスは含まれないといった感じのようです。

items[ここから:ここ未満] といった感じで覚えたら良さそうです。

スライスでももちろん負のインデックスは使えます

items = ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']
print(items[2:-1]);

>>> ['しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん']

開始位置終了位置ともに省略することも可能です。

開始位置を省略すると、頭から

終了位置を省略すると、最後まで

といった指定になります。

items = ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']

print(items[:3])
print(items[3:])

>>> ['ドラえもん', 'のび太くん', 'しずかちゃん']
>>> ['ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']

便利だ!!

リストの連結と複製

+でリストを連結できて、 *でリストを複製できます。

* は面白かったです。まるでフエルミラー

items1 = ['どら焼き1', 'どら焼き2']
items2 = ['どら焼き3', 'どら焼き4']
items = items1 + items2
print(items)
print(items * 5)

>>> ['どら焼き1', 'どら焼き2', 'どら焼き3', 'どら焼き4']
>>> ['どら焼き1', 'どら焼き2', 'どら焼き3', 'どら焼き4', 'どら焼き1', 'どら焼き2', 'どら焼き3', 'どら焼き4', 'どら焼き1', 'どら焼き2', 'どら焼き3', 'どら焼き4', 'どら焼き1', 'どら焼き2', 'どら焼き3', 'どら焼き4', 'どら焼き1', 'どら焼き2', 'どら焼き3', 'どら焼き4'] 

inとnot in

phpでいうin_array()と似たような感じで、リストの中に指定の要素が入っているか(in)、入っていないか(not in)を調べられます。

items = ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']

# in
print('ドラえもん' in items)
print('ジャイ子' in items)

>>> True
>>> False


# not in
print('美代子さん' not in items)
print('出来杉君' not in items)

>>> True
>>> False

indexメソッド

phparray_search()と似たような動きのようです。

ただ、違うところは、指定の要素がない場合は、Errorになるみたいです。

items = ['ドラえもん', 'のび太くん', 'しずかちゃん', 'ジャイアン', 'スネ夫', 'ドラミちゃん', '出来杉君']

print(items.index('しずかちゃん'))
print(items.index('先生'))

>>> 2
>>> ValueError: '先生' is not in list

insertメソッド

任意の場所に要素を追加できるメソッドです。

これは使えるなーと思いました。

append()もあるようですが、これは他の言語のpushなどと同じように、末尾に要素を追加できるものでした。

items = ['魔界大冒険', 'アニマルプラネット', '海底鬼岩城']
items.insert(1, 'パラレル西遊記')
print(items)

>>> ['魔界大冒険', 'パラレル西遊記', 'アニマルプラネット', '海底鬼岩城']

ちなみに、存在しないインデックスを指定してinsertすると、エラーは出ず、末尾に追加されました。

items = ['魔界大冒険', 'アニマルプラネット', '海底鬼岩城']
items.insert(100, 'パラレル西遊記')
print(items)

>>> ['魔界大冒険', 'アニマルプラネット', '海底鬼岩城', 'パラレル西遊記']

sortメソッド

リストの要素並べ替えのためのメソッドです。

items = [2980, 1980, 5980, 980, 3980]

# 昇順
items.sort()
print(items)

>>> [980, 1980, 2980, 3980, 5980]

# 降順
items.sort(reverse=True)
print(items)

>>> [5980, 3980, 2980, 1980, 980]

sort自体は使用したことがあるのですが、本で紹介されている注意点は知らなかったので、勉強になりました。

sortはASCIIコードでソートするので、文字列のソートでは、大文字が小文字より前に来る。
items = ['d', 'a', 'c', 'b', 'E']
items.sort()
print(items)

>>> ['E', 'a', 'b', 'c', 'd'] 

アルファベット順でソートさせたいときは、オプション引数の key=str.lower を渡すことでアルファベット順でソートしてくれるようです。

items = ['d', 'a', 'c', 'b', 'E']
items.sort(key=str.lower)
print(items)

>>> ['a', 'b', 'c', 'd', 'E']

phpではどうなのだろうと試してみたところ、phpのsort()もASCIIコードでソートしているようでした。

無知なダメ男ですいません。。。

<?php
$test = ['d', 'a', 'c', 'b', 'E'];
sort($test);
echo var_export($test, true);

>>> $ php test.php 
array (
  0 => 'E',
  1 => 'a',
  2 => 'b',
  3 => 'c',
  4 => 'd',

phpで、pythonsort(key=str.lower)と同じ動きするのはどれかな?と調べたところ natcasesort というのがそれに当たるようです。

<?php
$test = ['d', 'a', 'c', 'b', 'E'];
natcasesort($test);
echo var_export($test, true);

>>> $ php test.php 
array (
  1 => 'a',
  3 => 'b',
  2 => 'c',
  0 => 'd',
  4 => 'E',

pythonの勉強しながらphpの勉強もできて、一挙両得でした。

タプル型

リストとよく似た感じですが、以下2つが違います。

  1. []ではなく()で要素を定義する。
  2. イミュータブル(変更ができないもの)である。
items = ('ルパン', '次元', '五右衛門')
print(items)

>>> ('ルパン', '次元', '五右衛門')

変更しないものかどうかというので、リストと使い分ける感じでしょうか。

ただ、調べると絶対変更できないというわけではないようで、スライスや連結を使えば追加、削除などは行えるようです。

# 追加(不二子、銭形を追加したい)
items1 = ('ルパン', '次元', '五右衛門')
items2 = ('不二子', '銭形')
items  = items1 + items2
print(items)

>>> ('ルパン', '次元', '五右衛門', '不二子', '銭形')

# 削除(不二子を消したい)
items1 = ('ルパン', '次元', '五右衛門', '不二子', '銭形')
items  = items1[0:3] + items1[-1:]
print(items)

>>> ('ルパン', '次元', '五右衛門', '銭形')

また、要素が一つのタプル型を作る際は、以下のように,を末尾につける必要があるようです。

つけないと、エラーは出ませんが、以下の例だと文字列型とみなされるようです。

items = ('ルパン', )
print(items)

>>> ('ルパン',)

items = ('ルパン')
print(items)

>>> ルパン

リストの参照渡し

リスト型を格納する変数を、別変数に代入した際は、phpでいう値渡しではなく参照渡しになるようです。

items = ['コナン', '平次', '蘭']
copy_items = items
copy_items.append('阿笠博士')
print(items)
print(copy_items)

>>> ['コナン', '平次', '蘭', '阿笠博士']
>>> ['コナン', '平次', '蘭', '阿笠博士']

面白い動きしますよね。

では値渡しなリストを作るにはどうしたらよいか調べるとcopyモジュールのcopyを使えばよいとのことでした。

import copy
items = ['コナン', '平次', '蘭']
copy_items = copy.copy(items)
copy_items.append('阿笠博士')
print(items)
print(copy_items)

>>> ['コナン', '平次', '蘭']
>>> ['コナン', '平次', '蘭', '阿笠博士']

ただ、以下のように入れ子のリストになっているような場合は、copyを使用しても参照渡しになってしまいます。

import copy
items = [['新一', '蘭', '平次'], ['コナン', '源太', '光彦', '歩美']]
copy_items = copy.copy(items)
copy_items[1].append('阿笠博士')
print(items)
print(copy_items)

>>> [['新一', '蘭', '平次'], ['コナン', '源太', '光彦', '歩美', '阿笠博士']]
>>> [['新一', '蘭', '平次'], ['コナン', '源太', '光彦', '歩美', '阿笠博士']]

これを解決するのが、 copyモジュールのdeepcopy() です。

import copy
items = [['新一', '蘭', '平次'], ['コナン', '源太', '光彦', '歩美']]
copy_items = copy.deepcopy(items)
copy_items[1].append('阿笠博士')
print(items)
print(copy_items)

>>> [['新一', '蘭', '平次'], ['コナン', '源太', '光彦', '歩美']]
>>> [['新一', '蘭', '平次'], ['コナン', '源太', '光彦', '歩美', '阿笠博士']]

なんでそうなるのだろうと色々調べてみてると、コチラの記事に詳しく書かれておりました。

勉強になりました。

辞書型

php連想配列的な使い方ができます。

items = {'name': 'ドラえもん', 'size': '100cm', 'type': '猫型ロボット'}
print(items)
print(items['name'])

>>> {'name': 'ドラえもん', 'size': '100cm', 'type': '猫型ロボット'}
>>> ドラえもん

辞書型には順番の概念がないので、以下の2つはTrueとなります。

item1 = {'name': 'ドラえもん', 'size': '100cm', 'type': '猫型ロボット'}
item2 = {'size': '100cm', 'type': '猫型ロボット', 'name': 'ドラえもん'}
print(item1 == item2)

>>> True

keys(), vaules(), items()

脳内変換できちゃいますが、keysはkeyの一覧、 valuesは値の一覧、itemsはkey, valueのセットを取得できます。

items = {'name': 'ドラえもん', 'size': '100cm', 'type': '猫型ロボット'}
print(items.keys())
print(items.values())
print(items.items())

>>> dict_keys(['name', 'size', 'type'])
>>> dict_values(['ドラえもん', '100cm', '猫型ロボット'])
>>> dict_items([('name', 'ドラえもん'), ('size', '100cm'), ('type', '猫型ロボット')])

setdefault()

指定のキーが辞書に登録されていない場合のみ指定の値を保存できるというメソッドです。

すでにセットされている場合は、上書きするのではなく、すでにセットされている値を返してくれます。

このメソッドは地味に便利だなーと思いました。

items = {'name': 'ドラえもん', 'size': '100cm', 'type': '猫型ロボット'}
items.setdefault('gender', '男?')
print(items)
print(items.setdefault('type', '狸ロボット'))
print(items)

>>> {'name': 'ドラえもん', 'size': '100cm', 'type': '猫型ロボット', 'gender': '男?'}
>>> 猫型ロボット
>>> {'name': 'ドラえもん', 'size': '100cm', 'type': '猫型ロボット', 'gender': '男?'}

便利な文字列メソッド

文字列でも結構いいメソッドが揃ってました。

新しい言語はおもしろいなー

upper(), lower(), isupper(), islower()

upper()は全ての文字を大文字に、lower()は全ての文字を小文字にします。

isupper()は文字列全てが大文字かどうか、islower()は文字列全てが小文字かどうかを調べます。

print("abcde".upper())
print("ABCDE".lower())
print("abcde".islower())
print("ABcde".islower())
print("abCDE".isupper())
print("ABCDE".isupper())

>>> ABCDE
>>> abcde
>>> True
>>> False
>>> False
>>> True

isalpha(), isalnum(), isdecimal(), isspace(), istitle()

  • isalpha()は、英文字のみで構成されているかどうかを調べます。
  • isalnum()は、英文字か数字から構成されているかどうかを調べます。
  • isdecimal()は、数字のみで構成されているかどうかを調べます。
  • isspace()は、スペースかタブか改行だけで構成されているかどうかを調べます。
  • istitle()は、先頭が大文字でそれ以降が小文字の英単語から構成されているかどうかを調べます。

istitle()おもしろいですね。

print('abcde'.isalpha())
print('abcde1'.isalpha())
print('abcde'.isalnum())
print('abcde'.isdecimal())
print('12345'.isdecimal())
print('abcde'.isspace())
print('     '.isspace())
print('This Is A Pen'.istitle())
print('This Is a Pen'.istitle())

>>> True
>>> False
>>> True
>>> False
>>> True
>>> False
>>> True
>>> True
>>> False

startswith(), endswith()

  • startswith()は、指定の文字列から始まっているかどうかを調べます。
  • endswith()は、指定の文字列で終わっているかどうかを調べます。
print('abcdefg'.startswith('ab'))
print('abcdefg'.startswith('bc'))
print('abcdefg'.endswith('fg'))
print('abcdefg'.endswith('de'))

>>> True
>>> False
>>> True
>>> False

rjust(), ljust(), center()

文字列を右揃え、左揃え、中央揃えしてくれます。

print('kojirock'.rjust(30, " "))
print('kojirock'.rjust(30, "="))
print('kojirock'.ljust(30, " "))
print('kojirock'.ljust(30, "="))
print('kojirock'.center(30, " "))
print('kojirock'.center(30, "="))

>>>                       kojirock
>>> ======================kojirock
>>> kojirock                      
>>> kojirock======================
>>>            kojirock           
>>> ===========kojirock===========

おもしろいメソッドでした。

 終わりに

いろいろおもしろい物ありました。

結構なボリュームになったな。。。

今回はこの本で紹介されていたpythonの基礎部分の勉強でしたが、次回は紹介されている応用編を、記事にしたいと思います。

ではでは。

リモートでの開発のデメリット

こんにちは。

夜中寝る前にスマホから投稿してます。

自分は今リモートでお仕事をさせてもらってます。

理由は、なるべく奥さんの子育てのサポートをするためです。

まぁそんな感じでお仕事してます。

で、ここ最近なんですが、仕事をこの時間まで、ひどい時には4時、5時くらいまでやったりしちゃってます。

リモートなので残業代もでないのに、この時間までなぜやっているのだろう?と思い、なんとなく投稿しました。

自分の中でも全然まとまってないので、理由も何も考えてないんですが、、、

まぁざっくり言うと見積もりのあまさと、リモートだからという甘えかなと。 いや、後者のほうが大きいかな。

後者があるから、見積もりも夜中がっつりやる前提で組んじゃったりしてました。

これってリモートあるあるですよね。 いや、意志が弱い人にはあるあるなのかな?

とにかく、これは問題だなと。

自分への研鑽で、夜遅くまでやるのは問題ないと思ってるんですが、仕事で夜遅くまでやるのは、意味がないとは言わないですが、もったいないなと思いました。

そもそも今年は継続力と成長の年にしたいのに、ずっと仕事してて、勉強できませんでしたー。なんて言い訳になりません。

明日からは、もっとメリハリつけて、仕事やっていきたいと思います。

JSON Server試してみた。

参考サイト

概要

こんにちは。Twitterをチラチラ見ていた時に、参考サイトの記事を拝見して、これは面白そうだなと思い、自分も試してみました。

json_serverの設定

下準備

# 作業ディレクトリ作成 & 移動
$ mkdir json_server_test
$ cd json_server_test

# インストールコマンド
$ npm install json-server

# jsonファイル保存場所を作成 & 移動
$ mkdir public

# API用jsonファイルを作成
$ touch public/test.json

test.jsonを記述

{
  "users": [
    {"id": 1, "name": "test1"},
    {"id": 2, "name": "test2"},
    {"id": 3, "name": "test3"}
  ]
}

json_server実行

$ ./node_modules/.bin/json-server public/test.json 
  \{^_^}/ hi!

  Loading public/test.json
  Done

  Resources
  http://localhost:3000/users

  Home
  http://localhost:3000

  Type s + enter at any time to create a snapshot of the database

何やら実行しています。

http://localhost:3000/users へアクセスしてみます。

f:id:kojirooooocks:20180204025445p:plain

ちゃんと狙ったjsonが帰ってきてます。

ターミナルを見ると

GET /users/ 200 5.170 ms - 128

追加されてました。

ちなみに今回のjsonでいうと、id3番の要素だけを返すようにアクセスすることも出来ます。

http://localhost:3000/users/3 へアクセスしてみます。

f:id:kojirooooocks:20180204025456p:plain

すばらしい!

中々使えそうです。

ngrokと連携

PCから接続するにはこれで問題ないんですが、端末チェックを行いたいときは、localhostではアクセスできません。

なので、ngrokで外部アクセスを許可します。

ngrokのインストールはコチラの記事に詳しく書いていましたので、未インストールの場合は確認してください。

json_serverはデフォルトでポート3000番で起動するので、3000番ポートを指定してngrokを起動します。

$ cd json_server_test/public
$ ngrok http 3000
ngrok by @inconshreveable                                                                                                                                                                                                                                                                                     (Ctrl+C to quit)
                                                                                                                                                                                                                                                                                                                              
Session Status                online                                                                                                                                                                                                                                                                                          
Account                       アカウント名                                                                                                                                                                                                                                                                    
Version                       2.2.8                                                                                                                                                                                                                                                                                           
Region                        United States (us)                                                                                                                                                                                                                                                                              
Web Interface                 http://127.0.0.1:4040                                                                                                                                                                                                                                                                           
Forwarding                    http://7cf0f7c7.ngrok.io -> localhost:3000                                                                                                                                                                                                                                                      
Forwarding                    https://7cf0f7c7.ngrok.io -> localhost:3000                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                                              
Connections                   ttl     opn     rt1     rt5     p50     p90                                                                                                                                                                                                                                                     
                              0       0       0.00    0.00    0.00    0.00                                                                                                                                                                                                                                                    

Forwarding に表示されている http://7cf0f7c7.ngrok.io に端末からアクセスしてみましょう。

test.jsonの中身が表示されるはずです。

個人での開発であればこれで全く問題ないですね!

終わりに

簡単なチェックでしたが、すごく使える感触でした。

自分も今React-Nativeを使ってアプリの開発を行っているので、早速使おうと思ってみたいと思います!

laravel/socialiteを使ってFacebookログインしてみる。

参考サイト

概要

お手伝いしているサイトで、Facebookログインの機能を追加したいという話があり、ちょうどサイトをLaravelに置き換えていたので、Laravelでいいツールないかなと、例のごとくPackagistをあさっていたところ、 laravel/socialite というツールが良さそうだったので、コチラを使ってFacebookLoginを実装してみようと思います。

環境

  • Laravel 5.5
  • PHP 7.1
  • Sociallite 3.0.9

インストール

$ composer require laravel/socialite

Laravel側もろもろ設定

1. config/app.php を修正

'providers' => [
    /*
     * Package Service Providers...
     */
    Laravel\Socialite\SocialiteServiceProvider::class,
],

'aliases` => [
    // 最後に追記
    'Socialite' => Laravel\Socialite\Facades\Socialite::class,
]

2. .env を修正

FACEBOOK_APP_ID=******************
FACEBOOK_APP_SECRET=******************
FACEBOOK_CALLBACK_URL=******************

3. config/services.php を修正

// 最後に追記
'facebook' => [
    'client_id'     => env('FACEBOOK_APP_ID'),
    'client_secret' => env('FACEBOOK_APP_SECRET'),
    'redirect'      => env('FACEBOOK_CALLBACK_URL')
]

4. routes/web.php を修正

Route::get('/auth/signin', 'Auth\SocialLiteController@signin');
Route::get('/auth/login', 'Auth\SocialLiteController@login');
Route::get('/auth/callback', 'Auth\SocialLiteController@callback');

5. app/Http/Controllers/SocialLiteController.php を作成

<?php
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Socialite;

class SocialLiteController extends Controller
{
    public function signin()
    {
        return view('auth/signin');
    }

    public function login()
    {
        return Socialite::driver('facebook')->redirect();
    }

    public function callback()
    {
        $user = Socialite::driver('facebook')->user();
        dd($user);
    }
}

6. resources/views/auth/signin.blade.php を作成

<html>
    <body>
        <a href="/auth/login">facebook login</a>
    </body>
</html>

Facebook側もろもろ設定

f:id:kojirooooocks:20180131042345p:plain

↑の画面で、APP IDとAPP SECRETを確認して、.envの FACEBOOK_APP_IDFACEBOOK_APP_SECRET に書き写す

f:id:kojirooooocks:20180131042401p:plain

↑の画面で、.envで設定しているFACEBOOK_CALLBACK_URLを設定する

実行してみる。

facebook login リンクをクリックすると以下のような画面に行くと思います。

f:id:kojirooooocks:20180131042526p:plain

ログインを実行すると、設定したコールバック先に通信が来ます。

現状だと以下のような dd() で表示しているデータが表示されます。

f:id:kojirooooocks:20180131042537p:plain

感想

コード量も少なくあっという間に出来ました。

Laravelは本当にいろんなライブラリでてて楽です。

他にも良さそうなのあったら随時記事あげていこうと思います。

php-cs-fixerでPSR2を守らせつつインデントはタブにしたい

概要

今携わっているプロジェクトのコードが、だいぶ昔のソースコードで、かつ色んな人が触っているから書き方がバラバラという、まぁなるべくしてなったレガシーコードでした。

せっかくなので、php-cs-fixerを導入して、PSR2を守らせたコードにしたいと奮起して導入まではしたのですが、厄介な問題がありました。

インデントがタブだった。

↑のせいで、rules=PSR2とかってやると、ほぼほぼ全部のコードが修正入れられてしまい、レビューが死んでしまいます。

なんとかPSR2を守らせつつ、インデントはタブでやりたい!

と思い、csfixerのコードをおってると、なんのことはない以下が、そうでした。

setIndent("\t")

楽勝でしたねw

せっかくなんで、簡単に作った設定ファイルを貼っておきます。

<?php

return PhpCsFixer\Config::create()
    ->setRiskyAllowed(true)
    ->setIndent("\t")
    ->setRules([
        '@PSR2'                    => true,
        'array_syntax'             => ['syntax' => 'short'],
        'blank_line_before_return' => true,
        'function_typehint_space'  => true,
        'method_separation'        => true,
        'binary_operator_spaces'   => [
            'align_double_arrow' => true,
            'align_equals'       => true
        ],
    ])
    ->setFinder(PhpCsFixer\Finder::create()
        ->exclude('vendor')
        ->in(__DIR__)
    );

おまけ

みなさんいつcs-fixer流していますか?

自分はコチラの記事を参考にさせてもらい、pre-commitで実行するようにしていますが、これだと個人個人実装する必要あるので、ちょっと面倒だなと思いました。

cs-fixer掛けるとかけた後でcommitを分けられるのはいいんですけどね。

自分はcomposerのscriptに以下の様に書いて、都度実行しています。

    "scripts": {
        "dry-fix": [
            "target_file_list=$(git status -uno --short | grep -E '^ [AUM].*.php$' | cut -c4-); for php_file in $target_file_list; do php-cs-fixer fix --dry-run --diff --config=.php_cs.dist $php_file; done"
        ],
        "fix": [
            "target_file_list=$(git status -uno --short | grep -E '^ [AUM].*.php$' | cut -c4-); for php_file in $target_file_list; do php-cs-fixer fix --config=.php_cs.dist $php_file; done"
        ]
    }

git statusで表示されるphpファイルだけをcs-fixerかけるという感じです。

毎回実行していますが、composer installすればみんな一緒に使えるのでそれで良いかなと。

今回は小ネタでしたが、こんな感じです。

EC2に立てたJenkinsにLet's Encryptを適用させる

EC2に立てたJenkinsにLet's Encryptを適用させる

参考サイト

概要

現在お仕事を頂いている会社にCIを導入したいなと思いまして、Jenknis入れようと思いました。

CircleCIやTravisCIも考えましたが、一番慣れてたJenkinsにしました。

で、せっかく立ち上げたので、オレオレではなく、Let's Encryptを使ってキチンとSSL化しようと思います。

導入

Jenkninsインストール

この辺はネットにいっぱい転がっているのですが、コマンド的には以下です。

## OpenJDKのインストール
$ sudo yum -y install java-1.8.0-openjdk-devel

## Jenkinsのインストール
$ sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
$ sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
$ sudo yum install jenkins

Jenkinsの設定

次にJenkinsの設定を変更します。

vim /etc/sysconfig/jenkins で以下の項目を変更します。

JENKINS_PORT=""
JENKINS_HTTPS_PORT="8443"
JENKINS_ARGS="--prefix=/jenkins"

Let's Encryptのインストール

参考サイトに記載している記事がとてもわかり易かったです。

$ sudo curl https://dl.eff.org/certbot-auto -o /usr/bin/certbot-auto
$ sudo chmod 700 /usr/bin/certbot-auto
$ sudo certbot-auto certonly -d ドメイン --email メールアドレス

インタラクティブな選択が出てて、apacheを選択すれば以下の場所に、以下のようなファイルが作成されます。

# ll /etc/letsencrypt/live/ドメイン/
合計 4
-rw-r--r-- 1 root root 543  1月 22 23:10 README
lrwxrwxrwx 1 root root  38  1月 22 23:10 cert.pem -> ../../archive/ドメイン/cert1.pem
lrwxrwxrwx 1 root root  39  1月 22 23:10 chain.pem -> ../../archive/ドメイン/chain1.pem
lrwxrwxrwx 1 root root  43  1月 22 23:10 fullchain.pem -> ../../archive/ドメイン/fullchain1.pem
lrwxrwxrwx 1 root root  41  1月 22 23:10 privkey.pem -> ../../archive/ドメイン/privkey1.pem

Apacheとの連携

先程の証明書を指定して、JenkinsとApache連携します。

<VirtualHost *:443>
  NameVirtualHost *:443

  <IfModule mod_proxy.c>
    SSLEngine On
    SSLProxyEngine on

    SSLCertificateFile /etc/letsencrypt/live/ドメイン/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ドメイン/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/ドメイン/chain.pem

    ProxyPass /jenkins https://localhost:8443/jenkins nocanon
    ProxyPassReverse /jenkins https://localhost:8443/jenkins
    ProxyRequests Off
  </IfModule>
</VirtualHost>

JenkinsとApacheを起動すれば以下のように有効な証明書となります。

f:id:kojirooooocks:20180123105410p:plain

証明書の更新

Let's Encryptは有効期限が3ヶ月と短いので気づいたらあっという間に切れているということになりそうです。

なので、cronで更新のスクリプトを叩くように設定しておきます。

00 01 * * * root /usr/bin/certbot-auto renew --post-hook "service httpd restart"

現状実行しても作成したばかりなので処理がスキップされますが、更新1ヶ月前に確認して、更新されるかをチェックします。

感想

Let's Encryptを使用したことなく今回はじめて使ったのですが、簡単に実装できるものなのですね。もっと積極的に使っていきたいと思います。

今から始めるWebフロントエンド開発を読んで勉強した(パート2)

前回の記事の続きです。

多くなったので、2つに分けました。

前回はモダンなフロントエンド開発を行うためのライブラリ群の紹介になってましたが、今回はそれらのライブラリ + Reactを使用したTODOアプリを作成したいと思います。

TODOアプリを作成ながら、Reactの勉強になったところを記事にして、自分の知識にしていきたいと思います。

Redux

作成するTODOアプリでは、React + Reduxという枠組みで作成していくようです。

Reduxってなに?だったので調べました。

Reduxは 設計思想(デザインパターン) ということでした。

Reduxの大本にはFluxという物があるようで、そちらも調べてみました。

Fluxのポイントは、 データを一方向にしか流れない設計 ということのようです。

Action -> Dispatcher -> Store -> View

ReduxはFluxからの派生の設計ということです。

今回読んでいる本を見てみるとReduxの流れは以下のようです。

  1. Viewがユーザーの入力を受けつける
  2. ViewがActionCreatorに入力値をわたす
  3. ActionCreatorは「何をするのか」というActionをViewに返す
  4. Viewは受け取ったActionをそのままStoreに渡す
  5. Storeは受け取ったActionとStoreが保持している「今の状態」を示すStateをReducerに渡す
  6. Reducerは貰ったActionStateを解釈して、「新たな状態」となるStateをStoreに返す
  7. StoreはReducerから貰った新たな状態を持ち直して、その後Reactがデータバインディングを用いてViewに渡す(反映する)

登場人物がいっぱいいるようでしたが、View, ActionCreator, Store, Reducer です。

View

Viewに関するロジック以外は一切持たないことが特徴で、ユーザーから何かしらの入力があれば、ActionCreatorに通達して、そのまま横流しで貰ったActionをStoreに渡すだけなので、シンプルに実装できます。

View関係のロジックなのでDOMの変更なども行います。

View以外のロジックを持たないので、デザイナ・エンジニアで作業の切り分けが楽になります。

ActionCreator

どんな操作が生じるのか(できるのか)だけを知っているだけです。

その操作を行うことでどんな処理を実装するか、どんな影響があるかは気にしません。

アプリケーションで行う操作が増えたらActionCreatorに扱える操作を一つ増やすという感じです。

Store

「今の状態」を保持しているStateを管理する場所です。

Reducer

「○○が起きたら、○○の状態になる」という状態の変化についての知識を持つ場所です。

状態変化の知識のみで、データの状態や表示の変更はStoreやViewがやるので、そのあたりは一切管理しません。

Reactで簡単なものを作ってみる

早速何か作ってみます。

サンプルのTODOアプリそのままだと、流石にまずいので少し改良版で行きたいと思います。

また、今回はReduxのはなしにして、Reactだけしようしたものを作成したいと思います。

とりあえず、主要ライブラリ群をインストールします。

今回は、依存関係解決のためのツールは、browserifyではなく、 webpackを使ってみようと思います。

webpackのほうが後発で、jsだけでなく、css, imageなどもまとめることが出来る優れもののようです。

今回は yarn でインストールしてみます。

$ yarn add css-loader style-loader babel-loader babel-core babel-preset-es2015 babel-preset-react webpack webpack-dev-server --dev
$ yarn add react react-dom

webpack.config.js

webpackの設定ファイルは以下になりました。

const webpack        = require('webpack');
const path           = require('path');
const distPath       = path.resolve(__dirname, 'dist');
const nodeModulePath = path.resolve(__dirname, 'node_modules');

const config = {
    entry:  './src/app.js',
    output: {
        path:     distPath,
        filename: 'app.js'
    },
    module: {
        rules: [{
            test:    /\.js$/,
            exclude: distPath,
            loader:  'babel-loader',
            query:   {
                presets: ['react', 'es2015']
            }
        }, {
            test:    /\.css$/,
            exclude: nodeModulePath,
            loader:  ['style-loader', 'css-loader']
        }]
    },
    devServer: {
        contentBase: distPath,
        port:        5260
    }
};

module.exports = config;

webpack-dev-serverを立ち上げると、Reactの環境を実行できます。

今回作成したアプリはコチラに上げておきます。

とりあえず、今回はここまで・・・

周辺知識はなんとなくわかってきましたが、肝心のReactは難しいです。

最終的にはReact-Nativeでアプリを作るところがゴールなので、もう少し勉強します・・・!