Progate Ruby on Rails5
Ruby on Railsの環境構築をしてみよう!
windowsOS
- Ruby のインストール(略)
- SQLite3のインストール
- https://sqlite.org/index.html にアクセスして Download
- Precompiled Binaries for Windows (sqlite-dll-win64-x64-3320100.zip) (64bitの場合) をインストールして,
sqlite3.dll
をC:\Ruby26-x64\bin
にコピー (32bitのときは32bit用のものをインストール) - Precompiled Binaries for Windows (sqlite-tools-win32-x86-3320100.zip) をインストールして,
sqlite3.exe
をC:\Ruby26-x64\bin
にコピー
- Rails のインストール
gem install rails -v "5.2.3" # gem はパッケージマネージャー rails -v
- Rails アプリケーションの作成
rails new sample_app -G # sample_app はアプリケーション名 ## 以下は, sqlite3のインストールに失敗してエラーが出た場合 ### 多分, Installing sqlite3 1.4.2 with native extensions のこと cd sample_app ridk exec pacman -S mingw-w64-x86_64-sqlite3 bundle install ## 以上, sqlite3のインストールに失敗してエラーが出た場合
- ローカルにサーバを立てる
cd sample_app rails s # これで localhost:3000 にアクセスできる # Ctrl + C でサーバは止まる
macOS
- Homebrew, rbenv はインストール済みとする
rbenv versions # Rails 5系はRuby 2.2.2以上対応
- Rails のインストール
gem install rails -v "5.2.4.1" rails -v
- アプリケーションの作成とローカルにサーバを立てる
rails new sample_app # sample_app はアプリケーション名 cd sample_app rails s # これで localhost:3000 にアクセスできる # Ctrl + C でサーバは止まる
Ruby on Rails5 I
- アプリケーションの作成:
$ rails new アプリケーション名
サーバの起動:
$ rails server
ページの生成:
$ rails generate controller home top
(コントローラー名, アクション名)- views:
app/views/home/top.html.erb
が自動生成される - controller:
app/controllers/home_controller.rb
が自動生成され,top
アクションが追加される。 - routing:
config/routes.rb
にget "home/top" => "home#top"
が自動追記される。 - scss:
app/assets/stylesheets/home.scss
が自動生成される
- views:
ただし, コントローラーが存在する場合はこのコマンドは使えないので,
- routing を追記する
- 対応する controller のアクションを追記する
- それで呼び出すファイルを新規作成する
処理の流れ
GET /home/top
を受け取る- routing により,
home
コントローラーのtop
アクションが呼ばれる - それが,
app/views/home/top.html.erb
を返す。
構成要素
- views: ページの見た目を作るためのHTMLファイル
- controller: ブラウザに返すビューを views フォルダの中から見つけ出して返す役割をもつ。コントローラ内のメソッドをアクションと呼ぶ。
- routing:
get "URL" => "コントローラー名#アクション名"
という文法(対応表のような感じ)で, リクエストを受け取り, コントローラーを呼び出す。
- ルーティングは手動で変更可能
/
はget "/" =>
/top
はget "top" =>
<a href="/top">
のようにリンクを張る
- 「stylesheets」フォルダの中に保存されているCSSファイルはすべてのビューに適用される。
- 画像は
public
フォルダに置く。public/hoge.png
は<img src="/hoge.png" >
のようにアクセスできる。
Ruby on Rails5 II
$ rails generate controller
は$ rails g controller
と省略可能- view ファイルの拡張子の
erb
はEmbedded Ruby
- コードは
<% %>
で囲む - 変数埋め込みは
<%= 変数名 %>
- コードは
# view で使う変数は一般にアクションで定義する # ただし, その場合の変数名は @ で始める必要がある def index @items = ["A", "B", "C"] end
<% @items.each do |item| %><!-- 呼び出しも当然 @ が付く--> <li><%= item %></li> <% end %>
# app/models/post.rb class Post < ApplicationRecord end
$ rails console # Post のコンストラクタやsaveメソッドはApplicationRecordを継承している > post1 = Post.new(content: "Hoge") # レコードの生成 > post1.save # DB に登録 > p1 = Post.first # DB の最初のレコードの取り出し > p1.content # カラムの値をみる。 > pall = post.all # 全てを配列として取り出す > post.all[0].content
- 例えば, 次のように DB の値を埋め込む
def index @records = Post.all end
views/layouts/application.html.erb
に共通のHTMLを書いておく- つまり, 表示の共通部分(ヘッダなど)はここに書いて, それ以外を各
erb
ファイルにこれまで通り書く。それが, このファイルの<%= yield %>
に埋め込まれて表示される。
- つまり, 表示の共通部分(ヘッダなど)はここに書いて, それ以外を各
- リンク生成メソッド link_to
<%= link_to("hoge","/top") %>
は<a href="/top">hoge</a>
として埋め込まれる
Ruby on Rails5 III
モデル名.find_by(カラム名: 値)
で, カラムがその値なレコードを返す。- パラメータをとるルーティング
# config/routes.rb Rails.application.routes.draw do get "posts/index" => "posts#index" # ルーティングは合致するURLを上から順に探す。 get "posts/:id" => "posts#show" # /posts/hoge などが該当 end
# app/controllers/posts_controller.rb class PostsController < ApplicationController def index @posts = Post.all.order(created_at: :desc) # created_at カラムの値を降順(:desc)に並び替えた配列にする end def show @id = params[:id] @post = Post.find_by(id: @id) end end
<!-- app/views/posts/show.html.erb --> <p><%= "idが #{@id} のとき" %></p> <p><%= @post.content %></p>
- post
# config/routes.rb Rails.application.routes.draw do get "posts/new" => "posts#new" post "posts/create" => "posts#create" # post を受ける end
# app/controllers/posts_controller.rb class PostsController < ApplicationController def new end def create @post = Post.new(content: params[:content]) # params[:content] でリクエストパラメータを受け取る # 代わりに content: "hoge" のようにすればデフォルトの値を設定できる。 @post.save redirect_to("/posts/index") # view を用意する代わりにリダイレクトする end end
<!-- app/views/posts/new.html.erb --> <%= form_tag("/posts/create") do %> <!-- <form action="/posts/create" method="post"> --> <!-- 上で, do , 下で, end を忘れないように --> <textarea name="content"></textarea> <input type="submit" value="投稿"> <% end %> <!-- 今回は </form> -->
Ruby on Rails5 IV
- DB の書き換え
post = Post.find_by(id: 1) # インスタンスをDBから取り出して post.content = "hoge" # 代入するだけ post.save # 変更後のインスタンスをDBに保存
- DB のレコードの削除
post = Post.find_by(id: 1) # インスタンスをDBから取り出して post.destroy # 破棄して DB 更新
- 編集ページ
get "posts/:id/edit" => "posts#edit"
- 編集ページ
app/views/posts/edit.html.erb
の用意- edit コントローラで
@post = Post.find_by(id: params[:id])
とレコードを変数としてページに渡す <textarea name="content"><%= @post.content %></textarea>
のように初期値を設置する/posts/:id/update
とかに post する(:id
は@post.id
を埋め込む)
- edit コントローラで
- 表示ページ(
/posts/show/:id
) から,<%= link_to("編集", "/posts/#{@id}/edit") %>
のようなリンクを張っておく) - アクション
posts#update
の用意params[:id]
,params[:content]
を受け取る- レコードを書き換えて
/posts/#{params[:id]}/show
とかにリダイレクトする
- 破棄(ページを用意しない分簡単)
link_to("破棄", /posts/#{@post.id}/delete, {method: "post"})
で/posts/:id/show
とかからリンクを張るlink_to
の第三引数でメソッドを指定できる(デフォルトでget
)
Ruby on Rails5 V
- validation
# app/models/post.rb class Post < ApplicationRecord validates: content, {presence: true, length: {maximum: 140}} # これで Post のインスタンス(e.g. post)は content カラムが # 空, または 文字数140字以上 # だと post.save 出来なくなる # さらに, post.errors.full_messages にエラーメッセージの配列が格納される。(デフォルトは空の配列) end
- save の戻り値は true または false なので, これを受けてその後の動きを変更すれば良い
- 表示
redirect_to("URL")
: get "URL" にリダイレクトされる。そのため, ルーティングされたコントローラのアクションを経由する。(e.g.redirect_to("/posts/index")
)render("PATH")
: 別のアクションを経由せずに、直接ビューを描画する。PATH は pwd が views で, 拡張子はいらない。(e.g.render("posts/index")
)
- ページ上に1度だけ表示(リロードすると消える)されるメッセージをフラッシュと呼ぶ。
- アクションで
flash
というハッシュをflash[:hoge] = "fuga"
とすると, view でflash[:hoge]
を使用できる。 - この
hoge: "fuga"
は1度表示された後に自動で削除される。
- アクションで
Ruby on Rails5 VI
- name, email カラムを持つ users データベースの作成
$ rails g model User name:string email:string
$ rails db:migrate
- validation
# app/models/user.rb class User < ApplicationRecord validates :name, {presence: true} validates :email, {presence: true, uniqueness: true} # 他のレコードと重複無し end
Ruby on Rails5 VII
- テーブルの新規作成
# db/migrate/20170418070645_create_users.rb class CreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| t.string :name t.string :email t.timestamps end end end
# app/models/user.rb class User < ApplicationRecord end
- テーブルのカラム追加
$ rails g migration add_image_name_to_users
: マイグレーションファイルのみの作成db/migrate/20200531023644_add_image_name_to_users.rb
が自動生成される。- これに下のように追記する。
# db/migrate/20200531023644_add_image_name_to_users.rb class AddImageNameToUsers < ActiveRecord::Migration[5.0] def change # ここから先を追記する add_column :users, :image, :string # テーブル名, カラム名, データ型を指定する。 # 同じ要領で, remove_column でカラムの削除が可能 end end
- 画像の投稿
<%= form_tag("/users/upload",{multipart: true}) do %> <!-- {multipart: true} を与える --> <input type="file" name="gazo"> <!-- type="file" --> <input type="text" name="name"> <input type="submit" value="投稿"> <% end %>
- これを
ユーザid.jpg
としてDBにファイル名を登録し, public/user_images/ユーザid.jpg
としてファイル本体を保存する
# app/controllers/users_controller.rb class UsersController < ApplicationController def update @user = User.find_by(id: params[:id]) @user.name = params[:name] if params[:gazo] # 画像がある場合のみ @user.image_name = "#{@user.id}.jpg" # このファイル名で保存するので一意である必要がある。 image = params[:gazo] # 画像のバイナリが入っている # 保存先のパスと image.read File.binwrite("public/user_images/#{@user.image_name}", image.read) # cf. テキストの保存は write メソッド # File.write("public/sample.txt", "Hello World!") end @user.save end end
Ruby on Rails5 VIII
- ルーティングで, 同じURLにget, postを設置可能。ただし, コントローラーは違うアクションにする必要がある。
- ログイン機能
- ユーザ名とパスワードを入力するフォームを作る
- ユーザ名(
{uniqueness: true}
なカラム)とパスワードを "/login" とかに post する <input type="password">
: 入力文字が伏字になる。
- ユーザ名(
- post "/login" をうけるコントローラーを作る
@user = User.find_by(name: params[:name], password: params[:password])
- 複数カラムをアンド検索することができる
@user
が存在するかで挙動を分岐- あれば
flash[:notice]
とかしてログインページにリダイレクト
- あれば
- 存在しなければ, ログインフォームを再描画
- リダイレクトではないのは, 受け取ったパラメータを @email, @password に代入してこれを埋め込むため。
- エラーメッセージは @error_message とかに固定値を代入してこれを埋め込めばよい
- 最初にフォームをGETしたときはこれらは
nil
なので, <%= @email %> で何も埋め込まれない?
- 最初にフォームをGETしたときはこれらは
- ログイン後のユーザー情報の保持
- ユーザ情報の表示
- view側で管理する方法(あんまりよくない)
app/views/layouts/application.html.erb
(各htmlを埋め込む先のファイル) に<% current_user = User.find_by(id: session[:id]) %>
を書いて置く- この共通htmlで
<% if current_user %>
でログイン中かで分岐可能 - 各ページで
<% current_user.name %>
でカラムにアクセス可能
- この共通htmlで
- controller で before_action として定義する方法
- view側で管理する方法(あんまりよくない)
- ユーザ名とパスワードを入力するフォームを作る
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base before_action :set_current_user # ※ 全アクションの前に実施するアクション def set_current_user @current_user = User.find_by(id: session[:user_id]) end def authenticate_user # ログインしていない場合(@current_user == nil)に表示させないためには, アクションの前にリダイレクトさせてしまえばよい。 if @current_user == nil flash[:notice] = "ログインが必要です" redirect_to("/login") # 当然だが, このページをログイン必須にするとリダイレクトがループする。 end end def forbid_login_user # 逆にログインしているとアクセスできないページ if @current_user flash[:notice] = "すでにログインしています" redirect_to("/posts/index") end end def ensure end
# app/controllers/users_controller.rb class UsersController < ApplicationController # 上の before_action :set_current_user (※の行)は継承されている before_action :authenticate_user, {only: [:index, :show, :edit, :update]} # :authenticate_user は継承されている。 # only をつけた場合は配列で指定されたアクションの前だけに実行される。 before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]} before_action :ensure_correct_user, {only: [:edit, :update]} def index @users = User.all end # 以下略 def ensure_correct_user # ここで定義することもできる if @current_user.id != params[:id].to_i # これで id が違う場合に書き換え系のアクション にはアクセスできなくなる。 flash[:notice] = "権限がありません" redirect_to("/posts/index") end end end
Ruby on Rails5 IX
- インスタンスメソッドをmodelに定義することも可能
# app/models/post.rb class Post < ApplicationRecord validates :user_id, {presence: true} def user # 自身(postsテーブルのレコード)のuser_id と一致する id を持つusersテーブルのレコードを返す return User.find_by(id: self.user_id) end end
- レコードの検索
find_by
メソッドはレコードを一件だけ見つけてそのレコードを返す。where
メソッドはレコードを全て見つけて, レコードの配列を返す。(引数などはfind_by
と同じ。)
Ruby on Rails5 X
- コントローラーは手動でも作成可能(viewファイルが不要な時)
- html要素に対して
link_to
を使うとき, 第一引数の文字列の代わりに下のようにする。- 第二引数以降は同じ。
<%= link_to("URL", {method: "post"}) do %> <!-- 上で do が必要, 下で end が必要, --> <img src="URL"> # 画像など <% end %>
Ruby on Rails5 XI
- Gemfile (package.jsonみたいな感じ)
gem 'パッケージ名', 'バージョン'
を列挙- バージョンの指定はオプションで, 範囲指定もできる。
- 指定なしの場合は最新のものとなる。
- dependencies, devDependencies よりも細かくインストールする環境を指定できるらしい。
source 'https://rubygems.org' gem 'rails', '5.0.3' # Use Puma as the app server gem 'puma', '3.6.2' # Use SCSS for stylesheets gem 'sass-rails', '5.0.6' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '3.0.4' gem 'pry-rails', '0.3.4' # Use jquery as the JavaScript library gem 'jquery-rails', '4.2.2' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks gem 'turbolinks', '5.0.1' group :development, :test do gem 'sqlite3', '1.3.13' gem 'byebug', '9.0.6', platform: :mri gem 'web-console', '3.4.0' gem 'listen', '3.0.8' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring', '2.0.1' gem 'spring-watcher-listen', '2.0.1' end
- Gemfile.lock:
bundle
などで自動生成されるgemの依存関係を示したもの(package-lock.jsonみたいな感じ) $ bundle install
Gemfile.lock
を元にインストールを行います。- ただし,
Gemfile.lock
になく,Gemfile
にある gem があるとき, 必要な gem たちをインストールした上でGemfile.lock
を更新する。($ npm ci
に近い)
$ bundle update
$ npm i
にほぼ同じ。
パスワードの暗号化
gem 'bcrypt'
- パスワードを暗号化したいDBテーブルのmodelのクラスを下記のようにする。
- そのうえで, カラム名は
password_digest
とする。 - ただし, テーブル上のカラム名は
password_digest
だが, パスワードのセットはpassword
に対して行う(それがpassword_digest
)に自動反映される。 - パスワードの比較は, レコードに対して authenticate メソッドを使う
@user.authenticate("hoge")
で,@user
のpassword_digest
が文字列 hoge を暗号化したものに一致するかを真偽値として返す。
# app/models/user.rb class User < ApplicationRecord has_secure_password end
Progate Ruby
Rubyの開発環境を用意しよう!
windowsOS
- インストール
- https://rubyinstaller.org/downloads/
-
=> Ruby+Devkit 2.6.5-1 (x64)
- I accept the License を選択した後は全てNext
- (コマンドプロンプトが出現したら)
1,2,3
と入力して Enter
- 動作確認
ruby -v echo puts 1 + 2 > fuga.rb ruby fuga.rb
macOS
# macOS には標準でインストールされている ruby -v # homebrew はインストール済みの前提 rbenv -v # command not found なはず brew install rbenv ruby-build rbenv -v echo $SHELL ## /bin/bash の場合 echo 'eval "$(rbenv init -)"' >> ~/.bash_profile source ~/.bash_profile ## /bin/zsh の場合 echo 'eval "$(rbenv init -)"' >> ~/.zshrc source ~/.zshrc rbenv install --list rbenv install 2.7.1 rbenv versions rbenv global 2.7.1 ruby -v
Ruby I
- Python との共通点
- Python との相違点
- 13/4 -> 3
- コーディング規約の例: https://shugo.net/ruby-codeconv/codeconv.html
- 文字列中での変数展開:
#{変数名}
を文字列に入れる (ダブルクォーテーションの場合のみ) - if文の記述(動きはPythonと同じ)
- true, false (Python は True, False)
- puts のようなメソッドの括弧は省略可能(省略しなくてもよい)
if a > 1 # 後ろに : はつけない puts "a>1" # インデントは 2つのスペース を推奨(インデント自体必須ではない) elsif a < 0 # elif でも, elseif でもない puts "a<1" else puts "a==1" end # end で閉じる
- 論理演算に関して
and
,&&
,or
,||
がある- 違いは優先度のみ (
&&
>=
>and
) - 評価値はオペランドの一方(JavaScriptと同じ)
A && B
で A が偽なら A そのもの, A が真なら B そのものを返す。
Ruby II
- Python との共通点
- 配列:
numbers = ["A","B","C"]
と[]
によるアクセス
- 配列:
Python との相違点
- ハッシュ:
info = {"name" => "hoge", "age" => 23}
- アクセス, 要素の追加, 更新などは同じ
- 存在しない要素へのアクセスは
nil
となるnil
はputs
で表示されない。nil
の評価はfalse
- 存在しない要素へのアクセスは
- キーをシンボルとすることもできる。(
:name
)- シンボルは文字列に似ているが, 互換性はない
- キーにシンボルを用いるとき,
:name => "hoge"
はname: "hoge"
と書ける- このときも
info[:name]
- このときも
- アクセス, 要素の追加, 更新などは同じ
- ハッシュ:
表示メソッド
puts
: 引数が配列のとき各要素を出力(要素ごとに改行される)。引数が文字列のとき文字列はクォートで囲まれない。print
: 引数が配列のとき配列として出力。引数が文字列のとき文字列はクォートで囲まれない。p
: 引数が配列のとき配列として出力。引数が文字列のとき文字列はクォートで囲まれる。
items.each do |item| # 配列 items の各要素を item に格納しながらループ puts item end
Ruby III
def method1 # ruby のメソッドはいわゆる関数 puts "hoge" end # endつける method1 # 引数無しのメソッド呼び出しの() はなくても分かるので普通省略する def method2(arg1) puts "#{arg1}です" return arg1 end
- 真偽値を返すメソッド名は慣用的に
isEmpty
ではなくempty?
とする - キーワード引数(呼び出し順序は不問になる)
def method3(a,b: 3) # b のデフォルト値は 3(デフォルト値は省略可能。b: とする。(:b ではない)) return a + b # ここでは :b ではなく b end method3(2, b: 4) # 呼び出しはシンボルとして method3(2, :b => 4) # なので, これも可
Ruby IV
class Hoge attr_accessor :name # name はインスタンス変数 def initialize(name) # コンストラクタ(キーワード引数を用いてもよい) self.name = name # this ではない end def getName # インスタンスメソッド return self.name end end hoge = Hoge.new("fuga") # インスタンス生成 puts hoge.name puts hoge.getName
require "ファイルパス"
ファイルパスは拡張子省略gets.chomp
入力を文字列として受け付ける
a = gets.chomp.to_i # to_i は整数に変換するメソッド
Ruby V
- 継承
class 子クラス < 親クラス
- オーバーライドの動作は同じ
- オーバーライドしたメソッドの中で super メソッドを呼び出すと親クラスの同名のメソッドとされる。(super には必要なら実引数を渡す)
- ライブラリの利用
require "date" date = Date.new(2020,5,29) puts date # 2020-05-29 if date.sunday? # デフォルトで用意されているメソッド today = Date.today # today はクラスメソッド
Progate PHP
PHP I
- 機能はHTMLだが, 拡張子はphp。
- 冒頭は
<!DOCTYPE html>
- 冒頭は
<?php ?>
の中がphpが有効な領域。この領域がHTMLに変換された上で埋め込まれて解釈される。- 文末
;
。ただし, 一行の<?php ?>
に1文であれば省略できる。 - コメントは
//
- 文字列のクォートは不問
- 変数定義
変数名 = 値;
ただし, 変数名は$
から始まり, 次は英字。 ++
,--
もある- 変数は
<?php ?>
をまたいでも有効。 - 文字列や変数の連結は
文字列.文字列
.=
も存在する。
- ダブルクォーテーションで文字列を囲んだ場合、文字列の中で
{変数名}
として変数を埋め込み可能- シングルクォーテーションで文字列を囲んだ場合は変数展開されない。
true
,false
,&&
,||
,!
if(条件){} elseif(条件) {} else {}
:elseif
の間にスペースがないことに注意switch(式){}
仕様は C++ に同じ。for($i=0;$i<5;$i++){}
while(条件){}
break;
,continue;
: while, for, foreach 等の繰り返しで利用- 配列
- 配列の初期化:
配列名 = array(値1, 値2, ・・・);
- 末尾に追加:
配列名[] = 値;
- 値の上書き:
配列名[2] = 値;
- 配列の初期化:
- 連想配列
- 配列の初期化:
配列名 = array('キー名' => '値1', ・・・);
- 値の追加, 上書き:
配列名[キー] = 値;
- 配列の初期化:
- 配列ループ
echo
: 後ろに置いたものが評価されて埋め込まれる。(echo "hoge";
,echo 2 + 3;
)- 埋め込まれるだけで, 改行はされない。
echo '<br>';
や,echo $hoge."<br>";
など改行タグを埋め込めばよい。
- 埋め込まれるだけで, 改行はされない。
- 組み込み関数
strlen(文字列)
: 文字列の文字数を返す。count(配列)
: 配列の要素数を返す。rand(2,4)
:2,3,4
のいずれかをランダムに返す。
<?php // 使い方 $radius = 4; $area = $radius * $radius * 3.14; echo $area; ?>
- 関数定義
<?php function add($arg1, $arg2){ // 関数名に $ 不要 $tmp = $arg1 + $arg2 echo $tmp; return $tmp; // 呼び出しは add(3,5) } ?>
- リクエストの受け取り
$_POST
: form で POST するとContent-Type: application/x-www-form-urlencoded
となり, ボディーがクエリになる。そのリクエストを受ける側において,$_POST
にそれが json として格納される。(ref. https://developer.mozilla.org/ja/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data)$_GET
: GET要求を受けた時, そのリクエストのクエリパラメータが json として格納される。form で GET したときなど。
- 以下, 送信フォームと受信部
<!-- php 要素を持たない部分は <?php ?> は不要--> <form method="post" action="sent.php"> <!-- {AAA:"...",BBB:"..."} をphpに渡す --> <input type="text" name="AAA"> <!-- name属性がjsonのキー, 記述(単一行)がvalueとなる --> <textarea name="BBB"></textarea> <!-- name属性がjsonのキー, 記述(複数行可)がvalueとなる --> <!-- この下に送信ボタンを作りましょう --> <select name="CCC"> <?php for($i=0;$i<100;$i++) { echo "<option value='opt{$i}'>選択肢{$i}</option>"; // 変数展開されて, <option value='opt1'>選択肢1</option> とかが埋め込まれる // ブラウザに表示されるのは「選択肢0」から「選択肢99」 } ?> </select> <input type="submit" value="送信"> <!-- 送信ボタンで, value属性でボタンの文字を指定 --> </form>
<!-- sent.php 送信ボタンを押すと, phpが埋め込まれたhtmlが表示される --> <?php echo $_POST["CCC"]."<br>"; // opt0.<br> , opt1.<br>, ... のいずれかが埋め込まれる。 // $_POST に post した json が格納されている。 ?>
PHP II
- クラス
class Hoge { //クラス名に $ 不要 // public, private は Java 等と同じ。 public $prop1; // $ 必要 private $prop2 = ""; // 初期化も可能 public function __construct($prop1){ // コンストラクタの名前は __construct で固定 $this->prop1 = $prop1; } public function method1(){ // メソッド名に $ 不要 echo $this->prop1."<br>"; // $this はクラス内のメソッドの定義の中でのみ使用可能 return $this->prop1; // return も可能 } } $hoge = new Hoge("hoge"); $hoge->prop1 = "fuga"; // プロパティ名に $ 不要 $hoge->method1();
- PHP のコードを各部分は, 埋め込まない部分は大きな塊で書き, 埋め込む部分は小さく書く。
- 次の二つは等価(下のようにすると, HTML の埋め込みが分かりやすい)
{
を:
に}
をendforeach
にendif
endfor
endwhile
endswitch
- ちなみに,
if():
else:
endif
<?php $words = array("hoge", "fuga"); foreach($words as $word){ echo "<p>".$word."</p>"; } ?>
<?php $words = array("hoge", "fuga"); ?> <?php foreach($words as $word): ?> <p><?php echo $word ?></p> <?php endforeach ?>
- 他のファイルの埋め込み
require("ファイルパス")
: 埋め込むrequire_once("ファイルパス")
: 1回目に呼び出された時だけ埋め込む
PHP III
- クラスプロパティ
- 定義:
public static $hoge = 0;
のようにstatic
をつける(Javaと同様) - クラス外でのアクセスは
$instance->hoge
ではなくHoge::$hoge
($
の位置に注意) - クラス内でのアクセスは
$this->hoge
ではなくself::$hoge
($
の位置に注意)
- 定義:
- クラスメソッド(個々のインスタンスのデータに関係ない処理を行いたい時)
- 定義:
public static function fn() {}
のようにstatic
をつける(Javaと同様) - アクセスは
$instance->fn()
ではなく,Hoge::fn()
($
無しに注意)
- 定義:
- 継承
インスタンス instanceof クラス名
->true
,false
PHP IV
- クエリパラメータ
URL?キー=値&キー=値
Progate Go
- コーディング規約に関して: https://golang.org/doc/effective_go.html
Go I
go fmt ファイル名
でフォーマットできるらしい。- 文法の特筆事項
- コメントは
//
または/* */
- 文末セミコロンなし
- 13/3 -> 4
- 数値, 文字列, 真理値 とその演算あたりは C++やJava とほぼ同じ。
- 変数定義は
var 変数名 変数型
。初期化しなくてもよい。- 初期化は
var hoge int = fuga
であるが, 型は省略可能。(TypeScriptに近い)- 特に,
var hoge = 10
など自明なとき。 - さらに, 上は
hoge := 10
と省略して定義することもできる。 hoge = 10
は定義済み変数に対する代入。
- 特に,
- 初期化は
- 変数型
- 文字列は
string
型 (+
で連結できる)で, ダブルクォート限定。 int
- 文字列は
- 変数関連エラー
- 現時点で未定義な変数の呼び出し
- 定義済み変数の再定義
- 定義済み変数の未使用
- 変数に対して定義された時と違う型を代入
- コメントは
if 条件 {処理} else if 条件 {処理} else {処理}
で条件に括弧不要switch 式 {処理}
も同様に式に括弧不要case 3,5:
とすれば 3または5 のときと解釈される。case
をbreak
無しで終えると, 自動でbreak
が付与される。
package main func main() { var hoge int = 10 // 変数の初期化 println("Hello", "World") // 標準出力は Python に近い if hoge > 10 { // 括弧不要。囲ってもエラーにはならないが。 println(hoge) } }
Go II
- 使用しないパッケージをインストールするとエラーになる。
- パッケージ
fmt
: 出力関連fmt.Println()
:println()
より表示できるデータ型の種類が多いfmt.Printf()
: 書式付き出力。第2引数以降にに埋め込む値を並べる。%s
: 文字列,%d
: 整数- 型が違うとエラーになる。
math/rand
: 乱数関連。import "math/rand"
rand.Intn(10)
: 0,1,2,...,9 の乱数を生成して返す。import "time"
したうえでrand.Seed(time.Now().Unix())
を最初に呼び出すとよい。
package main // import よりも先に書く import "fmt" // fmt 標準パッケージのインストール func main(){ //ファイル実行時に呼び出される関数。 fmt.Println("hoge") // 自動で改行される fmt.Printf("%s is Hoge, %s is Fuga\n", "Hoge", "Fuga") // 自動で改行されない }
for i:=0; i<3 ;i++ {処理}
のように,for
も C++ から条件の括弧を取った形。var i int = 0
と初期化するとエラーになるので, 必ず:=
の省略形を使う
Go III
fmt.Scan(&変数名)
: 標準入力を受け取って変数に代入する(変数のポインタを渡している)- 関数の特筆事項
- 利用するより先に定義しなくてもよい。(変数は先に定義する必要)
- 引数は値渡し
// 関数定義 fn2("hoge") で呼び出せる。 func fn2(s string) string { // 引数や戻り値の型の指定は TypeScript に近い // s は値渡し。 return s + s }
Go IV
- 変数のポインタは
&変数名
で得られる。Type
のポインタの型は*Type
Type*
ではない。var intPtr *int = &intNum
としたとき,*intPtr
はintPtr
の指す変数(すなわちintNum
)と同一になる。
Progate Java
C++ と文法がかなり近いので, 比較してまとめる。
Java I
- C++ との共通点
- 文字, 文字列のクォーテーション
- 文末セミコロン
- コメント
- 四則演算
- 文字列の連結
- 変数, 変数の
=
による初期化, 代入 - ODR
int
+=
,++
- 暗黙の型変換(ルールが同じかは分からない)
(int)x
等のキャスト- インデントできるが文法的な強制力はない
- C++ との相違点
String
- 変数名は camelCase 推奨
- 下記基本型(Javaは速度ではなく汎用性重視)
- 基本型
class Main { public static void main(String[] args) { System.out.println("Hello World"); // 末尾は改行される } }
Java II
- C++ との共通点
true
,false
, 比較演算子&&
,||
,!
if
,switch
,while
,do
,for
(おそらく構文が完全に一致)break
,continue
[]
による配列アクセス
- C++ との相違点
- 拡張for文
Java III
C++ との相違点(クラス)
- Java には関数はない(多分)ので, まとまった処理はクラス内でメソッドとして定義する。
- クラス内のメソッドは
メソッド名()
で呼び出せる。 - クラス外のメソッドは
クラス名.メソッド名()
で呼び出す - main メソッドの戻り値の型は int ではなく void ?
- Java は「 1 ファイル 1 クラス 」を原則とする (ので, 以下はその場合を想定)
- Javaはファイルではなくクラスを実行する。
- ファイル名を
クラス名.java
とする(必須)- 外部ファイルのクラスはローカルにあれば
import
不要(コンパイル時に指定) - 外部ライブラリのクラスは
import クラス名;
と, 使用するファイル内でimport
する。import java.lang.Math;
としたときは, クラス名はMath
なのでMath.round(3.5)
のように呼び出せる。- ただし,
java.lang
にあるクラスはimport
不要
- 外部ファイルのクラスはローカルにあれば
- クラスを実行すると, そのクラスの
main
メソッドが実行される。- ゆえに,
main
メソッドを持つクラスしか実行できない。 - クラス名に関係なく, クラスの実行時には
main
メソッドが呼ばれる。
- ゆえに,
C++との共通点(の抜粋)
- メソッドは多重定義可能
- クラス名は PascalCase
// Main.java <-- クラス名が Main だから。 class Main { public static void main(String[] args) { // この main とクラス名の Main は関係ない。 String added = hello("ABC"); // クラス内メソッドの呼び出しではクラス名は指定不要 Hoge.hoge(); // クラス外メソッドの呼び出し } public static String hello(String name) { return "Hello "+name; } }
// Hoge.java import java.util.Scanner; // import は利用するファイルで。 class Hoge { // クラス定義 public static void hoge() { Scanner scanner = new Scanner(System.in); // Scanner クラスのインスタンス生成 String name = scanner.next(); // 空白までの入力を受け付けて, 文字列として格納する // scanner.nextLine() は改行までの一行を受け付ける。 // scanner.nextInt() // scanner.nextDouble() System.out.println(name); } }
Java IV
- C++との相違点
- C++との共通点
class Person { // 変数の定義(クラスの最初に書く) public String name; // python と違い, クラス側に定義が必要? public static int id = 0; // クラスフィールドは static を付ける。Person.id++ のように使う // コンストラクタの定義 Person(String name) { this.name = name; } // インスタンスメソッドの定義 public void hello() { // static がない System.out.println("hello"+this.name); } // クラスメソッドの定義 public static void hoge(){ // static がある System.out.println("hoge"); } }
Person person1 = new Person(); person1.hello(); // インスタンスメソッドは インスタンス名.メソッド名() としてよびだす。 Person.hoge(); // クラスメソッドは クラス名.メソッド名() としてよびだす。
Java V
- 継承:
class サブクラス名 extends スーパークラス名
- スーパークラスのインスタンスメソッドなどはそのまま使える。
- 同名であればサブクラスで定義されたものが優先される(オーバーライド)。
- サブクラス内で, スーパークラスで定義された
private
なものは参照できない(ゲッタやセッタ使う)private
の代わりに,protected
を使えばサブクラス内からはアクセスできるようになる。
- サブクラス内で, スーパークラスで定義されたメソッドを使うとき,
- 同名のものが同じサブクラス内で定義されていない場合:
メソッド名()
でよい - 同名のものが同じサブクラス内で定義されている場合:
super.メソッド名()
- 同名のものが同じサブクラス内で定義されていない場合:
- サブクラスでコンストラクタを定義するとき, 必ずコンストラクタの先頭でスーパークラスのコンストラクタを呼びださなければならない。スーパークラスのコンストラクタは
super();
で呼び出せる(括弧内には実引数を与える). - 抽象メソッド:
abstract public void hello(String name) ;
のようにメソッドの先頭にabstractをつける。;
に注意。- 具体的な処理が未確定なメソッドであることを示す。
- サブクラスでそのメソッドをオーバーライドしていなければエラーになる。
- つまり, サブクラスがオーバーライドし処理内容を定義することを強制できる。
- 抽象メソッドを1つでも持つクラスは「抽象クラス」と呼ばれ、クラス定義を
abstract class Hoge {}
とする。
- クラスの変数として他のクラスのインスタンスを持たせることもできる。
- 多態性(要素が複数の型に属することを許すという性質):
- つまり, クラス B が クラス A を継承する場合, クラス B のインスタンス b は, B型でもあると同時に A型でもある。よって,
A b = new B()
が許される。このとき, b は B型でもあるので, Bでオーバーライドされる場合はそちらが優先される。
- つまり, クラス B が クラス A を継承する場合, クラス B のインスタンス b は, B型でもあると同時に A型でもある。よって,
Progate Python
Pythonの開発環境を用意しよう!
windowsOS
- https://www.python.org/
- Downloads タブ
- Python3.8.3 のボタン
Add Python 3.6 to PATH
にチェックを入れてInstall Now
$ python --version
macOS
- Homebrew のインストール(略)
- pyenv のインストール
brew install pyenv pyenv -v ## 以下は, bash のとき echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile echo 'eval "$(pyenv init -)"' >> ~/.bash_profile source ~/.bash_profile ## 以下は, zsh のとき echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc echo 'eval "$(pyenv init -)"' >> ~/.zshrc source ~/.zshrc pyenv install --list ## 切り替え可能なリストの表示 pyenv install 3.8.2 pyenv versions ## git branch みたいな感じ(versionではなくversions) pyenv global 3.6.5 ## git checkout みたいな感じ python --version ## これで通常の python コマンドで指定したバージョンが実行できる
Python I
- 文末に
;
等は不要 - コメントは
#
(複数行のコメントはなく, 三重クォートの文字列にする) - 文字列はシングルクォートでもダブルクォートでもよい。
5/2
は 2.5,5//2
は 2- クラスは
PascalCase
, それ以外はsnake_case
- 文字列の連結は
"hoge" + "fuga"
- print は文字列や数値型など複数の型を引数にとれる。最後に改行される。
- 文字列の連結で数値型が混ざるときは型変換が必要 (
"answer:" + str(5)
)
if 条件: 処理 elif 条件: 処理 # インデントで意味が変わる else: 処理
- 真理値は
True
False
and
or
not
- 変数の受け取り:
変数 = input('コンソールに表示したい文字列')
ただし, 受け取ったのは文字列扱い
Python II
- リスト: [], append,
for 変数名 in リスト:
- ディクショナリ: Python 3.7以降はキーの順序を保証する。
- 辞書名[新しいキー名] = 値 : 辞書に新しい要素を追加
- ただし、辞書にすでにあるキー名を指定すると、値の追加ではなく更新
for 変数名 in 辞書:
変数名に格納されるのはキー
while 条件式:
break
,continue
Python III
- 関数定義
def 関数名(仮引数の並び):
- デフォルト引数, return
- モジュール(hoge.py) -> hoge がモジュール名になる。
- 呼び出される側は同じ
- 呼び出す側は
import hoge
(拡張子不要, クォーテーション不要) hoge.関数名()
で呼び出せる。
import random
random.randint(x, y)
: xからyまでの整数をランダムに取得
Python IV
- クラス定義
class Hoge:
- メソッド
class Hoge: def __init__(self, value): # インスタンス生成時に自動で呼び出される(つまり, コンストラクタ) self.value = value # Hoge(5) のようにインスタンスを生成 def method1(self): # メソッドの第一引数は変数を使わなくても self とする。__init__ も同様 # self はインスタンス自身(つまり hoge_instance など) # 呼び出しは hoge_instance.method1() となる pass #何もしない文 def method2(self,x): print(self.value + round(x)) # round(小数) で小数点第一位を四捨五入
from モジュール名 import クラス名
のようなインポートも可能
Python V
- クラスの継承
class クラス名(親クラス名):
- デフォルトでそのまま親クラスのインスタンスメソッドが引き継がれる
- 親クラスにないメソッドは同様に追加可能
- 親クラスにあるメソッドはオーバーライドされる(親クラスのメソッドは見えなくなる)
- その場合でも, 呼び出しを
super().メソッド名()
とすることで, 親クラスのメソッドを呼び出せる。(2つ目の括弧の中身は親クラスのメソッドを呼び出すときの実引数)
def __init__(self, name,price,amount): super().__init__(name,price) self.amount()
Progate React
React I
- HTML like な JSX を用いる。HTML との違いは以下の通り。
- React の記述ファイル
// app.js import React from "react"; // react のインポート class App extends React.Component { // React.Component クラスを継承する render() { // render メソッドを定義(このなかにreturnを書く) const text = "Hello World!"; const imgUrl = "https://..."; return ( // return の内側には JSX, 外側には JavaScript を書く <h1>{text}</h1> // JSX の内部での参照は {変数} <img src={imgUrl}/> // タグ内にも持ち込める ); } } export default App; // クラスをエクスポートする
- イベントの設置
<button onClick={アロー関数とか}>クリック時の動作を規定</button>
- state の定義
- 変数の保存, 参照, 変更
class App extends React.Component { constructor(props) { super(props); // props はこのクラスを呼び出す側で指定するやつ this.state = {count: 5}; // state はオブジェクトとして定義する } counterSetting(num) { this.setState({count: num}) // メソッド化できる // this.state.count = 0 のような代入による変更は不可 // 変更はリアルタイムに反映される } render() { return ( <h1>{this.state.count}</h1> {/* 参照 */} <button onClick={()=>{this.counterSetting(0)}}>0セット</button> ); } }
React II
- 構成: App.js は index.js を介して index.html に挿入される
- CSS も有効
/index.html /src/index.js /src/components/App.js /stylesheet.css
// /src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './components/App'; // クラスのインポート // インポートしたクラスの return の中身を id が 'root' な位置に突っ込む. ReactDOM.render(<App />, document.getElementById('root'));
<link rel="stylesheet" href="stylesheet.css"> <!-- /index.html の一部 --> <div id='root'></div> <script src="bundle.js"></script>
<Hoge name="hoge" age=25 /> {/*改行すると見やすい*/} <Hoge name={ValueDefinedInThisFile} age=5 />
- 呼び出される側(Hogeクラス)では
this.props.age
などとして使える。 - return の中で return を呼び出せる
render(){ const list = ["hoge", "fuga"]; return( <div> { list.map((item)=>{ return(<p>{item}</p>) })} </div> ) }
React III
- 変数にJSXを格納
render() { let text; let modal if(this.state.isDisplay){ text=<p>変数にJSXを格納可能</p>; modal=( <div> <p>複数行にわたるときは括弧で囲んで代入(returnも同じ)</p> </div> ); } return( <div> <h2>{text}<h2> {/*ブロック内変数なのでthisはいらない*/} {modal} {/*空なら表示されない*/} </div> ) }
React IV
- HTML と JSX の違い
<input>
:<input/>
<textarea></textarea>
:<textarea/>
- イベント
<form onSubmit={()=>{}}> </form>
<button onClick={()=>{}}> </button>
<input onChange={()=>{}}>
変更が起きた時の処理
入力値をstateにセットする
<input value={this.state.inputValue} onChange={(event)=>{ this.handleMethod(event); }}>
handleMethod(event) { const inputString = event.target.value; this.setState({inputValue:inputString}); }
constructor(props) { super(props); this.state = {inputValue:""}; }