L08084のブログ

技術記事の執筆は祈り

【Angular】GitHub Pagesの更新方法がわからない

はじめに

Angularで作成したサイト(GitHub Pagesにデプロイ)を、更新したくなった時はどうすればいいんだろう?私、わかりません...という記事です。ググるなり Stack Overflowで聞くなりしろよという話なんですが

バージョン情報

WebサイトはAngular v7で作成しました、Web APIとかはない。

そもそもどうやってデプロイしたのか?

モールス信号翻訳

上記のサイトを、angular-cli-ghpagesというライブラリを利用してデプロイしました(デプロイ対象のブランチはgh-pages)。

デプロイするにあたって実行したコマンドは下記となります。

$ npm install -g angular-cli-ghpages
$ ng build --prod --base-href "https://l08084.github.io/morse-code-translate-website/"
$ git checkout -b gh-pages
$ git push origin gh-pages
$ ng build --prod --base-href "https://l08084.github.io/morse-code-translate-website/"
$ ngh --dir=dist/morse-code-tweet

結局どうしたのか?

普通に修正したい資源を更新して、gh-pagesブランチにプッシュするだけだとサイトの表示が変になってしまったので、適当なやり方でサイトの更新をしました。正しい更新方法が知りたい。

  • 適当なやり方
    1. ローカルとリモートのgh-pagesブランチを削除する
    2. 資源を更新する
    3. 再度、はじめからデプロイの手順をやる

【JavaScript】Angularでモールス信号を翻訳するWebサイトを作成した

f:id:l08084:20190421173047g:plain

はじめに

Angularを使用して、日本語・英語をモールス信号に変換するWebサイト「モールス信号 翻訳」を作成しました。

↓のURLから実際に触ることができます

https://l08084.github.io/morse-code-translate-website/

GitHubにソースコードもアップしています

github.com

使用ライブラリ・言語のバージョン情報

TypeScript(JavaScriptのスーパーセット)のフレームワークであるAngular(v7)を使用して作成しました。 CSSフレームワークはAngular Materialを利用しています。

  • Angular@7.3.6
  • AngularCLI@7.3.6
  • Angular Material@7.3.5
  • rxjs@6.3.3
  • TypeScript@ 3.2.4
  • webpack@4.29.0

「モールス信号 翻訳」の機能

「モールス信号 翻訳」には、日本語・英語をモールス信号に変換する機能と、モールス信号を日本語・英語に逆変換する機能があります。

アカウント登録などの機能はないためAPIがない、いわゆる静的サイトになっています。(フロントサイドで完結するから作るのが楽だったということを言いたい)

実装

ソースコードの中身について解説していきます

ディレクトリ構成

$ tree -I node_modulesコマンドで出力したディレクトリ構成(一部ファイル省略)。

.
├── src
│   ├── app
│   │   ├── app.component.html
│   │   ├── app.component.scss
│   │   ├── app.component.ts
│   │   ├── app.module.ts
│   │   ├── components
│   │   │   ├── description
│   │   │   │   ├── description.component.html
│   │   │   │   ├── description.component.scss
│   │   │   │   └── description.component.ts
│   │   │   ├── header
│   │   │   │   ├── header.component.html
│   │   │   │   ├── header.component.scss
│   │   │   │   └── header.component.ts
│   │   │   ├── input
│   │   │   │   ├── input.component.html
│   │   │   │   ├── input.component.scss
│   │   │   │   └── input.component.ts
│   │   │   ├── output
│   │   │   │   ├── output.component.html
│   │   │   │   ├── output.component.scss
│   │   │   │   └── output.component.ts
│   │   │   ├── select
│   │   │   │   ├── select.component.html
│   │   │   │   ├── select.component.scss
│   │   │   │   └── select.component.ts
│   │   │   └── share-button
│   │   │       ├── share-button.component.html
│   │   │       ├── share-button.component.scss
│   │   │       └── share-button.component.ts
│   │   └── service
│   │       ├── convert.service.spec.ts
│   │       └── convert.service.ts
│   ├── assets
│   │   └── mapping.json
│   ├── index.html
│   ├── styles.scss
└── tslint.json

コンポーネントの構成

ディレクトリ構成をみればわかる通り(?)、ルートコンポーネントに下記のコンポーネントがぶら下がっている構成になっています。

  • header コンポーネント
    • ただのヘッダー
  • select コンポーネント
    • ドロップダウンのコンポーネント。変換方式を選択する
  • input コンポーネント
    • 変換対象のテキストを入力するテキストエリアのコンポーネント
  • output コンポーネント
    • 変換結果が表示されるテキストエリアのコンポーネント
  • share-button コンポーネント
    • facebook、はてブ、Twitterのシェアボタンを表示するコンポーネント
  • description コンポーネント
    • サイトの使い方などを説明するテキストを表示しているコンポーネント

上記のコンポーネントに加えて、テキスト⇄信号 変換のビジネスロジックが記述されているConvert サービスクラスがあります

ルートコンポーネントの実装

ルートコンポーネント(AppComponent)では、子コンポーネントにAngularの@Input@Outputを使用して値の受け取りと受け渡しを行なっています。

ルートコンポーネントのテンプレートファイル

input コンポーネントの実装

input コンポーネントは、翻訳したいテキスト・モールス信号を入力するテキストエリアの役割を持っています。

f:id:l08084:20190421193154p:plain
input コンポーネント

input コンポーネントでは、下記の処理を行なっています。

  • 翻訳形式によって、placeholderとヒント文を切り替える
  • テキストエリアの値が変更されてから500ミリ秒経過した後に、翻訳サービスロジック(Convert サービスクラス)を呼び出す

input コンポーネントクラス

convert サービスクラスの実装

テキストからモールス信号に変換するロジックですが、Mapデータ構造を使用しました。具体的には下記の手順になります。

  1. JSONファイルでモールス信号と、カタカナやアルファベットのリストを作成する
  2. keyにカタカナとアルファベット、valueにモールス信号を設定したMap型のデータを作成する
  3. 入力テキストを1文字ずつ分割する
  4. 2で作成したMapを経由することでテキストをモールス信号に変換する...といった流れです(逆変換の場合はこの逆です)

share-buttonコンポーネントの実装

f:id:l08084:20190421175510p:plain
share-button コンポーネント

数字がずっと0から変わらない気がする...share-buttonコンポーネントの実装、ひいてはSNSシェアボタンの表示方法ですが、各種SNSの開発者サイトにいくとシェアボタンのコードが提供されているので、それをコピペして貼り付けるだけです(開発者アカウントの登録などは必要ありません)。

注意点としては、SNSの開発者サイトだと、ボタンのHTMLタグとスクリプト(script)タグが一緒くたにされているため、コピペするときは分割する必要があります。ボタンのHTMLについては、コンポーネントのHTMLにコピペして、<script>については、index.htmlの方に貼り付ける必要があります。

テンプレートファイルには、SNSシェアボタンのHTMLタグだけを貼り付けます。

share-buttonコンポーネントのテンプレートファイル

SNSシェアボタンの<script>index.htmlに貼り付けます

  • index.html
<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>モールス信号翻訳</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="日本語(ひらがな・カタカナ)や英語(アルファベット)をモールス信号に変換するサービスです。">
  <meta name="keywords" content="モールス信号,モールス符号,モールス,和文モールス,和文モールス符号,和文モールス信号">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  <script async defer crossorigin="anonymous" src="https://connect.facebook.net/ja_JP/sdk.js#xfbml=1&version=v3.2">
  </script>
  <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
  <script type="text/javascript" src="https://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async">
  </script>
</head>

<body>
  <app-root></app-root>
</body>

</html>

デプロイ

GitHub Pageへのデプロイ方法について

GitHub Pagesにデプロイする

How to deploy an Angular 7 app to Github Pages – Code Sketch – Medium

Angular 7系以降のデプロイ方法については、上のサイトが詳しいです。

↓は自分がGitHub Pagesにデプロイした時のコマンドです。

$ npm install -g angular-cli-ghpages
$ ng build --prod --base-href "https://l08084.github.io/morse-code-translate-website/"
$ git checkout -b gh-pages
$ git push origin gh-pages
$ ng build --prod --base-href "https://l08084.github.io/morse-code-translate-website/"
$ ngh --dir=dist/morse-code-tweet

終わりに

休日にテキストとモールス信号のマッピング表を作ってると虚無感がすごい。「あ・い・う・え・お」とか打つ必要があるので(虚無感というか虚無そのものだった気がする)

【Git】SouceTreeでpushが失敗する「hint: Updates were rejected because the tag already exists in the remote.」

SourceTreeでgit pushを実行した時に下記のようなメッセージが表示されて失敗した。

