dev/mom0tomo

技術メモ

Sinatra(Ruby)とGoの標準パッケージで立てたサーバを見比べる

たまたま同じ時期に0からサーバーを立てる機会に恵まれて、似てるなと思ったので比較してみる。

Sinatra

app.rb

require 'sinatra'

get '/' do
  erb :index
end

index.erb

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>タイトル</title>
  </head>
  <body>
    <p>Sinatraだよ</p>
  </body>
</html>

Go

init.go

package main

import "net/http"

func init() {
    http.HandleFunc("/", index)
}

index.go

package main

import (
    "html/template"
    "net/http"
)

var indexTmpl = template.Must(template.New("index").Parse(`<!DOCTYPE html>
<html>
  <head>
      <meta charset="UTF-8">
      <title>タイトル</title>
  </head>
  <body>
      {{.}}
  </body>
</html>`))

func index(w http.ResponseWriter, r *http.Request) {
    fmt.Println(w, "Goだよ")
}

改めてGoの標準パッケージすごい。そして html/templateつらい。

selfを理解する

mom0tomo.hateblo.jp 前回の続き。

selfについて、実務であまり使うこともなくちゃんと理解しているのが怪しかったので確認する。


self は、クラス内部の変数やメソッドを明示して使うときに利用する。

class Person
  attr_accessor :name, :age

  def initialize
    self.name = 'もも'
    self.age = 22
  end

def cording(programing_language)
    puts "#{self.name}#{programing_language}を利用しています。"
  end
end

mom0tomo = Person.new
mom0tomo.cording('Go言語ʕ ◔ϖ◔ʔ') # ももはGo言語ʕ ◔ϖ◔ʔを利用しています。
p mom0tomo # #<Person:0x00007fa1b684d640 @name="もも", @age=22>

selfは、呼び出されたときのインスタンス (ここではmom0tomo)を指す。

つまり、mom0tomoインスタンスから cording('Go言語ʕ ◔ϖ◔ʔ')メソッドが呼び出されたとき、

mom0tomo.cording('Go言語ʕ ◔ϖ◔ʔ')

mom0tomo. が、 self. に代入される。

attr_accessorメソッド

attr_accessor はクラス内で変数を定義するためのメソッド。

下記のように、引数として与えられたシンボルをクラス内の変数として定義する。

class Person
  attr_accessor :name, :age

  def initialize
    self.name = 'もも'
    self.age = 22
  end
end

mom0tomo = Person.new

p mom0tomo

selfについては次回。

リテラルとはなにか

簡単にいうと、 リテラルは値 である。

  • a = 'hoge' としたとき、'hoge' のことを「文字列リテラル」と呼ぶ。
  • a = 1 としたとき、1 のことを「数値リテラル」と呼ぶ。
  • 配列・ハッシュ・論理値・nilリテラルである。

リテラルは値なので、変数に代入できる。

つまり変数に何かを代入するときは、 変数 = リテラル という形を取っていることになる。

Rubyのattr_readerについて

読んだもの

ref.xaio.jp

学んだこと

attr_readerメソッドはアクセサメソッドを定義する。 アクセサメソッドとは、クラスやモジュールにインスタンス変数を読み出すためのメソッドである。 引数には、インスタンス変数名をシンボルか文字列で指定する。

下記はBookクラスにtitleメソッドとpriceメソッドを定義する例。beforeはattr_readerを使わない場合の書き方。

before

class Book
  def title
    @title
  end

  def price
    @price
  end
end

上の例をattr_readerを書き直すと、下記のようになる。

after

class Book
  attr_reader :title, :price
  
  def initialize(title, price)
    @title = title; @price = price
  end
end

Rubyのmapとeachの違い

読んだもの

manji602.hatenablog.com

すごくわかりやすかった。

学んだこと

each

eachはレシーバ自身が返る。

def each_sample
  (1..10).to_a.each do |i|
    i + 10
  end
end

=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

レシーバ i が返っており、インクリメントはされていない。

map

mapはブロックの戻り値を集めて返す。

def map_sample
  (1..10).to_a.map do |i|
    i + 10
  end
end

=> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Rubyのelsifとガード節について

コードレビューで、if elseは条件が対称な場合にだけ使った方が良いという指摘を受けた。

# if elseを使うのに適しているものの例

if number.odd?
  # 奇数の場合の処理
else
  # 偶数の場合の処理
end

上のように分岐の条件に対称性がある場合はif elseを使う。 そうでない場合は、早期リターンを使ったほうが意図が伝わりやすいという指摘だった。

読んだもの

blog.livedoor.jp techracho.bpsinc.jp

学んだこと

  def display_kanri_fee # 管理費(画面表示用に整形する)
    if kanri_fee.blank? # 管理費がない場合
      '- 円' => 
    elsif kanri_fee_type.blank? # 月額/年額表示がない場合
      number_to_currency(kanri_fee, unit: '')
    else
      "#{number_to_currency(kanri_fee, unit: '')} / #{kanri_type_i18n}"
    end
  end

ガード節で書き直す

  def display_kanri_fee
    return '- 円' if kanri_feeblank?
    return number_to_currency(kanri_fee, unit: '') if kanri_fee_type.blank?
    "#{number_to_currency(kanri_fee, unit: '')} / #{kanri_type_i18n}"
  end

なるほど、わかりやすい気がする。

Railsのja.ymlでEnumの内容が被ったら

Enumの内容がかぶると、重複エラーになる。

You tried to define an enum named "monthly" on the model "Room", but this will generate a instance method "monthly?", which is already defined by another enum.

こういうときはprefixとsuffixをつけて区別してあげればいい。

読んだもの

api.rubyonrails.org

学んだこと

修正前

model/Room.rb

  enum yachin_type: {
    monthly: 1, # 月額
    yearly: 2 # 年額
  }

  enum kanrihi_type: {
    monthly: 1, # 月額
    yearly: 2 # 年額
  }

# => 重複エラーになる

修正(prefixをつける場合)

model/Room.rb

  enum yachin_type: {
    monthly: 1, # 月額
    yearly: 2 # 年額
  }, _prefix: :kanrihi_type

  enum kanrihi_type: {
    monthly: 1, # 月額
    yearly: 2 # 年額
  }

修正(suffixをつける場合)

model/Room.rb

  enum yachin_type: {
    monthly: 1, # 月額
    yearly: 2 # 年額
  }, _suffix: true

  enum kanrihi_type: {
    monthly: 1, # 月額
    yearly: 2 # 年額
  }

Decorator Helper 違い

Helperに書かれたメソッドをDecoratorに切り出そうとして、「引数どうするんだっけ」と思った。

Helperだけ、Decoratorだけ0-1で書くときはそれほど迷わないことでも、リファクタリングなど2つ同時に作業するとき意外と迷う。

改めてまとめてみた。

読んだもの

tech.misoca.jp qiita.com izumin.hateblo.jp

学んだこと

Helperとは

  • ViewをよりシンプルにDRYに書くためのモジュール

    • View以外もhelpできるが、基本的にはViewをhelpする(ViewHelperと言ったりする)

    • rails g controllerを実施した際に作成される

Helperの例

module MembersHelper
  # 会員のフルネームを取得する
  def member_full_name(member)
    member.first_name + ' ' + member.last_name
  end
end

Decoratorとは

  • Viewと対応するModelごとに作れる

    • モデルの属性にアクセスする際に変数を介する必要がない
  • Controllerで宣言されたインスタンス変数すべてにdecorateメソッドを適用する

Decoratorの例

moduleMemberDecorator
  # 会員のフルネームを取得する
  def full_name
    first_name + ' ' + last_name
  end
end

Ruby / Railsで日付と日付の差分を求める

読んだもの

