Skip to content

Latest commit

 

History

History
301 lines (236 loc) · 11.8 KB

20211229.md

File metadata and controls

301 lines (236 loc) · 11.8 KB

hackmd-github-sync-badge

今週何知った? week:3

[name=makicamel]

Redis

gem

redis-objects を使う

# config/initializers/redis.rb
require 'connection_pool'
Redis::Objects.redis = ConnectionPool.new(size: 5, timeout: 5) { Redis.new(host: '127.0.0.1', port: 6379) }
class User < ApplicationRecord
  include Redis::Objects
  list :items
end

user = User.last
user.items.get
# => []
user.items << 'りんご'
user.items << 'ばなな'
user.items << 'マンゴー'
user.items.get
# => ["りんご", "ばなな", "マンゴー"]

最後に見た商品 5 個をトークンベースで記録する

  def update_token
    now = Time.zone.now.to_f
    redis = Redis.current
    redis.hset('login:', current_user.token, current_user.id)
    redis.zadd('recent:', now, current_user.token)
    redis.zadd('viewed:' + current_user.token, now, @item.id)
    redis.zremrangebyrank('viewed:' + current_user.token, 0, -6)
  end

alias

alias 新メソッド名 旧メソッド名 - クラス/メソッドの定義

以前は元のメソッドに何か付け加えたい時に以下のように利用してメソッドの書き換えを行っていたが、今は Module#prepend と super の組み合わせで実現することが多い。 元のメソッドを退避し別名で呼びたい場合は現在でも有効。

module Logging
  def log(message)
    puts message
  end
    
  def log_with_timestamp(message)
    log_without_timestamp("[#{Time.now}]#{message}")
  end
 
  # log を log_without_timestamp というメソッド名で呼べるように退避する
  alias log_without_timestamp log
  # log というメソッド名で log_with_timestamp を呼ぶようにする
  alias log log_with_timestamp
end

class AwesomeLogger
  include Logging
end

logger = AwesomeLogger.new
logger.log 'hoi'
# => [2021-12-24 05:02:06 +0900]hoi
logger.log_without_timestamp 'hoi'
# => hoi

alias_method_chain

以前は Rails に alias_method_chain が存在したが 5 系で deprecated になり今は削除された。 上述の通り Ruby2.0 で Module#prepend が実装されたため。

Method UnboundMethod

  • Method Object#method によりオブジェクト化されたメソッドオブジェクトのクラス unbindUnboundMethod オブジェクトにできる
method = '1 2'.method(:split)
# => #<Method: String#split(*)>
method.call
# => ["1", "2"]
method.unbind
# => #<UnboundMethod: String#split(*)>
# Method#source_location が present な場合、その値が表示される
hoi = Struct.new('Hoi') { def hoihoi; p 'hoi!'; end }.new
method = hoi.method(:hoihoi)
# => #<Method: Struct::Hoi#hoihoi() (irb):1>
method.call
# => "hoi!"
  • UnboundMethod レシーバを持たないメソッドを表すクラス 呼び出すためにはレシーバにバインドする必要があり、 bind で Method オブジェクトにできる
unbound_method = String.instance_method(:split)
# => #<UnboundMethod: String#split(*)>
unbound_method.call
# NoMethodError: undefined method `call' for #<UnboundMethod: String#split(*)>
# from (pry):1:in `__pry__'
method = unbound_method.bind('1 2')
# => #<Method: String#split(*)>
method.call
# => ["1", "2"]

Adapter pattern

Adapterパターンは,求めているものと,提供されているものの違いを吸収して,求めているものに適合させるものである. (中略) 実現する方法には2種類ある.クラスの関係を用いて「継承」を使ったものと,インスタンスを用いた「委譲」を使ったものがある.

form objectを使ってみよう - メドピア開発者ブログ であげられているフォームオブジェクトを例として考えてみる。

class Signup
  include ActiveModel::Model

  attr_accessor :email, :password, :password_confirmation

  validates :email, presence: true, format: { with: /\A.+@.+\z/ }
  validates :password, presence: true, length: { minimum: 6 }, confirmation: { allow_blank: true }

  def save
    return false if invalid?

    user = User.new(email: email, password: password, password_confirmation: password_confirmation)
    user.save!
    UserMailer.welcome(user).deliver_later
    true
  end