git -c diff.mnemonicprefix=false -c core.quotepath=false --no-optional-locks -c credential.helper= -c credential.helper="C:/Users/XXX/AppData/Local/ATLASS~1/SOURCE~1/GIT_EX~1/GIT-CR~1.EXE" push -v --tags origin master:master
Pushing to https:/XXX/gitlab/XX/XXX.api
To https://XXX/gitlab/XX/dXXX.api


updating local tracking ref 'refs/remotes/origin/master'
error: failed to push some refs to 'https:/XXX/gitlab/XX/XXX.api'
hint: Updates were rejected because the tag already exists in the remote.

解決方法

git pull --tags

ターミナルを立ち上げて上記コマンドを実行すると、git pushができるようになる。

参考サイト

https://stackoverflow.com/questions/31929667/updates-were-rejected-because-the-tag-already-exists-when-attempting-to-push-i

【Angular】NgRx入門

はじめに

AngularでFluxを実現するために採用されるライブラリについては、NgRxがデファクトスタンダードになりつつあるのではないか.....という話を結構前に聞いたのでNgRxの学習をそろそろ始めることにする。

NgRx以外のFluxライブラリを使ったことは何度かあるので、Fluxの概念については理解しているつもり

参考サイト

ngrx.io

バージョン情報

  • angular@7.3.6
  • ngrx/store@7.3.0

環境構築

Angular CLIを利用して、Angularプロジェクトを作成した後に@ngrx/storeライブラリをインストールする。

https://ngrx.io/guide/store/install

Angular CLIのバージョンが6以上の場合は、npmやyarnで@ngrx/storeライブラリをインストールする以外にも、ng addコマンドを使用して(Angular CLI経由で)@ngrx/storeライブラリをインストールすることができる。

$ ng add @ngrx/store

ng addコマンドで@ngrx/storeライブラリをインストールすると、app.module.tsの設定と、src/app/reducers/index.tsの新規作成まで自動でやってくれる。

ただ、今回は自分で設定をしたかったので、npm i @ngrx/storeでインストールを実行した。

開発

f:id:l08084:20190319220128p:plain
完成したカウンターアプリ
公式サイトで@ngrx/storeのチュートリアルアプリとして用意されているカウンターアプリを作成したので、解説する。(なお、公式サイトのものとはディレクトリ構成が異なっている)。

ディレクトリ構成

作成したカウンターアプリのディレクトリ構成を$ tree -I node_modulesコマンドで出力した(一部ファイルは省略している)。

├── src
│   ├── app
│   │   ├── app.component.html
│   │   ├── app.component.ts
│   │   ├── app.module.ts
│   │   └── components
│   │       └── my-counter
│   │           ├── action
│   │           │   └── counter.actions.ts
│   │           ├── reducer
│   │           │   └── counter.reducer.ts
│   │           └── view
│   │               ├── my-counter.component.html
│   │               └── my-counter.component.ts
└── ・・・

コード

まず、FluxのActionを担当するファイルであるcounter.actions.tsから解説する。今仕事で使っているFluxライブラリ(自社製)とはすでに大きく違っている。

カウンターアプリのイベントである"加算"、"減算"、"リセット"をそれぞれアクションとして定義している。

今の仕事で使っているFluxライブラリだと、アクションの定義だけでなくWebAPIの呼び出しや、実際にStateの値を変更するStoraクラスの呼び出しなど(ActionをStoreに渡す)をやっていたため、結構な違いを感じてとまどう。

カウンターアプリのアクションクラス

続いてReducerを担当しているcounter.reducer.tsについて。今仕事で使っているFluxライブラリだとStoreでStateの変更をおこなっているが、NgRxでは渡されたアクションに応じてReducerが新しいStateを返す形式になっているらしい。

export const initialState = 0;の部分でStateの初期化を行っている。

カウンターアプリのReducer

ルートモジュール設定ファイルであるapp.module.tsについて。NgRxに関連している設定として、imports[]でReducerの登録を行っている(StoreModule.forRoot({ count: counterReducer }))のと、Redux Dev Toolの設定をしている(StoreDevtoolsModule.instrument({}),)。

モジュールファイル

カウンターコンポーネントのテンプレートファイル。カウンター値の表示と、加算、減算、リセットボタンを表示を担当している。

stateの値であるcount$Observable型なのでasyncパイプを使用して値の表示を行っている。

カウンターコンポーネントのテンプレートファイル

selectstateの値の読み込みと、加算、減算、リセットのアクションをディスパッチして、Reducerを呼び出すメソッドをそれぞれ定義している。

カウンターコンポーネントのコンポーネントクラス

ルートコンポーネントでは、カウンターコンポーネントを定義しているだけ

ルートコンポーネントのテンプレートファイル

おわりに

少し触ってみた感想としては、NgRxはReduxよりのFluxライブラリなのでは...という印象を受けた。Redux使ったことないので習得に時間がかかりそう

【Python3】特徴的だと思った機能まとめ その4

引き続き、『入門 Python 3』を読んでいて印象に残った箇所をメモに残していく

前回の記事

【Python3】特徴的だと思った機能まとめ その3 - L08084のブログ

バージョン情報

  • Python 3.7.2

出典元

https://www.oreilly.co.jp/books/9784873117386/

オライリーの『入門 Python 3』

学習メモ

\による長い行の分割

バックスラッシュ(\)で行を分割することができる。

>>> age = 15

# 三項演算子の行を分割して読みやすくしている
>>> name = 'みゃー姉' \
... if age >= 18 \
... else 'アカネ'

>>> name
'アカネ'

内包表記

内包表記とは、イテレータ*1からPythonのデータ構造をコンパクトな構文で作成できる機能を指す。

内包表記で作成できるデータ構造として、リスト、辞書、集合などがあり、それぞれリスト内包表記、辞書内包表記、集合内包表記といった感じに命名されている。

リスト内包表記

リストをシンプルな構文で作成できる。リスト内包表記の文法は下記の通りとなる。

  • [expression for item in iterable]
    • リスト内包表記の最も単純な形式
  • [expression for item in iterable if condition]
    • 条件を追加した形式
# 単純な形式のリスト内包表記
>>> numList = [num for num in range(1, 7)]
>>> numList
[1, 2, 3, 4, 5, 6]

# 0 ~ 7の値を取り出して二乗した後、リスト化している
>>> squaringList = [i * i for i in range(0, 8)]
>>> squaringList
[0, 1, 4, 9, 16, 25, 36, 49]

# 条件を追加したリスト内包表記
>>> evenList = [j for j in range(0, 8) if j % 2 == 0]
>>> evenList 
[0, 2, 4, 6]
辞書内包表記

ディクショナリも内包表記を使用してワンライナーで作成することができる。{key_item : value_item for item in iterable}

# リストを定義
>>> marshalList = ['ランヌ', 'ミュラ', 'ダヴー', 'ベルティエ', 'ネイ']

# 内包表記でdictを作成
>>> marshal_dict = {i : marshalList[i] for i in range(0, 5)}
>>> marshal_dict 
{0: 'ランヌ', 1: 'ミュラ', 2: 'ダヴー', 3: 'ベルティエ', 4: 'ネイ'}

*1:要素を順番に取り出すことのできるオブジェクトのこと。リスト(配列)、辞書、集合、タプルなど

【Python3】特徴的だと思った機能まとめ その3

引き続き、面白いな〜と思った機能をまとめていく(2)

前回の記事

【Python3】特徴的だと思った機能まとめ その2 - L08084のブログ

バージョン情報

  • Python 3.7.2

出典元

https://www.oreilly.co.jp/books/9784873117386/

オライリーの「入門 Python 3」

学習メモ

del文によるリストや辞書の削除

del文を使用することで、指定したオフセットの要素または、配列(リスト)や辞書そのものを削除することができます。

>>> soulBorne = ['DARK SOULS', 'DARK SOULS II', 'DARK SOULS III', 'Bloodborne'] # リストを定義

>>> del soulBorne[1] # リストの2番目の要素を削除

>>> soulBorne # 要素が削除されていることを確認
['DARK SOULS', 'DARK SOULS III', 'Bloodborne']

>>> del soulBorne # 配列soulBorneごと削除

>>> soulBorne #削除されていることを確認
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'soulBorne' is not defined

あんまり使わなそうな機能な気がする。。Pythonの経験0なのでわかりませんが...

inを使った値の有無のテスト

リストや文字列、辞書や集合などに指定した値が含まれているかを確認する

>>> fromsoftware = ['DARK SOULS', 'DARK SOULS II', 'DARK SOULS III', 'Bloodborne', 'SEKIRO'] # リストを定義

>>> 'SEKIRO' in fromsoftware # 'SEKIRO'はリストに含まれている
True
>>> 'splatoon' in fromsoftware # 'splatoon'はリストに含まれていない
False

>>> 'hedoro' in 'Dorohedoro' # リストだけではなく、文字列にも使える
True
>>> 'hayashida' in 'Dorohedoro'
False

タプル

TypeScriptにもタプル型はあり、関数から複数の値を返す時などに使用することができます。
Pythonのタプルについても同様に一度に複数の変数に代入するなどの使い方もできますが、イミュータブルで値の追加・削除・変更ができない、定数リストとして使われることの方が多いそうです。

# ()を使って空のタプルを作成することができる
>>> empty_tuple = ()
>>> empty_tuple
()

# 2個の値を持ったタプルの作成
>>> brother = ('虎杖', '藤堂')
>>> brother
('虎杖', '藤堂')

# ()を省略してもカンマがあればタプルを作成できる
>>> freshman = '虎杖', '伏黒', '釘崎' 
>>> freshman
('虎杖', '伏黒', '釘崎')

# 一度に複数の変数に値を代入することができる(タプルのアンパックと呼ばれる)
>>> omimura, mikuriya = 'hinata', 'hikage'
>>> omimura
'hinata'
>>> mikuriya
'hikage'

次回の記事

【Python3】特徴的だと思った機能まとめ その4 - L08084のブログ

【Python3】特徴的だと思った機能まとめ その2

引き続き、面白いな〜と思った機能をまとめていく

前回の記事

【Python3】特徴的だと思った機能まとめ その1 - L08084のブログ

バージョン情報

  • Python 3.7.2

出典元

https://www.oreilly.co.jp/books/9784873117386/

オライリーの「入門 Python 3」

学習メモ

「入門 Python 3」を読んでいて、印象に残った関数・機能をまとめています。

文字列操作関数の種類が豊富(isalnum(), title(), capitalize(), center(), ljust(), rjust())

文字列をあれこれする関数が多い。正直、これいる?みたいなのもある。

文字列が英数字のみか判定するisalnum()

文字列が英数字のみだと、Trueを返す関数

>>> old_commic = 'koroshiya1'
>>> yondenai = 'ホムンクルス1巻'
>>> new_commic = 'HIKARI-MAN'

>>> old_commic.isalnum() # 英数字しか含まれていないため、True
True
>>> yondenai.isalnum() # 英数字以外が含まれているのにTrue(えっ????)
True
>>> new_commic.isalnum() # 英数字以外(記号)が含まれているため、False
False

実際にサンプルコードを書いてみて初めて気づいたんですが、全角文字はTrueと判定されるらしい。まじで何の役に立つんだ??英語圏の人間が憎い...

>>> 'アイウエオ'.isalnum() # 全角文字はTrueと判定される
True
文字列の単語の頭文字を大文字にするtitle()

一生使わない気がする

>>> 'fight club'.title() # 英字単語の頭文字が大文字になる
'Fight Club'
先頭の一文字を大文字にするcapitalize()

capitalize には「〜を大文字で書く(始める)」という意味があるそうな

>>> 'django unchained'.capitalize() # 先頭の一文字を大文字にする
'Django unchained'
文字列の左寄せ、中央寄せ、右寄せ(ljust(), center(), rjust())

ljust(), center(), rjust()は、空白を追加することによって、指定した文字列を左寄せ、中央寄せ、右寄せしてくれる関数です。
第一引数に生成する文字列の長さを指定してあげる必要があります。

>>> 'serpent'.center(15) # 中央寄せ
'    serpent    '
>>> 'serpent'.ljust(15) # 左寄せ
'serpent        '
>>> 'serpent'.rjust(15) # 右寄せ
'        serpent'

三項演算子の文法が独特

JavaとかJavaScriptでもおなじみの条件(三項)演算子ですが、Pythonだと文法がだいぶ異なります。

  • JavaScriptの場合

JavaScriptの条件演算子の文法は次のようになっています。

[条件] ? [真の場合に返される値] : [偽の場合に返される値]

// 年齢が20才以上だったら、statusに'adult'の文字列が代入される
const status = age >= 20 ? 'adult' : 'child';
  • Pythonの場合

Pythonの場合はこうです。

[真の場合に返される値] if [条件] else [偽の場合に返される値]

status = 'adult' if age >= 20 else 'child'

Pythonの三項演算子、JavaScriptのそれと比べると書き方がちょっとくどいなって感じたんですが、文法が冗長なぶん読みやすいので、好みの問題かもしれないです。

以上

次回の記事

【Python3】特徴的だと思った機能まとめ その3 - L08084のブログ