aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-22 23:42:41 +0900
committernsfisis <nsfisis@gmail.com>2026-06-22 23:43:02 +0900
commit3b783e97a9aac366a7d6e26059961ba53d5e8b20 (patch)
treec3e6bb44007a2ed50dde73ff5e3f625ee981b990
parentaa4e9ff27b974343beeccdd14e07e13f0e261599 (diff)
downloadphp-shirabe-3b783e97a9aac366a7d6e26059961ba53d5e8b20.tar.gz
php-shirabe-3b783e97a9aac366a7d6e26059961ba53d5e8b20.tar.zst
php-shirabe-3b783e97a9aac366a7d6e26059961ba53d5e8b20.zip
feat(script): make originating event polymorphic via enum
Script\Event extends BaseEvent in PHP, so setOriginatingEvent accepts both a base event and a nested Script\Event, and calculateOriginatingEvent walks the chain via an instanceof check. The port had pinned the field to a concrete Option<Box<BaseEvent>>, leaving calculate_originating_event as todo!() and the nested-event test unportable. Introduce an OriginatingEvent enum (Base/Script) to model the instanceof tag, implement the recursive flattening, and un-ignore both originating event tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
-rw-r--r--crates/shirabe/src/script/event.rs70
-rw-r--r--crates/shirabe/tests/script/event_test.rs52
2 files changed, 100 insertions, 22 deletions
diff --git a/crates/shirabe/src/script/event.rs b/crates/shirabe/src/script/event.rs
index 5680c22..1b1e76d 100644
--- a/crates/shirabe/src/script/event.rs
+++ b/crates/shirabe/src/script/event.rs
@@ -13,7 +13,13 @@ pub struct Event {
composer: ComposerWeakHandle,
io: std::rc::Rc<std::cell::RefCell<dyn IOInterface>>,
dev_mode: bool,
- originating_event: Option<Box<BaseEvent>>,
+ originating_event: Option<OriginatingEvent>,
+}
+
+#[derive(Debug)]
+pub enum OriginatingEvent {
+ Base(BaseEvent),
+ Script(Box<Event>),
}
impl Event {
@@ -46,22 +52,25 @@ impl Event {
self.dev_mode
}
- pub fn get_originating_event(&self) -> Option<&BaseEvent> {
- self.originating_event.as_deref()
+ pub fn get_originating_event(&self) -> Option<&OriginatingEvent> {
+ self.originating_event.as_ref()
}
- pub fn set_originating_event(&mut self, event: BaseEvent) -> &mut Self {
- self.originating_event = Some(Box::new(self.calculate_originating_event(event)));
+ pub fn set_originating_event(&mut self, event: OriginatingEvent) -> &mut Self {
+ self.originating_event = Some(Self::calculate_originating_event(event));
self
}
- fn calculate_originating_event(&self, event: BaseEvent) -> BaseEvent {
- // if ($event instanceof Event && $event->getOriginatingEvent()) {
- // return $this->calculateOriginatingEvent($event->getOriginatingEvent());
- // }
- //
- // return $event;
- todo!()
+ fn calculate_originating_event(event: OriginatingEvent) -> OriginatingEvent {
+ if let OriginatingEvent::Script(boxed) = event {
+ let mut inner_event = *boxed;
+ if let Some(originating) = inner_event.originating_event.take() {
+ return Self::calculate_originating_event(originating);
+ }
+ return OriginatingEvent::Script(Box::new(inner_event));
+ }
+
+ event
}
}
@@ -86,3 +95,40 @@ impl EventInterface for Event {
self.inner.stop_propagation();
}
}
+
+impl EventInterface for OriginatingEvent {
+ fn get_name(&self) -> &str {
+ match self {
+ OriginatingEvent::Base(e) => e.get_name(),
+ OriginatingEvent::Script(e) => e.get_name(),
+ }
+ }
+
+ fn get_arguments(&self) -> &Vec<String> {
+ match self {
+ OriginatingEvent::Base(e) => e.get_arguments(),
+ OriginatingEvent::Script(e) => e.get_arguments(),
+ }
+ }
+
+ fn get_flags(&self) -> &IndexMap<String, PhpMixed> {
+ match self {
+ OriginatingEvent::Base(e) => e.get_flags(),
+ OriginatingEvent::Script(e) => e.get_flags(),
+ }
+ }
+
+ fn is_propagation_stopped(&self) -> bool {
+ match self {
+ OriginatingEvent::Base(e) => e.is_propagation_stopped(),
+ OriginatingEvent::Script(e) => e.is_propagation_stopped(),
+ }
+ }
+
+ fn stop_propagation(&mut self) {
+ match self {
+ OriginatingEvent::Base(e) => e.stop_propagation(),
+ OriginatingEvent::Script(e) => e.stop_propagation(),
+ }
+ }
+}
diff --git a/crates/shirabe/tests/script/event_test.rs b/crates/shirabe/tests/script/event_test.rs
index e7e574b..d143bd2 100644
--- a/crates/shirabe/tests/script/event_test.rs
+++ b/crates/shirabe/tests/script/event_test.rs
@@ -11,7 +11,7 @@ use shirabe::event_dispatcher::EventInterface;
use shirabe::io::IOInterface;
use shirabe::io::null_io::NullIO;
use shirabe::package::{RootPackageHandle, RootPackageInterfaceHandle};
-use shirabe::script::Event;
+use shirabe::script::{Event, OriginatingEvent};
fn create_composer_instance() -> ComposerHandle {
let composer =
@@ -29,7 +29,6 @@ fn create_composer_instance() -> ComposerHandle {
}
#[test]
-#[ignore]
fn test_event_sets_originating_event() {
let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
let composer = create_composer_instance();
@@ -50,7 +49,7 @@ fn test_event_sets_originating_event() {
"originatingEvent is initialized as null"
);
- script_event.set_originating_event(originating_event);
+ script_event.set_originating_event(OriginatingEvent::Base(originating_event));
// assertSame: the originating event passed in is returned unchanged.
assert_eq!(
@@ -62,13 +61,46 @@ fn test_event_sets_originating_event() {
);
}
-// In PHP, the intermediate originating event is itself a Script\Event, and
-// getOriginatingEvent() recurses to return the upper-most event. Here
-// set_originating_event takes a concrete event_dispatcher::Event, so a Script
-// Event cannot be passed as the originating event (it is not polymorphic), and
-// the test cannot be expressed faithfully.
#[test]
-#[ignore = "Event::set_originating_event takes a concrete event_dispatcher::Event, so a nested script::Event cannot be passed as originating event; the recursive calculate_originating_event behavior is not expressible"]
fn test_event_calculates_nested_originating_event() {
- todo!()
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let composer = create_composer_instance();
+
+ let originating_event =
+ BaseEvent::new("upperOriginatingEvent".to_string(), vec![], IndexMap::new());
+
+ let mut intermediate_event = Event::new(
+ "intermediate".to_string(),
+ composer.downgrade(),
+ io.clone(),
+ true,
+ vec![],
+ IndexMap::new(),
+ );
+ intermediate_event.set_originating_event(OriginatingEvent::Base(originating_event));
+
+ let mut script_event = Event::new(
+ "test".to_string(),
+ composer.downgrade(),
+ io,
+ true,
+ vec![],
+ IndexMap::new(),
+ );
+ script_event.set_originating_event(OriginatingEvent::Script(Box::new(intermediate_event)));
+
+ // assertNotSame/assertSame: compare by name since Rust lacks PHP object identity.
+ let name = script_event
+ .get_originating_event()
+ .map(EventInterface::get_name);
+ assert_ne!(
+ name,
+ Some("intermediate"),
+ "getOriginatingEvent() SHOULD NOT return intermediate events"
+ );
+ assert_eq!(
+ name,
+ Some("upperOriginatingEvent"),
+ "getOriginatingEvent() SHOULD return upper-most event"
+ );
}