Project

General

Profile

Actions

バグ #1377

open

Diva::Modelの子クラス(A)で定義したフィールドの型がAの子クラス(B)で適用されない

Added by Yuto Tokunaga about 5 years ago. Updated about 5 years ago.

Status:
実装待ち
Priority:
通常
Target version:
プラグイン名:
ブランチ:
クラッシュする:
No

Description

Diva::Modelの子クラス(A)でfield.uri等で定義したフィールドの型が,Aの子クラス(B)ではStringになってしまい,期待した型が得られません.

require 'diva'

class A < Diva::Model
  field.uri :uri
  field.time :created
end

class B < Base
  field.uri :alt_uri
  field.time :updated
end

s = 'https://example.com/'
t = '2019-08-27T20:01:00'

a = A.new uri: s, created: t
b = B.new uri: s, alt_uri: s, created: t, updated: t

p a.uri.class.name # => "Diva::URI" 
p a.created.class.name # => "Time" 
p b.uri.class.name # => "String" 
p b.alt_uri.class.name # => "Diva:URI" 
p b.created.class.name # => "String" 
p b.updated.class.name # => "Time" 

Ruby v2.6.2, diva v1.0.0 で確認.

Actions #1

Updated by toshi_a 初音 about 5 years ago

Diva::Modelの孫クラスを作ろうと思っていなかったので、こういう継承をしたときにどうなるかはわかりませんね。

とはいえ、禁止しているとはどこにも書いた覚えがないので(それならそうと書いたほうが良かったと反省)、必要あれば何かしても良いかなと思います。どういう時に必要になりましたか?

Actions #2

Updated by toshi_a 初音 about 5 years ago

  • Assignee set to Yuto Tokunaga
Actions #3

Updated by Yuto Tokunaga about 5 years ago

複数のモデルに共通のフィールドをBaseクラスに実装してコードの重複を防ぎたいときに使います.

下の例では,ActivityStream 2.0のオブジェクトを表現するモデルを作るときに,Activity, Actor, Object等の全てのオブジェクトに共通のフィールドをBaseクラスで定義し,Baseを継承して利用しています.

# ActivityStream 2.0のオブジェクトの共通フィールドを定義
class Base < Diva::Model
  field.string :type, required: true
  field.uri    :id, required: true
  field.string :name, required: true
  field.uri    :url

  # Basis modelのフィールド定義
  # https://reference.mikutter.hachune.net/model/2017/05/06/basis-model.html
  alias title name
  alias uri id
  alias perma_link url
end

class Activity < Base
  field.has :actor, Actor
  field.has :object, Object
end

class Actor < Base
  # Actorのフィールド
end

class Object < Base
  # Objectのフィールド
end
Actions #4

Updated by toshi_a 初音 about 5 years ago

  • Status changed from 分類待ち to 実装待ち
  • Assignee changed from Yuto Tokunaga to toshi_a 初音

これ相当迷いましたが、継承したときにFieldも継承しても良いのではないか、という結論に至りました。

まず、今エクスポートのみができるDiva::ModelのSchema(Diva Schema)ですが、これをインポートすることでModelの定義とすることができるアップデートを予定しています。
これは、mikutterプロセスが分散した場合にModelを扱う手がかりになります。Spellなどは、このことを念頭に置いて設計されています。

Diva Schemaは継承関係を持たないので、継承を許すのは禍根になるのではないかと思っていました。
実際には継承されたDiva::SchemaのSchemaに親で定義された全てのFieldを出力してやれば、他のmikutterプロセスで復元されたModelから継承関係が欠落していても問題ありません。mikutterエコシステムはModelの継承関係を一切利用しないからです。

一方、サードパーティプラグインが特定のModelを継承したModelを要求するといった悪用をすることも懸念されます。しかしこういった使い方はあくまでそのサードパーティプラグインのエコシステムの中で閉じているため、そのプラグインの問題として完結しそうです。
したがって、定義が簡略化できるというメリットを取って、Fieldが子クラスに継承されるようにしても良いのではないか、と思いました。

Actions #5

Updated by Yuto Tokunaga about 5 years ago

ありがとうございます.

Model定義を簡略化するための別のアプローチとして,Module.includedを使う方法を知ったので追記しておきます.この方法だとdivaを修正せずに解決できます.これはcore/lib/diva_hacks/mixin/photo_mixin.rbでも使われています.

module ObjectMixin
  def self.included(klass)
    klass.field.string :type, required: true
    klass.field.uri    :id,   required: true
    klass.field.string :name, required: true
    klass.field.uri    :url
  end

  def title; name end
  def uri; id end
  def perma_link; url end
end

class Activity < Diva::Model
  include ObjectMixin

  field.has :actor, Actor
  field.has :object, Object
end

class Actor < Diva::Model
  include ObjectMixin

  # Actorのフィールド
end

class Object < Diva::Model
  include ObjectMixin

  # Objectのフィールド
end
Actions

Also available in: Atom PDF