diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:42:41 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-22 23:43:02 +0900 |
| commit | 3b783e97a9aac366a7d6e26059961ba53d5e8b20 (patch) | |
| tree | c3e6bb44007a2ed50dde73ff5e3f625ee981b990 /crates | |
| parent | aa4e9ff27b974343beeccdd14e07e13f0e261599 (diff) | |
| download | php-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>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/shirabe/src/script/event.rs | 70 | ||||
| -rw-r--r-- | crates/shirabe/tests/script/event_test.rs | 52 |
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" + ); } |
