Last active
September 10, 2025 00:19
-
-
Save sakuro/6b5aa262d44b4e2bb11e94e5e2e774b6 to your computer and use it in GitHub Desktop.
Dataクラスで位置パラメータも使えるようにするハック
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # まず素直に 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 入口でも同じ挙動 |
Author
sakuro
commented
Sep 9, 2025
- Data.define でまず普通にクラスを作る
- 省略可能にしたい属性は initialize 側でデフォルト埋めして super(**attrs)
- クラスメソッド [] は一度退避した元の [] をラップして、位置フラグを処理してから orig_brackets(**attrs) に渡す
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment