Commits

Michael Granger committed baf5b4b

* Added optional block to #conjuction to allow inline conversion of joined
objects.
* Added lprintf for injecting linguistics into formatted strings.

Comments (0)

Files changed (8)

+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>currentDocument</key>
+	<string>lib/linguistics/en/linkparser.rb</string>
+	<key>documents</key>
+	<array>
+		<dict>
+			<key>filename</key>
+			<string>Artistic</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>ChangeLog</string>
+		</dict>
+		<dict>
+			<key>name</key>
+			<string>docs</string>
+			<key>regexFileFilter</key>
+			<string>!(/\.(?!htaccess)[^/]*|\.(tmproj|o|pyc)|/Icon\r)$</string>
+			<key>regexFolderFilter</key>
+			<string>!.*/(\.[^/]*|CVS|\{arch\}|build|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+			<key>sourceDirectory</key>
+			<string>docs</string>
+		</dict>
+		<dict>
+			<key>name</key>
+			<string>experiments</string>
+			<key>regexFileFilter</key>
+			<string>!(/\.(?!htaccess)[^/]*|\.(tmproj|o|pyc)|/Icon\r)$</string>
+			<key>regexFolderFilter</key>
+			<string>!.*/(\.[^/]*|CVS|\{arch\}|build|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+			<key>sourceDirectory</key>
+			<string>experiments</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>install.rb</string>
+		</dict>
+		<dict>
+			<key>expanded</key>
+			<true/>
+			<key>name</key>
+			<string>lib</string>
+			<key>regexFileFilter</key>
+			<string>!(/\.(?!htaccess)[^/]*|\.(tmproj|o|pyc)|/Icon\r)$</string>
+			<key>regexFolderFilter</key>
+			<string>!.*/(\.[^/]*|CVS|\{arch\}|build|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+			<key>sourceDirectory</key>
+			<string>lib</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>makedist.rb</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>MANIFEST</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>README</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>README.english</string>
+		</dict>
+		<dict>
+			<key>name</key>
+			<string>redist</string>
+			<key>regexFileFilter</key>
+			<string>!(/\.(?!htaccess)[^/]*|\.(tmproj|o|pyc)|/Icon\r)$</string>
+			<key>regexFolderFilter</key>
+			<string>!.*/(\.[^/]*|CVS|\{arch\}|build|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+			<key>sourceDirectory</key>
+			<string>redist</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>test.rb</string>
+		</dict>
+		<dict>
+			<key>name</key>
+			<string>tests</string>
+			<key>regexFileFilter</key>
+			<string>!(/\.(?!htaccess)[^/]*|\.(tmproj|o|pyc)|/Icon\r)$</string>
+			<key>regexFolderFilter</key>
+			<string>!.*/(\.[^/]*|CVS|\{arch\}|build|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
+			<key>sourceDirectory</key>
+			<string>tests</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>TODO</string>
+		</dict>
+		<dict>
+			<key>filename</key>
+			<string>utils.rb</string>
+		</dict>
+	</array>
+	<key>fileHierarchyDrawerWidth</key>
+	<integer>200</integer>
+	<key>metaData</key>
+	<dict>
+		<key>lib/linguistics.rb</key>
+		<dict>
+			<key>caret</key>
+			<dict>
+				<key>column</key>
+				<integer>0</integer>
+				<key>line</key>
+				<integer>0</integer>
+			</dict>
+			<key>firstVisibleColumn</key>
+			<integer>0</integer>
+			<key>firstVisibleLine</key>
+			<integer>0</integer>
+		</dict>
+		<key>lib/linguistics/en.rb</key>
+		<dict>
+			<key>caret</key>
+			<dict>
+				<key>column</key>
+				<integer>0</integer>
+				<key>line</key>
+				<integer>0</integer>
+			</dict>
+			<key>firstVisibleColumn</key>
+			<integer>0</integer>
+			<key>firstVisibleLine</key>
+			<integer>0</integer>
+		</dict>
+		<key>lib/linguistics/en/infinitive.rb</key>
+		<dict>
+			<key>caret</key>
+			<dict>
+				<key>column</key>
+				<integer>0</integer>
+				<key>line</key>
+				<integer>0</integer>
+			</dict>
+			<key>firstVisibleColumn</key>
+			<integer>0</integer>
+			<key>firstVisibleLine</key>
+			<integer>0</integer>
+		</dict>
+		<key>lib/linguistics/en/linkparser.rb</key>
+		<dict>
+			<key>caret</key>
+			<dict>
+				<key>column</key>
+				<integer>0</integer>
+				<key>line</key>
+				<integer>84</integer>
+			</dict>
+			<key>firstVisibleColumn</key>
+			<integer>0</integer>
+			<key>firstVisibleLine</key>
+			<integer>71</integer>
+		</dict>
+		<key>lib/linguistics/en/wordnet.rb</key>
+		<dict>
+			<key>caret</key>
+			<dict>
+				<key>column</key>
+				<integer>30</integer>
+				<key>line</key>
+				<integer>231</integer>
+			</dict>
+			<key>firstVisibleColumn</key>
+			<integer>0</integer>
+			<key>firstVisibleLine</key>
+			<integer>200</integer>
+		</dict>
+	</dict>
+	<key>openDocuments</key>
+	<array>
+		<string>lib/linguistics/en.rb</string>
+		<string>lib/linguistics/en/infinitive.rb</string>
+		<string>lib/linguistics/en/linkparser.rb</string>
+		<string>lib/linguistics/en/wordnet.rb</string>
+		<string>lib/linguistics.rb</string>
+	</array>
+	<key>showFileHierarchyDrawer</key>
+	<true/>
+	<key>windowFrame</key>
+	<string>{{234, 8}, {993, 1020}}</string>
+</dict>
+</plist>

experiments/conjunct-with-block.rb

+#!/usr/bin/ruby
+#
+# Written to find a minimal testcase for the #conjunction-with-block bug.
+# 
+# Time-stamp: <04-Nov-2005 07:43:36 ged>
+#
+
+BEGIN {
+	base = File::dirname( File::dirname(File::expand_path(__FILE__)) )
+	$LOAD_PATH.unshift "#{base}/lib"
+
+	require "#{base}/utils.rb"
+	include UtilityFunctions
+}
+
+require 'linguistics'
+
+Linguistics::use( :en, :installProxy => true )
+array = %w{sheep shrew goose bear penguin barnacle sheep goose goose}
+
+$defout.puts "Called via language proxy: ",
+  array.en.conjunction {|word| "%s-word" % [word[0,1]]}
+
+$defout.puts "Called via delegator proxy: ",
+  array.conjunction {|word| "%s-word" % [word[0,1]]}
+
+$defout.puts "Called via language proxy: ",
+  array.en.conjunction {|word| "%s-word" % [word[0,1]]}
+
+
 
 		### Autoload linguistic methods defined in the module this object's
 		### class uses for inflection.
-		def method_missing( sym, *args )
+		def method_missing( sym, *args, &block )
 			return super unless self.class.langmod.respond_to?( sym )
 
 			self.class.module_eval %{
 				end
 			}, "{Autoloaded: " + __FILE__ + "}", __LINE__
 
-			self.method( sym ).call( *args )
+			self.method( sym ).call( *args, &block )
 		end
 
 
 	### Install a regular proxy method in the given klass that will delegate
 	### calls to missing method to the languageProxy for the given +language+.
 	def self::installDelegatorProxy( klass, langcode )
+		raise ArgumentError, "Missing langcode" if langcode.nil?
 
 		# Alias any currently-extant
 		if klass.instance_methods( false ).include?( "method_missing" )
 
 		# Add the #method_missing method that auto-installs delegator methods
 		# for methods supported by the linguistic proxy objects.
-		klass.module_eval {
-			define_method( :method_missing ) do |sym, *args|
+		klass.module_eval %{
+			def method_missing( sym, *args, &block )
 
-				if self.send( langcode ).respond_to?( sym )
+				# If the linguistic delegator answers the message, install a
+				# delegator method and call it.
+				if self.send( :#{langcode} ).respond_to?( sym )
 
-					# $stderr.puts "Installing linguistic delegator method #{sym} " \
+					# $stderr.puts "Installing linguistic delegator method \#{sym} " \
 					#	"for the '#{langcode}' proxy"
 					self.class.module_eval %{
-						def #{sym}( *args )
-							self.#{langcode}.#{sym}( *args )
+						def \#{sym}( *args, &block )
+							self.#{langcode}.\#{sym}( *args, &block )
 						end
 					}
-					self.method( sym ).call( *args )
+					self.method( sym ).call( *args, &block )
 
 				# Otherwise either call the overridden proxy method if there is
 				# one, or just let our parent deal with it.
 				else
 					if self.respond_to?( :__orig_method_missing )
-						return self.__orig_method_missing( sym, *args )
+						return self.__orig_method_missing( sym, *args, &block )
 					else
-						super( sym, *args )
+						super( sym, *args, &block )
 					end
 				end
 			end
 				when String
 					langcode = config[:installProxy].intern
 				when TrueClass
-					langcode = DefaultLanguages[0]
+					langcode = languages[0] || DefaultLanguages[0] || :en
 				else
 					raise ArgumentError,
 						"Unexpected value %p for :installProxy" %

lib/linguistics/en.rb

 	#################################################################
 
 	### Return the name of the language this module is for.
-	def language
+	def language( unused=nil )
 		"English"
 	end
 
 	### Return the plural of the given +phrase+ if +count+ indicates it should
 	### be plural.
 	def plural( phrase, count=nil )
+		phrase = numwords( phrase ) if phrase.is_a?( Numeric )
+
 		md = /\A(\s*)(.+?)(\s*)\Z/.match( phrase.to_s )
 		pre, word, post = md.to_a[1,3]
 		return phrase if word.nil? or word.empty?
 			].compact.join( config[:joinword] )
 		end
 	end
+	alias_method :QUANT, :quantify
 
 
     ### Return the specified +obj+ (which must support the <tt>#collect</tt>
 
 		return phrases.join( sep )
 	end
+	alias_method :CONJUNCT, :conjunction
 
 
 	### Turns a camel-case +string+ ("camelCaseToEnglish") to plain English
 		}.join
 	end
 
+
+	### Format the given +fmt+ string by replacing %-escaped sequences with the
+	### result of performing a specified operation on the corresponding
+	### argument, ala Kernel.sprintf.
+	### %PL::
+	###   Plural.
+	### %A, %AN::
+	###   Prepend indefinite article.
+	### %NO::
+	###   Zero-quantified phrase.
+	### %CONJUNCT::
+	###   Conjunction.
+	def lprintf( fmt, *args )
+		$deferr.puts "Args = %p" % [args]
+
+		fmt.to_s.gsub( /%([A-Z_]+)/ ) do |match|
+			op = $1
+			case op
+			when 'PL'
+				args.shift.plural
+			when 'A', 'AN'
+				args.shift.a
+			when 'NO'
+				args.shift.no
+			when 'CONJUNCT'
+				args.shift.conjunction
+			else
+				raise "no such formatter %p" % op
+			end
+		end
+	end
+
 end # module Linguistics::EN
 
 
 ### Add the #separate and #separate! methods to Array.
-class Array # :nodoc:
+class Array
 
 	### Returns a new Array that has had a new member inserted between all of
 	### the current ones. The value used is the given +value+ argument unless a

lib/linguistics/en/wordnet.rb

 #  $Id: wordnet.rb,v 1.3 2003/09/14 11:28:02 deveiant Exp $
 # 
 
-module Linguistics
-module EN
+module Linguistics::EN
 
 	@hasWordnet		= false
 	@wnError		= nil
 	### WordNet lexicon and return a WordNet::Synset object.
 	def synset( word, pos=nil, sense=1 )
 		lex = Linguistics::EN::wnLexicon
-		if pos.is_a?( Fixnum)
+		if pos.is_a?( Fixnum )
 			sense = pos
 			pos = nil
 		end
 	# methods to show up in RDoc.
 	def_synset_function :frames
 
+
+	# Returns the synsets for the receiver's antonyms, if any. Ex:
+	# 'opaque'.en.synset.antonyms
+	#   ==> [#<WordNet::Synset:0x010ca614/454927 clear (adjective): "free
+	#        from cloudiness; allowing light to pass through; "clear water";
+	#        "clear plastic bags"; "clear glass"; "the air is clear and clean""
+	#        (similarTos: 6, attributes: 1, derivations: 2, antonyms: 1,
+	#        seeAlsos: 1)>]
 	def_synset_function :antonyms
+
 	def_synset_function :hypernyms
+    def_synset_function :instanceHypernyms
 	def_synset_function :entailment
 	def_synset_function :hyponyms
+    def_synset_function :instanceHyponyms
 	def_synset_function :causes
 	def_synset_function :verbgroups
 	def_synset_function :similarTo
 	def_synset_function :usageMembers
 
 
-end # module EN
-end # module Linguistics
+end # module Linguistics::EN
 

tests/en/conjunction.tests.rb

 # Unit test for English conjunctions 
 # $Id: conjunction.tests.rb,v 1.2 2003/09/11 05:03:12 deveiant Exp $
 #
-# Copyright (c) 2003 The FaerieMUD Consortium.
+# Copyright (c) 2003, 2005 The FaerieMUD Consortium.
 # 
 
 unless defined? Linguistics::TestCase
 ### parses in which the actual parser-generator's behaviour is defined.
 class EnglishConjunctionsTestCase < Linguistics::TestCase
 
-	Linguistics::use( :en )
+	Linguistics::use( :en, :installProxy => true )
 	include Linguistics::EN
 	
 	Tests = {
 	###	T E S T S
 	#################################################################
 
+	Items = %w{cow chicken blancmange cyclist}
 
+	# Test for defect #6
+	def test_conjunction_should_use_supplied_block_for_object_transform_on_first_invocation
+		rval = nil
+
+		# Create a new class, as we need to guarantee that this will be the
+		# first #conjunction call to it.
+		collection = Class::new {
+			include Enumerable, Linguistics
+			def initialize( *ary )
+				@ary = ary.flatten
+			end
+
+			# Delegate #each to the contained Array
+			def each( &block )
+				@ary.each( &block )
+			end
+		}
+
+		obj = collection.new( 'foo', 'bar', 'baz' )
+
+		assert_nothing_raised do
+			rval = obj.en.conjunction {|word| "%d-letter word" % word.length }
+		end
+	end
+
+
+	def test_conjunction_should_use_supplied_block_for_object_transform
+		rval = nil
+
+		assert_nothing_raised do
+			rval = Items.en.conjunction {|word| "%s-word" % word[0,1]}
+		end
+
+		assert_equal "three c-words and a b-word", rval
+	end
+
+
+	def test_conjunction_should_use_supplied_block_for_object_transform_through_autoproxy
+		rval = nil
+
+		assert_nothing_raised do
+			rval = Items.conjunction {|word| "%s-word" % word[0,1]}
+		end
+
+		assert_equal "three c-words and a b-word", rval
+	end
 
 end
 

tests/en/inflect.tests.rb

 # Unit test for English inflection 
 # $Id: inflect.tests.rb,v 1.2 2003/09/11 05:04:04 deveiant Exp $
 #
-# Copyright (c) 2003 The FaerieMUD Consortium.
+# Copyright (c) 2003, 2005 The FaerieMUD Consortium.
 # 
 # Much of this test was adapted from the test script for Lingua::EN::Inflect by
 # Damien Conway:
 
 
 	### Try the specified code block, printing the given 
-	def try( msg, bind=nil )
+	def try( msg, bind=TOPLEVEL_BINDING )
 		result = ''
 		if msg =~ /^to\s/
 			message "Trying #{msg}...\n"