Changeset 284
- Timestamp:
- 09/21/08 14:29:30 (2 months ago)
- Location:
- trunk
- Files:
-
- 5 added
- 6 removed
- 8 modified
-
. (modified) (2 props)
-
FaerieMUD.tmproj (deleted)
-
TEMPLATE.rb.tpl (deleted)
-
lib/fm/gameobject.rb (modified) (2 diffs)
-
lib/fm/locus.rb (modified) (2 diffs)
-
lib/fm/mixins.rb (modified) (4 diffs)
-
lib/fm/organism.rb (modified) (2 diffs)
-
lib/fm/perception.rb (modified) (3 diffs)
-
lib/fm/periodicobject (added)
-
lib/fm/periodicobject.rb (modified) (14 diffs)
-
lib/fm/periodicobject/element.rb (added)
-
rake (deleted)
-
redist (deleted)
-
spec/fm/organism.tests.rb (deleted)
-
spec/fm/organism_spec.rb (modified) (1 diff)
-
spec/fm/perception.tests.rb (deleted)
-
spec/fm/perception_spec.rb (added)
-
spec/fm/periodicobject_spec.rb (added)
-
spec/lib/constants.rb (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:ignore
-
old new 1 coverage.info 1 2 test.log 2 3 .glimpse*
-
- Property svn:externals set to
- Property svn:ignore
-
trunk/lib/fm/gameobject.rb
r277 r284 24 24 require 'digest/md5' 25 25 require 'logger' 26 require ' sync'26 require 'monitor' 27 27 28 28 require 'fm' … … 39 39 FaerieMUD::HTML, 40 40 FaerieMUD::Linguistics 41 42 include MonitorMixin 41 43 42 44 ### Class constants -
trunk/lib/fm/locus.rb
r277 r284 98 98 # 99 99 100 require ' sync'100 require 'monitor' 101 101 102 102 require 'fm/entity' … … 151 151 ### contents of the receiver. 152 152 def add_contents( *objects ) 153 @mutex.synchronize( Sync::SH )do153 synchronize do 154 154 objects.each do |obj| 155 155 if obj.contains?( self ) -
trunk/lib/fm/mixins.rb
r280 r284 1 1 #!/usr/bin/ruby 2 # 3 # This file contains various mixins for use in FaerieMUD classes. 4 # 5 # Currently contains the following modules: 6 # 7 # [<tt>FaerieMUD::ArgCheckFunctions</tt>] 8 # Functions for checking arguments for types, signatures, and hash members. 9 # 2 3 require 'monitor' 4 5 require 'fm/exceptions' 6 10 7 # [<tt>FaerieMUD::Propertied</tt>] 11 8 # Adds the ability to interact with FaerieMUD::Property objects to including … … 51 48 # Please see the file COPYRIGHT in the 'docs' directory for licensing details. 52 49 # 53 54 require 'cgi'55 require 'sync'56 57 require 'fm/exceptions'58 59 50 module FaerieMUD 60 61 ### Mixin that adds some type-checking functions to the current scope62 module ArgCheckFunctions63 64 ### The Ouroboros Trick65 def self::included( klass )66 super67 klass.extend( self )68 end69 70 71 ###############72 module_function73 ###############74 75 ### Check <tt>anObject</tt> to make sure it's one of the specified76 ### <tt>validTypes</tt>. If the object is not one of the specified value77 ### types, and an optional block is given it is called with the object being78 ### tested and the array of valid types. If no handler block is given, a79 ### <tt>TypeError</tt> is raised.80 def check_type( anObject, *validTypes ) # :yields: object, *validTypes81 warn "Deprecated method 'check_type' called from %s" %82 [ caller(1).first ] if $VERBOSE83 return true84 end85 86 87 ### Check each object in the specified <tt>objectArray</tt> with a call88 ### to #check_type with the specified validTypes array.89 def check_each_type( objectArray, *validTypes, &errBlock ) # :yields: object, *validTypes90 warn "Deprecated method 'check_each_type' called from %s" %91 [ caller(1).first ] if $VERBOSE92 return true93 end94 95 96 ### Check <tt>anObject</tt> for implementations of <tt>requiredMethods</tt>.97 ### If one of the methods is unimplemented, and an optional block is given it98 ### is called with the method that failed the responds_to? test and the object99 ### being checked. If no handler block is given, a <tt>TypeError</tt> is100 ### raised.101 def check_response( anObject, *requiredMethods ) # yields method, anObject102 requiredMethods.flatten!103 requiredMethods.compact!104 105 if requiredMethods.size > 0 then106 requiredMethods.each do |method|107 next if anObject.respond_to?( method )108 109 if block_given? then110 yield( method, anObject )111 else112 raise TypeError, "Argument '#{anObject.inspect}' does "\113 "not answer the '#{method}()' method",114 caller(1).find_all {|frame| frame.include?(__FILE__)}115 end116 end117 end118 119 return true120 end121 122 123 ### Check each object of <tt>anArray</tt> for implementations of124 ### <tt>requiredMethods</tt>, calling the optional <tt>errBlock</tt> if125 ### specified, or raising a <tt>TypeError</tt> if one of the methods is126 ### unimplemented.127 def check_each_response( anArray, *requiredMethods, &errBlock ) # :yeilds: method, object128 raise ScriptError,129 "First argument must be Enumerable" unless130 anArray.is_a?( Enumerable )131 132 anArray.each do |anObject|133 if block_given? then134 check_response anObject, *requiredMethods, &errBlock135 else136 check_response( anObject, *requiredMethods ) {|method, object|137 raise TypeError, "Argument '#{anObject.inspect}' does "\138 "not answer the '#{method}()' method",139 caller(1).find_all {|frame| frame.include?(__FILE__)}140 }141 end142 end143 144 return true145 end146 147 148 ### Check to be sure the specified +args+ object is a Hash and contains149 ### the given +keys+. Each key in +keys+ can be either a Symbol, a150 ### String, or an Array of either.151 def check_for_hash_args( args, *keys )152 unless args.is_a?( Hash )153 raise TypeError,154 "Arguments are not in Hash form.",155 caller(1).find_all {|frame| /#{__FILE__}/ !~ frame}156 end157 158 unless keys.empty?159 nicetrace = caller( 1 ).delete_if {|frame|160 /#{__FILE__}:\d+:in/i =~ frame161 }162 keys.each {|required|163 case required164 when Symbol165 raise ArgumentError,166 "Missing required argument :#{required}",167 nicetrace unless168 args.key?( required )169 when String170 raise ArgumentError,171 "Missing required argument :#{required}",172 nicetrace unless173 args.key?( required.intern )174 when Array175 raise ArgumentError,176 "Missing required argument :#{requiredKey}",177 nicetrace unless178 required.179 collect {|ak| ak.to_s.intern }.180 find {|ak| args.keys.include?(ak) }181 end182 183 }184 end185 186 return true187 end188 189 end # module ArgCheckFunctions190 191 51 192 52 ### A mixin that adds logging to its including class. … … 648 508 ### constructor private. 649 509 def self::extend_object( obj ) 650 unless obj.is_a?( Class ) 651 raise TypeError, 652 "Can only extend Classes, not a #{obj.class.name}" 653 end 654 super 510 obj.extend( MonitorMixin ) 655 511 end 656 512 … … 716 572 attr_locked( sym, true, true ) 717 573 end 718 719 720 ### Defines an attribute named +sym+ for the calling class, as well as a721 ### mutator called +name=+ that is accessed through an exclusive mutex,722 ### and whose argument is tested (using #kind_of?) against the specified723 ### +types+. If +reader+ is +true+, a reader which accesses it through a724 ### sharable mutex is also created. Depends on an instance variable725 ### called '@mutex' being present in the including class which contains726 ### an instance of the Sync class or a compatible replacement; one will727 ### be added to the object on the first call to a method generated by728 ### this function if one is not already present.729 def attr_typelocked( sym, reader=true, *types )730 raise SyntaxError, "No valid types specified" if types.empty?731 ivarname = "@#{sym.id2name}"732 733 # Define the accessor734 if reader735 define_method( sym ) {736 if instance_variables.include?( ivarname )737 @mutex = Sync::new unless defined? @mutex738 @mutex.synchronize( Sync::SH ) {739 instance_variable_get( ivarname )740 }741 else742 nil743 end744 }745 end746 747 # Define the mutator748 define_method( "#{sym}=".intern ) {|arg|749 FaerieMUD::ArgCheckFunctions::check_type( arg, *types )750 @mutex = Sync::new unless defined? @mutex751 @mutex.synchronize( Sync::EX ) {752 instance_variable_set( ivarname, arg )753 }754 }755 end756 757 758 ### Define a type-checked mutator via #attr_typelocked for the attribute759 ### specified by +sym+ and the given +types+.760 def attr_typelocked_writer( sym, *types )761 attr_typelocked( sym, false, *types )762 end763 764 765 ### Define a type-checking locked accessor and mutator via766 ### #attr_typelocked for the attribute specified by +sym+ and the given767 ### #+types+.768 def attr_typelocked_accessor( sym, *types )769 attr_typelocked( sym, true, *types )770 end771 772 574 end # module AccessorFunctions 773 575 -
trunk/lib/fm/organism.rb
r283 r284 1 1 #!/usr/bin/ruby 2 3 require 'fm/mixins' 4 require 'fm/exceptions' 5 require 'fm/item' 6 2 7 # 3 # Th is file contains the FaerieMUD::Organism class, a derivative of4 # FaerieMUD::Item which has an associated Species. Derivatives of this class are naturally-occurring organic5 # o bjects in the game world, and can be generally categorized into animal,6 # vegetable, or mineral.8 # The FaerieMUD::Organism class, a derivative of FaerieMUD::Item which has an 9 # associated Species. Derivatives of this class are naturally-occurring 10 # organic objects in the game world, and can be generally categorized into 11 # animal, vegetable, or mineral. 7 12 # 8 13 # == Subversion ID … … 20 25 # Please see the file COPYRIGHT in the 'docs' directory for licensing details. 21 26 # 22 23 require 'fm/mixins'24 require 'fm/exceptions'25 require 'fm/item'26 27 ### Derivatives of this class are physical objects in the game world.28 27 class FaerieMUD::Organism < FaerieMUD::Item 29 28 -
trunk/lib/fm/perception.rb
r277 r284 1 1 #!/usr/bin/ruby 2 3 require 'fm/mixins' 4 require 'fm/exceptions' 5 require 'fm/gameobject' 6 7 2 8 # 3 # This file contains the FaerieMUD::Perception class, a derivative of 4 # FaerieMUD::Entity. Instances of this class model a FaerieMUD::Character's 5 # ability and limits of perception of the world around her. 6 # 9 # The FaerieMUD::Perception class, a derivative of FaerieMUD::Entity. 10 # Instances of this class provide a perceptual model for FaerieMUD::Character 11 # objects. This object is the entity that gathers and transmits descriptions 12 # of all PerceptualEvents and decides whether or not each can be detected by 13 # the character. It is also the object principally involved in active 14 # perception (i.e., via the Verb that contains 'look', 'watch', etc.). 15 # 7 16 # == On Perception in the FaerieMUD World 8 17 # … … 23 32 # Please see the file COPYRIGHT in the 'docs' directory for licensing details. 24 33 # 25 26 require 'fm/mixins'27 require 'fm/exceptions'28 require 'fm/gameobject'29 30 31 32 ### A perceptual model for FaerieMUD::Character objects. This object is the33 ### entity that gathers and transmits descriptions of all PerceptualEvents that34 ### can be detected by the character. It is also the object principally involved35 ### in active perception (i.e., via the Verb that contains 'look', 'watch',36 ### etc.).37 34 class FaerieMUD::Perception < FaerieMUD::Entity 38 35 … … 66 63 end 67 64 68 69 70 65 end # class FaerieMUD::Perception 71 66 72 73 __END__74 -
trunk/lib/fm/periodicobject.rb
r277 r284 1 1 #!/usr/bin/ruby 2 # 3 # This file contains the FaerieMUD::PeriodicObject class, a derivative of 4 # FaerieMUD::GameObject. PeriodicObjects are values in a periodic system. A 5 # periodic system is one which exhibits periodicity -- the tendency of 6 # sub-attributes to recur at regular intervals, sharing attributes between 7 # similarly-positioned elements. 2 3 require 'fm/mixins' 4 require 'fm/gameobject' 5 6 # 7 # The FaerieMUD::PeriodicObject class, a derivative of FaerieMUD::GameObject. 8 # PeriodicObjects are values in a periodic system. A periodic system is one 9 # which exhibits periodicity -- the tendency of sub-attributes to recur at 10 # regular intervals, sharing attributes between similarly-positioned elements. 8 11 # 9 12 # In FaerieMUD, the "periodic system" you'll be dealing with is generally The … … 20 23 # differentiated self. 21 24 # 22 # == Synopsis23 #24 #25 #26 25 # == SVNId 27 26 # … … 43 42 # Please see the file COPYRIGHT in the 'docs' directory for licensing details. 44 43 # 45 46 require 'fm/mixins'47 require 'fm/gameobject'48 49 ### Periodic value datatype.50 44 class FaerieMUD::PeriodicObject < FaerieMUD::GameObject 51 45 include FaerieMUD::AccessorFunctions, FaerieMUD::HTML 52 46 contributors :scotus, :ged 53 47 54 # Alias the HTML module for convenience55 #HTML = FaerieMUD::HTML56 57 ### A flyweight class for elements of The Pattern, based on the periodic58 ### table of elements.59 class Element < FaerieMUD::GameObject60 include FaerieMUD::Flyweight61 contributors :scotus, :ged62 63 64 #########################################################65 ### C O N S T A N T S66 #########################################################67 68 # SVN Revision69 SVNRev = %q$Rev$70 71 # SVN Id72 SVNId = %q$Id$73 74 # Element chemical symbols indexed by atomic number75 Symbols = [nil] + %w{H He Li Be B C N O F Ne Na Mg Al Si P S Cl Ar K76 Ca Sc Ti V Cr Mn Fe Co Ni Cu Zn Ga Ge As Se Br Kr Rb Sr Y Zr Nb Mo Tc77 Ru Rh Pd Ag Cd In Sn Sb Te I Xe Cs Ba La Ce Pr Nd Pm Sm Eu Gd Tb Dy78 Ho Er Tm Yb Lu Hf Ta W Re Os Ir Pt Au Hg Tl Pb Bi Po At Rn Fr Ra Ac79 Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr Rf Db Sg Bh Hs Mt Ds Uuu80 Uub Uut Uuq Uup Uuh Uus Uuo}81 82 # Element names indexed by atomic number83 Names = [nil] + %w{Hydrogen Helium Lithium Beryllium Boron Carbon84 Nitrogen Oxygen Fluorine Neon Sodium Magnesium Aluminum Silicon85 Phosphorous Sulfur Chlorine Argon Potassium Calcium Scandium86 Titanium Vanadium Chromium Manganese Iron Cobalt Nickel Copper Zinc87 Gallium Germanium Arsenic Selenium Bromine Krypton Rubidium88 Strontium Yttrium Zirconium Niobium Molybdenum Technetium Ruthenium89 Rhodium Palladium Silver Cadmium Indium Tin Antimony Tellurium90 Iodine Xenon Cesium Barium Lanthanium Cerium Praeseodymium Neodymium91 Promethium Samarium Europium Gadolinium Terbium Dysprosium Holmium92 Erbium Thullium Ytterbium Lutetium Hafnium Tantalum Tungsten Rhenium93 Osmium Iridium Platinum Gold Mercury Thallium Lead Bismuth Polonium94 Astatine Radon Francium Radium Actinium Thorium Protactinium Uranium95 Neptunium Plutonium Americium Curium Berkelium Californium96 Einsteinium Fermium Mendelevium Nobelium Lawrencium Rutherfordium97 Dubnium Seaborgium Bohrium Hassium Meitnerium Darmstadtium Unununium98 Ununbium Ununtrinium Ununquadium Ununpentium Ununhexium Ununseptium99 Ununoctium}100 101 # The maximum atomic number (in this Pattern, anyway)102 MaxElement = Symbols.nitems103 104 # The periodic table, minus the rare earths, for doing period-traversal105 Table = [106 [ 1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 2 ],107 [ 3, 4, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 5, 6, 7, 8, 9, 10 ],108 [ 11, 12, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 13, 14, 15, 16, 17, 18 ],109 [ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 ],110 [ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54 ],111 [ 55, 56, 57, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86 ],112 [ 87, 88, 89, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118 ],113 ]114 115 # Shift the table over and down one so we don't have to do off-by-one for everything116 Table.each_index {|i| Table[i].insert(0, nil)}117 Table.insert( 0, nil )118 119 # IUPAC group numbers -- a hash keyed by number, with an array of120 # elements within that group as the value. Rare earths (Lanthanides121 # and Actinides) get put in after.122 Groups = Table[1..-1].inject({}) {|hash, row|123 124 # Map rows of the table into a Hash of Arrays of elements keyed125 # by group number, dropping nil elements.126 row.each_with_index {|elem,i|127 next unless i.nonzero? # Skip shift128 hash[i] ||= []129 hash[i].push( elem ) unless elem.nil?130 }131 hash132 }133 134 # The rare earths go in group 3 (3B). It's a slice because the first135 # element in the series is already in the Table above.136 Lanthanides = (57..71).to_a137 Groups[3].push( *(Lanthanides[1..-1]) )138 Actinides = (89..103).to_a139 Groups[3].push( *(Actinides[1..-1]) )140 141 # Interior groups function similarly to regular groups. They also142 # use CAS group names or can be accessed via the IUPAC number.143 InteriorGroups = [144 {145 1 => (1..26).to_a,146 2 => [27],147 3 => (28..56).to_a,148 18 => (71..MaxElement).to_a149 },150 {151 1 => (1..44).to_a,152 2 => [45],153 3 => (46..88).to_a,154 18 => (103..MaxElement).to_a155 },156 {157 1 => (1..76).to_a,158 2 => [77],159 3 => (78..MaxElement).to_a160 },161 {162 1 => (1..108).to_a,163 2 => [109],164 3 => (110..MaxElement).to_a165 }166 ]167 168 ### Interior groups for rare earths169 (4..17).each {|i|170 ### The lanthanide series171 InteriorGroups[ 0 ][ i ] = [i+53]172 ### The actinide series173 InteriorGroups[ 1 ][ i ] = [i+85]174 }175 176 # Hidden groups function similarly to interior groups. They also177 # use CAS group names or can be accessed via the IUPAC number.178 HiddenGroups = [179 {180 1 => (1..61).to_a,181 2 => [62],182 3 => (63..MaxElement).to_a183 },184 {185 1 => (1..93).to_a,186 2 => [94],187 3 => (95..MaxElement).to_a188 }189 ]190 191 # Array of CAS group names indexed by IUPAC group numbers (leading192 # nil to offset by one)193 GroupName = [nil] + %w{1A 2A 3B 4B 5B 6B 7B 8 8 8 1B 2B 3A 4A 5A 6A 7A 8A}194 195 196 #########################################################197 ### C L A S S M E T H O D S198 #########################################################199 200 ### This function maps element numbers to (IUPAC) Group number.201 def self::number_to_group( atomic_number )202 Groups.keys.find {|num| Groups[num].include?( atomic_number )}203 end204 205 206 ### This function maps element numbers to (IUPAC) Interior Groups,207 ### which are returned in a 3-element Array.208 def self::number_to_interior_groups( atomic_number )209 return InteriorGroups.collect do |groupmap|210 group = groupmap.find {|num,elements|elements.include?( atomic_number )}211 group.first212 end213 end214 215 216 ### This function maps element numbers to (IUPAC) Hidden Groups,217 ### which are returned in a 2-element Array.218 def self::number_to_hidden_groups( atomic_number )219 return HiddenGroups.collect {|groupmap|220 groupmap.find {|num,elements|221 elements.include?( atomic_number )222 }[0]223 }224 end225 226 227 ### This function maps element numbers to IUPAC standard period228 ### numbers.229 def self::number_to_period( atomic_number )230 FaerieMUD::ArgCheckFunctions::check_type( atomic_number, Integer )231 232 case atomic_number233 when 1..2234 1235 when 3..10236 2237 when 11..18238 3239 when 19..36240 4241 when 37..54242 5243 when 55..86244 6245 when 87..MaxElement246 7247 else248 raise RangeError,249 "No such element #{atomic_number.inspect} on this periodic table."250 end251 end252 253 254 # Alias away the ::fetch method given to the class by the Flyweight255 # mixin so it can be overridden but still be called.256 alias_class_method :super_fetch, :fetch257 258 ### Fetch a new PeriodicObject::Element object with the specified259 ### atomic number or element name +elem+.260 def self::fetch( elem=1 )261 262 # Allow elem to be an Element object for implementations of element=263 # mutators.264 return elem if elem.is_a?( self )265 266 # Attempt to convert names or chemical symbols to atomic numbers.267 if elem.is_a?( String ) || elem.is_a?( Symbol )268 name = elem.to_s.capitalize269 elem = Symbols.index(name) || Names.index(name) or270 raise ArgumentError, "No such element '#{name}'"271 end272 273 super_fetch( elem,274 number_to_period(elem),275 number_to_group(elem),276 Symbols[elem],277 Names[elem],278 number_to_hidden_groups(elem),279 number_to_interior_groups(elem) )280 end281 282 283 284 #########################################################285 ### I N S T A N C E M E T H O D S286 #########################################################287 288 ### Initialize a new PeriodicObject::Element with the specified289 ### atomic +number+, +period+, +group+, chemical +symbol+, +name+,290 ### +hidden_groups+, and +interior_groups+.291 def initialize( number, period, group, symbol, name,292 hidden_groups, interior_groups ) # :nonew:293 @atomic_number = number294 @period = period295 @group = group296 @group_name = GroupName[ @group ]297 @symbol = symbol298 @name = name299 @series = group_to_series( @group )300 301 @hidden_groups = hidden_groups302 @hidden_group_names = @hidden_groups.collect {|gr| GroupName[gr]}303 @hidden_series = @hidden_groups.collect {|gr| group_to_series( gr )}304 305 @interior_groups = interior_groups306 @interior_group_names = @interior_groups.collect {|gr| GroupName[gr]}307 @interior_series = @interior_groups.collect {|gr| group_to_series( gr )}308 end309 310 311 312 ######313 public314  
