singleton method Data.define

define(*args) -> Class[permalink][rdoc][edit]
define(*args) {|subclass| block } -> Class

Data クラスに新しいサブクラスを作って、それを返します。

サブクラスでは値オブジェクトのメンバに対するアクセスメソッドが定義されています。



Dog = Data.define(:name, :age)
fred = Dog.new("Fred", 5)
p fred.name # => "Fred"
p fred.age  # => 5

メンバの値を書き換えることはできません。



Dog = Data.define(:name, :age)
fred = Dog.new("Fred", 5)
fred.age = 6 # => NoMethodError

メンバを持たないサブクラスも定義可能です。以下のように、パターンマッチに利用できます。



class HTTPFetcher
  Response = Data.define(:body)
  NotFound = Data.define

  def get(url)
    # ダミーの実装
    if url == "http://example.com/"
      Response.new(body: "Current time is #{Time.now}")
    else
      NotFound.new
    end
  end
end

def fetch(url)
  fetcher = HTTPFetcher.new
  case fetcher.get(url)
  in HTTPFetcher::Response(body)
    body
  in HTTPFetcher::NotFound
    :NotFound
  end
end

p fetch("http://example.com/")     # => "Current time is 2023-01-10 10:00:53 +0900"
p fetch("http://example.com/404")  # => :NotFound
[PARAM] args:
値オブジェクトのクラスを定義するための可変長引数。Symbol または String を指定します。
[RETURN]
Data のサブクラスを返します。
[EXCEPTION] TypeError:
引数に Symbol, String (String に暗黙の型変換が行われるオブジェクトを含む) 以外を指定した場合に発生します。

ブロックを指定した場合

Data.define にブロックを指定した場合は定義した Data をコンテキストにブロックを評価します。また、定義した Data はブロックパラメータにも渡されます。



Customer = Data.define(:name, :address) do
  def greeting
    "Hello #{name}!"
  end
end
p Customer.new("Dave", "123 Main").greeting # => "Hello Dave!"

なお、Dataのサブクラスのインスタンスを生成する際にオプション引数を使用したいときは、 initialize メソッドをオーバーライドすることで実現できます。



Point = Data.define(:x, :y) do
  def initialize(x:, y: 0)
    super
  end
end

p Point.new(x: 1)        # => #<data Point x=1, y=0>
p Point.new(x: 1, y: 2)  # => #<data Point x=1, y=2>