Skip to content

Instantly share code, notes, and snippets.

@sakuro
Last active September 10, 2025 00:19
Show Gist options
  • Select an option

  • Save sakuro/6b5aa262d44b4e2bb11e94e5e2e774b6 to your computer and use it in GitHub Desktop.

Select an option

Save sakuro/6b5aa262d44b4e2bb11e94e5e2e774b6 to your computer and use it in GitHub Desktop.
Dataクラスで位置パラメータも使えるようにするハック
# まず素直に Data.define
Style = Data.define(:foreground, :background, :bold, :italic, :underline, :inverse)
class Style
# クラス内に置く小細工モジュール
module CtorFlags
# クラスごとに上書き可能な“設定”
def bool_flag_keys = %i[bold italic underline inverse]
def kw_defaults = { foreground: nil, background: nil }
.merge(bool_flag_keys.to_h { |k| [k, false] })
private def normalize_ctor_args(*flags, **kw)
syms = flags.flatten.map! { |f| f.to_sym }
unknown = syms - bool_flag_keys
raise ArgumentError, "Unknown flag(s): #{unknown.join(', ')}" unless unknown.empty?
attrs = kw_defaults.merge(kw) # 既定 → 最後にKWで上書き(明示優先)
syms.each { |k| attrs[k] = true }
attrs
end
# [] を包む(super は元の [])
def [](*flags, **kw)
super(**normalize_ctor_args(*flags, **kw))
end
# new も同仕様。環境で new が無ければ [] にフォールバック。
def new(*flags, **kw)
attrs = normalize_ctor_args(*flags, **kw)
begin
super(**attrs)
rescue NoMethodError
self.[](**attrs)
end
end
end
# 特異クラスにだけ適用
singleton_class.prepend CtorFlags
end
# 使い方
p Style[foreground: :blue] # => background=nil, bold=false, ...
p Style[:bold, foreground: :blue] # => bold=true(位置は true 扱い)
p Style[:bold, bold: false] # => 衝突は KW 勝ち → bold=false
p Style.new(:bold, foreground: :blue) # => new 入口でも同じ挙動
@sakuro
Copy link
Author

sakuro commented Sep 9, 2025

  1. Data.define でまず普通にクラスを作る
  2. 省略可能にしたい属性は initialize 側でデフォルト埋めして super(**attrs)
  3. クラスメソッド [] は一度退避した元の [] をラップして、位置フラグを処理してから orig_brackets(**attrs) に渡す

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment