Quantcast
Channel: 初心者タグが付けられた新着記事 - Qiita
Viewing all 21583 articles
Browse latest View live

Cloud9とGithubを連携する方法

$
0
0

前提

  • Githubのアカウントを持っている
  • Cloud9を使用できる状態

Cloud9でSSH認証の公開鍵を作成する

  1. ./sshに移動する
    $ cd ~/.ssh

  2. 公開鍵を作成する
    $ ssh-keygen

色々聞かれますが、とりあえずはEnterで進めて大丈夫です。

3.公開鍵ができているか確認する
$ ls

コマンド実行後、id_rsaとid_rsa.pubというファイルが出来てたらOKです。
→id_rsa.pubファイルの中身が公開鍵になります。

4.公開鍵をコピーする
$ cat id_rsa.pub

実行後に表示された、文字列をコピーしてください。

Githubに公開鍵を登録する

GithubのSettingsSSH and GPG keysNew SSH keyをクリック

スクリーンショット 2020-01-11 0.34.04(2).png

以上の設定でCloud9からGithubへSSH接続ができるようになります!

参考記事

Cloud9とGitHubを連携させる方法(初心者向け)


【Vue】Vue.jsでアボカドチーズバーガーを作ってみることにした(の使い方ハンズオン)

$
0
0

はじめに

今日はハンバーガーを食べたので、ついでにVue.jsのコンポーネントの機能のひとつ<slot>の基本的な使い方についてまとめました。

Vue.jsでアボカドチーズバーガーを作っていきましょう:relaxed:
image.png

環境

OS:macOS Catalina 10.15.1Vue:2.6.10

1.バンズを用意し、皿に乗せる

最近はレタスで肉を挟んだハンバーガーもありますが、やっぱりバンズでしょう。

まずはバンズを用意します。
Bun.vue

Bun.vue
<template><div><divclass="bun bun-top">バンズ(上)</div><divclass="bun bun-bottom">バンズ(下)</div></div></template><style>.bun{width:200px;height:50px;background:brown;}.bun-top{border-radius:40px40px00;}.bun-bottom{border-radius:0020px20px;}</style>

テーブルに直に置くわけにはいきません。
お皿も用意し、とりあえずバンズだけ載せましょう。
Dish.vue

Dish.vue
<template><div><Bun></Bun><divclass="dish"></div></div></template><script>importBunfrom'./humburger/Bun'exportdefault{components:{Bun,}}</script><style>.dish{width:200px;height:10px;border-radius:5px;background:grey;}</style>

image.png

現状、こうなります。

またお腹がすいてきました。
どんどんいきましょう!

2.切れ込みを入れる(slotを仕込む)

切れ込み(<slot>)を入れます。

Bun.vue
<template><div><divclass="bun bun-top">バンズ(上)</div><slot></slot><divclass="bun bun-bottom">バンズ(下)</div></div></template>
...

image.png

現状はこうなります。

ポイントは、まだ見た目に変化はないということです。

そう、ただの切れ込みなので具材がなくても、別に違和感なく食すことができます。

さて、次は具材です。

3.パティ(ビーフ100%)を用意する

まずはパティ(肉)がないといけませんね。
仕込みましょう。

BeefPatty.vue
<template><divclass="beef">パティ(ビーフ100%)</div></template><style>.beef{width:200px;height:30px;background:rgb(72,19,19);border-radius:5px;}</style>

そして、ついにバンズに挟むときが!
<slot>の活用

Dish.vue
<template><div><Bun><BeefPatty></BeefPatty></Bun><divclass="dish"></div></div></template><script>importBunfrom'./humburger/Bun'importBeefPattyfrom'./humburger/BeefPatty'exportdefault{components:{Bun,BeefPatty,}}</script>
...

image.png

結果はこうなります。

事前に切れ込みを入れていたので、このようにして具材を挟み込むことが出来ます。

さあ、パティだけでは寂しいので他の具材も仕込んで挟みましょう!

4.その他の具材を用意する

確か...食べたアボカドチーズバーガーに入っていた具材は残り3種類。

  • アボカド
  • トマト
  • チーズ
Avocato.vue
<template><divclass="avocado">アボカド</div></template><style>.avocado{width:200px;height:20px;background:greenyellow;border-radius:10px;}</style>
Tomato.vue
<template><divclass="tomato">トマト</div></template><style>.tomato{width:200px;height:40px;background:red;border-radius:5px;}</style>
Cheese.vue
<template><divclass="cheese">チーズ</div></template><style>.cheese{width:200px;height:20px;background:yellow;border-radius:10px;}</style>

具材を挟みます。

Dish.vue
<template><div><Bun><Avocado></Avocado><Tomato></Tomato><Cheese></Cheese><BeefPatty></BeefPatty></Bun><divclass="dish"></div></div></template><script>importBunfrom'./humburger/Bun'importBeefPattyfrom'./humburger/BeefPatty'importAvocadofrom'./humburger/Avocado'importTomatofrom'./humburger/Tomato'importCheesefrom'./humburger/Cheese'exportdefault{components:{Bun,BeefPatty,Avocado,Tomato,Cheese,}}</script>
...

image.png

結果はこうなります。
彩り豊かで美味しそうです!

このように、切れ込みを入れてあるので、いくつでも具材が挟み込めます

これでも十分なのですが、もしかするとこれではお腹が満たされないという人もいるかもしれません。

次は、もう一つ切れ込みを入れてみましょう。

5.もう一つ切れ込みを入れる(更にslotを仕込む)

Bun.vue
<template><div><divclass="bun bun-top">バンズ(上)</div><slot></slot><divclass="bun bun-middle">バンズ(中)</div><slot></slot><divclass="bun bun-bottom">バンズ(下)</div></div></template><style>....bun-middle{height:30px;}...</style>

image.png
結果はこうなります。
...ボリューミィ!

slotが2つになったので、それぞれのslot同じ具材が挟まれてしまいました。

これではやりすぎなので、それぞれのslotに対して名前をつけて、挟む具材を指定出来るようにしましょう。

6.切れ込み毎に具材を変える(名前付きslot

Bun.vue
<template><div><divclass="bun bun-top">バンズ(上)</div><slotname="upper"></slot><divclass="bun bun-middle">バンズ(中)</div><slotname="lower"></slot><divclass="bun bun-bottom">バンズ(下)</div></div></template>
...
  • 上側の切れ込み:upper
  • 下側の切れ込み:lower

という名前をつけてあげました。

これでそれぞれ挟む具材を変更できます。
※名前なしの場合、defaultという名前がついています。

では、具材を挟んでいきましょう!

Dish.vue
<template><div><Bun><templatev-slot:upper><Avocado></Avocado><Tomato></Tomato><Cheese></Cheese><BeefPatty></BeefPatty></template><templatev-slot:lower><Cheese></Cheese><BeefPatty></BeefPatty></template></Bun><divclass="dish"></div></div></template>
...

ここで挟む場所を明記するため、templateタグにv-slot:スロット名としてあげて、中身を囲ってあげます。

※ここで、v-slot:defaultとすると、名前無しスロットに紐づきます。

これでOKです。
image.png

結果はこちら。
いい感じですね!

以上です!

あとはお好みで具材を変えたり10段バーガーにしたりしてお楽しみ下さい:yum:

おわりに

最後まで読んで頂きありがとうございました:bow_tone1:

どなたかの参考になれば幸いです:relaxed:

参考にさせて頂いたサイト(いつもありがとうございます)

MacでGit導入(Homebrew利用)

$
0
0

概要

エンジニアでMac買ったらまずやることはGit導入ですね。
Gitないと何もできません。

環境

端末:Mac book Pro(13-inch,2019)
OS:macOS Catalina 10.15.2

前提

Homebrewの利用を前提とした導入方法になります。
※HomebrewとはmacOSでよく使われるパッケージマネージャです。ターミナルからパッケージなどをインストール際に使用するのでこのタイミングで導入しちゃいましょう!

手順

Xcodeをインストール

App storeからXcodeをインストール
https://apps.apple.com/jp/app/xcode/id497799835?ls=1&mt=12

Homebrewをインストール

$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

以下の結果が取得できればインストール成功

$ brew doctor
  Your system is ready to brew.

Gitのインストール

$ brew install git

以下の結果が取得できればインストール成功

$ git --version
  git version 2.24.1

Mac に Terraform をインストールする(homebrew 利用)

$
0
0

概要

homebrewを使ってTerraformを導入する。
※Terraformとは
 クラウドのインフラアーキテクチャを「.tfファイル」に記述/定義することで
 定義した内容の応じて自動で環境を構築してくれる。

環境

端末:Mac book Pro(13-inch,2019)
OS:macOS Catalina 10.15.2

前提

Homebrewの利用を前提とした導入方法になります。
※HomebrewとはmacOSでよく使われるパッケージマネージャです。ターミナルからパッケージなどをインストール際に使用するのでこのタイミングで導入しちゃいましょう!
まだHomebrewを導入していない場合は以下の記事を参照ください。
https://qiita.com/kimurayut/items/6f50cf1060e44e664c3b

手順

以下を実行するだけです(他にも方法ありますが個人的にはこれが一番簡単)

$ brew install terraform

【TypeScript】🔰プログラミング初心者向け

$
0
0

はじめに

JavaScriptの基礎をある程度終え、次の開発環境がReactをTypeScriptで書くということだったので一通り学んでみました。
今回は羽山 博さんのTypeScriptで学ぶJavaScript入門を参考にしてまとめました。文章やコードはサイトから引用したものになります。2014年から2015年に連載されたものなので情報が古い点があるかもしれません。プログラミング初学者向けに書かれた記事だったので大変わかりやすかったです。
詳しい内容などは、サイトを参考にしてください。全部まとめたの結構長いです。3、4日かけて読みました。

TypeScriptとは

・マイクロソフトが開発したスクリプト言語である。
・オープンソースである。
・TypeScriptのソースコードはJavaScriptのソースコードにコンパイルされる。

JavaScriptから追加された点

・変数のデータ型をあらかじめ決めておける(静的型付け)。
・クラスを簡単に記述できる。
・1つの関数定義で異なるデータ型の引数を処理できる(総称型)。
・引数の文字列によって異なる関数を実行できる(文字列によるオーバーロード)。


ここからTypeScripについてまとめていきます。

変数について

TypeScriptの変数の特徴

・変数を使う前には宣言が必要である。
・変数の宣言時には変数の名前を指定する必要がある。
・変数の宣言時には変数のデータ型が指定できる。

JavaScriptでは特に宣言をせずに、変数がつかえる。しかし、TypeScriptでは変数の宣言が必須である。

データ型を指定して変数を宣言する

TypeScriptでは、変数の宣言時にデータ型が指定できる。データ型は変数名の後に「:」で区切ってしてする

・データ型の指定
var price:number;

・データ型を指定した変数宣言と値の代入
var price:number = 1200;

・同じ型の複数の変数を一度に宣言
var x, y:number;

・異なるデータ型の変数を一度に宣言
var name:string, age:number;

TypeScriptでよく使われるデータ型について
・number型・・・数値(整数, 浮動小数点)
・string型・・・文字列
・boolean・・・真偽値(trueまたはfalse)
・enum・・・列挙型

変数のデータ型を指定しない場合は、「any」が指定されたものとする。

・型指定のない変数宣言とany型の変数宣言(以下の2つはほぼ同義)
var something;
var something:any;

anyは既存のJavaScriptのライブラリを利用するときに、互換性を維持するために使われる。型が決まっている場合は、anyではなく、numberやstringを使ったほうがよい。

TypeScriptでは宣言時に変数の値を代入(初期化)しておくと、変数のデータ型が自動的に推測されて決められる。

・データ型を指定せずに変数の宣言を行い初期値も代入する
var price = 1200
この場合、price変数は数値を代入したためnumber型とみなされる。したがって、次の2つのコードのうち上はエラーとならないが、下はエラーとなる。

・データ型を書かないとany型とみなされる
var price; //any型
price = 1200;
price = "無料"; //文字列も入力できる

・データ型を書いていないが、数値が初期化しているのでnumber型とみなされる
var price = 1200; //number型と推測される
price = "無料"; //文字列を代入しようとするとエラーになる

変数のデータ型と代入されるデータ型が一致していない例

var price:number = 1,200;
->数値の表記に桁区切りのカンマは使えない

var price:number = "1200";
->「1200」を引用符で囲んでいるので、数値ではなく文字列とみなされる。

var customerId:string = 100;
->数値を文字列型の変数に代入しようとしているためエラー。

var isAbsent:boolean = "true";
->データ型が真偽値の変数なので「true」の文字列を代入しようとしたためエラー。

var isAbsent:string = true;
->文字列型の変数に真偽値を代入しようとしているためエラー。

リテラルと列挙型

決まった値を表すリテラル

リテラルとは決まった値のことをさす。真偽値を表すtrueやfalseもリテラルである。

・整数値リテラルには、10進数、16進数、8進数がある。
(例)
1200
-3
0x1F //16進数の1F。10進数なら31
012 //8進数の12。10進数なら10。だたし8進数の表記はTypeScriptではエラーになる

・浮動小数点リテラルは、小数点うあ指数表記を使った数値である。
(例)
3.14
0.12e+4 //0.12×10の4乗を表す
-2.178E-3 //-2.178x10の-3乗を表す

・文字列リテラルは引用符に囲まれた文字列である。シングルクォーテーション(')も使用できる。
(例)
"Hello"
"こんにちは"
"100"

・ブール型のリテラルには、trueまたはfalseがある。

種類を区別するのに便利な列挙型 (enum)型

「enum」とは「enumurate」の略で、「列挙する」という意味になる。

・季節を表示するプログラム
enum SEASONS{SPRING, SUMMER, AUTUMN, WINTER};
alert(SEASONS.AUTUMN) //=> 2

「enum」というキーワードの後に好きな名前を指定し、「{}」の中に要素をかく。通常の変数やリテラルと区別できるように、ここでは大文字で書いている。

列挙型の名前は変数の宣言に使用できる。というより、変数を宣言してこそ意味がある。
・列挙型の変数の宣言
var season:SEASONS
ここでは「:」で区切ってデータ型にenum型の名前を指定している。

演算と演算子

注意点

・算術演算子は、0で除算することは許されないため「infinity(無限大)」になる。
・0/0の場合は、NaNとなる。
(Not a Number=数値でない値。不正な値を利用して数値演算が行われたことを表す値)

演算子の結合方向に注意

・結合方向とは
同じ優先順位の演算が実行される順序のこと。

・代入演算子の結合方向を確認するプログラム
var a, b: number;
b = 10;
a = b +=2; // 「b += 2」が実行された後、「a = b」が実行される
alert("aの値は" + a + "\nbの値は" + b);

・インクリメント(加算。「++」)とデクリメント(「--」)の演算子には、結合方向が示されない。理由は、複数個使われないため。

.次のプログラムは実行すると「0」という結果が表示される。ただし、変数countは1になる。
var count:number;
count = 0;
alert(count++);

「++」を変数名の前につけると、変数の値が増やされ、その増やされた値が返される。(前置型)しかし、「++」を変数名の後につけると、変数の値を増やされるが、返される値は増やされる前の値である。(後値型)

条件分岐

条件分岐の特徴

・if...else文 (式の値によって異なる文を実行する。if文を組み合わせ、異なる変数の値を調べて条件分岐させることもできる。

sample.ts
//午後であるか午前であるかによって、背景色をかえるプログラムvarc:string;varh:number,d:Date;//Dateオブジェクトの作成d=newDate();h=d.getHours();//getHoursメソッドで時刻を求めるif(h<12){c="skyblue";}else{c="lightyellow";}document.body.style.backgroundColor=c;//色の名前を背景色にする

・if...else文のネスト (if..else文の中にif...else文をかくことをネストまたは入れ子と呼ぶ)

sample.ts
varmessage:string;varage,sex:number;enumSEX{MALE,FEMALE};sex=SEX.FEMALE;//女性とするage=17;if(sex==SEX.MALE){if(age>=18){message="結婚できます";}else{message="まだ結婚できません";}}else{if(age>=16){message="結婚できます";}else{message="まだ結婚できません";}}alert(message);//=>結婚できます

条件式の書き方

if(425 < rbc < 570) //誤った書き方
if(rbc > 425 && rbc < 570) //正しい書き方
誤った書き方では、「425 < rbc」の結果がtrueまたはfalseになってしまう。よって、次の比較が「true < 570」や「false < 570」になってしまい条件が常に成り立ってしまうため。ただし、TypeScriptでは、変数の型をチェックすルため誤った書き方をするとコンパイルエラーとなる。

switch文による多分岐

if文は汎用的な条件分岐の構文だが、switch文は1つの変数や式が特定の値であるかどうかを判定して多分岐させるときに便利な構文である。

sample.ts
//おみくじプログラムvarfortune:string;varn:number;n=Math.floor(Math.random()*7);//0~6までの整数の乱数.floorメソッドで小数点以下を切り下げ.switch(n){case0:case1:fortune="大吉";//0と1の場合break;case2:fortune="中吉";break;case3:case4:fortune="小吉";break;case5:fortune="";break;default:fortune="大凶";//上記以外の場合}alert(n+":"+fortune);

switch文のポイント
・switchの後の()の中の変数や式の値によって実行する文が変えられる
・()の中の変数や式の値がcaseの後に指定した値に一致すれば、それ以降の文が全て実行される
・1つのcaseの中に複数の文を書いてもよい
・ただし、break文があると、そこでswitch文を抜けて次の文に進む
・dafaultは他のcaseで指定していない全ての値に一致する

注意すべき点
一致した箇所の文だけが実行されるのではないため、一致した箇所の文だけを実行したいときには、その部分の最後にbreakをかく必要がある

?演算子 (条件演算子)

?演算子を使うと、条件によって利用する式が変えられる。変数に代入する値を条件によって変えるときに便利な式である。

sample.ts
//割引額を表示するプログラムvardiscount:number;//割引金額varprice:number=1000;//1000円の商品varrank:string="gold";//顧客ランク(goldランクとする)//goldなら2割引,それ以外なら1割引discount=(rank=="gold"?price*0.2:price*0.1);//tureであれば:の前の値を返す.falseであれば:の後ろの値を返すalert(discount);//ネストさせる場合discount=(rank=="gold"?price*0.2:(rank=="silver"?price*0.15:price*0.1));

?演算子の構文 [ 式1 ? 式2 : 式3 ]

条件が多くなる場合は可読性が悪くなるのでif...else文かswitch文を使ったほうがいい。

繰り返し処理 : while/do...while文

繰り返し処理の方法

条件を満たしている間、同じ構文を繰り返して実行したり、一定の回数だけ文を繰り返し実行したりするときに使用する。

・while文...式の値がtrueである間、文を繰り返し実行する、式の値を毎回の繰り返しの前に判定する(全判定型while)
・do ... while文...式の値がtrueである間、文を繰り返し実行する。式の値をマイカの繰り返しの後に判定する(後判定型while)
・for文...初期設定、繰り返しの条件、毎回の繰り返しの後に実行する処理をまとめてかける文。一定回数の繰り返し処理によく使われる
・for...in文オブジェクトの全てのプロパティの値に対して繰り返し処理を行う

while文を使った例

sample.ts
//6が出るまでに何回サイコロを振ったかがわかるプログラムvarcount:number=0;vardice:number;dice=Math.floor(Math.random()*6)+1;while(dice!=6){count++;dice=Math.floor(Math.random()*6)+1;}alert(count);

注意点
while文では、条件として指定する式がtureの間、文を繰り返し実行するので、式がfalseにならない限り無限に繰り返される。これを無限ループという。

while文を簡潔にかく

sample.ts
//function文を使って関数を作成し、プログラムを簡潔にするvarcount:number=0;while(dice()!=6){//dice関数を呼び出して、乱数を求めるcount++;}alert(count);window.close();functiondice():number{//関数が返す値のデータ型の指定returnMath.floor(Math.random()*6)+1;}

do...whileを使った例

do...while文では、条件を判定するための式を毎回の繰り返しの後に評価する。この場合、繰り返し処理は最低でも1回は実行される。

sample.ts
//6が出るまでに何回サイコロを振ったかがわかるプログラムvarcount:number=0;vardice:number;do{dice=Math.floor(Math.random()*6)+1;count++;}while(dice!=6);alert(count);

繰り返しを途中で抜けるには

sample.ts
//1が出た時点でゲームオーバーとするプログラムvarcount:number=0;vard:number;while((d=dice())!=6){if(d==1){// (2)alert("NGな目が出ました");break;// 1が出たらその時点でおしまい}count++;}alert(count);window.close();functiondice():number{returnMath.floor(Math.random()*6)+1;}

次の繰り返しに即座に移る

break文のように繰り返しを完全に抜けるのではなく、その時点で後ろの処理を実行せずに次の繰り返しに移るにはcontinue文を使う。

sample.ts
//同じ目が連続して出た時は1回と数えるプログラムvarcount:number=0;vard:number;varprev:number=0;//最初はありえない値vardup:number=0;//重複した回数while((d=dice())!=6){if(prev==d){dup++;continue;//前回と同じなら数えない}count++;prev=d;//今回の値を保持しておく}alert(count+":"+dup);functiondice():number{returnMath.floor(Math.random()*6)+1;}

for文を使った例

sample.ts
//「ピザ」という文字を10回表示するfor(vari=0;i<10;i++){document.body.innerHTML+="ピザ<br/>";}//データ型を指定していないが、ここでは初期値によってデータ型が推測されている

for文の書き方

for (式1; 式2; 式3) {
文1;
文2;
:
}

・式1...最初に1回だけ実行される、一般的には、この式で繰り返しの回数を数えるための変数(制御変数)の初期値を設定する。初期化式とも呼ばれる。
・式2...trueかfalseかを返す式を指定する。式2がtrueである間、文が繰り返し実行される。一般的には、制御変数が特定の間より小さい間(大きい間)といった意味の式が書かれる。条件式とも呼ばれる。
・式3...毎回の繰り返しの最後に実行される。一般的には、制御変数の値を変える式が書かれる。再初期化式とも呼ばれる。

for文をネストさせる

sample.ts
//10行10列の「.]を表すプログラムdocument.body.style.fontFamily="Courier","monospace";for(vari=0;i<10;i++){for(varj=0;j<10;j++){document.body.innerHTML+=".";}document.bodyHTML+="<br/>";}
sample.ts
//10列×10行の「.」のランダムな位置にモンスターを表示するプログラムvarm_name:string="D";varx:number=Math.floor(Math.random()*10);vary:number=Math.floor(Math.random()*10);document.body.style.fontFamily="Courier","monospace";for(vari=0;i<10;i++){for(varj=0;j<10;j++){if(i==y&&i==x){document.body.innerHTML+=m_name;}else{document.body.innerHTML+=".";}}}document.body.innerHTML+="<br/>";}

for...in文

for...in文はオブジェクトのプロパティ名を1つずつ取り出して順に処理していく。そして、取り出すプロパティ名がなくなると繰り返し終了となる。

sample.ts
//モンスターのステータスを表示するプログラムclassMonster{//クラスを定義name:string;hp:number;mp:number;}varm:Monster=newMonster();//クラスからオブジェクトを作成m.name="Dragon";m.mp=100;m.mp=200;document.body.innerHTML="モンスターのステータス一覧<br/>";for(varxinm){document.body.innerHTML+=x+":"+[x]+"<br/>";}

配列

配列とは

多数の変数を利用できるようにする仕組みが配列である。配列を宣言するには、全ての要素を代表するような変数名を一つつけておけばよい。配列の個々の要素はインデックスと呼ばれる番号で区別する。配列と似た連想配列がるが、これはインデックスとしての数値だけでなく文字列も使用できるものである。

簡単な配列の例

sample.ts
//五人囃子のうち、左から3番目の楽器の名前を取り出して表示するプログラムvarmusicians:string[]=newArray(5);musicians[0]="たいこ";musicians[1]="おおづつみ";musicians[2]="こづつみ";musicians[3]="ふえ";musicians[4]="うたい";alert(musicians[2]);//=>こづつみ//ポイント//・変数を宣言するときにデータ型の後ろに[]をつける//・new Arrayの後ろに()をかき、その中に要素数をかく

・配列を宣言する別の書き方
var musicians: Array<string> = new Array(5);

配列の宣言と初期化を一度に行う

var musicians: string[] = ["たいこ", "おおづつみ" ,"こづづみ" ,"ふえ" ,"うたい"];
この書き方では,new演算子を使う必要がないのでコードが簡単になる。

・配列の宣言と初期化の別の書き方
var musicians: Array<string> = ["たいこ", "おおつづみ", "こつづみ", "ふえ", "うたい"];

配列の注意点
要素数を指定して配列の宣言をしても、配列には後から要素を追加できる。また、配列のインデックスは0から並んでいるとは限らない。lengthプロパティで取得できる値は配列の要素数を表している訳ではない。

sample.ts
//配列のインデックスが連続でないことや、要素を追加できることを確認するためのプログラムvara:Array<number>=newArray(3);a[0]=0;a[1]=10;a[10]=100;a[20]=200;alert("2番目は"+a[2]+",10番目は"+a[10]+",配列のサイズは"+a.length);//=> 2番はundefined、10番は100、配列のサイズは21//lengthプロパティの値は「インデックスの最大値+1」になるため//配列の要素数を知るためにはObjectのkeysメソッドを使うalert("配列のサイズは"+Object.keys(a).length);

配列の繰り返し処理

sample.ts
//10個の要素と持つ配列を使って、0〜9の数値をランダムに並び替えるプログラムvarboard:Array<number>=newArray(10);vartemp,r1,r2:number;for(vari=0;i<10;i++){//変数iの値が0から10未満である間、値を1ずつ増やしながら処理を繰り返すboard[i]=i;//board[0]~board[9]には0~9が代入}for(varcount=0;count<100;count++){r1=Math.floor(Math.random()*10)r2=Math.floor(Math.random()*10)temp=board[r1]=board[r2];board[r2]=temp;}alert(board);

2次元の配列を利用する

TypeScriptで2次元の配列を宣言するには、[]を2つ書けばよい。

sample.ts
//2次元の配列を作成して、連番を入れるプログラムvarboard:number[][]=newArray();for(vari=0;i<9;i++){board[i]=newArray();for(varj=0;j<9;j++){board[i][j]=i*9+(j+1);}}alert(board);

連想配列

連想配列はインデックスとして数値だけでなく文字列を使用できる。連想配列を利用する2つの方法。
・オブジェクトリテラルを使ってオブジェクトを作成し、プロパティを追加して連想配列のように扱う。
・Arrayオブジェクトを作成して、配列のインデックスに文字列を指定する。

オブジェクトリテラルを使って連想配列を作る

オブジェクトリテラルとは、オブジェクトに含まれる要素を{}で囲んで記したもの。

sample.ts
//守備位置と名前の連絡配列から、投手の名前を取り出して表示するvarPlayer={Pitcher:"岩田",Catcher:"梅野"};//Playerという名前のObject型変数の宣言alert(Player["Pitcher"];//インデックスは文字列だが、引用符で囲んでも囲まなくてもよい。//だが、インデックスが数字で始まる場合や、途中にスペースを含む場合は引用符で囲む必要がある。varPlayer={Pitcher:"岩田",Catcher:"梅野","1st":"ゴメス","2nd":"上本","short stop":"鳥谷"};

オブジェクトとは、関連性を持ったさまざまなデータや手続きをまとめて取り扱うためのものである
上のように作成したオブジェクトは汎用的なオブジェクトであり、必要に応じて、数値や文字列、関数などを含めることができる。ここでは、Object型のオブジェクトを基として作られる。

連想配列に要素を追加する

新しいインデックスを指定すれば、連想配列の要素は自由に追加できる

sample.ts
//連想配列に要素を追加するvarPlayer=newObject();//new演算子を使って新しいオブジェクトを作成し、後から要素を追加するPlayer["Pitcher"]="岩田";Player["Catcher"]="梅野";alert(Player["Pitcher"]);//空のオブジェクトリテラルを使ってオブジェクトを作成varPlayer={};

JavaScriptとの違い

JavaScriptでもTypeScriptでも連想配列を作成したら、そこにインデックスと値を追加したり、要素を削除できる。
ただし、JavaScriptではそれらは常にプロパティとしてアクセス可能であるのに対して、TypeScriptでは常にプロパティとしてアクセスできるとは限らない。

sample.ts
//「.」で区切ってプロパティを利用する。このコードはTypeScriptではエラーになるvarPlayer={};//変数Playerの型は「{}」となる.この時に「Pitcher」というプロパティが存在しないのでアクセスエラーとなるPlayer["Pitcher"]="岩田";alert(Player.Pitcher);//Pitcherプロパティの値を取り出すPlayer.Catcher="梅野";//Catcherプロパティに値を代入

連想配列の要素を削除

delte Player["Pitcher"]; //Pitcherというインデックスをもつ要素を削除

連想配列のすべての要素を取り扱う

連想配列ののインデックスは数値ではないので、for文を使ったり繰り返し処理ができない。そこで、for...in文を使えばオブジェクトのプロパティを全て取り出せるので、それらのプロパティに対する値を求めれば、連想配列の要素を全て処理できる。

sample.ts
//オブジェクトのプロパティ名を全て表示するvarPlayer={Pitcher:"岩田",Catcher:"梅野"};for(varxinPlayer){alert(x);//要素数の数だけアラートボックスが表示される}//連想配列の各要素の値を表示したい場合varPlayer={Pitcher:"岩田",Catcher:"梅野"};varMembers:string="";for(varxinPlayer){Members+Player[x]+"\n";//各要素の値を連結して一度に表示できるようにする}alert(Members);

インデックスや要素のデータ型を指定する

TypeScriptではインデックスシグネチャと呼ばれる仕組みによって、インデックスや要素のデータ型を指定できる。

sample.ts
//インデックスシグネチャを指定して、連想配列に含まれる要素のデータ型を指定するvarPlayer:{[index:string]:string;}={Pitcher:"岩田",Catcher:"梅野"};alert(Player["Pitcher"]);//このようにデータ型を指定しておけば、数値型の値などを代入しようとした場合エラーになる

・インデックスシグネチャの書き方
var Player: {[index: string]: string;} = ...
var Player: {[インデックスのデータ型]: (要素のデータ型);} = ...となる

インデックスシグネチャーを追加すると、プログラムが読みづらくなるので、interfaceと呼ばれるキーワードを使って、インデックスシグネチャに名前をつけることもできる。

sample.ts
//「interface]の後に、自分で型名をかき、その後にインデックスシグネチャの内容をかくinterfaceDictionary{}//インデックスシグネチャの部分に型名をかくvarPlayer:Dictionary={Pitcher:"岩田",Catcher:"梅野"};alert(Player["Pitcher"]

配列のインデックスに文字列を指定する方法

Array型を配列を宣言し、インデックスに文字列を指定して連想配列を作成することができる。

sample.ts
varPlayer:string[]=newArray(9);//(1)Player["Pitcher"]="岩田";Player["Catcher"]="梅野";alert(Player["Pitcher"];//(1)配列の宣言の別の書き方varPlayer:Array<string>=newArray(9);

関数

関数とはひとまとまりの処理を記述して名前をつけたもの。関数に与える値を引数と呼び、戻り値とは関数が返す処理の結果のことである。戻り値を返り値とも呼ぶ。

関数の利点
・一度関数を書いておけば、内部でどういう処理をしているか詳しく知らなくても利用できる。
・必要な箇所で何度も利用できる。
TypeScriptやJavaScriptの特徴としては関数もオブジェクトであるということだ。

関数の書き方
・関数宣言を使う方法
・関数式を使う方法
・アロー関数式を使う方法

関数宣言を使う書き方

sample.ts
//2つの数を与えるとその和を返す関数add2の定義と利用functionadd2(x:number,y:number):number{//関数add2の定義returnx+y;}varanswer:number=add2(10,20);//関数add2を呼び出して、戻り値を変数に代入alert(answer);

書き方
function 関数名(仮引数の名前: データ型, ...):戻り値のデータ型 {
return 戻り値;
}

呼び出し方
var answer: number = 関数名(実引数のリスト);
実引数とは、仮引数に与える値のことである
英語では仮引数のことを「parameter」(パラメーター)と呼び、実引数を「argument」と呼ぶ。

関数式を利用する書き方

関数はオブジェクトであるため、変数にも代入できる

sample.ts
//関数オブジェクトを作成して、変数に参照を代入するvaradd2=function(x:number,y:number):number{//(1)returnx+y;};varanswer:number=add2(10,20);//(2)alert(answer);//(1)function演算子を使って関数オブジェクトを作成し、その参照を変数add2に代入している//(2)変数add2に関数を代入しているため、変数add2を利用すれば関数が呼び出せるようになっている

書き方
var 関数を参照する変数の名前 = function (仮引数の名前: データ型, ...): 戻り値のデータ型 {
return 戻り値;
};

この時変数のデータ型は型推論の機能により、function型になっている。

アロー関数式を使う書き方

アロー関数あるいはラムダ式と呼ばれる簡潔な書き方だ。

sample.ts
//アロー関数を使って簡潔に関数を定義するプログラムvaradd2=(x:number,y:number):number=>x+y;varanswer:number=add2(10,20);alert(answer);

1つの関数で複数の戻り値を返す方法

書き方は1つしか指定できないが、戻り値にオブジェクトを指定すれば、複数の値をまとめて返せる。

sample.ts
//複数の値を返すプログラムfunctiondiv2(x:number,y:number){varq:number=Math.floor(x/y);varr:number=x-q*y;return{quotient:q,reminder:r}//(1)};varresult=div2(20,8);alert("商は"+result.quotient+",余りは"+result.reminder);//(1)戻り値のデータ型は複雑になるため、宣言に含めずに推測型を使用している

オプションの引数

関数を定義するときには、仮引数としてオプションの引数が指定できる。仮引数をオプションとするとその仮引数に対応する実引数を省略することもできるようになる。

sample.ts
functioncalcCost(price:number,amount:number,discount?:number):number{if(discount){//別の書き方 if (discount != undefined)returnprice*amount*(1-discount);}else{returnprice*amount;}}alert(calcCost(1200,10));//=> 12000

可変長引数を使う、関数を呼び出すときにコオtなる数のデータを渡せる。

sample.ts
//省略可能な引数と可変長引数functionparamtest(arg1:number,...restparam:number[]){return"first item of restparam: "+restparam[0]+"\nlength of restparam: "+restparam.length;}alert(paramtest(1,2,3,4,5));

paramtest関数の第一引数(arg1)は省略不可能であり、次のrestparamが可変長引数となっている。可変このデータを受け取る仮引数は「...」に続けてその名前を記述する。この場合仮引数の型は配列型でなければいけない。特に指定しない場合はany[]型になる。「1」が仮引数arg1に、残りの2~5が配列としてrestparamに割り当てられる。
注意点として、省略可能な引数や可変長引数は、指定する順序が決まっているということだ。省略可能な引数は省略できない引数の後に書き、可変長引数がある場合には引数リストの最後に指定する。可変長引数は一つしかかけないことも注意しよう。

引数の規定値を設定する

省略可能な引数には規定値が設定できる。そのためには、仮引数の名前の後に、「=規定値」を指定すれば良い。その場合、仮引数の名前の後に「?」は必要ない。

sample.ts
//省略可能な引数に規定値を設定するfunctioncalcCost(price:number,amount:number,discount=0):number{//(1)returnprice*amount*(1-discount);}alert(calcCost(1200,10));//(1)discountにデータ型が指定されていないが、規定値として0を代入しているので、型推論によりnumber型になる

省略できない引数、省略可能な引数、可変長引数を全て指定した例

sample.ts
//省略不可能な引数、省略可能な引数、可変長引数functionparamtest(arg1:number,arg2:number=2,restparam:number[]{return"arg1: "+arg1+"\narg2: "+arg2+"\nfirst item of restparam: "+restparam[0]+"\nlength of restparam: "+restparam.length;}alert(paramtest(1,undefined,3,4,5));//引数が省略されている場合は「undefind」と記述する。

関数のオーバーロード

オーバーロードとは、同じ名前をもち、異なる引数リストや戻り値の型をもつ複数の関数を定義することである
TypeScriptで、関数をオーバーロードするには、実装なしで引数リストと戻り値の型だけを指定したオーバーロード関数を続けて書き、最後にいずれの形式の関数呼び出しにも対応できるような実装をかく。

sample.ts
functiongetLength(x:number):number;//(1)functiongetLength(x:string):number;//(2)functiongetLength(x:any):number{if(typeof(x)=="string"){returnx.length}else{if(x==0)return1;returnMath.floor(Math.log(x)/Math.LN10)+1;}}alert(getLength(123));//=> 3

(1)と(2)を宣言することで、string型もしくはnumber型以外の引数を指定するとTypeScriptコードのコンパイル時点でエラーになるので、型のチェックができるようになる。

ジェネリックス

ジェネリックスとは、データ型を仮に決めておき、実際に使用するデータ型を呼び出し時に変えられるようにする機能で、総称型とも呼ばれる。ジェネリックスはを利用するとデータ型を関数の呼び出し時に決められるので、似てような処理を異なるデータ型の引数に対して行うことができる。

sample.ts
//ジェネリックスを利用した関数functionparrot<T>(data:T):T{//仮引数や戻り値のデータ型を「T」などの文字で表しておくvarret:T;ret=data;returnret;}alert(parrot<number>(100));//=>100

ジェネリックスを使った関数を呼び出すときには、関数名の後に「<>」を書き、その中に実際にどのデータ型を使用するのかをかけば良い。ジェネリックは、様々なデータ型の引数に対してきめ細かく処理を分けるためではなく、どのデータ型に対しても同じような処理をしたい場合に使うと良い。

クロージャー

クロージャーとは、関数が定義された環境にある変数を利用できる機能である。このクロージャーはTypeScript独自の機能ではなく、JavaScriptに備わっている機能である。

sample.ts
//クローザーを使ったプログラムfunctiongetSerialNumber(){varorigin=0;functioncountUp(delta:number):number{returnorigin+=delta;}returncountUp;};varinside=getSerialNumber();alert(inside(2));alert(inside(3));//=>2//=>5
sample.ts
//無名関数を使ってクロージャーをかくvarcountUp=function(){varorigin=0;returnfunction(delta:number){returnorigin+=delta;};}();//関数の定義の後に()をつけると即時実行関数となり、定義と同時に実行されるalert(countUp(2));alert(countUp(3));//=> 2//=> 5
sample.ts
//アロー関数式を使ってクロージャーをかくvarcountUp=(()=>{varorigin=0;return(delta:number)=>{returnorigin+=dalta;};})();alert(countUp(2));alert(countUp(3));

クラスの利用

クラスとは、個々のオブジェクトではなく、オブジェクトのひな形のようなものである。

sample.ts
//クラスを使って猫クラスを表すclassCat{length:number;weight:number;}//変数の宣言に使っていたvarは書かなくていい。

クラスの中に含まれる変数はプロパティと呼ばれ、関数はメソッドと呼ばれる。このプロパティとメソッドを合わせてクラスのメンバーと呼ぶ。

クラスからインスタンスを作成する

クラスはいわばひな型のようなものなので、実際のデータを扱うにはインスタンスを作成する必要がある。

sample.ts
//Catクラスのインスタンスの作成classCat{length:number;weight:number;}varmyCat=newCat();//インスタンスの作成には、new演算子を使う。

newの後に「クラス名()」とかけば新しいインスタンスが作成できる。

クラスのメンバーを利用する

「.」で区切ってメンバーをかけば、クラスのメンバーが利用できる。

sample.ts
//クラスの定義から、インスタンスの作成、メンバーの利用までclassCat{length:number;weight:number;}varmyCat=newCat();myCat.length=30.5;myCat.weight=2,5;alert("体調は"+myCat.length+"cm, 体重は"+myCat.weight+"kgです");

クラスのメンバーとしてメソッドを定義する

クラスにメソッドを定義する。

sample.ts
//Catクラスにmeowメソッドとeatメソッドを追加するclassCat{length:number;weight:number;meow():string{return"にゃーん";}eat(){this.length+=0.1;this.weight+=0.1;}}varmyCat=newCat();myCat.length=30.5;myCat.weight=2.5;myCat.eat();alert("私の猫は"+myCat.meow()+"と鳴き, \n体長は"+myCat.length+"cm, 体重は"+myCat.weight+"kgです")

メソッドのオーバーロード

メソッドはオーバーロードできる。

sample.ts
//CatクラスのmeowメソッドをオーバーロードするclassCat{length:number;weight:number;meow():string;meow(s:string):string;meow(s?:any):string{if(typeof(s)=="string"){returns;}else{return"にゃーん";}}eat(){this.length+=0.1;this.weight+=0.1;}}varmyCat=newCat();myCat.length=30.5;myCat.weight=2.5;myCat.eat();alert("私の猫は"+myCat.meow("ミャオ")+"と鳴き, \n体長は"+myCat.length+"cm, 体長は"+myCat.weight+"kgです");

コンストラクター

コンストラクターとは、インスタンスの作成時に自動的に実行されるメソッドで、初期値の設定などに使われる。
コンストラクターを定義するには、constructorという名前の関数をかけばよい。

sample.ts
//コンストラクターを定義するclassCat{length:number;weight:number;name:string;constructor(){//constructorの定義this.name="名無し";}}varmyCat=newCat();//自動的にコンストラクターが実行されるので、そのまま名前を表示できるalert("名前は"+myCat.name+"です");

コンストラクターのオーバーロード

コンストラクターをオーバーロードさせれば、インスタンス作成時の引数の指定により、動作を変えることができる。

sample.ts
//コンストラクターのオーバーロードclassCat{length:number;weight:number;name:string;constructor(s:string);constructor(s?:string){if(typeof(s)=="string"){this.name=s;}else{this.name="名なし";}}}varmyCat=newCat("タマ");varyourCat=newCat();alert("私の猫の名前は"+myCat.name+"で、あなたの猫の名前は"+yourCat.name+"です");

情報の隠蔽

重要な情報をプライベート変数にして、クラスの外から勝手に変更されないことを「情報の隠蔽」と呼ぶ。

sample.ts
//プライベートな変数にアクセスするメソッドを作るclassCat{privatename:string;//privateを指定して、クラス外からはアクセスできない変数となる。publicsetName(s;string){this.name=s.slice(0,8);//0文字目から8文字目の手前までが切り出される}publicgetName():string{returnthis.name;}}varmyCat=newCat();myCat.setName("じゅげむじゅげむごこうのすりきれねこ");alert("私の猫の名前は"+myCat.getName()+"です");

変数の宣言やメソッドの定義の前に何も書かなかった場合には、publicが指定されたものとみなされることに注意する。

クラスの継承とメソッドのオーバーライド

継承とは、元のクラス(親クラス)の機能を全て受け継いだ新しいクラス(子クラス)を定義することでもある。

sample.ts
//Catクラスを継承したTigerクラスを定義するclassCat{privatename:string;publicsetName(s:string){this.name=s.slice(0,8);}publicgetName():string{returnthis.name;}publicmeow():string{return"にゃーん";}}classTigerextendsCat{publicmeow():string{return"がおー";}}varmyTiger=newTiger();myTiger.setName("とらお");alert("私の虎の名前は"+myTiger.getName()+"で, "+myTiger.meow()+"と鳴きます");

クラスを継承するには、新しいクラスの名前の後にextendsというキーワードを書き、その後に親クラスの名前をかけば良い。親クラスにある機能が子クラスでは異なる働きをすることもある。このように、親クラスのメソッドを子クラスで定義し直すことを、オーバーライドと呼ぶ。

親クラスのメソッドを呼び出したいときには、メソッドの名前にsuperをつければ良い。

sample.ts
classCat{privatename:string;publicsetName(s:string){this.name=s.slice(0,8);}publicgetName():string{returnthis.name}publicmeow():string{return"にゃーん";}}classTigerextendsCat{publicmeow():string{return"がおー";}publicmeowlikecat():string{returnsuper.meow();}}varmyTiger=newTiger();myTiger.setName("とらお");alert("私の虎の名前は"+myTiger.getName()+"ですが、甘えてくるとには"+myTiger.meowlikecat()+"と鳴きます";

あとがき

修正点など、間違いがございましたら、ご指摘ください。

AlamofireでAF.requestが出ない時に確認すること

$
0
0

今回は自分がAlamofireでAF.requestが出なくて苦しんでいたのですが
そのときに何を確認すればいいか書きました。
初心者なら起こしやすいミスなのではないかと思います。
なお、この記事ではcocoapodsのインストールなどについては触れません。

内容
・最新版のAlamofireが入っているか確認しよう
・podfileの対象iosなどが合っているか確認しよう

Alamofireの最新版の確認

まず、Alamofireについて調べます。
"外部ライブラリーでは、そのGithub上に使用方法などがのっているので確認してみてください"

Alamofireのリンクはこちらから

したら下の方にスクロールすると、これが出てきます。
スクリーンショット 2020-01-11 13.39.39.png
この pod 'Alamofire', '~> 5.0.0-rc.3' が自身のpodsの中で最新であるか、確認してターミナルで追加して、pod update でアップデートしてみてください。

podfileの対象iosなどが合っているか確認しよう

最新の状態にしたのに直ってない場合は、対象のiosのversionが合っていない可能性があります!
その場合は、AlamofireのGithubページ内でこちらを確認してみましょう。

スクリーンショット 2020-01-11 12.42.36.png

こちらには、最低でもこのバージョンを準備しないと使えないよと言われています。

iosの確認の仕方は
自身のファイルの中にPodfileがあるのでこちらを開きます。
スクリーンショット 2020-01-11 13.55.54.png

そうしますと上の方にこのように書かれていると思います。

スクリーンショット 2020-01-11 13.59.51.png

ここの、IOSのバージョンが先ほど確認した、最低でも用意しなくてはいけない。
ところよりも、古いバージョンですとAF.reuestは出ないかなと思います。
バージョンを変更した場合は、必ず自身のディレクトリーに行って pod update をしてください。
pod内の確認の仕方は nano Podfileなどでも確認できますので
そちらの方は自身で検索してみてください。

あまり深く説明できませんでしたが、この記事が少しでも役立つことを願っています。

swiftで、simpleライフゲームを作る 2年目クラス編

$
0
0

前回のライフゲームを、クラスとして実装します。
記事はここから

今回は、クラス化します。
追加機能として、以下の2つを追加します。

  • 端をつなげる 
  • 長く生き残っているCellを強調する

橋をつなげるのは下のような感じです。グライダーが上から下に抜けて行っています。

glider.swift
|0|1|2|3|4||0|1|2|3|4||0|1|2|3|4|⬜️⬛️⬛️⬛️⬜️:0⬜️⬛️⬛️⬜️⬜️:0⬜️⬛️⬜️⬛️⬜️:1⬜️⬛️⬜️⬜️⬜️:1⬜️⬛️⬜️⬛️⬜️:0⬜️⬛️⬜️⬜️⬜️:1⬜️⬜️⬛️⬜️⬜️:2⬜️⬜️⬜️⬜️⬜️:0⬜️⬜️⬜️⬜️⬜️:1⬜️⬜️⬜️⬜️⬜️:3⬜️⬜️⬜️⬜️⬜️:0⬜️⬜️⬜️⬜️⬜️:1⬜️⬜️⬜️⬜️⬜️:4⬜️⬜️⬛️⬜️⬜️:0⬜️⬛️⬛️⬜️⬜️:10年目1年目2年目

強調は、同じ場所で長く生き残った場合に強調します。

  • 5年以上生き残ったら🟨
  • 7年以上生き残ったら🟥
kyoutyou.swift
現在の世界を表示します|0|1|2|3|4|5|6|7|⬜️⬜️⬛️⬜️⬜️⬜️⬜️⬜️:0⬜️⬜️⬛️⬜️⬛️⬜️⬜️⬜️:1⬛️⬜️⬛️🟥⬜️⬜️⬛️⬜️:2⬜️⬜️⬜️⬜️⬜️⬛️⬛️⬛️:3⬜️⬜️⬜️⬛️⬜️⬛️⬜️⬜️:4⬜️⬛️⬛️🟨⬛️⬛️⬜️⬜️:5⬜️⬛️⬜️🟨⬜️⬛️⬛️⬜️:6⬜️⬛️⬜️⬜️⬜️⬛️⬜️⬛️:78年目-生き残りは24です約37%です

それと次の記事の準備として変数や機能が足されています。
今後の予定として、フィールドを大きくしたり、スタンプ機能を実装する準備として変数を色々足します。

前回の記事はここから
GitHubはここからです。

今回は、前回の記事のクラス化と言うことで、雑多な説明は、コード内に埋め込んでいます。
基本的な考え方やコードは前回の記事と変わりません。
この記事では、大まかな目的と説明していない構文を説明します。
説明するにあたって、ひとつのコードを見ながらやるのはわかりづらいので、
クラス宣言のみをして、その他のコード、関数や付属する列挙型は、拡張(extension)を使って
個別に説明していきます。

LifeGameClass初期化

前回のlifeDataとmapCreateをまとめたものです。
lifeGameのモデルを提供します。

  1. lifeData :[[Bool]]型のライフゲームのデータを入れておく場所です。Classのプロパティになります。
  2. macCreate : ライフゲームマップを製造します。外部からのアクセスを認めます。列挙型で動作を受け取らせます。
  3. CellMaker : セル製造するクロージャー(無名関数)を返します。外部呼び出しに耐えるために、Class外に置きます。

前回と大きな違いは、cell生成が列挙型に変更されました。
列挙型CellMakerが宣言されています。

クラスについて
単純に言うと設計図です。今回は、lifeGameの実物(実体:インスタンス)を作るための設計図です
実物(実体)に、製造(生成)して利用します。
プログラム上では、let 実体 = 設計図(仮引数)と記します。
今回だと、 let lifeGame実体 = lifeGameクラス(仮引数)となります。
クラス内部には、関数やプロパティ(定数や変数)を作ることができます。
関数やプロパティの呼び出しは、.(ドット)関数名で行います。
実体.関数名 で内部の関数を呼び出して使います。
今回の場合、lifeGame実体.lifeView になります。
その他、継承・カプセル化・多様性、等々ありますが、詳しい説明は省きます。
ここの記事では、lfieGameの設計図を作ることが目標です。

クラス化にあたって、変数が複数宣言されています。ゲームデータの保存は、クラス内変数のlifeDataに格納されました。
変数の格納は、拡張extensionで追加することが難しいので、クラス宣言の中に書く必要性があります。
拡張については後で説明します。
swiftの初期化(init)においては、全ての変数に、値を与える必要があります。
安全のために、できる限り初期値が与えてあります。

列挙型について
複数の定数を一つにまとめたものです。複数の定数から、一つの定数(case)を選んで使用します。
宣言は、
enum 列挙型名{case  列挙ケース1 case 列挙ケース2 }
となります。
今回は enum CellMaker{ case dathe case live メンバ関数 }
の形で利用されています。
swiftの列挙型は、非常に機能が多く、整数の集合だけではなく、実数、真理値、文字列の実態をとることができます。
実態を持たない、共用型も作ることが可能です。内部に関数とプロパティを持つことができます。
そのため、クラスのように振る舞えわせることが可能です。
列挙型は、定数の集合です。定められた定数によって機能を変えることもできます。

今回の場合、入力を簡便化するのと、機能追加の際に、複数の箇所を変更しなくて済むように、列挙型を利用しています。
実例としては、セルの生成方法に利用されいます。なぜ利用するかと言うと、

  • セル生成は、様々な箇所で利用するので、外部化する利益が大きい
  • 整備性が良い。具体的には、セルの生成を調整したいとき、列挙ケースを追加するだけで済むからです。
init.swift
/**
 ライフゲームのモデルを提供します
 内部データはlifeData:[[Bool]]です。
 */classLifeGameEngine{//格納型プロパティ///ライフゲームの基礎マップ 2重配列の真理値 ライフゲームの基礎データ[X軸[Y軸]] 変更した場合 自動でlifeMapLiveYearが修正されますvarlifeData:[[Bool]]=[[Bool]](){didSet{//年数経過をとめるguardusedLifeMapLiveYearelse{usedLifeMapLiveYear=truereturn}//マップのサイズが変更された場合。生存年数と過密度をリセットするguardlifeData.count==oldValue.count&&lifeData[0].count==oldValue[0].countelse{//ライフデータが何も入っていないと動作停止するので、警告を出し,既定値で初期化するiflifeData.count!=0{lifeMapLiveYear=Array(repeating:Array(repeating:0,count:lifeData[0].count),count:lifeData.count)lifeKamitudo=Array(repeating:{Array(repeating:0,count:lifeData[0].count+2)}(),count:lifeData.count+2)}else{print("ライフデータが何も入っていません。エラーです。調査して下さい。")lifeData=[[false]]return}return}//生存年数の計算forxin0..<lifeData.count{foryin0..<lifeData[0].count{iflifeData[x][y]==true{ifoldValue[x][y]==true{lifeMapLiveYear[x][y]+=1}}else{lifeMapLiveYear[x][y]=0}}}}}///ライフセルの生存年数varlifeMapLiveYear=[[Int]]()///生存年数の経過停止 falseにすると一度だけ更新を行わない。ずっと止めていたければ、毎回falseを与えること。varusedLifeMapLiveYear=true///ライフセルの過密度varlifeKamitudo=[[Int]]()///端の処理 反対側と接続するかどうか tureで端を反対側と接続する X(横方向)の接続 Y(縦方向)の接続varmapEdge:(x:Bool,y:Bool)=(true,true)///強調表示基準 設定された値を超えたら強調する いわゆるマジックナンバーだが、外部からいじることもないだろうしこのままで行く。varcoreLevel:(Int,Int)=(5,7)///経過年月varyearCount=0//計算型プロパティ///生きているセル数 計算型 get節のみvarlifeCellCount:Int{varkotae=0lifeData.forEach{(y:[Bool])iny.forEach{(c:Bool)inifc==true{kotae+=1}}}returnkotae}///総合セル数 計算型 get節のみvarcellAllCount:Int{returnlifeData.count*lifeData[0].count}/**
     セルのxy軸(x:Int,y:Int) 計算型 get節のみ
     同じデータが複数の場所に保存されると危険なので、計算型にして値を保持しないようにしている。
     */varcellXY:(x:Int,y:Int){return(x:lifeData.count,y:lifeData[0].count)}//なぜ危険なのか、それは値を変えれば内部が変わると思って変更された際に、同じことを示すデータが二つあると衝突を起こすからである。//どっちらに従うべきか分からず問題になるので、同じデータなら、保存場所は一カ所に統一したい。//mapCreateを基本にして、必要な情報を増やしている/**
     LifeGameを構成します。内部が見たい場合は、LifeData[[Bool]]を呼び出して確認して下さい。

     - parameter Size : LifeGameMapのサイズ 上限は10,000です 
     - parameter seisei : セルの生死指定 CellMakerを選択して下さい。
     - parameter Edge : 端の処理の仕方。trueの場合、反対側と接続されます。 x横方向 y縦方向
     */init(Sizesize:(x:Int,y:Int),seiseis:CellMaker=.raddom,Edgeedge:(x:Bool,y:Bool)=(true,true)){varxSize=size.xvarySize=size.yifxSize>10000||xSize<0{xSize=10000}ifySize>10000||ySize<0{ySize=10000}//lifeDataを作るletinitLifeData=LifeGameEngine.mapCreate(Xjiku:xSize,Yjiku:ySize,seisei:s)lifeData=initLifeData//生存年数の初期化lifeMapLiveYear=(Array(repeating:{Array(repeating:0,count:ySize)}(),count:xSize))//過密度の初期化lifeKamitudo=(Array(repeating:{Array(repeating:0,count:ySize+2)}(),count:xSize+2))//端の処理の初期化mapEdge=edge}//外部から呼び出したい場合があるので、公開するためにclass関数化する/// マップを生成してくれる 引数 X軸,Y軸,値生成方法(デフォルはランダム)省略可classfuncmapCreate(Xjikux:Int,Yjikuy:Int,seiseis:CellMaker=.raddom)->[[Bool]]{varmap=[[Bool]]()//seiseiはクロージャではなく列挙型をを受け取っているので、クロージャーを呼び出し格納するletboolmaker=s.maker()for_in0..<x{varyjiku=[Bool]()for_in0..<y{//値生成部分 yjiku.append(boolmaker(true))}map.append(yjiku)}returnmap}}/**
 セルをどのような値にするかをcaseで選ぶ。
 maker()でcaseにあった、処理をおこなうクロージャを返値として得られる
 (Bool)->Bool の型で受け取れる
 stripesは、自動で生死が切り替わる仕様です。生死順番を調整したい場合は、stripesBoolを調整して下さい。
 live+numberは、生存セルの割合です。
 */enumCellMaker{casedathecaselivecasereversecaseraddomcasestripescaselive33caselive20staticvarstripesBool=false///caseに合わせて処理用のクロージャを返します。funcmaker()->(Bool)->Bool{switchself{case.dathe:return{_infalse}case.live:return{_intrue}case.raddom:return{_inBool.random()}case.reverse:return{(t:Bool)->Boolinreturn!t}case.stripes:return{_inCellMaker.stripesBool=!CellMaker.stripesBoolreturnCellMaker.stripesBool}case.live33:return{_->Boolinletikiteriru=[true,false,false]returnikiteriru[Int.random(in:0...2)]}case.live20:return{_->Boolinreturn(Int.random(in:1...5)==5)}}}}

実行コードは、配列の表示と、変数へのアクセスを行ってみます。まだ導入コードが少ないので簡素になります。
クラス実体(インスタンス)は、定数(Let)にするのが基本です。内部の変数は、変更可能のなので、特に困ることはありません。
swiftにおいて、クラスは参照渡しにです。もし引き渡しが必要であれば、その都度定数に移して利用して下さい。

initRun.swift
print("Qiita2年目の実行コード")letgameStart=LifeGameEngine(Size:(x:3,y:3),seisei:CellMaker.raddom,Edge:(x:true,y:true))print("lifeDataの内容を表示します\(gameStart.lifeData)")print("現在の生存セル数は、\(gameStart.lifeCellCount)セルです。")print("マップの大きは、\(gameStart.cellXY)")

実行結果

Qiita2年目の実行コード
lifeDataの内容を表示します[[true, true, true], [true, true, true], [false, false, true]]
現在の生存セル数は、7セルです。
マップの大きは、(x: 3, y: 3)

これでクラス実体が製造可能になりました。
ここを基準として、機能を追加していきます。

LifeView 画面表示+生存年数強調

lifeViewを搭載していきます。
LifeGameのセルマップを表示します
具体的機能は、2つあります。
1. lifeDataをゲーム画面を表示する
2. セルの生存年数(lifeMapLiveYear)に基づいて強調表示する

拡張について
今回、メソッドlifeViewを追加するにあたって、拡張(extension)を利用します。
拡張とは、既存のクラスや列挙型などに、機能(メソッドやプロパティ)を追加する方法です。利用法は、下記の通りです。

extension 既存のクラス名 { 追加メソッド 追加計算型プロパティ}

今回の場合 extension LifeGameEngine {lifeView{プログラム}}となります。
拡張は、どこにでも書くことができます。システムが提供する既存のクラス(Intやprint)などにも機能追加することができます。
必要な機能を一時的(そのコードの中でだけ)に、追加するような運用も可能です。

セルの強調表示は、5年以上続いたら🟨、7年以上で🟥とします。
プログラムでは、変数coreLevelと比較して強調します。格納型のインスタンスプロパティは、swiftの拡張(extension)では追加できないので、class宣言に追加してあります。

///強調表示基準 設定された値を超えたら強調する いわゆるマジックナンバーだが、外部からいじることもないだろうしこのままで行く。
var coreLevel:(Int,Int) = (5,7)

lifeView.swift
extensionLifeGameEngine{/**
     ブロック状に表示します。コマンドラインではゲーム画面を表示するのに利用しますが、UIVIewでは、デバック用として使って下さい。
     */funclifeView(){print("現在の世界を表示します")//今回は生存は、黒、絶滅は白の記号で表示していく 非常に長く続いているところは、黄色くする。さらに続いたところは赤くするletlife=["⬛️","🟨","🟥"]letdeath="⬜️"print("|",separator:"",terminator:"")foryin0..<lifeData[0].count{//列番号の表示 きれいに表示されるのは,10*10くらいまでprint("\(y%10)|",separator:"",terminator:"")}print("")//ループを回して、マップを読み込むforyin0..<lifeData[0].count{forxin0..<lifeData.count{//値を把握して、どちらを表示するか決めるiflifeData[x][y]==true{vart=0switchlifeMapLiveYear[x][y]{casecoreLevel.1...:t=2casecoreLevel.0..<coreLevel.1:t=1default:t=0}print(life[t],separator:"",terminator:"")}else{print(death,separator:"",terminator:"")}}//改行コード 端まできたら改行する//行番号の表示print(":\(y)",separator:"",terminator:"\n")}//生存者数を受け取るletikinokori=lifeCellCountprint("\(yearCount)年目 - 生き残りは、\(ikinokori)です。約\(ikinokori*100/(cellXY.x*cellXY.y))%です。")}}

実行していきます。ゲーム画面の表示としては、同じ画面を更新する形で行いたいのは山々ですが、今回は、毎回別の表示になる形式で行きます。
実行コードと実行結果が同時に書かれています。
それと、強調表示の動作を確認するために、年数を経過(nextLife(_:))させています。

lifeViewRun.Swift
print("lifeViewを実行しています")gameStart.lifeView()gameStart.nextLife(count:10)gameStart.lifeView()///実行結果///lifeViewを実行しています現在の世界を表示します|0|1|2|3|4|⬜️⬜️⬜️⬛️⬜️:0⬜️⬛️⬜️⬜️⬜️:1⬛️⬜️⬜️⬜️⬜️:2⬛️⬛️⬜️⬛️⬜️:3⬛️⬛️⬛️⬜️⬜️:40年目-生き残りは9です約36%です現在の世界を表示します|0|1|2|3|4|⬜️⬜️⬜️⬜️⬜️:0🟥⬜️⬜️⬜️🟥:1⬜️🟨⬜️🟨⬜️:2🟥⬜️⬜️⬜️🟥:3⬜️⬜️⬜️⬜️⬜️:410年目-生き残りは6です約24%です

nextLife 年次経過

nextLifeを実装します。行っていることは前回のnextLifeとほぼ同様です。
マップの年数を経過させます。

大まかな作業手順及び、追加コード
1. 過密度をマップ(lifeKamitudo)に起こします
2. マップ端の過密度を、接続性(mapEdge)に基づき、接続側に加算します
3. 過密度に基づき、生き残るセルを決定します。
4. マップの経過年数とセル毎生存年数(lifeCellLiveYear)を加算する。
・ 複数回実行したいときのために、回数(count)を要求して複数回実行するコードも用意する。

lifeDataが内部化されているので、返値がなくなっています。直接インスタンスプロパティにアクセスできるので不要になりました。
map端の処理は、過密度を対象方向に加算する実装になっています。
ここでは、生存年数(lifeCellLiveYear)は、登場しません。すでにclass宣言の際に自動計算化されています。
生存年数は,lifeDataが更新された際に自動で計算されるようになっています。値変更の自動計算はwillSetdidSetで行えます。

プロパティオブザーバー willSetとdidSet
willSet
値が変更する前に呼び出される。newValueで更新後の値が呼び出せる
didSet
値が変更された後に呼び出される。oldValueで更新前の値が呼び出せる。

プロパティオブザーバーを利用すると、特定の変数と連動して他の値を変えることができます。
今回で言えば、lifeDataが更新されるとlifeCellLiveYearが変更されるようになっています。
注意点として、初期化の際の値変更には適応されません。初期化の際は、直接値を与えるか、初期値を設定して置いて下さい。

nextLife(count:Int)について
nextLifeをcountの回数実行するコードです。nextLifeと名前が同じことに注目して下さい。
同じ名前で、引数ラベルや引数、返値が違うものを実装することを、オーバーロード(overload)と言います。
同じ名称で実装することで、使いやすく理解しやすくするための機能です。機能が違ったり、引数や返値の型が違う定義が可能です。
ただし、返値の型については、出来れば変更せずに利用して下さい。トラブルが多いです。

nextLife.swift
extensionLifeGameEngine{funcnextLife(){letxCount=lifeData.countletyCount=lifeData[0].countlifeKamitudo=Array(repeating:{Array(repeating:0,count:yCount+2)}(),count:xCount+2)varnextWorld=LifeGameEngine.mapCreate(Xjiku:xCount,Yjiku:yCount,seisei:.dathe)//引数worldを読み込み過密状況を調査するforxin0..<xCount{foryin0..<yCount{//マスに生命が存在したら、周辺の過密度を上昇させるiflifeData[x][y]==true{//過密度を書き込むループ 9方向に加算するforiin0...2{fortin0...2{lifeKamitudo[x+i][y+t]+=1}}//自分は隣接する個数に含まれないので、1減らすlifeKamitudo[x+1][y+1]-=1}}}//新設された端の解決。//何度も呼び出すと重いので一時変数(Temp)に受けるletkamituXTemp=lifeKamitudo.count-1letkamituYTemp=lifeKamitudo[1].count-1ifmapEdge.x==true{foryin1..<kamituYTemp{//端の過密度を反対側に加算するlifeKamitudo[1][y]+=lifeKamitudo[kamituXTemp][y]lifeKamitudo[kamituXTemp-1][y]+=lifeKamitudo[0][y]}}ifmapEdge.y==true{forxin1..<kamituXTemp{lifeKamitudo[x][1]+=lifeKamitudo[x][kamituYTemp]lifeKamitudo[x][kamituYTemp-1]+=lifeKamitudo[x][0]}}//角の斜め方向の処理ifmapEdge==(true,true){//左上lifeKamitudo[1][1]+=lifeKamitudo[kamituXTemp][kamituYTemp]//左下lifeKamitudo[1][kamituYTemp-1]+=lifeKamitudo[kamituXTemp][0]//右上lifeKamitudo[kamituXTemp-1][1]+=lifeKamitudo[0][kamituYTemp]//右下lifeKamitudo[kamituXTemp-1][kamituYTemp-1]+=lifeKamitudo[0][0]}// lifeKamitudo(過密度)に基づき生存判定をしていくforxin1...xCount{foryin1...yCount{switchlifeKamitudo[x][y]{//3なら誕生case3:nextWorld[x-1][y-1]=true//2なら、マスに生命がいれば生存させるcase2:iflifeData[x-1][y-1]==true{nextWorld[x-1][y-1]=true}//それ以外は、基礎値でfalseのままdefault://xcodeのエラー抑止 *defaultに何も設定しないと警告が出ます。{}()}}}lifeData=nextWorld//年数を一年進める。yearCount+=1}///nextLifeを複数回実行する 最大1000まで nextLifeをオーバーロード 中身は規定数nextLifeを呼んでいるだけfuncnextLife(countc:Int=1){varcTemp=cifc>1000||c<=0{cTemp=1000}for_in1...cTemp{nextLife()}}}

実行していきます。実行結果も同時に表示しています。
nextLife(Count:_)は、実行結果が長くなるので、結果を省略しています。

nextLifeRun.swift
print("nextLifeを実行しています")gameStart.lifeView()//通常のnextLifeの呼び出しgameStart.nextLife()gameStart.lifeView()//nextLifeをオーバーロードして、countを呼び出しているgameStart.nextLife(count:5)gameStart.lifeView()///実行結果///nextLifeを実行しています現在の世界を表示します|0|1|2|3|4|⬛️⬛️⬛️⬛️⬜️:0⬛️⬜️⬜️⬛️⬛️:1⬜️⬛️⬛️⬜️⬛️:2⬛️⬜️⬜️⬜️⬜️:3⬛️⬛️⬜️⬛️⬜️:40年目-生き残りは14です約56%です現在の世界を表示します|0|1|2|3|4|⬜️⬜️⬜️⬜️⬜️:0⬜️⬜️⬜️⬜️⬜️:1⬜️⬛️⬛️⬜️⬜️:2⬜️⬜️⬜️⬛️⬜️:3⬜️⬜️⬜️⬛️⬜️:41年目-生き残りは4です約16%です

kamiNoTe マップを操作する

セルを直接操作します。前記事とほぼ変わっていません。
指定されたセルに、与えられた作用を実行します。

作用は、CellMakerを受け取るように改良します。
セル生存年数(lifeMapLiveYear)が、セル変更の際に自動計算されてしまうので、自動計算を止めるフラグを立てます。フラグは、class.swiftで下記のように宣言しました。

var usedLifeMapLiveYear = true

フラグの使用に際して、一度立てるとそのままのタイプのフラグだと、折り忘れがあるので、今回は一度判定されると、自動で折られるようになっています。

//年数経過をとめる
guard usedLifeMapLiveYear else {
usedLifeMapLiveYear = true
return
}

guard文について
guard文は、条件が真で無い場合、else内部が実行され、そのコードが終了されるコードです。returnかbreakがプログラム内に必須です。下記のように使います

guard 条件式 else { プログラム returnまたはbreak }

コードの安全を確保するために使用する文法です。条件部分は、プロパティの代入(let 定数名 = 実引数)(代入できなかったら偽)、パターンマッチ(範囲内に含まれるかどうか)など、様々な条件を設定する事が出来ます。elseプログラム内部には、構文から抜けるコード(return または break)が必須です。使い方は、引数が正しいかどうかの判定に用いることが多いです。今回の場合は、フラグによって実行すかどうかを判定しています。

kamiNote.swift
extensionLifeGameEngine{///特定のマスを指示してデータを操作する関数 worldは現在の状態、pointは編集する場所(X軸,Y軸)、sayouは、セルに行う操作 デフォルトは、反転funckamiNoTe(pointp:(Int,Int),sayous:CellMaker=.reverse){letsTemp=s.maker()//生存年数が計算されないように止める。usedLifeMapLiveYear=falselifeData[p.0][p.1]=sTemp(lifeData[p.0][p.1])}}

実行していきます。マップの
0行目を生存に
1行目を反転
2行目を死亡
3行目をストライプに変えます。

kamiNoTerun.swift
print("神の手を実行します。")gameStart.lifeView()foriin0..<gameStart.cellXY.x{gameStart.kamiNoTe(point:(i,0),sayou:CellMaker.live)gameStart.kamiNoTe(point:(i,1),sayou:.reverse)gameStart.kamiNoTe(point:(i,2),sayou:.dathe)gameStart.kamiNoTe(point:(i,3),sayou:.stripes)}gameStart.lifeView()///実行結果///神の手を実行します現在の世界を表示します|0|1|2|3|4|⬜️⬛️⬜️⬛️⬜️:0⬜️⬜️⬛️⬛️⬛️:1⬜️⬛️⬛️⬜️⬛️:2⬜️⬜️⬜️⬛️⬜️:3⬜️⬜️⬛️⬜️⬜️:40年目-生き残りは10です約40%です現在の世界を表示します|0|1|2|3|4|⬛️⬛️⬛️⬛️⬛️:0⬛️⬛️⬜️⬜️⬜️:1⬜️⬜️⬜️⬜️⬜️:2⬛️⬜️⬛️⬜️⬛️:3⬜️⬜️⬛️⬜️⬜️:40年目-生き残りは11です約44%です

gameMode コンソールで遊ぶ

lifeGameをコンソールで操作し遊べるようにします。
呼び出し方が変わった程度で、前回と変わらないので畳んでおきます。

gameMode.swift
gameMode.swift
extensionLifeGameEngine{/**コマンドラインで遊ぶゲームモードを起動します
     ゲームモードと言う以上個別起動できたほうがいいので、class関数かします
 */classfuncgameMode(){print("/////////ゲームモードを開始します/////////")///世界の大きさvarookisa:Int=0///ゲームモードのインスタンスletgameData:LifeGameEngine///端の接続性varhaji=(true,true)repeat{print("数字を入力してください1~50まで")//readLineで入力を受け付けるletreadOokisa=readLine()??"0"ookisa=Int(readOokisa)??0}whileookisa==0||ookisa>50varreadLineTemp=""repeat{print("X端の接続性を選択して下さい。trueまたは,false")readLineTemp=readLine()??""}while!(readLineTemp=="false"||readLineTemp=="true")haji.0=Bool(readLineTemp)!repeat{print("Y端の接続性を選択して下さい。trueまたは,false")readLineTemp=readLine()??""}while!(readLineTemp=="false"||readLineTemp=="true")haji.1=Bool(readLineTemp)!print("サイズ\(ookisa),端接続\(haji)受け取りました。マップを製造します")gameData=LifeGameEngine(Size:(x:ookisa,y:ookisa),seisei:CellMaker.live33,Edge:haji)gameData.lifeView()//操作するループ next change changeAll view exti//文字入力用文字列varreadString=""repeat{print("操作を半角英数字で入力して下さい。\n next:次の時代に進みます \n change:対象のマスを変更します \n changeAll:すべてを変更します \n view:現在の状態を表示します 即時実行されます \n exit:終了します")readString=readLine()??""//switch文で条件分岐switchreadString{case"next":varreadKaisuu=""varnextkaisuu=0repeat{print("どれくらい進めますか?1回以上")readKaisuu=readLine()??"0"nextkaisuu=Int(readKaisuu)??0}whilenextkaisuu==0for_in0..<nextkaisuu{gameData.nextLife()}case"change"://x軸letxMax=gameData.cellXY.x//入力間違えてもエラーになるようにエラー値を入れているvarxjiku:Int=xMaxrepeat{print("x軸を入力して下さい。最大値は\(xMax-1)です")letreadX=readLine()??""xjiku=Int(readX)??xjiku}whilexjiku>=xMax||xjiku<=0//y軸letyMax=gameData.cellXY.y//入力間違えてもエラーになるようにエラー値を入れているいvaryjiku:Int=yMaxrepeat{print("y軸を入力して下さい。最大値は\(yMax-1)です")letready=readLine()??""yjiku=Int(ready)??yjiku}whileyjiku>=yMax||yjiku<=0//操作部print("x:\(xjiku) y:\(yjiku)を、反転させます")gameData.kamiNoTe(point:(xjiku,yjiku))case"changeAll":print("世界を再構成します")//新たにマップを作って上書きする。gameData.lifeData=mapCreate(Xjiku:ookisa,Yjiku:ookisa)gameData.lifeMapLiveYearReset()case"view":gameData.lifeView()case"exit":print("終了します")default:print("指示を理解できません")}//exitが入力されない限り繰り返す}whilereadString!="exit"}}

実行の際には、main.swiftで、下記のように呼び出して下さい。

LifeGameEngine.gameMode()

この呼び出しは、クラスメソッドの呼び方です。
クラス名.クラスメソッド名になっています。
クラスメソッドは、実体を生成せずに、呼び出すこととのできるメソッドで型に関する手続きや実態を用いずに、実行したいときに使います。メソッドだけではなく、プロパティも設定可能です。プロパティの場合、変更の影響が、同一クラスすべてに及ぶので、注意して下さい。

実行結果

gameModeRun.swift
LifeGameEngine.gameMode()///実行結果////////////ゲームモードを開始します/////////マップの大きさをを半角数字で入力してください1~50まで5X端の接続性を選択して下さいtrueまたは,falsetrueY端の接続性を選択して下さいtrueまたは,falsetrueサイズ5,端接続(true,true)受け取りましたマップを製造します現在の世界を表示します操作を半角英数字で入力して下さいnext:次の時代に進みますchange:対象のマスを変更しますchangeAll:すべてを変更します view:現在の状態を表示します 即時実行されます exit:終了しますview現在の世界を表示します|0|1|2|3|4|⬛️⬜️⬜️⬜️⬜️:0⬛️⬛️⬜️⬜️⬛️:1⬛️⬛️⬜️⬛️⬜️:2⬜️⬛️⬜️⬛️⬛️:3⬜️⬜️⬛️⬜️⬛️:40年目-生き残りは12です約48%ですview現在の世界を表示します|0|1|2|3|4|⬛️⬛️⬜️⬛️⬜️:0⬜️⬛️🟨⬜️⬜️:1⬜️⬜️⬛️⬜️⬜️:2⬜️⬜️⬜️⬜️⬜️:3⬜️⬜️⬛️⬜️⬜️:410年目-生き残りは7です約28%です

終わりにクラス化

前回導入されていた機能のクラス化が終了しました。クラス化することによって、main.swfitにプログラムをコピペするのではなく、ファイルを移せば使えるようになります。
gitHubで落として、LifeGameEngine.swiftを移せば即時利用可能です。

クラス化は、オブジェクト指向の基本です。前回の記事と比較して読んで見て下さい。
main関数(起動時に読み込まれるプログラム)が、だいぶ簡略化されています。

今回のmain.swift
main.swift
print("Qiita2年目の実行コード")letgameStart=LifeGameEngine(Size:(x:5,y:5),seisei:CellMaker.live20,Edge:(x:true,y:true))print("lifeDataの内容を表示します\(gameStart.lifeData)")print("現在の生存セル数は、\(gameStart.lifeCellCount)セルです。")print("マップの大きは、\(gameStart.cellXY)")print("lifeViewを実行しています")gameStart.lifeView()gameStart.nextLife(count:10)gameStart.lifeView()gameStart.reset()print("nextLifeを実行しています")gameStart.lifeView()//通常のnextLifeの呼び出しgameStart.nextLife()gameStart.lifeView()//nextLifeをオーバーロードして、countを呼び出しているgameStart.nextLife(count:5)gameStart.lifeView()gameStart.reset()print("神の手を実行します。")gameStart.lifeView()foriin0..<gameStart.cellXY.x{gameStart.kamiNoTe(point:(i,0),sayou:CellMaker.live)gameStart.kamiNoTe(point:(i,1),sayou:.reverse)gameStart.kamiNoTe(point:(i,2),sayou:.dathe)gameStart.kamiNoTe(point:(i,3),sayou:.stripes)}gameStart.lifeView()//ゲームモードを実行しています。LifeGameEngine.gameMode()

前回に比べて読みやすく、書きやすくバグが起きづらいと思います。
オブジェクト指向において、名前が重要だと言われます。呼び出していく過程が、読める文章になっていると使いやすいからです。もちろん名前が適当に付けられてしまうと解りづらくなります。それと、私の名前付けは、あまり良くないので、私にあまり影響を受けずに、解りやすい名前付けを目指して下さい。

それと次回から記事一つ一つを小さくする予定です。

インフルで死にかけた時にGoogle Assistantに助けてもらった話

$
0
0

はじめに

数日間、高熱で寝込むことがあり、その際にスマートスピーカーがとても有能
ということに気づいたので、記事にしました。
当たり前っちゃ当たり前のことなのですが、いざ使ってみると感動しました。

高熱時の私の状態

  1. 基本ずっと寝込んでいる
  2. 感染拡大防止のため、隔離されている
  3. 寝すぎて今が何時なのかかもよくわかってない
  4. しんどすぎて目も開けたくない(暗い部屋の中で光を見るのもつらい)
  5. しんどすぎて腕も動かしたくない

高熱下の人間の楽しみとできること

上述の通り、39℃を超えてくると、しんどすぎて目を開けることすら辛い(たぶん)です。
なので、耳から入ってくる音で情報を集めることが唯一の楽しみになります。
一方で、体は動かせないので、自分からのアウトプット手段は声だけです。

スマートスピーカーがあると何が便利なのか

目を開けなくてもいい

熱にうなされながらでも、マスクをしながらでも、寝返りをうつことなく、スピーカーの方向を意識することなく
「OK Google, ラジオかけて」と言えばラジオが聞けます。
地味にラジオ聞けるのは楽しいです。なぜなら目を開けるのもつらいから。

また、ず~~っと寝ていると時間すらもわかりません
自分が何時間寝たのかもよくわからないので、日常生活ではほぼ使うことのない、
「OK Google, 何時か教えて」というのも使っていました。

腕を動かさなくてもいい

我が家ではIFTTTやNature Remoと連動させているので、
照明のON/OFFや室温の取得、エアコンの操作ができます。
寝ながらにして、これらが操作できるのはとても重宝しました。
だって寝ていてGoogleにお願いすれば、すぐにやってくれるから。

孤独感からの解放

とりあえず話しかけたら必ず返事をしてくれる というのは、
一人暮らしの人なんかには特にありがたいです。
そしてGoogle Assistantは基本ネガティブなことは言わず、ほぼ100%励ましてくれます。
実はこれがなによりうれしかったりします。。。
「OK Google, しんどい」とか言うと、「大丈夫ですか?頑張りすぎなくてもいいですよ」とか言ってくれる。やさしい。

その他

スマートスピーカーと書きましたが、別にスマホのGoogle Assistantや
Siriでも似たようなことはできると思います。
ただ、毎回スマホの画面が光るのは、意外と鬱陶しいので、スマートスピーカーがおすすめです。


【体験談】未経験から半年でweb系エンジニアになるために、、、

$
0
0

はじめに

エンジニアの皆様、今日も元気に開発やっておりますでしょうか。

この度、半年前まで全くの未経験だった私がrailsの自社開発企業に内定をいただき2020/2からwebエンジニアとして働くことになりました。
友人から経緯や通っていたプログラミングスクールについての質問がちょこちょこ来るようになったので、これからエンジニアに未経験転職する方や独学中の皆様の励みになればと思い記事をまとめることにしました。

私について

まずはじめに、少しだけ自分のプロフィールについて話します。
現在23歳で、早稲田大学文化構想学部を卒業後、食品のメーカーで営業をしていました。
1年半ほど勤めた後に、退職し、エンジニアになることを決めました。
(詳しい経緯や動機は需要があれば書きます、、、)

2019/6末日に退職し、プログラミングスクールTECH::EXPERTに通うことを決めました。
独学ではなくスクールに通った理由は以下の2点

  • 短期間で学習+転職活動を終わらせて、実務経験を積みたかったため
  • ある程度の強制力がないと自分を律せないと思ったため

その中でもrubyをメイン言語としている点とチーム開発がカリキュラムに組み込まれている点を重視して、
TECH::EXPERTに通うことを決めました。

正直、この6ヶ月間の資金繰りは結構辛かったです。

Left alignRight align
TECH::EXPERT受講費60万円
日々の食費5万円/月
居住費5万円/月
水光熱費1万円/月
通信費1万円/月
交通費1万円/月
交際費2万円/月
雑費3万円/月

ざっと見積もってもこんくらいでした。他にも先払い住民税やmacbook新調費や転職活動の交通費等結構お金はかかります。私は友人の家に転がり込んだのでなんとか人間らしい生活はできていました(笑)
少なくとも受講費とは別に半年間くらい生活できる貯金はしておいた方がいいかもです。

話が少し外れましたが、そんなこんなで2019/7/20からTECH::EXPERTで本格的にプログラミングの勉強をはじめました。

エンジニアになるための6ヶ月

準備

前職は営業だったためプログラミングはズブの素人でした。
「まずは自分の環境を整えないと」とおもい色々生活環境を変えました。

  • まずは退職。(両親には結構反対されました(笑))
  • プログラミングスクールTECH::EXPERTの申し込み。
  • 東京へ引っ越し。(前職の勤務地が名古屋だったため)
  • progateをとりあえず1周。
  • macbook pro購入
  • twitter,Qiitaアカウント開設

こんなかんじですかね。結構色々環境を変えました。
あと退職してから時間あったので、東南アジアに1週間くらい旅行いってました(笑)

1ヶ月目-7月

私が通っていたプログラミングスクールでは入校の2週間前からカリキュラムを受講できたので、
7/20まではひたすらガリガリカリキュラムを進めていました。

内容はHTML,CSS,Ruby,Railsの基礎を一通りやる。
その後、カリキュラムに沿ってtwitter風アプリを作るって感じでした。

正直、初めはちんぷんかんぷんでした。
「クラスってなに?オブジェクト指向?」
「環境構築ってこんな時間かかるの?」
「やること多すぎ!!」

って感じでした。

それでも毎日12時間、休みなしでスクールに通って、帰宅してからも家で勉強していました。
(ちなみにこれを3ヶ月続けていました)
『よく体調壊さなかったな』と今では思います。

制作物

twitter風アプリ

2ヶ月目-8月

8月からは応用のカリキュラムに入り、メッセージアプリを作成していました。
またGit,Github,jQuery,AWS,SQLも並行して勉強していました。

このあたりからrubyやrailsの挙動について少しずつ慣れてきました。
バグが起こっても仮説→調査→原因発見→解決のサイクルを回せるようになり、
ほとんどのバグを一人で解決できるようになりました。

簡単なアプリケーションは一人で作れるようになり、
gemの使い方やCRUDは何も見なくてもガリガリコードをかけるかけるようになってきたのもこの頃です。

隙間時間にLINEのBOTや日記アプリ、マッチングアプリも制作していました。
とにかく寝る時間と食う時間以外はコードを書いていました。

またスクールでは友人もたくさんできて、学習が楽しくなってきたのもこの頃からです。
わからないことや新しく得た知識も教え合い、モチベーションも保てました。
20代が多かったので共通の話題や価値観も近い人が多く、普通に居心地がよかったです。
ちなみに卒業してからもプライベートで遊んだりする友人もできました。

制作物

メッセージアプリ

3ヶ月目-9月

いよいよプログラミングスクールのカリキュラムも残り1ヶ月になり、
最終課題のチーム開発を残すのみになりました。

最終課題では某フリマサイトのクローンを作るというものでした。
SNS認証からAjax通信での検索や決済機能、AWSデプロイ、SSL化などアプリケーション作成の基礎をフロントからインフラまで集大成で行いました。
ここからカリキュラムはないので、自分自身でやり方を調べながら実装していかなければなりません。

このチーム開発を通して、かなり技術的にレベルアップしたように感じます。
答えがないため、頭から尻まで考えて実装しなければならないし、
ありがたいことにスクラムマスターをやらせていただいたため、
チームでの開発の難しさを感じれたのも良い経験でした。

制作物

フリマサイト
フリマサイトソースコード

4ヶ月目-10月

ここから就職活動に入る人もいましたが、私はポートフォリオの作成にとりかかりました。
「エンジニア向けのコミュニケーションアプリ」を作成しました。

概要が気になる方はソースコードを見てください。

  • Bootstrapとメディアクエリを活用したレスポンシブ対応
  • jQueryを用いた動的アニメーション/ajax通信の実装(インクリメンタルサーチ/メッセージ自動更新)
  • 外部APIを利用したログイン機能
  • CircleCIとGitHubを連携させて自動テスト、gem selenium-webdriver/ChromeDriverを用いてのブラウザでテスト
  • インフラ周り(AWSを使用/Capistranoによる自動デプロイ/ELBをエンドポイントとする常時SSL化/画像データ保存でクラウドストレージS3を使用)

特に力を入れて作った点です。制作期間は3週間くらいでした。
スクリーンショット 2020-01-10 22.53.16.png

制作物

エンジニア向けのコミュニケーションアプリ
ソースコード

5ヶ月目-11月

さて、ここから就活です!!!

スクールでも企業を紹介してくれますが、基本的には自分での申し込みをメインとしていました。
基本的にはRailsの自社開発企業に狙いを絞って受けていました。

まずはwantedlyで100社くらい「話を聴きに行きたいボタン」をぽちぽちしていましたが、
全然通りません。。。

返信が来たのは10社/100社くらいだったと思います。

並行して、直接企業のホームページから申し込みもしていました。
だいたい10社くらい応募しましたが、意外と反応が良く、書類で落とされることは少なかったです。

スクール経由でも10社くらい応募し、
ありがたいことに書類や面接で落とされることはほぼなく、途中辞退するか内定をいただきました。

6ヶ月目-12月

そんなこんなで、12月の2週目くらいに就職活動を終えました。

4社から内定をいただき、
最終的には2社でかなり迷いました。

  • 東証一部上場の某ECサイト
  • 人材系ベンチャー

どちらも私にはもったいないくらい魅力的な企業でしたが、
会社風土やベンチャーに勤めたいという当初の意思を鑑みて
人材系ベンチャーに入社することを決めました。

2020/1から恵比寿の人材系ベンチャーでバリバリコードを書いています。

プログラミングスクールってどうなの?

プログラミングスクールに入学するか迷われている方もいるんじゃないでしょうか?

結論から言うと
プログラミングスクールに入ってよかったと私は思っています。

良かった点

- やらざるを得ない環境

「プログラミングを独学で勉強をすると95%の人が挫折する」と聴きます。
実際、私の周りでもプログラミング独学を挫折した人は多いです。
ですが私の同期で入学した人の8割くらいは卒業し、エンジニアとして働いています。

エンジニアになるための学習量はとても多いです。
未経験からエンジニアになるためには1000時間以上学習しなければならないとも言われています。
1日10時間勉強したとしても100日かかる計算です。

「なんのために勉強してるんだっけ?」
「思ったよりも学ぶことが多すぎる!」

絶対に誰もが1度は感じます。

しかし、スクールのカリキュラムはそんなことを考える暇もないほど、
忙しいです。

1日10時間休みなしで学習を進め、
定期的にテストがあり、合格しなければ次に進めない。
毎日同期と競争する環境。

良い意味で脳死でプログラミングができます。
3ヶ月間、何も考えずに自分の技術力を向上させるためだけに学習します。

- 自分を追い込めたこと

人間は易き方向に流れる生き物です。
「明日から頑張ればいいや」「今日は昼頃起きよう」

ある程度の強制力がないとほとんどの人間は自堕落になります。
みんな自宅では集中できないから、図書館やカフェで勉強します。

それと同じです。

肉体的にも精神的にも自分をかなり追い込めます。
特に最終課題のチーム開発の時にはそれが顕著に現れていました。

「このバグを解決してから寝よう」
「あと少しだけカリキュラムを進めよう」
「ここまで進めてたら明日チームの奴らビビるだろうな」

こうして気がつけば朝になっていたこともあります。

この追い込みは独学ではできなかったと思います。

- 一緒に学習する仲間の存在

綺麗事はあまり好きな質ではないのですが、
スクールに入って価値観が近い友人が数人できました。

これは自分にとってかなり大きかったです。

「フリーランスとして死ぬほど稼ぎたい」
「自分のブランドをwebで集客できるようにしたい」

面白い生き方や価値観を持っている人間が多かったと思います。
「こいつらに負けていられんな」
何度もモチベーションを上げさせてもらいました。

もちろんITのこととか技術的なこともたくさん学べましたし、
一緒にゼロから学習していた友人は大きな励みになっています。

悪かった点

良いことばかり並べててもステマっぽいので悪いことも記しておきます。

- メンター/カリキュラムの質が低い

メンターは正直かなり質が低かったように感じます。
ほとんどがエンジニアとしての実務経験がないアルバイトでした。

正直、学習を初めて2ヶ月くらい経てば(それなりに自分自身で学習を頑張っていれば)、
メンターより自分の方が技術力が高い状況になります。
質問をしていたのも最初の1ヶ月くらいだけです。

中には親切で技術力が高い方もいますが、かなり少数ですし、
その方が毎回コーチングしてくれる訳ではないです。

カリキュラムに関してはrailsチュートリアルを少し優しくしたような感じでした。
フロントからインフラまで全て網羅してるせいもあってか、
一つ一つの項目が薄いです。

今となっては「なんでここを深掘りしてカリキュラムを作らなかったんだろう?」と思う箇所も多々あります。

ネットに転がっている無料のカリキュラムの方がわかりやすいと個人的には思ったほどです。

- 受講料が高すぎる

ほとんどの人が思うのではないでしょうか?
私が入学した時は3ヶ月の短期コースで60万、6ヶ月の夜間コースで80万くらいだったと思いますが、
普通の金銭感覚をしている人からすれば安い金額ではありません。

別途でmacの購入費だったり、転職活動の費用もかかります。
しかもその間無職になるので、金銭的なコストは安いとは言えないです。

「カリキュラムやメンターのためだけに60万を払うべきか?」と聞かれれば
私は「NO」と答えます。

結論

プログラミングスクールは環境を買うものだと思いました。
カリキュラムやメンターのために入学するのはやめた方が良いでしょう。

「本気でエンジニアになりたい」人が短期間で濃密な学習ができるのはまちがいないです。
自分を追い込める機会だったり、やらざるを得ない状況はそう簡単に作り出せるものではないです。
どれだけ強い覚悟を持っていても、時間が経てばそれが薄れていくことも往々にしてあります。
それが人間なので。

結局はその人次第と言ってしまえばそれまでですが、
自分を律せない私にとっては最高の環境を買えたと思っています。

おすすめ技術本

- イラスト図解式 この一冊で全部わかるWeb技術の基本
おすすめ度 ★★★★★

すごく薄くて読みやすい上に、わかりやすいです。
プログラミングの技術書というよりはwebに関する全般的な知識についての本なので、
エンジニアもそうでない方も1回は読んでおくと良いです。
私はwebの知識がほぼ皆無でしたので、この1冊にすごく助けられました。

- webを支える技術
おすすめ度 ★★★★★

『イラスト図解式 この一冊で全部わかるWeb技術の基本』を深掘りしたような内容になっています。
ボリュームが結構ありますが、読みやすいです。
私は転職活動の合間に読んでいました。

- 現場で使える Ruby on Rails 5速習実践ガイド
おすすめ度 ★★★★☆

これは結構使えました。それなりに分厚い本なので読み応えがあります。
初歩的なことから割と実践的なことも書いてあるので働き始めてからも重宝しています。

- スッキリわかるSQL入門 ドリル215問付き!
おすすめ度 ★★★★☆

SQLの本ならこれが一番わかりやすいと思いました。
かなり薄いですし、手も動かせるので学習には最適です。
SQLはどの言語を使う際にも必要(最近ではビジネスサイドでもSQLを使いこなす人が沢山いるらしい、、、)なので、
マスターするのに損はないです。

- Amazon Web Services実践入門
おすすめ度 ★★★☆☆

初め、一読した時は難しいと思いました。
その後、udemyでawsを一通り勉強したあとだとスッと頭に入ってきたので、
入門本としてはあまりお勧めではないです。
ただ、内容は結構濃いので一通り勉強したあとに購入するのは良いと思います。

- Everyday Rails - RSpecによるRailsテスト入門
おすすめ度 ★★★★☆

RSpecに関する本が僕の探した限りではこの1冊しかありませんでした。
内容自体はわかりやすいです。
ただテスト自体はRSpec以外でもかけますし、
わざわざこの本を読んでテストを書くというよりは、
必要になった時に購入するのが良いと思います。

- Ruby on Rails チュートリアル
おすすめ度 ★★★☆☆

rubyをある程度理解している上で進んでいくので、初学者には少し難しいかもしれません。
ただ、アプリケーションを1からつくるため、制作の流れはわかります。
progate等で基礎の基礎を理解したあとでやると良いでしょう。

- 1冊ですべて身につくhtml & cssとwebデザイン入門講座
おすすめ度 ★★★★☆

私が初めて読んだ技術本です。
マークアップの勉強はとりあえずこれから初めて見ると良いでしょう。
この1冊を完璧にすれば、LPの案件をクラウドソーシングで取れるレベルにはなります。

- udemy
おすすめ度 ★★★★★★★★

結局udemyが最強です。
勉強をはじめて2ヶ月くらいが経ってから、ほとんど本での勉強はしなくなりました。
値段が高いのがネックですが、四六時中セールをやっているので、
その時に購入しましょう。
活字よりも、映像や音声の方が確実にわかりやすいし、頭に入ってきます。

エンジニア就活について

転職活動は1ヶ月半〜2ヶ月費やしました。
人によってバラバラですが、これくらいの期間は見ておくと良いでしょう。
この期間は9社/週くらいのペースで面接していました。
1日3社面接はしごする日もありました。

志望企業

スクールを卒業し、ポートフォリヲを提げてエンジニアとしての転職活動に臨みました。

はじめは、肌感を掴むためにもあまりこだわりを持たずに受けてみようと思い、
wantedlyで100社くらい「話を聞きに行きたい」ボタンをぽちぽちしました。

結果は10社くらい返信が来ました。

その中ですぐに選考してくれた企業もいくつかあり、
面接を初めて2社目でクラウド事業を展開しているベンチャーに内定をいただきました。

待遇面も悪くないし、海外展開もしていて楽しそうだったのですが、
結局、「自分のやりたい職種と微妙に違う」と思い、内定を辞退しました。

ある程度面接を受けた後、
兼ねてからの希望だった「Railsの自社開発企業」に的を絞り、活動していました。

自分でホームページから書類を送った企業の中には誰もが知っているサービスを展開している企業もありましたが、
幸いにも書類で弾かれることはあまりありませんでした。

結果、4社から内定をいただき、いろいろ悩んだ結果、
人材系ベンチャーに入社することを決めました。

        wantedly   直接応募スクール紹介
書類応募100?118
書類通過     1187
一次通過(辞退) 9(4)5(3)6(5)
二次通過 (辞退)4(2)21
内定       211

よく聞かれた質問

- どうしてエンジニアになろうとおもったのか?
よく聞かれる度 ★★★★★

ほとんどの面接で聞かれるため、回答を事前に用意しておくことはマストです。
プログラミングに興味を持った経緯→転職した理由のストーリーをわかりやすく説明できると良いでしょう。
教科書通りのテンプレではなく、自分の体験談を具体的に話すと良いでしょう。
「なぜプログラミングを勉強しようと思ったのか?」
「なぜ退職に踏み切れたのか?」
自分自身で深掘りしておくことが必要だと思います。

- 前職で頑張ったこと
よく聞かれる度 ★★★★★

この質問もほとんどの面接で聞かれます。
頑張った経験=エンジニアになる理由
だとベストですが、
全員がそうではないと思いますので、
前職で力を入れたことや大変だったことを話せれば◎
この時気をつけていたのは、
面接官は自分の前職についての知識はほとんどないということです。
専門用語や競合など前提知識はないので、
小学生にもわかるくらい噛み砕いて説明することを意識していました。

- 将来なりたいエンジニア像
よく聞かれる度 ★★★★☆

大きく2種類に分けられます。
「マネジメントを行うPM的な役割」
「技術を追求していくTHEエンジニア」

どちらでもよいと思いますが、なぜそうなりたいかは考えておく必要があります。

- どんな風に勉強しているか
よく聞かれる度 ★★★★☆

入社後にどうやってスキルアップしていってくれるか測る質問です。
正直に答えていました。
背伸びをする必要はないと思いますので、普段やっていることを簡潔に話しましょう。

- 志望理由
よく聞かれる度 ★★★★★

これも必ず聞かれるので、あらかじめ考えておく必要があります。
企業のHPや決算資料はもちろん、
技術ブログやSNSなども見ておいた方が良いです。
その上で自分がなぜ志望するのかを深掘りしておきましょう。
「なぜ自社開発企業なのか」→「なぜ◯◯業界なのか」→「なぜこの会社じゃないとだめなのか」→「なぜこのサービスに携わりたいのか」
なぜ?を何度も自問自答していました。

ポートフォリオって必要なの?

ポートフォリオは作っていた方が良いです。

未経験エンジニアではポテンシャルを示すことが一番重要です。
実務の経験がないので、面接官からすればどれだけ会社に貢献できるか未知数なのです。

「この人はこんな技術を使っているから、普段から勉強しているんだな」
「ドキュメントが少ないのに実装しているから、自走力がありそうだな」

こう思ってもらうことが大事です。

しかし、残念なことに我々が思っているほど面接官は我々に興味がありません。
人気な企業はわざわざ未経験を育成する必要もないし、
面接官も暇人ではありません。

面接を通してしっかり機能やコードを見てくれているなと感じた企業は片手で数える程しかありませんでした。

ポートフォリオ作成で気をつける点

そこで、面接官が見てくれるポートフォリオを心がけていました。

  • 未経験が使わないような技術を使う
  • テストユーザーを作ってログインを簡単にする
  • トップページを見ればある程度の機能がわかるようにする
  • どんなデバイスからも閲覧できるようにする
  • readmeはわかりやすく、読みやすく書く

工夫できる点はたくさんありますが、面接官が
「こいつに会ってみたい」
「見やすい」
「おもしろい技術使ってるな」

と1mmでも思わせたら勝ちだと思って、
ポートフォリオを作成していました。

技術選考

会社によっては技術の選考があります。
ほとんどの場合、選考の初期段階(1次選考前後)で行われました。

口頭で質問されるケースや紙に記述するケース、webでの試験など
多種多様でしたが、未経験エンジニア向けの質問なのでそこまで難しい質問が飛んでくる訳ではありません。

  • セッションとcookieの違いは?
  • オブジェクト指向のメリットとデメリットは?
  • includeとextendの違いってなに?
  • メソッドのアクセス権でprivateとprotectedの違いってなに? ここらへんの質問がすらすら答えられれば問題ないと思います。

コーディングの試験はpaizaで隙間時間に勉強していれば余裕です。

アウトプットの重要さ

アウトプットはかなり重要だと痛感しました。
特に転職活動においては「アウトプットをしているか」必ず聞かれます。
私はQiitaとtwitterを主軸にしてアウトプットしていました。

- 技術的な向上を図れる
他人に伝えるには、まず自分が完全に理解していないと教えられません。
また頭ではわかったつもりでもいざ言語化しようとするとできないことが多々あります。

文字に起こして発信することでその技術に対する理解を深められます。
また自分より優秀なエンジニアからフィードバックしてもらえることもあります。

- 人と繋がれる
実は、10月(4ヶ月目)から仕事をいただいておりました。
Qiitaに上げていた私の記事を読んだweb制作会社の社長さんが
「リモートで仕事をしてみない?」と声をかけてくださり、10月から80H/月、フルリモートで既存のwebサービスの開発に携わらせていただいておりました。

業務内容はバグ修正とRSpecを使ったテストの実装でしたが、
この経験はかなり力になりました。経済面でも助けられました(笑)

そもそも実際に稼働しているサービスのソースコードを見るのも初めてでしたし、
自分が作っていたポートフォリオとのレベルの違いに驚愕しました。
「こんなメソッドあるんだ」
「コントローラー70個くらいあるじゃん、、、」

転職活動をする前に実務経験を積めたのはすごくよかったです。
今も継続してお仕事をもらっています。(いつクビになるかわかりませんが、、、)
そして、社長さんには本当に感謝しています。

アウトプットをしていれば誰かが見ていてくれるし、
それが無駄になることはないと思います。
小さなことでも良いので続けることが大事ですね。

最後に

最後まで読んでいただきありがとうございました。
この6ヶ月は自分の人生の中で転機だったように思います。

いままで自分の人生は自分で選択しているようで選択していなかった人生だったのかもしれないなと今では思います。
偏差値の高い大学に行くのがあたりまえ。
大手の企業に行くのがあたりまえ。
上司に従うのはあたりまえ。

エンジニアになったこと以上に
自分で考え、決断したことに意味があると私は思っています。

私の決断を支えてくれた全ての人に感謝します。
本当にありがとうございました。

これからも私の挑戦は続いていきますので、
見守っていてください!!!

では!!!!

【Linux】pwd「今どこのディレクトリにいるかわかる」

$
0
0

何気に困る事

クライアント先で検証する時に、地味に困った事はないだろうか。

クライアント先であるという緊張感だけではない。

まだ新人だった頃、linuxに慣れるためにある簡単な作業を依頼される事になる。
手順書通りに、あるスクリプトを適用して欲しいとの事だった。
そしてスクリプト適用後に、終了ステータスを見て異常だった場合、
連絡して欲しいとこの事だった。

カタカタカタ。。。。
慣れた様子で先輩が作業を進めている。

手順書通りに、コマンドを入力して終わった所に手順書にチェックを入れていく。
黒字に白い文字が浮かぶその様子は、windowsに慣れ親しんだ身としては
不思議なカッコ良さを覚えた。

ログインすると

$

ダラーが浮かんでいる。

手順書通りに作業ディレクトリに移動する

$cd work
$
$
$su root
.略
.
#echo $?
0
#

お分かりだろうか。
ディレクトリ移動しても、$(ダラー)か#(シャープ、場所によってはイゲタという)しか表示されないのだ。
はたして指定の場所で実行されているのか、手順書に○✖︎つけてる
だけじゃわからない。
そんな時は心の友としてpwdを覚えておいた方がいい。
そして#か$しか表示しない画面にpwdの3文字を打ってみるといい。
彼は「今、どこの場所にいるのか」教えてくれるのだ。

Docker?あぁ!クジラのやつね

$
0
0

はじめに

Docker...あぁクジラが書いてあってコンテナがなんとやらのすげーやつね!
この程度の知識しかなく、かなり危機感を感じたので勉強することにしました。
書いて覚えるタイプなのと備忘録ってことで記事にしてみたいと思います。

Dockerってなに?

  • 次世代仮想化技術
  • アプリケーションをコンテナにパッケージングして使う
  • 同じ環境を共有することが容易(新規ローカル環境の構築とか楽)らしい
  • 仮想化技術っていってもvmWareやvirtualBoxなどとは別物

実際何がいいのか

  • Dockerfileでインフラをコード化して管理することができる。
  • ゲストOSがないのでオーバーヘッドが少ない(負荷が低い)

docker_graph.png

上記のようにほかの仮想化ソフトとは違いゲストOSが存在せず、DockerEngine上にコンテナなるものが存在しています。
このコンテナがアプリケーションを実行するための空間です。

通常はOS上に1つの空間が存在していますが、コンテナ型仮想環境では1つのOS上に複数のユーザ空間を用意することができます。
さらにdockerはコンテナの内容をDockerfileなるものにコードとして記述して管理できる仕組みがあるようです。
これによってコンテナ内のOSやライブラリ、環境変数とかをパッケージ化したり保存したり移動したり..したりしたりできるようです(・ω・)マジカ

Dockerイメージとコンテナ

Dockerにはイメージというものがあり実行環境などをパッケージングしたものがこれにあたり、これらをDockerEngine上で起動したものがコンテナになる。
イメージは起動したコンテナ内で必要なアプリをインストールしたり、各設定を変更したりしたものを保存することで新しいイメージとして使用、配布することが可能になります。

イメージ.png

イメージ層のレイヤは読み取り専用になっており、変更することはできません。
レイヤは一つのものをインストールすることでレイヤが積み重なっていきます。
イメージ空コンテナを起動して新しくミドルウェアなどをインストールすることで新しくレイヤを積み重ねることができます。
このコンテナから新しく作成(commit)することでイメージを新しく作成することもできます。その際は図の左のイメージにコンテナレイヤーで追加したものレイヤー3に重なったイメージができあがります。

Dockerfile

Dockerfileとは

DockerイメージはDockerHubから取得(pull)することもできますが、自分でイメージを作成する場合はDockerfileを作成しそれを使用してイメージを作成することができます。
Dockerfileにはベースにするイメージに対して実行する内容を記載します。

まとめ

  • Dockerはコンテナ型の仮想化技術
  • ゲストOSが存在せず、各環境をコンテナとして扱う
  • コンテナはイメージを起動することで使うことができ、コンテナから新たにイメージを作成することもできる
  • イメージを作成するにはDockerfileを作成しそれをもとにイメージを作成する

初回はDockerについて基本的なことをメモ程度に書かせて頂きました。
次回は実際にDockerを使用して開発環境を構築した記事を書いてみたいと思います。

第六回ドワンゴからの挑戦状 予選をPythonで解きたかった

$
0
0

はじめに

こんばんは。前回のABC150は残念ながらunratedになってしまったので、レートの変動はないです。そして、学校で模試があるのでなかなか時間が取れずに記事を書けませんでした。模試が終わったら終わったらたくさん書きます(フラグ)
今回はAしか解けませんでした。B以降は期待値が出てきて問題の意味が理解できなかった。

A問題

問題

考えたこと
問題を見ると複数行の標準入力が必要で、実装を知らなかったので検索。
とりあえず、曲名と時間で分割して別のリストにした。あとは、どこで寝てしまったを調べるだけ。

n=int(input())s=[]forainrange(n):s.append(input().split())x=input()m_l=[]foriins:m_l.append(i[0])t=[]forjins:t.append(int(j[1]))m_s=n-m_l.index(x)-1ans=0forrinrange(m_l.index(x)+1,n):ans+=t[r]print(ans)

分割したリストにするならdictでもできるのかなと思った。

B問題

問題

考えたこと
できませんでした。期待値の意味が分らなくてずっと考えていた。数Aの確率、場合の数も苦手で避けてきたので自業自得ではある。むしろ、それ以外ない。
操作の一行目の等確率で選ぶ意味を理解できなくて、random.choiceなのかなと思った()
コードはひどかったので載せません。TLEしたコードなんて載せても意味ないし。

まとめ

確率の勉強します。明日のABC151もがんばります。

【JavaScript】オブジェクトを要素に持つ配列で、条件に当てはまる要素を全削除する方法

$
0
0

はじめに

JavaScriptの配列操作で、条件に当てはまる要素を全削除する方法を備忘録として記載します。

対象はオブジェクトを要素に持つ配列です。

環境

OS:macOS Catalina 10.15.1

結論

constarray=[{id:1,n:1,m:2},{id:2,n:1,m:3},{id:3,n:1,m:2},];//上記配列からnが1, mが2のオブジェクトを全削除する。//つまり、nが1, mが2「でない」配列に置き換えるconstnewArray=array.filter(item=>!(item.n===1&&item.m===2));

出力

array;// => [ { id: 1, n: 1, m: 2 }, { id: 2, n: 1, m: 3 }, { id: 3, n: 1, m: 2 } ] newArray;// => [ { id: 2, n: 1, m: 3 } ] 

おわりに

以下記事を参考に、自分用にメモさせて頂きました:bow_tone1:

参考にさせて頂いたサイト(いつもありがとうございます)

HTML 少数入力時に「有効な値を入力してください」と出たときの話

$
0
0

目次

  • input要素などで数値入力を行う際に少数の入力で「有効な値を入力してください。」と出てしまったときに少数の入力を可能にする方法をまとめる。

結論

  • input要素にてstepを指定する。

書き方の例

  • 問題箇所のinput要素を下記に記載する。

    <inputtype="number"name="study_time">
  • 小数点第一位までの入力に対応されたい場合は下記のようにstepを登録する。

    <inputtype="number"step="0.1"name="study_time">
  • 少数点第二位までの入力に対応させたい場合は下記のようにstepを登録する。

    <inputtype="number"step="0.1"name="study_time">
  • 100の位以下の入力を行わせたくない場合は下記のようにstepを登録する。

    <inputtype="number"step="100"name="study_time">

軽量なDocker Imageを作成する

$
0
0

目的

この記事では、軽量のDocker Imageを生成するDockerfileを作成する手順を書いていきます。

余談

有名な仮想化ソフトとして、Virtual Box(+ Vagrant)がありますが、以下のような問題点があります。

  • 仮想マシン起動が遅い
  • イメージの容量が大きい
    • 2GBとか

勿論、Virtual Boxは、ホストOS(PC)の中にそのままOSを立ち上げるため、ネットワーク周り等扱いやすいと言えば扱いやすいのですが、コンテナ立ち上げ時に時間がかかったり、ほかの人と同じ仮想環境を共有する際、2GBのイメージを交換したりするのは大変です。

そこで、Dockerという仮想化ソフトの出番ですが、実際に使ってみると初心者は特に、以下の課題が発生するかと思います。

  • Docker Imageが1GBを超える

仮想環境のイメージを共有する際、Virtual Boxとは異なり、Imageを生成するためのテキストで記述されたDockerfileを使用することに関しては、イメージ共有を効率化するのですが、何も考えずイメージを作成していしまうと、1GBのイメージになってしまい、それなりにリソースを食います。

やはり、かっこいいのは、軽量化されたイメージだと思うので、今回は自分で目的に沿ったイメージを作成したいと思います。

開発環境

今回のDocker Imageは、以下の環境で作成/テストを行います。

  • OS: Windows 10
  • Docker: Docker Toolbox version 19.03.1

Dockerfileの作成

ゴール

Ruby on RailsのWebアプリケーション(rails newした初期アプリ)が入っているDocker Imageを生成するDockerfileを作成します。

ハードウェア容量が少ないサーバー等に需要があるかと思います。

また、Docker Imageを共有するときも、軽い方がImageの生成が素早くていいと思います。

作成するDocker Image

Ruby公式の軽量イメージのalpineイメージを使用します。

このalpineイメージ、最小のソフトしかインストールされていない為、Ruby on Railsのアプリケーション起動に必要なソフトをインストールしながらDockerfileを作成します。

インストールするアプリケーションのバージョンは、以下です。

  • Ruby: 2.6.5
  • Ruby on Rails: 6.0.1

Dockerfileの作成手順

Dockerfileを作成するの手順は以下の様に行います。

  1. ベースイメージのPull
  2. ベースコンテナの立ち上げ
  3. コンテナ内で必要ソフトのインストール
  4. Dockerfileの作成
  5. Dockerfileの実行

地道な作業になりますが、やる気をそがれず、後戻りせず行うためには、上記のような手順になるかと思います。

それでは、実際にイメージを作成していきます。

Dockerはインストールするされていることが前提で解説をします。

1.ベースイメージのPull

以下のコマンドでベースとなるDocker Imageをローカルにダウンロードします。

どのバージョンのRubyイメージがあるかは、公式HPDescriptionタブに記述があります。

docker pull ruby:2.6.5-alpine3.10

2.ベースコンテナの立ち上げ

以下のコマンドで、Pullしたイメージを使用し、コンテナを立ち上げます。

docker run -it ruby:2.6.5-alpine3.10 /bin/ash

alpineイメージでは、bashは使用できないため、/bin/ashを指定して実行します。

3.コンテナ内で必要ソフトのインストール

コンテナ内でRailsアプリケーションを立ち上げるために必要なソフトをインストールします。

インストールしたソフトやコマンドに関しては、Dockerfileまたはメモに書き残します。

エラーが発生した場合、エラー文を読んだり、検索したりして対処を行います。

また、コマンド実行後に、y/nの選択肢が出る場合は、記録を行い、Dockerfileでは-yなどのオプションをつけて記述していきます。

今回は、railsをインストールして、必要なパッケージをインストールする方法をとりました。

コンテナ内で実行したコマンド

/ # apk update
/ # apk add yarn nodejs
/ # gem install bundler
/ # gem install rails <- C compilerなどがなく エラー
/ # apk add gcc
/ # apk add g++
/ # apk add make
/ # gem install rails <- 成功
/ # mkdir app
/ # cd app
/ # rails new . <- sqlite3がなくエラー
/ # apk add sqlite-dev
/ # rails s
... <- rails sができるまで試す
メモ
apk update
apk add yarn nodejs
gem install bundler
apk gcc g++ make
apk add sqlite-dev
...

4.Dockerfileの作成

3でメモしたコマンドを元に、Dockerfileを作成します。

作成したDockerfileが以下です。

Dockerfile
FROM ruby:2.6.5-alpine3.10

ENV APP_HOME /app
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD . $APP_HOME

RUN apk update \
    && apk add  --no-cache gcc g++ make sqlite-dev yarn nodejs \
    && gem install bundler \
    && bundle install \
    && yarn install

EXPOSE 3000
CMD ["rails", "s", "-b", "0.0.0.0"]

5.Dockerfileの実行

4.で作成したDockerfileを実行します。

railsのアプリケーションディレクトリの中に、Dockerfileを置き、イメージを生成します。

ディレクトリは以下のような構成になります。

app/
   ├ Dockerfile
   ├ bin/
   ├ config.ru
   ├ Gemfile
   ├ Gemfile.lock
   ├ lib/
   ├ node_modules/
   ├ postcss.config.js
   ├ Rakefile
   ├ storage/
   ├ tmp/
   ├ yarn.lock
   ├ babel.config.js
   ├ config/
   ├ db/
   ├ log/
   ├ package.json
   ├ public/
   ├ README.md
   ├ test/
   └ vendor/

また、4.でrails sを実行した際に、Please add gem 'tzinfo-data' to your Gemfile and run bundle installといったエラーが出たので、ホストOSのGemfileを変更します。

- (修正前) gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+ (修正後) gem 'tzinfo-data'

以下のコマンドでDockerfileをビルドします。

docker build -t rails-app .

作成したイメージを使用して上手くコンテナが起動できない場合は、以下のコマンドを使用して、ログを確認しつつ、エラーを解消していきます。

docker logs <コンテナID>

作成したイメージからコンテナを立ち上げ、ブラウザなどから、Railsアプリケーションの起動が確認できれば終了です。

docker run -d -p 3000:3000 rails-app

curl http://192.168.99.100:3000

公式イメージとの比較

Rubyの公式イメージにrailsをインストールしたDocker Imageと比較しました。

イメージ名容量
rails-app649MB
ruby(公式)1.29GB

容量はあくまでも参考にしてください。
そもそも、Rubyの公式イメージ自体、840MBあるので、今回作成したイメージが軽量化されていることがわかります。

docker-composeを使用して、ホストOS側のアプリケーションディレクトリをマウントすると、もっとイメージ自体の容量が少なくなります。
Macを使用して、ホストOSからエディタで開発をする場合はdocker-composeを使用した方がいいかもしれません。

ポイントとしては、rails new .をするまでの過程の中で、必要最低限のものしかインストールしない事だと思います。
例えば、alpine-sdkをインストールすれば、gccやmakeがインストールできるのですが、その他gitやcurlなど必要のない物もインストールされてしまいます。
なので、gem install railsbundle installした際にエラーが出て、インストールが必要なものだけ入れるのが良いと思います。

また、今回使用したruby:2.6.5-alpine3.10には、viが入っていたので、この辺りも削除するとよいと思います。


Rails超基本コマンドチートシート(モデル/ビュー/コントローラーの追加)

$
0
0

Ruby/Rails エンジニアとして働き始め2ヶ月ほど立ちますが、まだ Rails のコマンドを業務では使ったことがありませんのでほとんど忘れてしまっています。就職前に学習したので調べれば思い出せるとはいえ、この程度のコマンドならば、業務で必要になった時にわざわざ1つずつ調べるのは時間がかかりすぎます。
そこで、必要な時にサクッと思い出せるよう、チートシートとしてにまとめます。

前提

各コマンドの意味や内容は割愛しますので、詳細は、 Rails ガイド(https://railsguides.jp/) などをお読みください。

モデル関連

モデル生成

モデルとマイグレーション生成する

$ rails generate model Name column_name:column_type

$ rails generate model User name:string number:integer

マイグレーション実行

マイグレーションを実行する

$ rails db:migrate

カラム追加

$ rails generate migration AddColumunNameToModelName

$ rails generate migration AddAccountIdToUsers

コントローラー・ビュー関連

 コントローラー生成

コントローラーとビューが生成する

$ rails generate controller Name action

$ rails generate controllser Users index show new edit

StrongParameters

モデルのインスタンスにどのパラメーターを保存してよいかを指定する

1つのパラーメーターの場合

def create
  User.create(params[:name])
end

複数のパラメーターの場合

def create
  User.create(user_params)
end

private
def user_params
  params.permit(:name, :number)
end

ルーティング関連

テーブル名とアクション名を指定する

resource :table_name, only:[:action]



resources :users, only: [:index, :show, :new, :create, :edit, :update, :destroy]

まとめ

その他にも多用するコマンドがあれば、随時追加していきます

#chat-space非同期通信の実装

$
0
0

chat-spaceというアプリを作成するときajaxを使用した非同期通信を実装したので復習も兼ねて初投稿します。

アプリの非同期通信の見本はこちら
chat-space

非同期通信とは
サーバにHTML形式ではないリクエストを送信し、 HTMLのファイルを読み込まず(ページ遷移を行わず)に、サーバから取得したデータとJavascriptを用いることで、ページの一部分だけを更新することです。 
今回はjQueryとRailsとjbuilderを用いたAjaxのコードで解説していきます。

流れ

  1. chat-spaceでjQueryが使えるように設定し,jQuery を記述するためのファイルを作成する。
  2. フォームが送信されたら、イベントが発火するようにする。
  3. 非同期通信でメッセージを保存するようにする。
  4. respond_toを使用してHTMLとJSON形式で返す。
  5. jbuilderを使用して、作成したメッセージをJSON形式で返す。
  6. 返ってきたJSONをdoneメソッドで受け取り、HTMLを作成する。
  7. 6で作成したHTMLをメッセージ画面の一番下に追加する
  8. メッセージを送信したとき、メッセージ画面を最下部にスクロールする
  9. 連続で送信ボタンを押せるようにする
  10. エラー時の処理を行う。

1. chat-spaceでjQueryが使えるように設定し,jQuery を記述するためのファイルを作成します。

①gem 'jquery-rails'を導入し、bundle installして、chat-space上でjQueryを利用できるようにします。

・Gemfile から turbolinksの部分をコメントアウトし、bundle installを実行します。

turbolinksを停止させましょう
turbolinksとはgemとしてRailsアプリケーションに導入されている機能です。
具体的には、手作業でAjaxを導入しなくても、同じような機能を実現してくれる機能です。今回は開発の過程で手作業でAjaxを実装しているので、こちらのturbolinksは削除します。手作業で作成したAjaxとturbolinksが競合してしまい、うまく作動しない可能性があるためです。

Gemfile
# 省略
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
# gem 'turbolinks', '~> 5' # コメントアウトする
# 省略

コメントアウトをしたら、bundle installを実行します。

②application.html.haml から turbolinks の関連部分を削除します。

application.html.haml
!!!
%html%head%meta{:content=>"text/html; charset=UTF-8","http-equiv"=>"Content-Type"}/
    %title ChatSpaceSample
    =csrf_meta_tags-# = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' ← このオプションを消す
-# = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' ← このオプションを消す
=stylesheet_link_tag'application',media: 'all'=javascript_include_tag'application'%body=render"layouts/notifications"=yield

③ application.js から turbolinks の関連部分を削除します。

application.js
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks ←この記述を消す
//= require_tree .

※上記だけでは、turbolinksを停止できない場合があります。
turbolinksの停止のさせ方は、今までの実装によって異なります。

※turbolinksを削除する方法以外にも、jsファイルでtuborlinksを読み込むことで競合を避ける方法もあります。

参考
turbolinks/turbolinks-ios

④j Queryを記述するためのファイルを作成します。
Ruby on rails内では、JavaScriptファイルをassets/javascripts以下に作成します。

app /assets / javascripts / message.js

2. フォームが送信されたら、イベントが発火するようにする。

message.js
$(function(){//from要素         //submitイベント $('#new_message').on('submit',function(e){e.preventDefault()// console.logを用いてイベント発火しているか確認})}

●解説
・フォームの要素を取得して、フォームが送信された時にon()メソッドを使ってイベントが動くようにします。フォームの要素を取得するには、メッセージ送信フォームのid属性をブラウザの検証ツールを使って調べます。

・「on()」は、さまざまなイベント処理を記述するために使われるメソッドになります。一般的な構文としては以下の通りです。
対象要素.on(イベント名,セレクタ,データ,関数)

. event.preventDefauit();
preventDefalt()で送信ボタンによるフォーム送信処理をキャンセルします。
「イベント」とは、分かりやすい例で言うと、フォームのテキストエリアの入力やチェックボックスのチェック、リンクのクリックなどが挙げられます。
preventDefault()でイベントがキャンセルされると、テキストエリアの入力やチェックボックスのチェック、あるいはリンク先への遷移は行われません。

console.logなどを用いて、フォームが送信されたときにイベントが発火しているかどうかを確認しておきましょう

3.非同期通信でメッセージを保存するようにする

フォームに入力されたデータを取得したら、必要なAjax関数のオプションを揃えて非同期通信を行います。
message.jsを以下のように編集します。

message.js
$(function(){$('#new_message').on('submit',function(e){e.preventDefault();varformData=newFormData(this);//formDataを取得varurl=$(this).attr('action');//urlを取得$.ajax({url:url,//送信先のurltype:'POST',//httpメソッドdata:formData,//コントローラーへ送信するデータdataType:'json',//応答データの種類processData:false,contentType:false,})})})

●解説

varformData=newFormData(this);

・formData
フォーム要素をjavaScriptのオブジェクトにしたもの。
input要素に入力した情報がjavaScriptのオブジェクトとしてキーとバリューとして表されます。
new FormData(フォーム要素)とすることでFormDataを作成できます。
今回FormDataオブジェクトの引数はthisとなっていますが、イベントで設定したfunction内でthisを利用した場合は、イベントが発生したノード要素を指します。今回の場合は、new_messageというIDがついたフォームの情報を取得しています。

varurl=$(this).attr('action');

.attrメソッド
「attr()」は、HTML要素の属性を取得したり設定することができるメソッドになります。
述方法としては、【 対象要素.attr( 属性, (変更する値) ) 】のように引数へ任意の属性を指定します。

また、属性を変更する場合のみ第2引数へ変更したい値を指定します。
今回はイベントが発生した要素のaction属性の値を取得しており、今回のaction属性にはフォームの送信先のurlの値が入っています。
これでリクエストを送信する先のURLを定義することができました。

・processDataオプション

dataに指定したオブジェクトをクエリ文字列に変換するかどうかを設定します。初期値はtrueで、自動的に "application/x-www-form-urlencoded" 形式に変換します。DOMDocumentそのものなど、他の形式でデータを送るために自動変換を行いたくない場合はfalseを指定します。

・contentTypeオプション
サーバにデータのファイル形式を伝えるヘッダです。こちらはデフォルトでは「text/xml」でコンテンツタイプをXMLとして返してきます。
ajaxのリクエストがFormDataのときはどちらの値も適切な状態で送ることが可能なため、falseにすることで設定が上書きされることを防ぎます。FormDataをつかってフォームの情報を取得した時には必ずfalseにするという認識で構いません。

Ajax関数のオプションの参考はこちら

・j Qurey 日本語リファレンス

4.メッセージを保存し、respond_toを使用してHTMLとJSONの場合で処理を分ける

messages_controller.rb
defcreate@message=@group.messages.new(message_params)if@message.saverespond_todo|format|format.html{redirect_togroup_messages_path,notice: 'メッセージを送信しました'}# HTMLリクエストの場合に呼ばれるformat.json# JSONリクエストの場合に呼ばれるend# 一部省略

.respond_to
respond_toを使うとリクエストに含まれているレスポンスのフォーマットを指定する記述を元に条件分岐ができます。
json形式で来たリクエストに対してjson形式のレスポンスを返すための記述を行います。この後、対応するcreate.json.jbuilderを作成することで、レスポンスをjson形式で返すことができます。

5.builderを使用して、作成したメッセージをJSON形式で返すようにする。

. j builder
rails newコマンドでアプリケーションを作成した際にgemfileにデフォルトで記述されているgemで、入力データをJSON形式で出力するテンプレートエンジンです。
jbuilderは、viewと同じように該当するアクションと同じ名前にする必要があります。
messageのcreateアクションに対応するjbuilderのファイルになるので、views/messages以下にcreate.json.jbuilderファイルを作成しす。

app /views / messages/ create.json.jbuilder

create.json.jbuilderのファイルを、決まった文法にそって記述します。JavaScriptで必要なmessageテーブルの情報を渡すようにしましょう。

create.json.jbuilder

json.カラム インスタンス変数.カラム
json.カラム インスタンス変数.カラム
...

上記の文法で記述します。

app/views/messages/create.json.jbuilder
json.user_name@message.user.namejson.created_at@message.created_at.strftime("%Y年%m月%d日 %H時%M分")json.content@message.contentjson.image@message.image_url

これでjbuilderファイルが編集できました。

『リクエストの送信先が正しく設定できているか』と『送信したメッセージのテキストや画像がparamsとしてコントローラで受け取れているか』をbinding.pryで確認しましょう。

参考

.Pikawaka 【Rails】Pryについて徹底解説!
.pry-byebug 3.7.0

6. 返ってきたJSONをdoneメソッドで受け取り、HTMLを作成する。

非同期通信の結果として返ってくるデータは、done(function(引数) { 処理 })の関数の引数で受け取ります。
この引数の値を元に、HTMLを組み立てます。

message.js
functionbuildHTML(message){//条件分岐varimage=message.image?`<img src= "${message.image}">`:"";//messageのhtmlvarhtml=`<div class ="message" data-message-id="${message.id}">
                  <div class ="upper-message">
                    <div class ="upper-message__user-name">
                      ${message.user_name}</div>
                    <div class ="upper-message__date">
                      ${message.date}</div>
                  </div>
                  <div class ="text-message">
                    <p class ="text-message__content">
                        ${content}</p>
                        ${image}</div>
                </div>`returnhtml;}$('#new_message').on('submit',function(e){e.preventDefault();varformData=newFormData(this);varurl=$(this).attr('action')$.ajax({url:url,type:"POST",data:formData,dataType:'json',processData:false,contentType:false}).done(function(data){//返ってきたJSONを受け取るvarhtml=buildHTML(data);})})});

●解説
doneメソッドで受け取ったjsonのdataをそのままbuildHTMLメソッドに渡し、その返り値として完成したHTMLの塊を受け取っています。

HTMLを組み立てる処理は以下のようなメソッドとして定義しましょう。条件(三項)演算子を使って画像がある場合とない場合で条件分岐して記述します。
JavaScriptの条件(三項)演算子は条件式? tureの処理 : falseの処理と記述します。

JavaScript入門】条件(三項)演算子の使い方と活用例まとめ!

また、追加したhtmlはテンプレートリテラル記法で記述します。
・テンプレートリテラル記法
ダブルクオートやシングルクオートの代わりにバックティック文字で囲むことで、複数行文字列や文字列内挿入機能を使用できます。
buildHTMLの引数として渡されたmessageはサーバから返されたデータであるjbuilderのデータであるため、ファイル内で定義したキーとバリューの形式で使用することができます。

7. 6で作成したHTMLをメッセージ画面の一番下に追加する

message.js
.done(function(data){varhtml=buildHTML(data);$('.messages').append(html);//受け取ったHTMLを'.messages'クラスの一番最後に追加する     $('form')[0].reset();//formを空にする})

.appendメゾット 対象の要素の末尾にテキストやHTML要素を追加するメソッド
受け取ったHTMLを、appendメソッドによって.messagesというクラスが適用されているdiv要素の子要素の一番最後に追加します。また、フォームを空にする処理も書きます。

8.メッセージを送信したとき、メッセージ画面を最下部にスクロールする

メッセージが溜まってきて画面いっぱいになった時、メッセージが入っているdiv要素に
overflow: scroll;プロパティが指定できていれば、縦にスクロールできます。

message.js
$('.messages').animate({scrollTop:$('.messages')[0].scrollHeight});// ページ先頭の位置に移動

.animateメソッド
アニメーションを実装するためのメソッドで、オブジェクトの移動や、透過率などを変更することができます。
書き方は以下のようになります。

$(function() {
  $(‘動かす要素名’).animate({
    ‘動かすアニメーション名’: ‘動かす距離’
  });
});

.scrollTop

「scrollTop()」は、ブラウザの画面をスクロールした時の位置(スクロール量)を取得できるメソッドです。
()の中に座標を指定することで任意の場所に飛ぶことができます。

.scrollHeight

overflowした画面上に表示されていないコンテンツを含む要素の内容の高さを表します。
どこの要素の高さを取得しているのかというと、$('.messages')[0]です。
メッセージクラスから生成されるjQueryオブジェクトは配列のように扱うことができるので、[0]と指定することで1番下の要素を取得します。

9. 連続で送信ボタンを押せるようにする

message.jsにこちらの記述を追加します。

message.js
$(".form__submit").prop("disabled",false);

buttonタグなどのdisabled属性の切り替えを、jQueryのprop()によって切り替えます。
htmlの仕様でsubmitボタンを一度押したらdisabled属性というボタンが押せない属性が追加されます。
そのため、disabled属性をfalseにすることでdisabledが外れてボタンが有効になります。

10. エラー時の処理を行う。

message.js
.fail(function(){alert('メッセージ送信に失敗しました');});

サーバーエラーの場合、failの関数が呼ばれます。
alert()メソッドとはアラートを出すメソッドです。
alert( 画面に表示させたい値 )
上記のように引数へ値を指定するだけで、任意の値をポップアップ表示させることができます。この値は、文字列や数値などさまざまな値を指定することが可能です。

これで非同期通信の実装が完成しました。

最後に完成コードを載せます。

message.js
functionbuildHTML(message){varimage=message.image?`<img src= "${message.image}">`:"";varhtml=`<div class ="message" data-message-id="${message.id}">
                  <div class ="upper-message">
                    <div class ="upper-message__user-name">
                      ${message.user_name}</div>
                    <div class ="upper-message__date">
                      ${message.date}</div>
                  </div>
                  <div class ="text-message">
                    <p class ="text-message__content">
                        ${content}</p>
                        ${image}</div>
                </div>`returnhtml;}$('#new_message').on('submit',function(e){e.preventDefault();varformData=newFormData(this);varurl=$(this).attr('action')$.ajax({url:url,type:"POST",data:formData,dataType:'json',processData:false,contentType:false}).done(function(data){varhtml=buildHTML(data);$('.messages').append(html);$("form")[0].reset();$('input').prop('disabled',false);$('.messages').animate({scrollTop:$('.messages')[0].scrollHeight});}).fail(function(){alert("メッセージ送信に失敗しました");});});
message_controller.rb
# 一部省略defcreate@message=@group.messages.new(message_params)if@message.saverespond_todo|format|format.html{redirect_togroup_messages_path(@group),notice: 'メッセージが送信されました'}format.jsonendelse@messages=@group.messages.includes(:user)flash.now[:alert]='メッセージを入力してください。'render:indexendend# 一部省略
app/views/messages/create.json.jbuilder
json.user_name@message.user.namejson.created_at@message.created_at.strftime("%Y年%m月%d日 %H時%M分")json.content@message.contentjson.image@message.image_url

Railsチュートリアルメモ - 第6章

$
0
0

メモの目次記事はこちら

Railsチュートリアル第6章へのリンク

6.1 Userモデル

Active Recordの使用方法についての章。Active RecordはたぶんRailsの中で最も核となるライブラリ。

ポイント

  • 以下コマンドでモデルを生成し、DBに反映できる
    • rails generate model User name:string email:string
    • rails db:migrate
  • Active Recordを使うことで、RailsからDBの詳細を隠蔽し、切り離すことができる。
  • SQLについて学ばずにDBに対してCRUD操作を行える。

6.2 ユーザーを検証する

バリデーションの実装方法についての章。

ポイント

  • テストクラスのsetupメソッド内に書かれた処理は、各テストが走る直前に実行される
  • modelの検証でエラーになった内容はuser.errors.full_messagesで確認できる
  • %w[]で文字列の配列を作れる e.g. %w[foo bar baz] => ["foo", "bar", "baz"]
  • callbackメソッド => ある特定の時点で呼び出されるメソッド

6.3 セキュアなパスワードを追加する

パスワードのハッシュ化保存の実装

ポイント

has_secure_passwordについて

  • Railsではhas_secure_passwordを記載するだけでパスワードのハッシュ化保存を実装できる(実際は別のライブラリを使うことが多いらしい)
  • has_secure_passwordをモデルに記載するだけで実装できるが、使用するには以下2点を満たす必要がある
    1. モデルにpassword_digest:stringを追加する必要がある
    2. 'bcrypt'gemが必要なので、Gemfileに追記してbundle installしておく
  • has_secure_passwordを追加すると、authenticateメソッドが使えるようになる

マイグレーション(カラムの追加)

  • rails generate migration add_password_digest_to_users password_digest:string
    • rails generate migrationで指定するマイグレーション名の最後に_to_usersを付与しておくと、usersテーブルへのカラム追加だと判断してファイルを作成してくれる。

基本文法

  • 多重代入 (Multiple Assignment)
    • 次のような文法で2箇所に同時に同じ値を代入できる
      • @user.password = @user.password_confirmation = "a" * 5
  • モデルのvalidateの文法
    • validates :name, presence: true, length: { maximum: 50 }

Python3 文系学生の独学メモ① 関数定義

$
0
0

1から100まで表示するプログラム

x = 0
while(x < 100):
    x += 1
    print(x)

defで定義して同様のプログラムを書く

def xplus(x):
    return x + 1

a = 0

while(a < 100):
    a = xplus(a)
    print(a)

上記のプログラムについてteratailで質問しています。
https://teratail.com/questions/234617

コラッツの問題(奇数なら+1、偶数なら÷2...を解く)

x = int(input())
while(x > 1):
    if x % 2 == 0:
        x //= 2
        print(x)
    else:
        x += 1
        print(x)

上記のプログラムについてteratailで質問しています。
https://teratail.com/questions/234626

【JavaScript】selectbox(プルダウン)の使い方メモ

$
0
0

1.はじめに

かなり昔に、jqueryのプラグインを使って100万行くらいのデータをグラフ化する
ツールを作る依頼を受けた。
その時に初めてjavascriptを調べて、ツールを作ったがそれ以来触ることが
無くなってしまった。

思い出すためにも、恐竜と鳴き声の回数をセットしたセレクトボックスを用意して
ボタンを押すと鳴き声を表示させるプログラムを練習用として作ってみた。

2.恐竜の鳴き声を指定回数表示してみよう。(ソース)

今回のポイント

  • セレクトボックスの使い方
  • セレクトボックスの値の取得の仕方
  • 指定場所のテキストの変更

鳴かせる恐竜は、我らがダークヒーロー「ティラノサウルス」と、
走る鎧こと「ユーオプロケファラス」
にした。
ユーオプロケファラスは尻尾攻撃が得意とのこと(jwaより)
ユーオプロケファラスの鳴き声は知らないので(というかティラノサウルスの声すら
聞いたことない)、尻尾攻撃の音にしてみた。

下のコードを記載したファイル(こんなのコピーする人がいるか
疑問だけど)を適当なところに保存して実行すると、実行イメージのように表示される。

dino_cry_for.html
<!DOCTYPE html><p>鳴き声<br><spanid="d_cry"></span></p><br><formname="test"><selectname="dino"><optionvalue="Tyranno">ティラノサウルス</option><optionvalue="Euoploce">ユーオプロケファラス</option></select><selectname="cry_n"><optionvalue="2">2</option><optionvalue="4">4</option><optionvalue="6">6</option></select></form><inputtype="button"value="dinosor_crying!!"onClick="OnClickCrying()"/><script type="text/javascript">functionOnClickCrying(){//セレクトボックスのidconstdino1=document.test.dino;// 値(数値)を取得constnum_dino=dino1.selectedIndex;constcry_n1=document.test.cry_n;//セレクトボックスの何番目を選択したかconstidx_cry=cry_n1.selectedIndex;//セレクトボックスで選択した値を取得constnum_cry2=cry_n1.options[idx_cry].value;varstr_dino="";varc_dino="";if(num_dino==0){c_dino="おおーん!!";}else{c_dino="ぴしっ!";}for(vari=0;i<num_cry2;i++){str_dino=str_dino+c_dino+"<br>";}document.getElementById("d_cry").innerHTML=str_dino;}</script></html>

3.実行結果

js_dino_for.jpg

Viewing all 21583 articles
Browse latest View live