root/trunk/lib/fm/entity.rb

Revision 285, 5.2 kB (checked in by ged, 4 months ago)
  • More build system updates
  • Cleanup of some documentation headers
  • More spec conversion/cleanup.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Rev Author URL Id
Line 
1#!/usr/bin/ruby
2#
3# This file contains the FaerieMUD::Entity class, a derivative of
4# FaerieMUD::GameObject. It is the base class for all objects which are capable
5# of interaction with other objects via events.
6#
7# It provides event-handling behavior via the #handle_event method, which
8# delegates handling to a secondary method which is based on the class of the
9# event being handled. The event being handled is queried for
10# appropriately-named handlers via its #handler_names method, and the first one
11# which is implemented by the entity recieving the event is called with the
12# event object as its argument. If no specific handlers are implemented, the
13# #handle_any_event method is used instead, which by default raises a
14# #FaerieMUD::UnhandledEventError.
15#
16# == Synopsis
17#
18#   
19#
20# == To Do
21# * Perhaps make the event handlers hash into something that dispatches
22#   intelligently to superclasses, ala MUES::Event::Handler.
23#
24# == Subversion ID
25#
26# $Id$
27#
28# == Authors
29#
30# * Michael Granger <ged@FaerieMUD.org>
31#
32# :include: LICENSE
33#
34#---
35#
36# Please see the file LICENSE for licensing details.
37#
38
39
40# 11. Tools
41#     Thirty spokes meet at a nave;
42#     Because of the hole we may use the wheel.
43#     Clay is moulded into a vessel;
44#     Because of the hollow we may use the cup.
45#     Walls are built around a hearth;
46#     Because of the doors we may use the house.
47#     Thus tools come from what exists,
48#     But use from what does not.
49#
50#       - Lao Tse, _Tao te Ching_
51#          translated by Peter Merel
52
53require 'fm/gameobject'
54require 'fm/mixins'
55require 'fm/exceptions'
56require 'fm/event'
57require 'fm/linguistics'
58
59
60### The base class for all objects which are capable of interaction with
61### other objects via events.
62class FaerieMUD::Entity < FaerieMUD::GameObject
63        contributors :ged
64        include FaerieMUD::Hookable,
65                FaerieMUD::Debuggable
66
67        # SVN Revision
68        SVNRev = %q$Rev$
69
70        # SVN Id
71        SVNId = %q$Id$
72
73
74        #############################################################
75        ###     I N S T A N C E   M E T H O D S
76        #############################################################
77
78        ### Initialize the entity's instance variables
79        def initialize( args={} ) # :notnew:
80                @event_handler_cache = {}
81                super
82        end
83
84
85        ######
86        public
87        ######
88
89        # The event-handler lookup cache (a Hash of method objects keyed by
90        # event class).
91        attr_reader :event_handler_cache
92
93
94        ### Multi-event dispatch method. Calls #handle_event for each of the given
95        ### +events+.
96        def handle_events( *events )
97                events.collect {|e| self.handle_event(e) }.flatten
98        end
99
100
101        ### Event dispatcher method. This method does dynamic dispatch to
102        ### class-specific event handler methods. For each +event+ given, it will
103        ### look for a method called <tt>handle<em>eventClass</em>>()</tt>, where
104        ### <tt><em>eventClass</em></tt> is the class of the event to handle. If no
105        ### explicit handler is found, each of the event's superclasses is tried as
106        ### well. If no explicit handler is defined, it tries to call a fallback
107        ### handler <tt>handle_any_event()</tt>. If no handler is found, a
108        ### FaerieMUD::UnhandledEventError is raised.
109        def handle_event( event )
110                debug_msg( 1, "Handling a #{event.class.name} event." )
111                handler = self.get_handler_for_event( event )
112                result = handler.call( event )
113
114                return Array( result )
115        end
116
117
118        ### Callback invoked whenever a singleton method is added to the
119        ### receiver. Clears the event handler lookup cache if the method being
120        ### added contains the word 'handle'. Also aliased to
121        ### #singleton_method_removed and #singleton_method_undefined.
122        def singleton_method_added( sym )
123                debug_msg( 3, "Flushing event handler lookup cache" )
124                @event_handler_cache.clear if /handler/ =~ sym.to_s
125                super
126        end
127        alias_method :singleton_method_removed, :singleton_method_added
128        alias_method :singleton_method_undefined, :singleton_method_added
129
130
131        #
132        #       Linguistics support
133        #
134
135        ### Returns +true+ if the entity should be considered plural for the
136        ### purposes of generating english text.
137        def plural?
138                return false
139        end
140
141
142
143        #########
144        protected
145        #########
146
147        ### Fallback event handler. The default implementation of this method
148        ### just raises an UnhandledEventError, so deriviatives will probably
149        ### want to override it.
150        def handle_any_event( event )
151                raise FaerieMUD::UnhandledEventError,
152                          "No handler defined for #{event.class.name}s"
153        end
154
155
156        ### Get a handler as a callable object for the given +event+.
157        def get_handler_for_event( event )
158                handler = @event_handler_cache[event.class]
159
160                # Search the event's class heirarchy for Event subclasses, and
161                # look up handler methods based on the class name
162                if handler.nil?
163                        event.handler_names.each do |methodName|
164                                debug_msg( 2, "Checking for a #{methodName} method..." )
165                                if self.respond_to?( methodName )
166                                        debug_msg( 2, "   found #{methodName}." )
167                                        handler = self.method( methodName )
168                                        break
169                                end
170                        end
171
172                        # If no handler has yet been found, try to fetch the fallback
173                        # handler.
174                        if handler.nil?
175                                if self.respond_to?( :handle_any_event )
176                                        handler = self.method( :handle_any_event )
177                                else
178                                        raise UnhandledEventError,
179                                                  "No handler defined for #{event.class.name}s"
180                                end
181                        end
182
183                        @event_handler_cache[ event.class ] = handler
184                end
185
186                return handler
187        end
188
189
190end # class FaerieMUD::Entity
Note: See TracBrowser for help on using the browser.