From: Michael 'entropie' Trommer Date: 2006-01-07T10:00:22+09:00 Subject: state pattern? --E39vaYmALEf/7YXx Content-Type: multipart/mixed; boundary="OXfL5xGRrasGEqWY" Content-Disposition: inline --OXfL5xGRrasGEqWY Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello, I found this State-pattern example on [1], and was interested to find a way to make this more useable for standard classes (not just servers as in the example) I'am not so skilled in OO coding and ruby, so iam interested what you all think. (and is it another implementation of the state pattern or iam on the wrong path?) [1] http://www.rubygarden.org/ruby?StatePattern So long -- Michael 'entropie' Trommer; http://ackro.org ruby -e "0.upto((a='njduspAhnbjm/dpn').size-1){|x| a[x]-=1}; p 'mailto:'+a" --OXfL5xGRrasGEqWY Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="state_pattern.rb" Content-Transfer-Encoding: quoted-printable # =3D Example # class StateTest # # include StateHelper # # def denied_during_curr_state_msg(meth, state) # "my method saz now: calling `#{meth}` during `#{state}` not allowed" # end #=09 # def initialize # @state =3D StateHelper::StateOff # end # # def on_msg(msg) # true # end # # def off_bar # true # end # # def meth # puts "sup?" # end # end # # a =3D StateTest.new # nothing cool happend # a.msg "foo" # is not allowed, because msg has the prefix `on`, rai= se NotAllowedDuringState # a.connect # toggles state, comes from module StateHelper # a.msg "bar" # is now allowed, raise NotAllowedDuringState error # a.connect # not allowed, because we are already "connected", rai= se NotAllowedDuringState # a.disconnect # allowed, comes as +connect* from StateHelper module # a.meth # returns "sup?" ;) # a.foo # raise a NoMethodError module StateHelper # def[ine] this method with argument meth and state for # yourself if you want DefaultErrDef =3D 'denied_during_curr_state_msg' class NotAllowedDuringState < Exception; end class StateOn < TrueClass; end class StateOff < FalseClass; end=09 def state?; @state; end =09 # toggles @state def toggle_state @state =3D (state? =3D=3D StateOn) ? StateOff : StateOn puts "state is now #{@state}" end # returns both state methods as array # first one is method for actual state, second only for debugging def mkMethodString(meth, state) arr =3D "off_#{meth}", "on_#{meth}" if @state.superclass =3D=3D TrueClass return arr.reverse end arr end =09 # grep virtual method call and check allowed during @state def method_missing(meth, *par) n, f =3D mkMethodString(meth, @state) if self.methods.include?(n) self.send(n, *par) elsif self.methods.include?(f) raise NotAllowedDuringState, denied_during_curr_state_msg(meth, @state) else # raise original expetion raise NoMethodError, "undefined method `#{meth}' #{self.inspect}" end end # toggles state alias :off_connect :toggle_state # toggles state alias :on_disconnect :toggle_state # ovewrite it if you need to def initialize @state =3D StateHelper::StateOff end end class StateTest include StateHelper # used to overwrite error msg... i dunno.. def denied_during_curr_state_msg(meth, state) "my error msg is cooler and saz: calling `#{meth}` during `#{state}` not = allowed" end =09 def on_msg(msg) true end def off_bar true end def meth puts "sup?" end end a=3DStateTest.new a.msg "foo" # is not allowed, because msg has the prefix `on` a.connect # toggles state, comes from module StateHelper a.msg "bar" # is now allowed a.connect # not allowed, because we are already "connected" a.disconnect # allowed a.meth # returns "sup?" ;) a.foo --OXfL5xGRrasGEqWY-- --E39vaYmALEf/7YXx Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2 (GNU/Linux) iD8DBQFDvxKOBBd8ye5RguQRAiE/AJ9mqEc1GoZDWkHvwfz61Hul1FgPpQCgwh/q YqK/fEvjaVim8sO8MIAjEcc= =BTFJ -----END PGP SIGNATURE----- --E39vaYmALEf/7YXx--