きっかけ
カレンダーのライブラリはいっぱい凄いがのあるけどカスタマイズしづらい....。 JSじゃなくてサーバーサイドである程度つくってしまえばカスタマイズしやすいのだろうか....?
実装方針(アルゴリズム的なもの)
- ある日付aを受け取る
- ある日付aが属する月の一日, 末日を取得する
- 初日の曜日(x)を取得する
- 月曜日(cwday=1)~からx曜日まで繰り返し dayが空のhashを入れる(hash①)
- 一日から末日までの hashの配列をつくる。dayには値を入れる(hash②)
- 末日から日曜日(cwday=7)まで繰り返し, dayが空のhashを入れる(hash③)
- hash①②③を結合して、each_slice(7)をし、週単位の配列をつくる。
サンプルコード
calendar.rb
require "date"
class Calendar
def initialize(date)
@datetime = date
assign_first_date_and_last_date_of_the_month
end
attr_reader :datetime, :first_date, :last_date
def generate
calendar = []
# 月曜から一日までのカレンダー紙面上における空白の日付を生成
(first_date.cwday - 1).times do
calendar << { date: "" }
end
# 一日から末日までの日付を作成。
1.upto(last_date.day) do |n|
calendar << { date: n }
end
# 末日から日曜までのカレンダー紙面上における空白の日付を生成
(7 - last_date.cwday).times do |n|
calendar << { date: "" }
end
calendar.each_slice(7).to_a
end
private
def assign_first_date_and_last_date_of_the_month
year, month = datetime.year, datetime.month
@first_date = Date.new(year, month, 1)
@last_date = Date.new(year, month, -1)
end
end
実行結果
こういう値を返します
- 週ごとにhashでまとまってる
- 空白のhashをつくってカレンダー上の空白を表現(つまりフロントでは
# 2019年2月のカレンダー
[{:date=>""}, {:date=>""}, {:date=>""}, {:date=>""}, {:date=>1}, {:date=>2}, {:date=>3}]
[{:date=>4}, {:date=>5}, {:date=>6}, {:date=>7}, {:date=>8}, {:date=>9}, {:date=>10}]
[{:date=>11}, {:date=>12}, {:date=>13}, {:date=>14}, {:date=>15}, {:date=>16}, {:date=>17}]
[{:date=>18}, {:date=>19}, {:date=>20}, {:date=>21}, {:date=>22}, {:date=>23}, {:date=>24}]
[{:date=>25}, {:date=>26}, {:date=>27}, {:date=>28}, {:date=>""}, {:date=>""}, {:date=>""}]
もっとクールに書く
@QUANON さん にもっとクールなコードを書いていただいたので転載。
samp.rb
require 'date'
class Calendar
attr_reader :date
def initialize(date)
@date = date
end
def to_a
[
*Array.new(first_date.wday),
*1..last_date.day,
*Array.new(6 - last_date.wday)
]
.map { |date| { date: date || '' } }
.each_slice(7)
.to_a
end
private
def first_date
Date.new(date.year, date.month, 1)
end
def last_date
Date.new(date.year, date.month, -1)
end
end
まとめ
これでサーバー側の値もいれることができそう...な気がする。
あとはJSONにして、ReactなりVueなりでよしなにやれば....勝てる...!
懸念
実サービスで活用するコードに変化させた時(例えば何かをDBからfetchしてくる)に
果たしてさくさく動いてくれるのかまだ検証しておらず。
単体でbenchmark取った結果は大して重くならなそうでしたが。