www.rubylife.jp

学んだこと

Timeクラスか、Dateクラスを使う。 時間まで使いたい場合はTimeクラス、日付だけ使いたい場合はDateクラスを使う。

2つのクラスのオブジェクトに対し、「-」を使って差を取得する(引き算ぽい)。

やりたかったこと

期限日と今日の差分を求めて、期限まであと何日か求めたい。

require 'date'

today = Date.current
dead_line = Date.new(2018, 7 ,6)

remain = (dead_line - today).to_i
# -> 3

Date.currentはTime.zoneを、Date.todayはTime.nowを参照している。

また、素のRubyならTimeクラスを使い、 RailsならTimeWithZoneクラスを使うのがいいみたい。

伊藤さんの記事に詳しく書いてあった。

RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い

なぜRailsのpartialではインスタンス変数を参照しない方がいいのか

読んだもの

kadoppe.com

学んだこと

なぜpartialではインスタンス変数を参照しない方がいいのか?

  • コントローラで何を用意すべきか明らかでなくなるから
  • インスタンス変数を介して、partialは呼び出し元のテンプレートだけでなくコントローラとも結びついてしまうので、再利用性が低くなるから

partialにインスタンス変数を使ってしまったところ、直すときcontrollerとの関連がわからなくなり、どこを削除していいのかわからなくなり、自分が書いたコードなのにハマった。

『Ruby on Rails5 アプリケーションプログラミング』 読んだメモ

  • クエリメソッドはその場でDBにアクセスしない(遅延ロード)

    • メソッドチェーン(連鎖して呼び出す)が可能
  • 生成されたクエリはPumaのコンソールに吐き出される

  • whereメソッドを使うと、プレイスホルダー(任意のパラメータを引き渡せる)が使える

    • 動きはfind_byと同じ
  • パラメータ数が少ない時は名前なしにする (params[:publish]))

    • 多い時は名前付きにする (publish: params[:publish])

Active Decoratorメモ

読んだもの

qiita.com GitHub - amatsuda/active_decorator: ORM agnostic truly Object-Oriented view helper for Rails 3, 4 and 5

学んだこと

  • テストのとき、ちょっと変わった書き方をする。
    • →ActiveDecorator::Decorator.instance.decorate(model_instance)を呼び出す

モデルの例

module OrganizationDecorator
  def full_name
    "#{first_name} #{last_name}"
  end
end

テストの例

describe '#full_name' do
  it 'returns the full organization name' do
    organization = Organization.new(first_name: 'John', last_name: 'Doe')
    decorated_organization = ActiveDecorator::Decorator.instance.decorate(organization)

    expect(decorated_organization.full_name).to eq('John Doe')
  end
end

ADの機能は、Rails組み込みのものだと勘違いしていた。

「使えるRSpec入門・その1 」読んだメモ

読んだもの

qiita.com

学んだこと

  • 原則として「1つの example につき1つのエクスペクテーション」で書く

    • テストの保守性が良くなるため
  • letで宣言できる変数

**インスタンス変数の例**
let(:user) { User.new(params) }

# 同じ意味
user = User.new(params)

ローカル変数の例

let(:params) { { name: 'たろう' } }

# 同じ意味
@params = { name: 'たろう' }
  • let は遅延評価される

    • before + インスタンス変数は遅延評価されない
    • 必要になる瞬間まで呼び出されないので効率がよい
  • it do ... endのことをexampleと呼ぶ

  • subject { user.greet } を宣言するときの決まり

    • expect(user.greet).to eq 'hogehoge'が
    • is_expected.to eq 'hodehode'という書き方になる
  • shared_examples 'foo' do ... end で再利用したいexampleを定義して、 it_behaves_like 'foo' で定義したexampleを呼び出せる

  • let の遅延評価によってテストが失敗する場合は、かわりに let! を使う

  • テストコードは「DRYさ」よりも「読みやすさ」を大事にする