定义知道自己 class 的工厂并查找值
Defining factories that know their own class and look up the values
我有一个验证器 class,它为 Foo
和 Bar
类型的对象定义有效事件。每个 Foo
对象都有属性 alert_events
、window_events
和 user_events
,每个 Bar
对象都有 state_events
和 user_events
。
class EventListConformanceValidator
VALID_EVENTS = {
foo: {
alert_events: {
onAlertLoad: String,
onAlertUnload: String,
},
window_events: {
onWindowLoaded: Array,
},
user_events: {
onLoginStatusChanged: String,
},
},
bar: {
state_events: {
onAborted: Float,
},
user_events: {
skipClicked: nil
}
}
}
end
我想使用 FactoryBot 动态生成工厂,它将为每个属性填充正确的事件类型。例如,对于 alert_events
,只应创建类型为 onAlertLoad
或 onAlertUnload
的事件。
天真地,我可以写出以下内容:
class Event
attr_accessor :type
end
FactoryBot.define do
factory :event do
type { nil }
end
factory :alert_event do
type { ["onAlertLoad", "onAlertUnload"].sample }
end
factory :window_events do
# and so on ...
end
end
但显然这会重复很多次。相反,我想要一个单一的事实来源,并从哈希 VALID_EVENTS
中获取定义。此外,还有一个问题是 user_events
可以同时存在于 Foo
和 Bar
,所以我不能单独使用 user_events
,因为它会产生歧义。
所以我尝试动态生成工厂foo_alert_event
、foo_window_event
等:
EventListConformanceValidator::VALID_EVENTS.each do |klass, attribute_hash|
attribute_hash.keys.map(&:to_s).uniq.each do |attribute|
factory_name = (klass.to_s + "_" + attribute.to_s.singularize).to_sym
factory factory_name, class: Event, parent: :event do
type { "how do I get the event types to sample?" }
end
end
end
但是在type
的动态求值中,我不知道如何引用实际的工厂class名称(foo
/bar
)或者属性名称(alert_events
等)以便我可以在 VALID_EVENTS
.
中查找键
我怎样才能做到这一点?
听起来你想要这样的东西(但我不明白你想要达到什么目的)
VALID_EVENTS = {
foo: {
alert_events: {
onAlertLoad: String,
onAlertUnload: String,
},
window_events: {
onWindowLoaded: Array,
},
user_events: {
onLoginStatusChanged: String,
},
},
bar: {
state_events: {
onAborted: Float,
},
user_events: {
skipClicked: nil,
},
},
}.freeze
class Event
attr_accessor :type
end
FactoryBot.define do
VALID_EVENTS.each do |klass, attribute_hash|
attribute_hash.each do |name, events|
factory_name = "#{klass}_#{name.to_s.singularize}".to_sym
types = events.keys.map(&:to_s)
factory factory_name, class: Event do
type { types }
end
end
end
end
describe "SO" do
it "works" do
klass = build(:foo_alert_event)
expect(klass.type).to eq(["onAlertLoad", "onAlertUnload"])
end
end
rspec
SO
works
Finished in 0.94792 seconds (files took 3.25 seconds to load)
1 example, 0 failures
我有一个验证器 class,它为 Foo
和 Bar
类型的对象定义有效事件。每个 Foo
对象都有属性 alert_events
、window_events
和 user_events
,每个 Bar
对象都有 state_events
和 user_events
。
class EventListConformanceValidator
VALID_EVENTS = {
foo: {
alert_events: {
onAlertLoad: String,
onAlertUnload: String,
},
window_events: {
onWindowLoaded: Array,
},
user_events: {
onLoginStatusChanged: String,
},
},
bar: {
state_events: {
onAborted: Float,
},
user_events: {
skipClicked: nil
}
}
}
end
我想使用 FactoryBot 动态生成工厂,它将为每个属性填充正确的事件类型。例如,对于 alert_events
,只应创建类型为 onAlertLoad
或 onAlertUnload
的事件。
天真地,我可以写出以下内容:
class Event
attr_accessor :type
end
FactoryBot.define do
factory :event do
type { nil }
end
factory :alert_event do
type { ["onAlertLoad", "onAlertUnload"].sample }
end
factory :window_events do
# and so on ...
end
end
但显然这会重复很多次。相反,我想要一个单一的事实来源,并从哈希 VALID_EVENTS
中获取定义。此外,还有一个问题是 user_events
可以同时存在于 Foo
和 Bar
,所以我不能单独使用 user_events
,因为它会产生歧义。
所以我尝试动态生成工厂foo_alert_event
、foo_window_event
等:
EventListConformanceValidator::VALID_EVENTS.each do |klass, attribute_hash|
attribute_hash.keys.map(&:to_s).uniq.each do |attribute|
factory_name = (klass.to_s + "_" + attribute.to_s.singularize).to_sym
factory factory_name, class: Event, parent: :event do
type { "how do I get the event types to sample?" }
end
end
end
但是在type
的动态求值中,我不知道如何引用实际的工厂class名称(foo
/bar
)或者属性名称(alert_events
等)以便我可以在 VALID_EVENTS
.
我怎样才能做到这一点?
听起来你想要这样的东西(但我不明白你想要达到什么目的)
VALID_EVENTS = {
foo: {
alert_events: {
onAlertLoad: String,
onAlertUnload: String,
},
window_events: {
onWindowLoaded: Array,
},
user_events: {
onLoginStatusChanged: String,
},
},
bar: {
state_events: {
onAborted: Float,
},
user_events: {
skipClicked: nil,
},
},
}.freeze
class Event
attr_accessor :type
end
FactoryBot.define do
VALID_EVENTS.each do |klass, attribute_hash|
attribute_hash.each do |name, events|
factory_name = "#{klass}_#{name.to_s.singularize}".to_sym
types = events.keys.map(&:to_s)
factory factory_name, class: Event do
type { types }
end
end
end
end
describe "SO" do
it "works" do
klass = build(:foo_alert_event)
expect(klass.type).to eq(["onAlertLoad", "onAlertUnload"])
end
end
rspec
SO
works
Finished in 0.94792 seconds (files took 3.25 seconds to load)
1 example, 0 failures