Project

seh

0.0
No commit activity in last 3 years
No release in over 3 years
Structured event handler. Pure ruby event handling similar to w3c dom events. Synchronous, local event handling for complex emergent behaviors as required by something like a game engine. v0.3.0 improves a lot on v0.1.0.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

Seh

Structured event handler. Pure ruby event handling similar to w3c dom events. Check out examples/epic_battle.rb

Why Seh?

Seh was developed as a dependency of my ruby game engine. I couldn't find another ruby event library with the features I wanted.

You might want to use Seh if:

  • You need events/hooks/triggers/slots+signals
  • You need a synchronous system, because an event must be fully resolved before things can continue
  • An object/target/actor/thing might be affected by other things it doesn't know about
  • Your objects have underlying hierarchical / graph / observer relationships
  • You're hoping for complex emergent behaviors

You probably don't want to use Seh if:

  • You need distributed or asynchronous events/hooks/triggers/slots+signals
  • You're thinking "gee, this seems complicated, I really just need simple hooks" -> Seh is probably over-engineering for you

Features

Seh is driven by Seh::Event objects targeting objects of type Seh::EventTarget. Events are typed using Seh::EventType (which is mostly used implicitly).

In most event systems, such as w3c dom events in a web browser, events are handled by child nodes before the event bubbles to ancestor nodes. In Seh, each EventTarget which sees the Event may add callbacks to the event, before any callbacks on the event are executed. After each EventTarget has been visited, the Event executes its callbacks. This allows an ancestor object to affect an outcome on a descendant.

Major Features

  • EventTarget is a mixin allowing any object to be the target of an Event
  • Create an Event, add some targets - objects which mixin EventTarget - and dispatch the event. Each Event is one-use-only
  • Event has a list of types, e.g. :snow, :bad_weather, :sunshine; Types may be any object which defines equality ==
  • Bind callbacks to an EventTarget, e.g. my_target.bind(:snow) { "It's snowing!" }
  • Bind target callbacks using a type boolean expression, e.g. my_target.bind( Seh::or :hurricane, Seh::and(:rain, :sunshine, Seh::not(:cold)) ) { "It's either a hurricane, or sunny and raining and not cold." }
  • Disconnect callback binds, my_bind = my_target.bind(:only_needed) { "for awhile" }; my_bind.disconnect
  • EventTarget#observers defaults to [], and can be overridden to create an object graph. Each EventTarget recursively reachable by EventTarget#observers receives the event as if it was a top-level target.
  • Event makes it easy for events to "inherit" from one another, so that you may develop a rich event hierarchy on your application side. Note that there's no real ruby class inheritance, e.g. in examples/event/, the Event::damage() method calls Event::hostile(), making each damage event a hostile event.
  • Event inherits from OpenStruct to easily define attributes on the event
  • Event stages provide fine-grained control over callbacks

Understanding Event Stages & Callbacks

See Seh::Event#dispatch. When #dispach is called:

  1. determine the full set of targets affected by this event
  2. run callbacks on targets which match this event's types
  3. run stage callbacks contained in this event; typically targets will append stage callbacks to this event using Event#bind, #start, #finish
  4. Callback execution order: (1) start callbacks; (2) stage callbacks - in the order stages were added to the event; (3) finish callbacks
target = Seh::EventTarget::Default.new # Default includes EventTarget
target.bind(:fireball) do |event| 
  puts "1"
  event.finish { puts "4" }
end

event = Seh::Event.new
event.type :fireball
event.target target
event.start { puts "2" }

event.add_stage :burn_enemy
event.bind(:burn_enemy) { puts "3" }

event.dispatch

The output of the above code is:

1
2
3
4

Roadmap

I'm working on efficiency, so tens of thousands of events can be used each second in a game engine. There's a toy benchmark in 'rake benchmark'.

Release Notes

  • v0.3.0 - updated api, significantly expanded test coverage, documentation, examples, released under the BSD license.
  • v0.1.0 - an older version of the API that's not backwards-compatible

License

Seh is released under the BSD license.