バグ #1377
未完了
Diva::Modelの子クラス(A)で定義したフィールドの型がAの子クラス(B)で適用されない
Yuto Tokunaga さんが約5年前に追加.
約5年前に更新.
説明
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 で確認.
Diva::Modelの孫クラスを作ろうと思っていなかったので、こういう継承をしたときにどうなるかはわかりませんね。
とはいえ、禁止しているとはどこにも書いた覚えがないので(それならそうと書いたほうが良かったと反省)、必要あれば何かしても良いかなと思います。どういう時に必要になりましたか?
複数のモデルに共通のフィールドを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
- ステータス を 分類待ち から 実装待ち に変更
- 担当者 を Yuto Tokunaga から 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が子クラスに継承されるようにしても良いのではないか、と思いました。
ありがとうございます.
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
他の形式にエクスポート: Atom
PDF