1. 関数宣言(Function declaration) function calcRectArea(width, height) { return width * height; } console.log(calcRectArea(5, 6)); // => 30 1-1. 関数宣言の巻き上げ 関数宣言は巻き上げられる hello(); // => "Hello" function hello(){ return "Hello"; } 関数式は巻き上げられない hello(); // => TypeError: hello is not a function const hello = function(){ return "Hello"; }; 2. 関数式(Function expression) 2-1. 名前付き関数(Named function) 名前付き関数は再帰的に関数を呼び出す際などに利用する // factorialは関数の外から呼び出せる名前 // innerFactは関数の外から呼び出せない名前 const factorial = function innerFact(n) { if (n === 0) { return 1; } // innerFactを再帰的に呼び出している return n * innerFact(n - 1); }; console.log(factorial(3)); // => 6 2-2. 無名関数(Anonymous Function) 無名関数はコールバック関数としてよく使われる const x = function(a, b) { return a * b; }; 3. アロー関数(Arrow function expression) アロー関数は関数式の代替構文(機能的な違いはいくつかある) ES2015から追加された const x = (a, b) => { return a * b; }; 3-1. アロー関数の省略記法 関数の仮引数が1つのときは()を省略できる 関数の処理が1つの式である場合に、ブロック({})とreturn文を省略できる その式の評価結果をreturnの返り値とする // 仮引数の数と定義 const fnA = () => { /* 仮引数がないとき */ }; const fnB = (x) => { /* 仮引数が1つのみのとき */ }; const fnC = x => { /* 仮引数が1つのみのときは()を省略可能 */ }; const fnD = (x, y) => { /* 仮引数が複数のとき */ }; // 値の返し方 const fnE = x => { return x + x; }; // ブロックの中でreturn const fnF = x => x + x; // 1行のみの場合はreturnとブロックを省略できる const fnG = x => { let y = 10; return x + y; }; // 関数の処理が複数行ある場合はreturnとブロックは省略できない 4. メソッド定義(Method definition) オブジェクトのプロパティである関数をメソッドと呼ぶ JavaScriptにおいて関数とメソッドの機能的な違いはない オブジェクト.メソッド名()でメソッドを呼び出す const obj = { method1: function () { return "this is method1"; }, // `function`キーワードでのメソッド method2: () => "this is method2" // Arrow Functionでのメソッド }; console.log(obj.method1()); // => "this is method1" console.log(obj.method2()); // => "this is method2" 次のように空オブジェクトのobjを定義してから、methodプロパティへ関数を代入してもメソッドを定義できる ...
【Git】複数のコミットを一つにまとめる(rebase -i で squash)
この記事では、git rebase -iを使って複数のコミットを一つにまとめる方法を紹介します。 1. 連続したコミットの場合 以下のedit2, edit3, edit4を一つにまとめて、edit 2 & 3 & 4にします。 $ git log --oneline 96a8b1e (HEAD -> main) edit4 30600dd edit3 452c39e edit2 ac56720 edit1 ac56720以降のコミットを表示させたいので、以下のコマンドを実行 $ git rebase -i ac56720 # git rebase -i HEAD~3でも可 テキストエディタに以下が表示される(古いコミットが上) pick 452c39e edit2 pick 30600dd edit3 pick 96a8b1e edit4 edit3とedit4のpickをs(またはsquash)に変更して、ファイルを保存して閉じる。 pick 452c39e edit2 s 30600dd edit3 s 96a8b1e edit4 f(fixup)にするとコミットメッセージの編集画面は表示されず、まとめられたコミットのコミットメッセージがedit2になる(squashとfixupの違いはこれだけ) 以下のコミットメッセージの編集画面が表示される # This is a combination of 3 commits. # This is the 1st commit message: edit 2 # This is the commit message #2: edit 3 # This is the commit message #3: edit 4 コミットメッセージをedit 2 & 3 & 4に変更してファイルを保存して閉じる。(他のコミットメッセージは消しても消さなくてもいい) ...
【Git】git reset --soft、--mixed、--hardで変更を取り消す
1. git reset git reset [<mode>] [<commit>] mode --soft:HEADの移動 --mixed:HEADの移動、インデックスの更新 --hard:HEADの移動、インデックスの更新、作業ディレクトリの更新 デフォルトで--mixedが指定される commit 巻き戻したいcommitを指定 デフォルトでHEADが指定される 2. git resetの各モードについて 2-1. –soft (HEADの移動) git reset --soft HEAD~ 直近のgit commitを取り消す 2-2. –mixed (インデックスの更新) git reset --mixed HEAD~ 直近のgit commitとgit addを取り消す 2-3. –hard (作業ディレクトリの更新) git reset --hard HEAD~ 直近のgit commitとgit addと作業ディレクトリの変更を取り消す 3. まとめ --soft :HEAD が指し示すブランチを移動する (--soft を使うと処理はここで終了) --mixed:--soft + インデックスの内容を HEAD と同じにする (--mixedを使うと処理はここで終了) --hard:--soft + --mixed + 作業ディレクトリの内容をインデックスと同じにする 【参考】 Git - git-reset Git reset | アトラシアンの Git チュートリアル Git - リセットコマンド詳説 第6話 git reset 3種類をどこよりもわかりやすい図解で解説!【連載】マンガでわかるGit ~コマンド編~ - itstaffing エンジニアスタイル
【RuboCopエラー】Use a guard clause instead of wrapping the code inside a conditional expression.
バージョン情報 rubocop 1.34.1 Ruby 3.1.2 エラー内容 Use a guard clause instead of wrapping the code inside a conditional expression. →例外処理の条件分岐のネストが深くなるのを防ぐためにGuard Clause(ガード節)を使いましょう。 エラー対処 # これを def image_check unless avatar.image? errors.add(:avatar, 'エラーメッセージ') end end # こうする def image_check return if avatar.image? errors.add(:avatar, 'エラーメッセージ') end 【参考】 Ruby Style Guide: Nested Conditionals Class: RuboCop::Cop::Style::GuardClause Guard clause instead of wrapping the code inside a conditional expression Rails - Stack Overflow [Ruby/Rails] 例外で深くなったネストをGuard Clauseですっきりさせる|TechRacho by BPS株式会社
【Ruby】Minitestの使い方
この記事では、minitestを使ってRubyのコードをテストする方法を紹介します。 Rubyのテストフレームワーク、Test::Unit・test-unit・minitestの違いについては以下を参照ください。 Ruby標準のテスティングフレームワークで手軽にテストコードを書く方法 #RSpec - Qiita Rubyのテスティングフレームワークの歴史(2014年版) - 2014-11-06 - ククログ minitestの使い方 minitestを使うための基本的なルールは以下です。 require 'minitest/autorun'を書く Minitest::Testを継承するクラス内にテストを書く メソッド名をtest_から始める $ tree . ├── sample.rb └── sample_test.rb sample.rb class Sample def self.hello 'Hello!' end end sample_test.rb require 'minitest/autorun' require_relative 'sample' class SampleTest < Minitest::Test def test_hello assert_equal 'Hello!', Sample.hello end end $ ruby sample_test.rb Run options: --seed 20412 # Running: . Finished in 0.001143s, 874.8906 runs/s, 874.8906 assertions/s. 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips 【参考】 minitest/unit Module: Minitest::Assertions
【Ruby3.1】ボウリングのスコア計算プログラムをオブジェクト指向で作る
非OOP版はこちら↓ 【Ruby 3.1】ボウリングのスコア計算プログラムを作る | あまブログ 1. 実行環境 macOS:12.6 Ruby:3.1.0 2. ソースコード bowling.rb #!/usr/bin/env ruby # frozen_string_literal: true require_relative 'game' shots = ARGV[0].split(',') game = Game.new(shots) puts game.score game.rb # frozen_string_literal: true require_relative 'frame' class Game def initialize(shots) @shots = shots end def score @frames = build_frames game_score = 0 (0..9).each do |idx| frame = Frame.new(@frames[idx]) game_score += frame.score @frames[idx + 1] ||= [] @frames[idx + 2] ||= [] game_score += calc_bonus_point(idx, frame) end game_score end def build_frames frame = [] frames = [] @shots.each do |s| frame << s if frames.length < 10 if frame.length >= 2 || s == 'X' frames << frame.dup frame.clear end else frames.last << s end end frames end def calc_bonus_point(idx, frame) if frame.strike? next_two_shots = (@frames[idx + 1] + @frames[idx + 2]).slice(0, 2) bonus_point = next_two_shots.sum { |s| Shot.new(s).score } elsif frame.spare? next_shot = @frames[idx + 1][0] bonus_point = Shot.new(next_shot).score else bonus_point = 0 end end end frame.rb ...
【Rails】gemのアンインストール方法
この記事では、RailsアプリでBundlerを使ってインストールしたgemを削除する方法を紹介します。 手順 $ bundle exec gem uninstall <gem名> ↓ Gemfileから該当のgemの行を削除 ↓ $ bundle install 上記によりGemfile.lockからも削除されます。 【参考】 gem uninstall gem install bundle exec 【Rails】gemのアンインストール・バージョン変更 #Rails5 - Qiita あえて言うほどではないけれどもGemを一括削除する方法 | TECHSCORE BLOG
【Bundler】Gemfileのバージョン指定の書き方
GemfileはBundlerでgemの依存関係を管理するために必要な設定ファイルです。 Gemfileにはgem名とバージョンをgem 'rails', '~> 6.1.5'のようなフォーマットで記述します。 ~> 6.1.5の正確な意味わかりますか? ~>の呼び方知ってますか?(トゥウィドルワッカと呼びます) この記事ではGemfileのバージョン指定の書き方を解説していきます。 1. Gemfileのバージョン指定子の意味 バージョン指定 意味 1.0 1.0のみ >= 1.0 1.0以上 ~> 1.0 1.0以上2.0未満 ~> 1.0.0 1.0.0以上1.1未満 指定なし 最新版 ~> 1.0はマイナーバージョン(0.x.0)は上がってもいいがメジャーバージョン(x.0.0)は上げたくないことを意味する ~> 1.0.0はパッチバージョン(0.0.x)は上がってもいいがマイナーバージョン(0.x.0)は上げたくないことを意味する # 以下二つは同じ意味 gem 'rails', '~> 6.1' gem 'rails', '>= 6.1', '< 7.0' # 以下二つは同じ意味 gem 'rails', '~> 6.1.5' gem 'rails', '>= 6.1.5', '< 6.2' 2. twiddle wakka(トゥウィドルワッカ)とは ~>がtwiddle wakkaです。 Gemfileのバージョン指定にはoptimistic version constraint(楽観的なバージョン指定)とpessimistic version constraint(悲観的なバージョン指定)があります。1 optimistic version constraint gem 'library', '>= 2.2.0' pessimistic version constraint gem 'library', '>= 2.2.0', '< 3.0' このpessimistic version constraintの省略記法としてできたのが~>(twiddle wakka)です。 ...
【Rails】ポリモーフィック関連付けを使ってコメント投稿機能を実装する
この記事では、Railsのポリモーフィック関連付けを使ってコメント投稿機能を実装する際のポイントを紹介します。 1. バージョン情報 macOS:12.6 Ruby:3.1.2 Rails:6.1.6 2. 前提条件 Userモデル(ユーザー) Bookモデル(本)のCRUD Userモデルに紐づいたReportモデル(日報)のCRUD 3. 実装時のポイント 3-1. ポリモーフィック関連付け BookモデルとReportモデルに従属するCommentモデルの作成 $ rails g model comment user:references commentable:references{polymorphic} content:text --no-test-framework app/models/comment.rb class Comment < ApplicationRecord belongs_to :user belongs_to :commentable, polymorphic: true validates :content, presence: true # 追記 end db/migrate/XXXX_create_comments.rb class CreateComments < ActiveRecord::Migration[6.1] def change create_table :comments do |t| t.references :user, null: false, foreign_key: true t.references :commentable, polymorphic: true, null: false t.text :content t.timestamps end end end マイグレーションを実行 $ rails db:migrate db/schema.rb create_table "comments", force: :cascade do |t| t.integer "user_id", null: false t.string "commentable_type", null: false t.integer "commentable_id", null: false t.text "content" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable" t.index ["user_id"], name: "index_comments_on_user_id" end commentable_typeカラムにセットされるのは参照する親モデルのクラス名(BookまたはReport) app/models/book.rb ...
【Rails】ユーザーフォロー機能を実装する
この記事では、RailsでTwitterやInstagramのようなユーザーフォロー機能を実装する際のポイントを紹介します。 1. バージョン情報 macOS:12.6 Ruby:3.1.2 Rails:6.1.6 2. 実装時のポイント 2-1. モデルの関連 Friendshipモデルの作成 $ rails g model Friendship follower_id:integer followed_id:integer --no-fixture --no-test-framework follower_id:フォロー(という行為)をしているユーザーのid 自分にとってのフォロワーじゃなくてフォローをしている人という意味のフォロワー(⇄フォロイー) followed_id:フォローされてるユーザーのid 意味的にはfollowee_idでもいい 生成されたdb/migrate/XXXX_create_friendships.rbに以下を追記。 add_index :friendships, :followed_id add_index :friendships, [:follower_id, :followed_id], unique: true add_index :friendships, [:follower_id, :followed_id], unique: trueが:follower_idで始まっているため、add_index :friendships, :follower_idは定義不要 unique: trueでデータベース側からユニーク制約をつけ、あるユーザーが同じユーザーを2回以上フォローすることを防ぐ(モデル側のバリデーションによる一意性チェックは後述) $ rails db:migrate User/Friendshipの関連付け app/models/friendship.rb class Friendship < ApplicationRecord belongs_to :follower, class_name: "User" belongs_to :followed, class_name: "User" validates :follower_id, uniqueness: { scope: :followed_id } end validates :follower_id, uniqueness: { scope: :followed_id } モデル側のバリデーションによる一意性チェック scopeを指定することでfollower_idとfollowed_idの組み合わせの一意性を保つ(あるユーザーが同じユーザーを2回以上フォローすることを防ぐ) app/models/user.rb class User < ApplicationRecord has_many :active_friendships, class_name: 'Friendship', foreign_key: :follower_id, dependent: :destroy, inverse_of: :follower has_many :passive_friendships, class_name: 'Friendship', foreign_key: :followed_id, dependent: :destroy, inverse_of: :followed end class_name class_nameオプションはhas_manyで指定した関連付け名と実際のモデル名が違う場合に使用するもの。今回のように一つのFriendshipモデルに対して二つの関連(active_friendshipsとpassive_friendships)を持たせたい場合、has_many :friendships(でuser.friendships)だとどちらの関連か区別できない。なのでhas_many :active_friendships(でuser.active_friendships)とする。ただこのままだとRailsは存在しないactive_friendshipsテーブルを探しに行くことになるので、実際に存在するfriendshipsテーブルを使うにはhas_many :active_friendships, class_name: 'Friendship'とする。以上によりactive_friendshipsという関連を実際のモデル名のFriendshipと対応付けることができる。 Railsガイド: Active Record の関連付け - 4.1.2.2 :class_name foreign_key 今回の場合、Railsは自動的にfriendshipsテーブルのuser_idを探しに行くが、friendshipsテーブルにuser_idカラムはないので、foreign_keyオプションで明示的にfollower_id(またはfollowed_id)を指定する必要がある Railsガイド: Active Record の関連付け - 4.1.2.5 :foreign_key dependent: :destroy Userモデルのデータリソースが削除されるとそれに紐づくFriendshipモデルのデータリソースも同時に削除される Railsガイド: Active Record の関連付け - 4.1.2.4 :dependent inverse_of Railsガイド: Active Record の関連付け - 3.5 双方向関連付け # inverse_ofの挙動 irb> a = User.first irb> b = a.active_friendships.first irb> a.name == b.follower.name => true irb> a.name = 'David' irb> a.name == b.follower.name => true # inverse_ofを指定しないとfalse # user(自分)が相手をフォローした場合 user.active_friendships.first.follower #=> 自分 user.active_friendships.first.followed #=> 相手 user.passive_friendships.first.follower #=> 相手 user.passive_friendships.first.followed #=> 自分 2-2. フォロー数・フォロワー数の表示 app/models/user.rb ...