Changeset 252
- Timestamp:
- 01/27/06 15:07:23 (3 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 11 modified
-
lib/fm/commandparser.rb (modified) (2 diffs)
-
lib/fm/entity.rb (modified) (1 diff)
-
lib/fm/gameobject.rb (modified) (1 diff)
-
lib/fm/linguistics.rb (modified) (2 diffs)
-
lib/fm/perception.rb (modified) (1 diff)
-
lib/fm/spirit.rb (modified) (7 diffs)
-
lib/fm/verb.rb (modified) (4 diffs)
-
lib/fm/verbs (added)
-
lib/fm/verbs/all.rb (added)
-
lib/fm/verbs/simple.rb (added)
-
tests/commandparser.tests.rb (modified) (6 diffs)
-
tests/linguistics.tests.rb (modified) (4 diffs)
-
tests/simpleverb.tests.rb (added)
-
tests/spirit.tests.rb (modified) (6 diffs)
-
tests/verb.tests.rb (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/fm/commandparser.rb
r219 r252 56 56 57 57 58 ### Return the set of FaerieMUD::Verb objects this parser knows about 59 def verbs 60 return @verbset.values.uniq 61 end 62 63 58 64 ### Update the parser's verb set from the given +verbs+. 59 65 def updateVerbSet( *verbs ) … … 80 86 81 87 88 89 82 90 end # class FaerieMUD::CommandParser 83 91 -
trunk/lib/fm/entity.rb
r251 r252 130 130 131 131 132 # 133 # Linguistics support 134 # 135 136 ### Returns +true+ if the entity should be considered plural for the 137 ### purposes of generating english text. 138 def plural? 139 return false 140 end 141 142 132 143 133 144 ######### -
trunk/lib/fm/gameobject.rb
r250 r252 154 154 155 155 156 ### Create an example instance of the receiving class. This is used to ease 157 ### the complexity of creating example objects for experimentation. This 158 ### should be overridden by object classes which require instantiation 159 ### arguments. 160 def self::example( args={} ) 161 self::new( args ) 162 end 163 164 156 165 ############################################################# 157 166 ### I N S T A N C E M E T H O D S -
trunk/lib/fm/linguistics.rb
r251 r252 97 97 include FaerieMUD::Linguistics 98 98 99 ### Create the sentence with the given +subject+, +verb+, and 100 ### optional +direct_object+. 101 def initialize( subject, verb, direct_object=nil, *prep_phrases ) 102 @subject = subject 103 @verb = verb 104 @direct_object = direct_object 105 @prep_phrases = prep_phrases 99 ### Create the sentence. Can be constructed either with an explicit 100 ### subject, verb, and optional direct object, or with a 101 ### FaerieMUD::Event that will provide these parts. 102 def initialize( *args ) 103 if args.length == 1 104 init_from_event( args.first ) 105 else 106 init_from_parts( *args ) 107 end 106 108 end 107 109 108 attr_reader :subject, :verb, :direct_object 110 111 # The subject of the sentence (a FaerieMUD::GameObject object) 112 attr_reader :subject 113 114 # The FaerieMUD;;Verb instance associated with the sentence 115 attr_reader :verb 116 117 # The FaerieMUD::GameObject which is the recipient of the action in the 118 # sentence, if any. 119 attr_reader :direct_object 109 120 110 121 … … 113 124 parts = [ 114 125 makeNounPhrase( @subject ), 115 conjugateVerb( @verb,@subject )126 @verb.inflect_for( @subject ) 116 127 ] 117 128 118 129 parts << makeNounPhrase( @direct_object ) if @direct_object 119 parts.push( *(@prep_phrases.flatten.compact) )120 130 121 131 return parts.join( " " ) + "." 122 132 end 133 134 135 ######### 136 protected 137 ######### 138 139 ### Set the members of the sentence from the parts of the given +event+ 140 ### (a FaerieMUD::Event object). 141 def init_from_event( event ) 142 init_from_parts( event.instigator, event.verb, event.target ) 143 end 144 145 ### Set the members of the sentence from the given +subject+, +verb+, 146 ### and +direct_object+. 147 def init_from_parts( subject, verb, direct_object=nil ) 148 @subject = subject 149 @verb = verb 150 @direct_object = direct_object 151 end 152 153 123 154 end 124 155 -
trunk/lib/fm/perception.rb
r251 r252 49 49 50 50 ### Create a new Perception for the given +perceiver+, which will be the 51 ### dele ated describer of any PerceptualEvents which are handled.51 ### delegated describer of any PerceptualEvents which are handled. 52 52 def initialize( perceiver, args={} ) 53 53 @perceiver = perceiver -
trunk/lib/fm/spirit.rb
r250 r252 120 120 ### Create a new FaerieMUD::Spirit object. 121 121 def initialize( args={} ) 122 @animatedObject s = []122 @animatedObject = nil 123 123 @parser = FaerieMUD::CommandParser::new 124 124 … … 134 134 } 135 135 136 @inputThread = nil 137 @running = false 138 136 139 super 137 140 end … … 145 148 attr_locked_reader :parser 146 149 147 # The AnimatedObject scontrolled by this Spirit.148 attr_locked_reader :animatedObject s150 # The AnimatedObject controlled by this Spirit. 151 attr_locked_reader :animatedObject 149 152 150 153 # IO Callbacks … … 173 176 self.writelocked do 174 177 object.controller = self 175 @animatedObjects += [ object ] 176 end 177 178 self.updateParser 178 @animatedObject = object 179 self.updateParser 180 end 179 181 end 180 182 … … 182 184 ### Remove the specified +object+ (FaerieMUD::AnimatedObject) from the 183 185 ### list being controlled by the Spirit. 184 def deanimate( object ) 186 def deanimate 187 return if @animatedObject.nil? 188 185 189 self.writelocked do 186 object.controller = nil187 @animatedObject s -= [ object ]190 @animatedObject.controller = nil 191 @animatedObject = nil 188 192 end 189 193 end … … 194 198 ### currently-animated objects. 195 199 def updateParser 196 verbs = @animatedObject s.collect {|aobj| aobj.verbs}.flatten200 verbs = @animatedObject.verbs 197 201 @parser.updateVerbSet( *verbs ) 198 202 end … … 204 208 end 205 209 210 211 ######### 212 protected 213 ######### 214 215 ### Start the input loop of the spirit to fetch use input. 216 def start 217 @inputThread = Thread::new( &inputLoop ) 218 end 219 220 221 ### Wait for input from the Player and pass it to the CommandParser for 222 ### action. 223 def inputLoop 224 Thread.current.abort_on_exception = true 225 226 @running = true 227 while @running 228 rawInput = @ioHandlers[:input].call or next 229 230 231 end 232 233 end 234 235 236 206 237 end # class FaerieMUD::Spirit 207 238 -
trunk/lib/fm/verb.rb
r217 r252 1 1 #!/usr/bin/ruby 2 2 # 3 # This file contains the FaerieMUD::Verb class , a derivative of4 # FaerieMUD::GameObject. Verbs are objects which are used to generate game5 # events. They react to stimulus in the form of Events, timers, or other action,6 # generating events which should be propagatedby the instigating object.3 # This file contains the FaerieMUD::Verb class. Verbs are objects which are used 4 # to generate game events. They react to stimulus in the form of Events, 5 # Activity timers, or other actions, generating events which should be propagated 6 # by the instigating object. 7 7 # 8 8 # == Subversion ID … … 28 28 29 29 30 ### Game verb class 30 ### Game verb class. 31 31 class FaerieMUD::Verb < FaerieMUD::GameObject 32 32 contributors :ged … … 56 56 57 57 ### Set up the verb's internal structure 58 def initialize # :notnew:58 def initialize( args={} ) # :notnew: 59 59 super 60 @words = self.class.generateWords()60 @words ||= self.class.generateWords() 61 61 end 62 62 … … 66 66 ###### 67 67 68 ### CommandParser interface: query the verb for the word/s which cause it to69 ### be invoked. By default this returns the name of the verb class with the70 ### 'verb' part removed.68 ### CommandParser interface: query the verb for the word/s which cause 69 ### it to be invoked. By default this returns the name of the verb class 70 ### with the 'verb' part removed. 71 71 attr_reader :words 72 72 73 73 74 ### Return the primary English word for this noun. 75 def word 76 @words.first 77 end 78 79 74 80 ### Event interface: "run" the verb, generating the event/s necessary to 75 ### express the action in the game world. The given +instigator+, +origin+,76 ### and +target+ will be used when building event/s. See81 ### express the action in the game world. The given +instigator+, 82 ### +origin+, and +target+ will be used when building event/s. See 77 83 ### FaerieMUD::Event::new for definitions 78 def invoke( instigator, origin , target=nil )84 def invoke( instigator, origin=nil, target=nil ) 79 85 raise NotImplementedError, 80 86 "Required method #invoke not implemented in %s" % 81 [self.class.name] 87 [self.class.name] 88 end 89 90 91 ### Return the Verb's word inflected for the given +subject+, which should 92 ### be an object that responds to #plural?. 93 def inflect_for( subject ) 94 word = self.words.first 95 return "#{self.word}s" unless subject.plural? 96 return word 82 97 end 83 98 -
trunk/tests/commandparser.tests.rb
r212 r252 4 4 # $Id$ 5 5 # 6 # Copyright (c) 2003 , 2004, 2005The FaerieMUD Consortium.6 # Copyright (c) 2003-2006 The FaerieMUD Consortium. 7 7 # 8 8 … … 19 19 20 20 require 'fm/commandparser' 21 require 'fm/verbs/all' 21 22 22 23 ### This test suite tests the CommandParser of FaerieMUD. … … 30 31 31 32 33 def setup 34 @parser = FaerieMUD::CommandParser::new 35 end 36 32 37 33 38 ################################################################# … … 35 40 ################################################################# 36 41 37 ### Instance test38 def test_Instance39 printTestHeader "CommandParser: Instantiation"40 rval = nil41 42 assert_instance_of Class, FaerieMUD::CommandParser43 assert_nothing_raised {44 rval = FaerieMUD::CommandParser::new45 }46 assert_instance_of FaerieMUD::CommandParser, rval47 end48 49 50 42 ### Parser should accept a list of verbs from which to derive its command 51 43 ### table. 52 def test_UpdateVerbsShouldUpdateVerbset 53 printTestHeader "CommandParser: Updating the parser's verb list should " + 54 "update its verbset" 55 parser = FaerieMUD::CommandParser::new 44 def test_parser_should_update_its_command_table_from_given_verbs 56 45 verb = MockVerb::new 57 46 … … 62 51 63 52 # Now add the verb to the parser 64 assert parser.verbset.empty?, "Parser's verbset should be empty initially"53 assert @parser.verbset.empty?, "Parser's verbset should be empty initially" 65 54 assert_nothing_raised do 66 parser.updateVerbSet( verb )55 @parser.updateVerbSet( verb ) 67 56 end 68 57 69 58 # Verify that everything went as planned. 70 59 verb.verify 71 assert !parser.verbset.empty?, 72 "Parser's verbset should not be empty after updating" 73 assert parser.verbset.key?("test"), 60 assert @parser.verbset.key?("test"), 74 61 "Parser should have the 'test' verb after updating" 75 assert parser.verbset.key?("try"),62 assert @parser.verbset.key?("try"), 76 63 "Parser should have the 'try' verb after updating" 77 64 end … … 80 67 ### Parser should raise an exception if two verbs try to register the same 81 68 ### command. 82 def test_UpdateVerbsShouldRaiseOnCollision 83 printTestHeader "CommandParser: Updating the parser's verb list should " + 84 "raise an exception for command collisions" 85 parser = FaerieMUD::CommandParser::new 69 def test_parser_should_raise_an_exception_if_two_verbs_are_registered_with_the_same_command 86 70 87 71 # Make two mock verbs with colliding wordsets 88 verb1 = MockVerb::new 89 verb1.setReturnValues( :words => [%w[test try]], :eql? => false ) 90 verb2 = MockVerb::new 91 verb2.setReturnValues( :words => [%w[trim try]], :eql? => false ) 72 verb1 = Class::new( FaerieMUD::SimpleVerb ) do 73 set_words %w[test try] 74 end.instance 75 verb2 = Class::new( FaerieMUD::SimpleVerb ) do 76 set_words %w[trim try] 77 end.instance 92 78 93 79 assert_raises( FaerieMUD::CommandCollisionError ) do 94 parser.updateVerbSet( verb1, verb2 )80 @parser.updateVerbSet( verb1, verb2 ) 95 81 end 96 82 end 97 83 98 84 99 ### Parser should ignore verbs it already has 100 def test_UpdateVerbsShouldIgnoreDuplicates 101 printTestHeader "CommandParser: Updating the parser's verb list should " + 102 "ignore words it already has" 103 104 parser = FaerieMUD::CommandParser::new 105 106 verb1 = MockVerb::new 107 verb1.setReturnValues( :words => [%w[test try]] ) 85 ### Parser should ignore verbs it already knows about 86 def test_parser_should_ignore_verbs_it_already_knows_about_when_updating_its_verb_list 87 verb = Class::new( FaerieMUD::SimpleVerb ) do 88 set_words %w[test try] 89 end.instance 108 90 109 91 # Add it once 110 92 assert_nothing_raised do 111 parser.updateVerbSet( verb1)93 @parser.updateVerbSet( verb ) 112 94 end 95 96 # The parser's verbset should now contain the added verb 97 assert_equal 1, @parser.verbs.length 113 98 114 99 # Add it again, which shouldn't fail 115 100 assert_nothing_raised do 116 parser.updateVerbSet( verb1)101 @parser.updateVerbSet( verb ) 117 102 end 118 103 104 # The parser's verbset shouldn't contain more than one verb still 105 assert_equal 1, @parser.verbs.length, 106 "Verbset expected to only contain one verb (%p)" % [@parser.verbset] 119 107 end 120 108 end -
trunk/tests/linguistics.tests.rb
r250 r252 4 4 # $Id$ 5 5 # 6 # Copyright (c) 2005 The FaerieMUD Consortium.6 # Copyright (c) 2005, 2006 The FaerieMUD Consortium. 7 7 # 8 8 … … 19 19 20 20 require 'fm/linguistics' 21 require 'fm/verbs/simple' 21 22 22 23 … … 24 25 class FaerieMUD::LinguisticsTestCase < FaerieMUD::TestCase 25 26 27 # For testing mixin functions 26 28 class ThingerieThing 27 29 include FaerieMUD::Linguistics 28 30 end 29 31 32 # For testing sentence construction 30 33 class TestingEntity < FaerieMUD::Entity; end 34 class DriveEvent < FaerieMUD::Event; end 35 class DriveVerb < FaerieMUD::SimpleVerb 36 set_event_class DriveEvent 37 end 31 38 32 39 40 ### Setup/teardown 33 41 def setup 34 42 @obj = ThingerieThing.new 35 43 @entity = TestingEntity.new 44 @verb = DriveVerb.instance 36 45 end 37 46 … … 80 89 81 90 91 def test_sentence_created_with_subjectverb_event_creates_readable_text 92 rval = nil 93 event = @verb.invoke( @entity ) 94 sentence = FaerieMUD::Linguistics::Sentence.new( event ) 95 96 assert_nothing_raised do 97 rval = sentence.to_s 98 end 99 100 assert_equal "a testing entity drives.", rval 101 end 102 82 103 end 83 104 -
trunk/tests/spirit.tests.rb
r235 r252 4 4 # $Id$ 5 5 # 6 # Copyright (c) 2003 , 2004, 2005The FaerieMUD Consortium.6 # Copyright (c) 2003-2006 The FaerieMUD Consortium. 7 7 # 8 8 … … 18 18 end 19 19 20 require 'flexmock' 20 21 require 'fm/spirit' 21 22 require 'fm/animatedobject' … … 24 25 class FaerieMUD::SpiritTestCase < FaerieMUD::TestCase 25 26 26 # Mock the classes that interact with the Spirit so it can be tested inside-27 # out.28 class MockAnimatedObject < Test::Unit::MockObject( FaerieMUD::AnimatedObject ); end29 30 27 31 28 ### Setup methods (aliased for older versions of Test::Unit) 32 29 def setup 33 @ testAnimObj = MockAnimatedObject::new30 @spirit = FaerieMUD::Spirit.new 34 31 super 35 32 end 36 alias_method :set_up, :setup37 38 ### Teardown methods (aliased for older versions of Test::Unit)39 def teardown40 @testAnimObj = nil41 super42 end43 alias_method :tear_down, :teardown44 33 45 34 … … 48 37 ################################################################# 49 38 50 ### Instance test 51 def test_00_Instance 39 def test_spirit_objects_should_have_aspects_of_immortality 52 40 rval = nil 53 printTestHeader "Spirit: Instantiation"54 55 assert_instance_of Class, FaerieMUD::Spirit56 57 # Test with a valid argument list58 assert_nothing_raised {59 rval = FaerieMUD::Spirit::new60 }61 assert_instance_of FaerieMUD::Spirit, rval62 63 # Make Spirit objects for each further test64 self.class.addSetupBlock {65 @testSpirit = FaerieMUD::Spirit::new66 }67 self.class.addTeardownBlock {68 @testSpirit = nil69 }70 end71 72 73 ### Test the aspects of immortality (proxies for constituents of animated74 ### objects)75 def test_10_AspectsOfImmortality76 rval = nil77 printTestHeader "Spirit: Aspects of Immortality"78 41 79 42 # Aspect accessors (ComposedObject::Constituents) 80 43 %w{physical mental creative}.each do |atype| 81 44 meth = atype 82 assert_respond_to @ testSpirit, meth83 assert_nothing_raised { rval = @ testSpirit.send(meth) }45 assert_respond_to @spirit, meth 46 assert_nothing_raised { rval = @spirit.send(meth) } 84 47 assert_kind_of FaerieMUD::ComposedObject::Constituent, rval 85 48 end … … 87 50 # Statistic accessors -- developmental 88 51 %w{incarnativity kenning divinity}.each do |aspect| 89 assert_respond_to @ testSpirit, aspect90 assert_nothing_raised { rval = @ testSpirit.send(aspect) }52 assert_respond_to @spirit, aspect 53 assert_nothing_raised { rval = @spirit.send(aspect) } 91 54 assert_instance_of FaerieMUD::DevelopmentalObject, rval 92 55 end … … 94 57 # Statistic accessors -- linear 95 58 %w{presence cognizance influence}.each do |aspect| 96 assert_respond_to @ testSpirit, aspect.intern97 assert_nothing_raised { rval = @ testSpirit.send(aspect) }59 assert_respond_to @spirit, aspect.intern 60 assert_nothing_raised { rval = @spirit.send(aspect) } 98 61 assert_instance_of Fixnum, rval 99 62 end 100 63 end 64 65 def test_animating_should_set_the_animated_objects_controller 66 FlexMock.use( "animated object" ) do |mockAnimObj| 67 mockAnimObj = FlexMock.new 68 mockAnimObj.should_receive( :controller= ).with( @spirit ) 69 mockAnimObj.should_receive( :verbs ).returns( [] ) 70 71 assert_nothing_raised do 72 @spirit.animate( mockAnimObj ) 73 end 74 end 75 end 76 77 def test_should_unset_previous_animated_objects_controller_when_animating_a_new_object 78 FlexMock.use( "original animated object", "second animated object" ) do |mockAnimObj, mockAnimObj2| 79 mockAnimObj = FlexMock.new 80 mockAnimObj.should_receive( :controller= ).with( @spirit ) 81 mockAnimObj.should_receive( :verbs ).returns( [] ) 82 mockAnimObj.should_receive( :controller= ).with( nil ) 83 84 mockAnimObj2 = FlexMock.new 85 mockAnimObj2.should_receive( :controller= ).with( @spirit ) 86 mockAnimObj2.should_receive( :verbs ).returns( [] ) 87 88 assert_nothing_raised do 89 @spirit.animate( mockAnimObj ) 90 @spirit.animate( mockAnimObj2 ) 91 end 92 end 93 94 end 95 96 101 97 end 102 98 -
trunk/tests/verb.tests.rb