end

この例では User 自身のバリデーションを実施するのは user.save! になるため Signup#valid?Signup#save の結果が異なり得る。

継承

User クラスの性質を持った SignupUser クラスを作成し処理を実行する。

- class Signup
-   include ActiveModel::Model
+ class SignupUser < User

委譲

User クラスのインスタンスを介して処理を実行する。 Signupsave メソッドを必要とせず valid? のみを必要としている場合、 ActiveRecord の性質を持つ User を継承するのは好ましくない。

class Signup
  include ActiveModel::Model
  # Signup#email, Signup#password にアクセスしたい場合は delegate する
  delegate :email, :password, to: :@user
  attr_accessor :invitation_code

  validates :invitation_code, presence: true, format: { with: /\A[\w\d]{6}\z/ }
  validate :user_validate
    
    
  def initialize(invitation_code:, attribute)
    @invitation_code = invitation_code
    @user = User.new(attribute)
  end
    
  # def valid?(*args)
  #   super & @user.valid?(*args)
  # end
    
  def error_messages
    # Signup#errors と User#errors をそれぞれ保持したい
    errors.full_messages + @user.errors.full_messages
  end
    
  private
    
  def user_validate
    @user.valid?
  end
end

Ruby の並列処理入門

Ruby で並列処理を実現するには以下の方法がある

  • プロセス メモリを独立して持つためスレッドに比較し独立性が高くコストも高い 特にプロセスの fork 時にメモリをまるごとコピーする場合メモリを逼迫する。コピーオンライト(利用時にコピーする)方式を採用する場合緩和される
  • スレッド メモリを共有するためプロセスに比較し独立性が低くコストも低い
  • Fiber ノンプリエンプティブ( CPU の管理を OS が行わず、各アプリケーションが自ら切換えする方式)な軽量スレッド
  • Ractor アクターモデル風の並行・並列制御機構であり、スレッド安全に関する懸念なく、Ruby で並列処理を行うための機能

Ruby ではグリーンスレッド(OS ではなく VM でスケジューリングするスレッド)を採用している。これは Matz が定めた方針 ref) It isn't Easy to Remove the GIL - Matzにっき(2007-09-13)

アプリケーションサーバ

[name=ken3ypa]

esaのショートカット

  • Cmd + i で自分のアイコン出す、ぐらいしか使ったことなかったけど、J, K が便利
キーボードショートカット 効果 使える場所
文字を選択 + P 選択部分がセットされた状態で、新しい投稿ページが開く 記事ページ
⌘ + K リンク記法を挿入 記事 or コメントの編集中
J, K 前のリビジョン/次のリビジョン リビジョン詳細ページ
J, K (同じカテゴリ内の)前の記事/次の記事 記事詳細ページ
[, ] (チーム内の)前の記事/次の記事 記事詳細ページ
? ショートカットのヘルプを表示 どこでも
/ 検索formにfocus どこでも

Chromeの拡張機能

  • Create Link
    • Markdown形式でコピーが出来て便利
    • GitHubに外部ページのURL貼るときなど便利

Copy Title and Url as Markdown Style - Chrome ウェブストア

中規模ストーリーの回し方的なお話

背景

  • 2人で1ヶ月ぐらいのタスク
  • 先に一人が入っていて、あとで自分が入った

結果

  • はじめて一緒にお仕事した人でもスムーズに進めることが出来た
  • お見合い状態から早めに抜けて、相談しやすい環境を作れた

流れ

  • キックオフ
    • 自分はどういう人間か・どう仕事を進めるか
      • 「ふつう」の認識合わせ
      • パフォーマンス出る時間・出にくい時間
      • PR を出していくサイクル
      • その分野の経験
    • タスクの不安な点の共有
      • 「ドメイン知識は任せろ、Ruby の書き方には不安がある」
      • 「Ruby の書き方は任せろ、ドメイン知識は不安がある」
    • MTGの頻度決め
      • 週次 MTG
    • タスクの窓口を決める
  • 定例MTG
    • 予実管理
    • 不安な点の共有
  • スポット
    • ペアプロの実施
  • 最後
    • KPTの実施

リンク