Skip to content
Browse files

* Finished conversion of test::unit tests to RSpec.

 * Fleshed out Rake-based build system
 * Updated to work with the latest Abiword link-grammar library (4.3.5)


git-svn-id: svn://deveiate.org/Ruby-LinkParser2/trunk@21 b2cd1750-8d09-db11-9627-0002b39e5648
  • Loading branch information...
1 parent a28c71e commit 72c9e1cec021645c98df62f7c704a8bf1334f5f1 deveiant committed
View
90 LinkParser Project.tmproj
@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>currentDocument</key>
- <string>ext/extconf.rb</string>
+ <string>ext/Rakefile</string>
<key>documents</key>
<array>
<dict>
@@ -21,35 +21,35 @@
<integer>281</integer>
<key>metaData</key>
<dict>
- <key>ext/dictionary.c</key>
+ <key>Rakefile</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
- <integer>0</integer>
+ <integer>124</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
- <integer>0</integer>
+ <integer>98</integer>
</dict>
- <key>ext/extconf.rb</key>
+ <key>ext/Rakefile</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
- <integer>38</integer>
+ <integer>0</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
- <key>ext/linkage.c</key>
+ <key>ext/dictionary.c</key>
<dict>
<key>caret</key>
<dict>
@@ -61,37 +61,23 @@
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
- <integer>558</integer>
- </dict>
- <key>ext/linkparser.c</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>4</integer>
</dict>
- <key>extconf.rb</key>
+ <key>ext/linkage.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
- <integer>44</integer>
+ <integer>0</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
- <integer>0</integer>
+ <integer>558</integer>
</dict>
- <key>lib/linkparser/linkage.rb</key>
+ <key>ext/linkparser.c</key>
<dict>
<key>caret</key>
<dict>
@@ -103,23 +89,23 @@
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
- <integer>170</integer>
+ <integer>4</integer>
</dict>
- <key>link-grammar-4.2.4.patch</key>
+ <key>lib/linkparser.rb</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
- <integer>23</integer>
+ <integer>0</integer>
<key>line</key>
- <integer>13</integer>
+ <integer>45</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
- <key>spec/bugfixes_spec.rb</key>
+ <key>lib/linkparser/linkage.rb</key>
<dict>
<key>caret</key>
<dict>
@@ -131,7 +117,7 @@
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
- <integer>0</integer>
+ <integer>170</integer>
</dict>
<key>spec/dictionary_spec.rb</key>
<dict>
@@ -147,27 +133,12 @@
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
- <key>spec/linkage_spec.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>36</integer>
- </dict>
</dict>
<key>openDocuments</key>
<array>
- <string>ext/extconf.rb</string>
- <string>spec/linkage_spec.rb</string>
- <string>link-grammar-4.2.4.patch</string>
- <string>extconf.rb</string>
+ <string>Rakefile</string>
+ <string>lib/linkparser.rb</string>
+ <string>ext/Rakefile</string>
</array>
<key>showFileHierarchyDrawer</key>
<true/>
@@ -179,20 +150,35 @@
<true/>
<key>subItems</key>
<dict>
- <key>docs</key>
+ <key>ext</key>
<dict>
<key>isExpanded</key>
<true/>
<key>subItems</key>
<dict/>
</dict>
- <key>ext</key>
+ <key>lib</key>
<dict>
<key>isExpanded</key>
<true/>
<key>subItems</key>
<dict/>
</dict>
+ <key>misc</key>
+ <dict>
+ <key>isExpanded</key>
+ <true/>
+ <key>subItems</key>
+ <dict>
+ <key>rake</key>
+ <dict>
+ <key>isExpanded</key>
+ <true/>
+ <key>subItems</key>
+ <dict/>
+ </dict>
+ </dict>
+ </dict>
<key>spec</key>
<dict>
<key>isExpanded</key>
@@ -204,6 +190,6 @@
</dict>
</dict>
<key>windowFrame</key>
- <string>{{64, 75}, {1044, 1503}}</string>
+ <string>{{1514, 75}, {1044, 1503}}</string>
</dict>
</plist>
View
468 Rakefile
@@ -1,60 +1,147 @@
-# LinkParser rakefile
-#
-# Based on the rakefiles of a long list of projects,
-# including plist, Gruff, Rake, Linen, ThingFish, and
-# others.
+#!rake
#
-# Copyright (c) 2007, 2008 The FaerieMUD Consortium
+# Ruby LinkParser library rakefile
#
-# Mistakes:
-# * Michael Granger <ged@FaerieMUD.org>
-# * Ben Bleything <ben@bleything.net>
+# Copyright (c) 2008, The FaerieMUD Consortium
+#
+# Authors:
+# * Michael Granger <mgranger@laika.com>
#
BEGIN {
require 'pathname'
basedir = Pathname.new( __FILE__ ).dirname
- libdir = basedir + "lib"
- extdir = basedir + "ext"
- docsdir = basedir + "docs"
-
+ libdir = basedir + 'lib'
+ docsdir = basedir + 'docs'
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
- $LOAD_PATH.unshift( extdir.to_s ) unless $LOAD_PATH.include?( extdir.to_s )
$LOAD_PATH.unshift( docsdir.to_s ) unless $LOAD_PATH.include?( docsdir.to_s )
}
-require 'fileutils'
-require 'pp'
+require 'rbconfig'
+require 'rubygems'
require 'rake'
+require 'rake/rdoctask'
require 'rake/packagetask'
require 'rake/gempackagetask'
-require 'rake/rdoctask'
+require 'pathname'
+require 'mkrf'
+
+
+include Config
+$dryrun = false
+
+# Pathname constants
+BASEDIR = Pathname.new( __FILE__ ).dirname.expand_path
+LIBDIR = BASEDIR + 'lib'
+EXTDIR = BASEDIR + 'ext'
+DOCSDIR = BASEDIR + 'docs'
+MISCDIR = BASEDIR + 'misc'
+RDOCDIR = DOCSDIR + 'rdoc'
+PKGDIR = BASEDIR + 'pkg'
+ARTIFACTS_DIR = Pathname.new( ENV['CC_BUILD_ARTIFACTS'] || '' )
+
+TEXT_FILES = %w( Rakefile README INSTALL ).
+ collect {|filename| BASEDIR + filename }
+
+SPECDIR = BASEDIR + 'spec'
+SPEC_FILES = Pathname.glob( SPECDIR + '**/*_spec.rb' ).
+ delete_if {|item| item =~ /\.svn/ }
+SPEC_EXCLUDES = 'spec,monkeypatches,/Library/Ruby'
+
+LIB_FILES = Pathname.glob( LIBDIR + '**/*.rb' ).
+ delete_if {|item| item =~ /\.svn/ }
+EXT_FILES = Pathname.glob( EXTDIR + '**/*.{c,h}' ).
+ delete_if {|item| item =~ /\.svn/ }
+EXT_RAKEFILE = EXTDIR + 'Rakefile'
+EXT_SO = EXTDIR + "linkparser_ext.#{CONFIG['DLEXT']}"
+
+RELEASE_FILES = TEXT_FILES + LIB_FILES + EXT_FILES + SPEC_FILES
+
-require 'spec/rake/spectask'
-require 'spec/rake/verify_rcov'
+### Rake helper functions
+require MISCDIR + 'rake/helpers'
-TEXT_FILES = %w( Rakefile README MANIFEST )
-SPEC_FILES = Dir.glob( 'spec/*_spec.rb' )
-LIB_FILES = Dir.glob( 'lib/**/*.rb' )
-EXT_FILES = Dir.glob( 'ext/*.c' ) + Dir.glob( 'ext/*.h' )
-BIN_FILES = Dir.glob( 'bin/*' )
+### Package constants
+PKG_NAME = 'linkparser'
+PKG_VERSION = find_pattern_in_file( /VERSION = '(\d+\.\d+\.\d+)'/, LIBDIR + 'linkparser.rb' ).first
+PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
-RELEASE_FILES = TEXT_FILES +
- SPEC_FILES +
- BIN_FILES +
- LIB_FILES
+RELEASE_NAME = "REL #{PKG_VERSION}"
+
+# Load task plugins
+RAKE_TASKDIR = MISCDIR + 'rake'
+Pathname.glob( RAKE_TASKDIR + '*.rb' ).each do |tasklib|
+ next if tasklib =~ %r{/helpers.rb$}
+ require tasklib
+end
+
+if Rake.application.options.trace
+ $trace = true
+ log "$trace is enabled"
+end
+
+if Rake.application.options.dryrun
+ $dryrun = true
+ log "$dryrun is enabled"
+ Rake.application.options.dryrun = false
+end
+
+### Default task
+task :default => [:build, :spec, :verify, :package]
+
+
+### Task: clean
+desc "Clean pkg, coverage, and rdoc; remove .bak files"
+task :clean => [ :clobber_rdoc, :clobber_package, :clobber_coverage ] do
+ files = FileList['**/*.bak']
+ files.clear_exclude
+ File.rm( files ) unless files.empty?
+ FileUtils.rm_rf( 'artifacts' )
+
+ if EXT_RAKEFILE.exist?
+ Dir.chdir( EXTDIR ) do
+ sh 'rake', 'clobber'
+ end
+ EXT_RAKEFILE.delete
+ end
+end
-task :default => 'spec:normal'
-###########################
-### DOCUMENTATION TASKS ###
-###########################
+### Task: docs -- Convenience task for rebuilding dynamic docs
+task :docs => [ :coverage, :rdoc ]
-# Task: rdoc
-Rake::RDocTask.new { |rdoc|
+
+### Task: build -- Build the C extension half
+
+file EXT_RAKEFILE.to_s => FileList[ 'Rakefile', EXTDIR + '*.c' ] do
+ Dir.chdir( EXTDIR ) do
+ Mkrf::Generator.new( 'linkparser_ext', FileList['*.c'] ) do |gen|
+ gen.cflags << ' -Wall'
+ gen.cflags << ' -DDEBUG'
+ gen.include_library( "link-grammar", "dictionary_create" ) or
+ fail( "Could not find link-grammar library." )
+ gen.include_header( "link-grammar/link-includes.h" ) or
+ fail( "Could not find link-includes.h" )
+ gen.include_header( "link-grammar/utilities.h" )
+ gen.has_function?( "linkage_get_current_sublinkage" ) or
+ fail "Link grammar library is unpatched."
+ end
+ end
+end
+
+task :build => EXT_RAKEFILE.to_s do
+ Dir.chdir( EXTDIR ) do
+ sh 'rake'
+ end
+end
+
+
+### Task: rdoc
+Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = 'docs/api'
- rdoc.title = "Ruby LinkParser library"
+ rdoc.title = "LinkParser - a natural language framework for Ruby"
rdoc.options += [
'-w', '4',
@@ -62,68 +149,281 @@ Rake::RDocTask.new { |rdoc|
'-i', 'docs',
'-f', 'darkfish',
'-m', 'README',
- '-W', 'http://deveiate.org/projects/Ruby-LinkParser/browser/trunk/'
+ '-W', 'http://deveiate.org/projects/linkparser/trunk/'
]
- rdoc.rdoc_files.include 'README'
- rdoc.rdoc_files.include LIB_FILES
- rdoc.rdoc_files.include EXT_FILES
-}
+ rdoc.rdoc_files.include TEXT_FILES.collect {|f| f.relative_path_from(BASEDIR).to_s }
+ rdoc.rdoc_files.include LIB_FILES.collect {|f| f.relative_path_from(BASEDIR).to_s }
+end
+
+
+### Task: gem
+gemspec = Gem::Specification.new do |gem|
+ pkg_build = get_svn_rev( BASEDIR ) || 0
+
+ gem.name = PKG_NAME
+ gem.version = "%s.%s" % [ PKG_VERSION, pkg_build ]
+
+ gem.summary = "a Ruby binding for the link-grammar library"
+ gem.description = <<-EOD
+ A Ruby binding for the link-grammar library, a syntactic English parser.
+ EOD
+
+ gem.authors = "Michael Granger, Martin Chase"
+ gem.email = "ged@FaerieMUD.org, stillflame@FaerieMUD.org"
+ gem.homepage = "http://deveiate.org/projects/Ruby-LinkParser/"
+
+ gem.has_rdoc = true
+
+ gem.files = RELEASE_FILES.
+ collect {|f| f.relative_path_from(BASEDIR).to_s }
+ gem.test_files = SPEC_FILES.
+ collect {|f| f.relative_path_from(BASEDIR).to_s }
+end
+Rake::GemPackageTask.new( gemspec ) do |task|
+ task.gem_spec = gemspec
+ task.need_tar = false
+ task.need_tar_gz = true
+ task.need_tar_bz2 = true
+ task.need_zip = true
+end
+
+
+### Task: install
+desc "Install LinkParser as a conventional library"
+task :install do
+ log "Installing LinkParser as a convention library"
+ sitelib = Pathname.new( CONFIG['sitelibdir'] )
+ Dir.chdir( LIBDIR ) do
+ LIB_FILES.each do |libfile|
+ relpath = libfile.relative_path_from( LIBDIR )
+ target = sitelib + relpath
+ FileUtils.mkpath target.dirname,
+ :mode => 0755, :verbose => true, :noop => $dryrun unless target.dirname.directory?
+ FileUtils.install relpath, target,
+ :mode => 0644, :verbose => true, :noop => $dryrun
+ end
+ end
+ Dir.chdir( EXTDIR ) do
+ sh 'rake', 'install'
+ end
+end
+
+### Task: install_gem
+desc "Install LinkParser as a gem"
+task :install_gem => [:package] do
+ installer = Gem::Installer.new( %{pkg/#{PKG_FILE_NAME}.gem} )
+ installer.install
+end
+
+desc "Uninstall LinkParser if it's been installed as a conventional library"
+task :uninstall do
+ log "Uninstalling conventionally-installed LinkParser library files"
+ sitelib = Pathname.new( CONFIG['sitelibdir'] )
+ dir = sitelib + 'linkparser'
+ FileUtils.rm_rf( dir, :verbose => true, :noop => $dryrun )
+ lib = sitelib + 'linkparser.rb'
+ FileUtils.rm( lib, :verbose => true, :noop => $dryrun )
+end
+
+### Task: uninstall_gem
+task :uninstall_gem => [:clean] do
+ uninstaller = Gem::Uninstaller.new( PKG_FILE_NAME )
+ uninstaller.uninstall
+end
+
+
+
+### Cruisecontrol task
+desc "Cruisecontrol build"
+task :cruise => [:clean, :coverage, :package] do |task|
+ raise "Artifacts dir not set." if ARTIFACTS_DIR.to_s.empty?
+ artifact_dir = ARTIFACTS_DIR.cleanpath
+ artifact_dir.mkpath
+
+ $stderr.puts "Copying coverage stats..."
+ FileUtils.cp_r( 'coverage', artifact_dir )
+
+ $stderr.puts "Copying packages..."
+ FileUtils.cp_r( FileList['pkg/*'].to_a, artifact_dir )
+end
-###########################
-### TESTING TASKS ###
-###########################
+### RSpec tasks
+begin
+ gem 'rspec', '>= 1.1.1'
+ require 'spec/rake/spectask'
-### Task: spec
-task :spec => 'spec:normal'
-namespace :spec do
- desc "Run specs outputting to STDOUT"
- Spec::Rake::SpecTask.new( :normal ) do |task|
- task.ruby_opts << '-rubygems'
- task.libs << 'lib' << 'ext'
+ COMMON_SPEC_OPTS = ['-c', '-f', 's']
+
+ ### Task: spec
+ Spec::Rake::SpecTask.new( :spec ) do |task|
task.spec_files = SPEC_FILES
- task.spec_opts = ['-f s', '-r linkparser', '-c']
+ task.libs += [LIBDIR]
+ task.spec_opts = COMMON_SPEC_OPTS
end
+ task :test => [:spec]
- desc "Generate plaintext output"
- Spec::Rake::SpecTask.new( :text ) do |task|
- task.ruby_opts << '-rubygems'
- task.libs << 'lib' << 'ext'
- task.spec_files = SPEC_FILES
- task.spec_opts = ['-f s', '-r linkparser']
- end
-
- desc "Generate HTML output for a spec run"
- Spec::Rake::SpecTask.new( :html ) do |task|
- task.ruby_opts << '-rubygems'
- task.libs << 'lib' << 'ext'
- task.spec_files = SPEC_FILES
- task.spec_opts = ['-f h', '-r linkparser', '-c']
- end
-
- task :autotest do
- require 'rspec_autotest'
-
- ra = RspecAutotest.new
- ra.spec_directory = 'spec'
-
- ra.run
+
+ namespace :spec do
+ desc "Run rspec every time there's a change to one of the files"
+ task :autotest do
+ require 'autotest/rspec'
+ autotester = Autotest::Rspec.new
+
+ autotester.exceptions = %r{\.svn|\.skel}
+ autotester.run
+ end
+
+
+ desc "Generate HTML output for a spec run"
+ Spec::Rake::SpecTask.new( :html ) do |task|
+ task.spec_files = SPEC_FILES
+ task.spec_opts = ['-f','h', '-D']
+ end
+
+ desc "Generate plain-text output for a CruiseControl.rb build"
+ Spec::Rake::SpecTask.new( :text ) do |task|
+ task.spec_files = SPEC_FILES
+ task.spec_opts = ['-f','p']
+ end
+ end
+rescue LoadError => err
+ task :no_rspec do
+ $stderr.puts "Testing tasks not defined: RSpec rake tasklib not available: %s" %
+ [ err.message ]
+ end
+
+ task :spec => :no_rspec
+ namespace :spec do
+ task :autotest => :no_rspec
+ task :html => :no_rspec
+ task :text => :no_rspec
end
end
-### Task: rcov
-desc "Check coverage"
-Spec::Rake::SpecTask.new( :coverage ) do |task|
- task.libs << 'lib'
- task.spec_files = SPEC_FILES
- task.rcov = true
+### RCov (via RSpec) tasks
+begin
+ gem 'rcov'
+ gem 'rspec', '>= 1.1.1'
+
+ RCOV_OPTS = ['--exclude', SPEC_EXCLUDES, '--xrefs', '--save']
+
+ ### Task: coverage (via RCov)
+ ### Task: spec
+ desc "Build test coverage reports"
+ Spec::Rake::SpecTask.new( :coverage ) do |task|
+ task.spec_files = SPEC_FILES
+ task.libs += LIB_FILES
+ task.spec_opts = ['-f', 'p', '-b']
+ task.rcov_opts = RCOV_OPTS
+ task.rcov = true
+ end
+
+ task :rcov => [:coverage] do; end
+
+ ### Other coverage tasks
+ namespace :coverage do
+ desc "Generate a detailed text coverage report"
+ Spec::Rake::SpecTask.new( :text ) do |task|
+ task.spec_files = SPEC_FILES
+ task.libs += FileList['plugins/**/lib']
+ task.rcov_opts = RCOV_OPTS + ['--text-report']
+ task.rcov = true
+ end
+
+ desc "Show differences in coverage from last run"
+ Spec::Rake::SpecTask.new( :diff ) do |task|
+ task.spec_files = SPEC_FILES
+ task.libs += FileList['plugins/**/lib']
+ task.rcov_opts = ['--text-coverage-diff']
+ task.rcov = true
+ end
+
+ ### Task: verify coverage
+ desc "Build coverage statistics"
+ VerifyTask.new( :verify => :rcov ) do |task|
+ task.threshold = 85.0
+ end
+
+ desc "Run RCov in 'spec-only' mode to check coverage from specs"
+ Spec::Rake::SpecTask.new( :speconly ) do |task|
+ task.spec_files = SPEC_FILES
+ task.libs += FileList['plugins/**/lib']
+ task.rcov_opts = ['--exclude', SPEC_EXCLUDES, '--text-report', '--save']
+ task.rcov = true
+ end
+ end
+
+rescue LoadError => err
+ task :no_rcov do
+ $stderr.puts "Coverage tasks not defined: RSpec+RCov tasklib not available: %s" %
+ [ err.message ]
+ end
+
+ task :coverage => :no_rcov
+ task :clobber_coverage
+ task :rcov => :no_rcov
+ namespace :coverage do
+ task :text => :no_rcov
+ task :diff => :no_rcov
+ end
+ task :verify => :no_rcov
end
-### Task: verify_rcov
-desc "Build coverage statistics"
-RCov::VerifyTask.new( :verify_coverage => :coverage ) do |task|
- task.threshold = 85.0
+
+
+### Coding style checks and fixes
+namespace :style do
+
+ BLANK_LINE = /^\s*$/
+ GOOD_INDENT = /^(\t\s*)?\S/
+
+ # A list of the files that have legitimate leading whitespace, etc.
+ PROBLEM_FILES = [ SPECDIR + 'config_spec.rb' ]
+
+ desc "Check source files for inconsistent indent and fix them"
+ task :fix_indent do
+ files = LIB_FILES + SPEC_FILES
+
+ badfiles = Hash.new {|h,k| h[k] = [] }
+
+ trace "Checking files for indentation"
+ files.each do |file|
+ if PROBLEM_FILES.include?( file )
+ trace " skipping problem file #{file}..."
+ next
+ end
+
+ trace " #{file}"
+ linecount = 0
+ file.each_line do |line|
+ linecount += 1
+
+ # Skip blank lines
+ next if line =~ BLANK_LINE
+
+ # If there's a line with incorrect indent, note it and skip to the
+ # next file
+ if line !~ GOOD_INDENT
+ trace " Bad line %d: %p" % [ linecount, line ]
+ badfiles[file] << [ linecount, line ]
+ end
+ end
+ end
+
+ if badfiles.empty?
+ log "No indentation problems found."
+ else
+ log "Found incorrect indent in #{badfiles.length} files:\n "
+ badfiles.each do |file, badlines|
+ log " #{file}:\n" +
+ " " + badlines.collect {|badline| "%5d: %p" % badline }.join( "\n " )
+ end
+ end
+ end
+
end
+
View
201 install.rb
@@ -1,201 +0,0 @@
-#!/usr/bin/ruby
-#
-# Module Install Script
-# $Id: install.rb 11 2005-08-07 03:30:22Z ged $
-#
-# Thanks to Masatoshi SEKI for ideas found in his install.rb.
-#
-# Copyright (c) 2001-2005 The FaerieMUD Consortium.
-#
-# This is free software. You may use, modify, and/or redistribute this
-# software under the terms of the Perl Artistic License. (See
-# http://language.perl.com/misc/Artistic.html)
-#
-
-require './utils.rb'
-include UtilityFunctions
-
-require 'rbconfig'
-include Config
-
-require 'pathname'
-require 'find'
-require 'ftools'
-require 'optparse'
-
-$version = %q$Revision: 11 $
-$rcsId = %q$Id: install.rb 11 2005-08-07 03:30:22Z ged $
-
-# Define required libraries
-RequiredLibraries = []
-
-class Installer
-
- @@PrunePatterns = [
- /CVS/,
- /~$/,
- %r:(^|/)\.:,
- /\.tpl$/,
- /\.[cho]$/,
- ]
-
- def initialize( testing=false )
- @ftools = (testing) ? self : File
- end
-
- ### Make the specified dirs (which can be a String or an Array of Strings)
- ### with the specified mode.
- def makedirs( dirs, mode=0755, verbose=false )
- dirs = [ dirs ] unless dirs.is_a? Array
-
- oldumask = File::umask
- File::umask( 0777 - mode )
-
- for dir in dirs
- if @ftools == File
- File::mkpath( dir, $verbose )
- else
- $stderr.puts "Make path %s with mode %o" % [ dir, mode ]
- end
- end
-
- File::umask( oldumask )
- end
-
- def install( srcfile, dstfile, mode=nil, verbose=false )
- dstfile = File.catname(srcfile, dstfile)
- unless FileTest.exist? dstfile and File.cmp srcfile, dstfile
- $stderr.puts " install #{srcfile} -> #{dstfile}"
- else
- $stderr.puts " skipping #{dstfile}: unchanged"
- end
- end
-
- public
-
- def installFiles( src, dstDir, mode=0444, verbose=false )
- directories = []
- files = []
-
- if File.directory?( src )
- Find.find( src ) {|f|
- Find.prune if @@PrunePatterns.find {|pat| f =~ pat}
- next if f == src
-
- if FileTest.directory?( f )
- directories << f.gsub( /^#{src}#{File::Separator}/, '' )
- next
-
- elsif FileTest.file?( f )
- files << f.gsub( /^#{src}#{File::Separator}/, '' )
-
- else
- Find.prune
- end
- }
- else
- files << File.basename( src )
- src = File.dirname( src )
- end
-
- dirs = [ dstDir ]
- dirs |= directories.collect {|d| File.join(dstDir,d)}
- makedirs( dirs, 0755, verbose )
- files.each {|f|
- srcfile = File.join(src,f)
- dstfile = File.dirname(File.join( dstDir,f ))
-
- if verbose
- if mode
- $stderr.puts "Install #{srcfile} -> #{dstfile} (mode %o)" % mode
- else
- $stderr.puts "Install #{srcfile} -> #{dstfile}"
- end
- end
-
- @ftools.install( srcfile, dstfile, mode, verbose )
- }
- end
-
-end
-
-
-if $0 == __FILE__
- dryrun = false
- linkgrammar_dir = '/usr/local'
-
- # Parse command-line switches
- ARGV.options {|oparser|
- oparser.banner = "Usage: #$0 [options]\n"
-
- oparser.on( "--with-linkgrammar-dir=DIRECTORY", '-d=DIRECTORY', String,
- "Specify the directory where linkgrammar is installed." ) do |dir|
- linkgrammar_dir = dir
- end
-
- oparser.on( "--verbose", "-v", TrueClass, "Make progress verbose" ) {
- $VERBOSE = true
- debugMsg "Turned verbose on."
- }
-
- oparser.on( "--dry-run", "-n", TrueClass, "Don't really install anything" ) {
- debugMsg "Turned dry-run on."
- dryrun = true
- }
-
- # Handle the 'help' option
- oparser.on( "--help", "-h", "Display this text." ) {
- $stderr.puts oparser
- exit!(0)
- }
-
- oparser.parse!
- }
-
- debugMsg "Sitelibdir = '#{CONFIG['sitelibdir']}'"
- sitelibdir = CONFIG['sitelibdir']
- debugMsg "Sitearchdir = '#{CONFIG['sitearchdir']}'"
- sitearchdir = CONFIG['sitearchdir']
- dlext = CONFIG['DLEXT']
-
- extpath = Pathname.new( "ext/linkparser_ext.#{dlext}" )
- unless extpath.exist?
- message "Building #{extpath}...\n"
- Kernel.load( "extconf.rb", "--with-linkgrammar-dir=#{linkgrammar_dir}" )
-
- system( 'make' )
- status = $?
-
- if not status.success?
- puts "Build failed.\n\n"
- exit status.exitstatus
- end
- end
-
- testflag = Pathname.new( ".tests.passed" )
- unless testflag.exist?
- message "Testing...\n"
- require "./test.rb"
- result = runtests()
-
- if not result.passed?
- response = promptWithDefault "Some tests failed. Install anyway?", 'n'
- exit unless response =~ /^y/i
- else
- testflag.open( "w" ) do |f|
- f.puts( result.to_s )
- end
- end
- end
-
- message "Installing...\n"
- i = Installer.new( dryrun )
- i.installFiles( extpath, sitearchdir, 0444, $VERBOSE )
- i.installFiles( "lib", sitelibdir, 0444, $VERBOSE )
-
- message "done.\n"
-end
-
-
-
-
View
3 lib/linkparser.rb
@@ -42,6 +42,9 @@ module LinkParser
require 'linkparser/sentence'
require 'linkparser/linkage'
+ # Release version
+ VERSION = '1.0.0'
+
# SVN Revision
SVNRev = %q$Rev$
View
66 link-grammar-4.2.4.patch
@@ -1,66 +0,0 @@
-diff -ru link-grammar-4.2.4/link-grammar/api.c link-grammar-4.2.4-fixed/link-grammar/api.c
---- link-grammar-4.2.4/link-grammar/api.c 2006-04-09 07:05:25.000000000 -0700
-+++ link-grammar-4.2.4-fixed/link-grammar/api.c 2006-10-28 19:06:30.000000000 -0700
-@@ -861,6 +861,10 @@
- return linkage;
- }
-
-+int linkage_get_current_sublinkage(Linkage linkage) {
-+ return( linkage->current );
-+}
-+
- int linkage_set_current_sublinkage(Linkage linkage, int index) {
- int errno;
- if ((index < 0) ||
-Only in link-grammar-4.2.4/link-grammar: api.c.rej
-Only in link-grammar-4.2.4-fixed/link-grammar: api.c~
-diff -ru link-grammar-4.2.4/link-grammar/link-grammar.def link-grammar-4.2.4-fixed/link-grammar/link-grammar.def
---- link-grammar-4.2.4/link-grammar/link-grammar.def 2006-06-18 11:44:25.000000000 -0700
-+++ link-grammar-4.2.4-fixed/link-grammar/link-grammar.def 2006-10-29 22:40:41.115153450 -0800
-@@ -72,6 +72,7 @@
- sentence_get_nth_word
- sentence_nth_word_has_disjunction
- linkage_create
-+linkage_get_current_sublinkage
- linkage_set_current_sublinkage
- linkage_delete
- linkage_get_sentence
-@@ -114,3 +115,4 @@
- linkage_constituent_node_get_end
- lperrno
- lperrmsg
-+string_delete
-Only in link-grammar-4.2.4-fixed/link-grammar: link-grammar.def.orig
-Only in link-grammar-4.2.4/link-grammar: link-grammar.def.rej
-Only in link-grammar-4.2.4-fixed/link-grammar: link-grammar.def~
-diff -ru link-grammar-4.2.4/link-grammar/link-includes.h link-grammar-4.2.4-fixed/link-grammar/link-includes.h
---- link-grammar-4.2.4/link-grammar/link-includes.h 2006-06-18 11:42:13.000000000 -0700
-+++ link-grammar-4.2.4-fixed/link-grammar/link-includes.h 2006-10-29 22:40:48.008902530 -0800
-@@ -219,6 +219,8 @@
- link_public_api(Linkage)
- linkage_create(int index, Sentence sent, Parse_Options opts);
- link_public_api(int)
-+ linkage_get_current_sublinkage(Linkage linkage);
-+link_public_api(int)
- linkage_set_current_sublinkage(Linkage linkage, int index);
- link_public_api(void)
- linkage_delete(Linkage linkage);
-@@ -325,6 +327,15 @@
- extern link_public_api(char)
- lperrmsg[];
-
-+
-+link_public_api(void)
-+ string_delete(char *s);
-+
-+link_public_api(CNode *)
-+ linkage_constituent_tree(Linkage linkage);
-+link_public_api(void)
-+ linkage_free_constituent_tree(CNode * n);
-+
- LINK_END_DECLS
-
- #endif
-Only in link-grammar-4.2.4-fixed/link-grammar: link-includes.h.orig
-Only in link-grammar-4.2.4/link-grammar: link-includes.h.rej
-Only in link-grammar-4.2.4-fixed/link-grammar: link-includes.h~
View
BIN link-grammar-4.2.4.tar.gz
Binary file not shown.
View
89 link-grammar-4.3.5.patch
@@ -0,0 +1,89 @@
+Only in link-grammar-4.3.5.patched: bin
+diff -ubr link-grammar-4.3.5/link-grammar/api.c link-grammar-4.3.5.patched/link-grammar/api.c
+--- link-grammar-4.3.5/link-grammar/api.c 2008-04-21 08:51:29.000000000 -0700
++++ link-grammar-4.3.5.patched/link-grammar/api.c 2008-05-26 12:55:58.000000000 -0700
+@@ -894,6 +894,10 @@
+ return linkage;
+ }
+
++int linkage_get_current_sublinkage(Linkage linkage) {
++ return( linkage->current );
++}
++
+ int linkage_set_current_sublinkage(Linkage linkage, int index) {
+ int errno;
+ if ((index < 0) ||
+Only in link-grammar-4.3.5/link-grammar: link-features.h
+diff -ubr link-grammar-4.3.5/link-grammar/link-grammar.def link-grammar-4.3.5.patched/link-grammar/link-grammar.def
+--- link-grammar-4.3.5/link-grammar/link-grammar.def 2008-04-21 08:50:48.000000000 -0700
++++ link-grammar-4.3.5.patched/link-grammar/link-grammar.def 2008-05-26 12:54:55.000000000 -0700
+@@ -75,6 +75,7 @@
+ sentence_get_nth_word
+ sentence_nth_word_has_disjunction
+ linkage_create
++linkage_get_current_sublinkage
+ linkage_set_current_sublinkage
+ linkage_delete
+ linkage_get_sentence
+@@ -120,6 +121,7 @@
+ linkage_constituent_node_get_end
+ lperrno
+ lperrmsg
++string_delete
+ is_entity
+ is_past_tense_form
+ set_data_dir
+diff -ubr link-grammar-4.3.5/link-grammar/link-includes.h link-grammar-4.3.5.patched/link-grammar/link-includes.h
+--- link-grammar-4.3.5/link-grammar/link-includes.h 2008-04-21 08:59:29.000000000 -0700
++++ link-grammar-4.3.5.patched/link-grammar/link-includes.h 2008-05-26 12:51:22.000000000 -0700
+@@ -223,6 +223,8 @@
+ link_public_api(Linkage)
+ linkage_create(int index, Sentence sent, Parse_Options opts);
+ link_public_api(int)
++ linkage_get_current_sublinkage(Linkage linkage);
++link_public_api(int)
+ linkage_set_current_sublinkage(Linkage linkage, int index);
+ link_public_api(void)
+ linkage_delete(Linkage linkage);
+@@ -335,6 +337,10 @@
+ extern link_public_api(char)
+ lperrmsg[];
+
++/* from utilities.c */
++link_public_api(void)
++ string_delete(char *s);
++
+ LINK_END_DECLS
+
+ #endif
+diff -ubr link-grammar-4.3.5/link-grammar/read-dict.c link-grammar-4.3.5.patched/link-grammar/read-dict.c
+--- link-grammar-4.3.5/link-grammar/read-dict.c 2008-04-01 09:47:17.000000000 -0700
++++ link-grammar-4.3.5.patched/link-grammar/read-dict.c 2008-05-26 12:53:28.000000000 -0700
+@@ -702,14 +702,17 @@
+ }
+ else if (is_idiom_word(dn->string))
+ {
++ if ( verbosity > 3 ) {
+ printf("*** Word \"%s\" found near line %d.\n", dn->string, dict->line_number);
+ printf(" Words ending \".Ix\" (x a number) are reserved for idioms.\n");
+ printf(" This word will be ignored.\n");
++ }
+ xfree((char *)dn, sizeof(Dict_node));
+ }
+ else if ((dn_head = abridged_lookup_list(dict, dn->string))!= NULL)
+ {
+ Dict_node *dnx;
++ if ( verbosity > 3 ) {
+ printf("*** The word \"%s\"", dn->string);
+ printf(" found near line %d of %s matches the following words:\n",
+ dict->line_number, dict->name);
+@@ -717,6 +720,7 @@
+ printf(" %s", dnx->string);
+ }
+ printf("\n This word will be ignored.\n");
++ }
+ free_lookup_list(dn_head);
+ xfree((char *)dn, sizeof(Dict_node));
+ }
+Only in link-grammar-4.3.5.patched: link-grammar-4.3.5.jar
+Only in link-grammar-4.3.5: link-grammar.spec
View
BIN link-grammar-4.3.5.tar.gz
Binary file not shown.
View
309 misc/rake/helpers.rb
@@ -0,0 +1,309 @@
+#####################################################################
+### G L O B A L H E L P E R F U N C T I O N S
+#####################################################################
+
+require 'pathname'
+require 'readline'
+require 'open3'
+
+# Set some ANSI escape code constants (Shamelessly stolen from Perl's
+# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
+ANSI_ATTRIBUTES = {
+ 'clear' => 0,
+ 'reset' => 0,
+ 'bold' => 1,
+ 'dark' => 2,
+ 'underline' => 4,
+ 'underscore' => 4,
+ 'blink' => 5,
+ 'reverse' => 7,
+ 'concealed' => 8,
+
+ 'black' => 30, 'on_black' => 40,
+ 'red' => 31, 'on_red' => 41,
+ 'green' => 32, 'on_green' => 42,
+ 'yellow' => 33, 'on_yellow' => 43,
+ 'blue' => 34, 'on_blue' => 44,
+ 'magenta' => 35, 'on_magenta' => 45,
+ 'cyan' => 36, 'on_cyan' => 46,
+ 'white' => 37, 'on_white' => 47
+}
+
+
+CLEAR_TO_EOL = "\e[K"
+CLEAR_CURRENT_LINE = "\e[2K"
+
+
+### Output a logging message
+def log( *msg )
+ output = colorize( msg.flatten.join(' '), 'cyan' )
+ $deferr.puts( output )
+end
+
+
+### Output a logging message if tracing is on
+def trace( *msg )
+ return unless $trace
+ output = colorize( msg.flatten.join(' '), 'yellow' )
+ $deferr.puts( output )
+end
+
+
+### Run the specified command +cmd+ with system(), failing if the execution
+### fails.
+def run( *cmd )
+ cmd.flatten!
+
+ log( cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
+ if $dryrun
+ $deferr.puts "(dry run mode)"
+ else
+ system( *cmd )
+ unless $?.success?
+ fail "Command failed: [%s]" % [cmd.join(' ')]
+ end
+ end
+end
+
+
+### Open a pipe to a process running the given +cmd+ and call the given block with it.
+def pipeto( *cmd )
+ $DEBUG = true
+
+ cmd.flatten!
+ log( "Opening a pipe to: ", cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
+ if $dryrun
+ $deferr.puts "(dry run mode)"
+ else
+ open( '|-', 'w+' ) do |io|
+
+ # Parent
+ if io
+ yield( io )
+
+ # Child
+ else
+ exec( *cmd )
+ fail "Command failed: [%s]" % [cmd.join(' ')]
+ end
+ end
+ end
+end
+
+
+### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
+def download( sourceuri, targetfile )
+ oldsync = $defout.sync
+ $defout.sync = true
+ require 'net/http'
+ require 'uri'
+
+ targetpath = Pathname.new( targetfile )
+
+ log "Downloading %s to %s" % [sourceuri, targetfile]
+ targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|
+
+ url = URI.parse( sourceuri )
+ downloaded = false
+ limit = 5
+
+ until downloaded or limit.zero?
+ Net::HTTP.start( url.host, url.port ) do |http|
+ req = Net::HTTP::Get.new( url.path )
+
+ http.request( req ) do |res|
+ if res.is_a?( Net::HTTPSuccess )
+ log "Downloading..."
+ res.read_body do |buf|
+ ofh.print( buf )
+ end
+ downloaded = true
+ puts "done."
+
+ elsif res.is_a?( Net::HTTPRedirection )
+ url = URI.parse( res['location'] )
+ log "...following redirection to: %s" % [ url ]
+ limit -= 1
+ sleep 0.2
+ next
+
+ else
+ res.error!
+ end
+ end
+ end
+ end
+ end
+
+ return targetpath
+ensure
+ $defout.sync = oldsync
+end
+
+
+### Return the fully-qualified path to the specified +program+ in the PATH.
+def which( program )
+ ENV['PATH'].split(/:/).
+ collect {|dir| Pathname.new(dir) + program }.
+ find {|path| path.exist? && path.executable? }
+end
+
+
+### Create a string that contains the ANSI codes specified and return it
+def ansi_code( *attributes )
+ attributes.flatten!
+ attributes.collect! {|at| at.to_s }
+ # $deferr.puts "Returning ansicode for TERM = %p: %p" %
+ # [ ENV['TERM'], attributes ]
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
+ attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
+
+ # $deferr.puts " attr is: %p" % [attributes]
+ if attributes.empty?
+ return ''
+ else
+ return "\e[%sm" % attributes
+ end
+end
+
+
+### Colorize the given +string+ with the specified +attributes+ and return it, handling
+### line-endings, color reset, etc.
+def colorize( *args )
+ string = ''
+
+ if block_given?
+ string = yield
+ else
+ string = args.shift
+ end
+
+ ending = string[/(\s)$/] || ''
+ string = string.rstrip
+
+ return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
+end
+
+
+### Output the specified <tt>msg</tt> as an ANSI-colored error message
+### (white on red).
+def error_message( msg, details='' )
+ $deferr.puts colorize( 'bold', 'white', 'on_red' ) { msg } + details
+end
+alias :error :error_message
+
+
+### Highlight and embed a prompt control character in the given +string+ and return it.
+def make_prompt_string( string )
+ return CLEAR_CURRENT_LINE + colorize( 'bold', 'green' ) { string + ' ' }
+end
+
+
+### Output the specified <tt>prompt_string</tt> as a prompt (in green) and
+### return the user's input with leading and trailing spaces removed. If a
+### test is provided, the prompt will repeat until the test returns true.
+### An optional failure message can also be passed in.
+def prompt( prompt_string, failure_msg="Try again." ) # :yields: response
+ prompt_string.chomp!
+ prompt_string << ":" unless /\W$/.match( prompt_string )
+ response = nil
+
+ begin
+ prompt = make_prompt_string( prompt_string )
+ response = Readline.readline( prompt ) || ''
+ response.strip!
+ if block_given? && ! yield( response )
+ error_message( failure_msg + "\n\n" )
+ response = nil
+ end
+ end while response.nil?
+
+ return response
+end
+
+
+### Prompt the user with the given <tt>prompt_string</tt> via #prompt,
+### substituting the given <tt>default</tt> if the user doesn't input
+### anything. If a test is provided, the prompt will repeat until the test
+### returns true. An optional failure message can also be passed in.
+def prompt_with_default( prompt_string, default, failure_msg="Try again." )
+ response = nil
+
+ begin
+ response = prompt( "%s [%s]" % [ prompt_string, default ] )
+ response = default if response.empty?
+
+ if block_given? && ! yield( response )
+ error_message( failure_msg + "\n\n" )
+ response = nil
+ end
+ end while response.nil?
+
+ return response
+end
+
+
+### Display a description of a potentially-dangerous task, and prompt
+### for confirmation. If the user answers with anything that begins
+### with 'y', yield to the block, else raise with an error.
+def ask_for_confirmation( description )
+ puts description
+
+ answer = prompt_with_default( "Continue?", 'n' ) do |input|
+ input =~ /^[yn]/i
+ end
+
+ case answer
+ when /^y/i
+ yield
+ else
+ error "Aborted."
+ fail
+ end
+end
+
+
+### Search line-by-line in the specified +file+ for the given +regexp+, returning the
+### first match, or nil if no match was found. If the +regexp+ has any capture groups,
+### those will be returned in an Array, else the whole matching line is returned.
+def find_pattern_in_file( regexp, file )
+ rval = nil
+
+ File.open( file, 'r' ).each do |line|
+ if (( match = regexp.match(line) ))
+ rval = match.captures.empty? ? match[0] : match.captures
+ break
+ end
+ end
+
+ return rval
+end
+
+
+### Search line-by-line in the output of the specified +cmd+ for the given +regexp+,
+### returning the first match, or nil if no match was found. If the +regexp+ has any
+### capture groups, those will be returned in an Array, else the whole matching line
+### is returned.
+def find_pattern_in_pipe( regexp, *cmd )
+ output = []
+
+ Open3.popen3( *cmd ) do |stdin, stdout, stderr|
+ stdin.close
+
+ output << stdout.gets until stdout.eof?
+ output << stderr.gets until stderr.eof?
+ end
+
+ result = output.find { |line| regexp.match(line) }
+ return $1 || result
+end
+
+
+### Extract all the non Rake-target arguments from ARGV and return them.
+def get_target_args
+ args = ARGV.reject {|arg| Rake::Task.task_defined?(arg) }
+ return args
+end
+
+
+
View
327 misc/rake/svn.rb
@@ -0,0 +1,327 @@
+#####################################################################
+### S U B V E R S I O N T A S K S A N D H E L P E R S
+#####################################################################
+
+require 'pp'
+require 'yaml'
+require 'English'
+
+# Strftime format for tags/releases
+TAG_TIMESTAMP_FORMAT = '%Y%m%d-%H%M%S'
+TAG_TIMESTAMP_PATTERN = /\d{4}\d{2}\d{2}-\d{6}/
+
+RELEASE_VERSION_PATTERN = /\d+\.\d+\.\d+/
+
+DEFAULT_EDITOR = 'vi'
+DEFAULT_KEYWORDS = %w[Date Rev Author URL Id]
+KEYWORDED_FILEPATTERN = /^(?:Rakefile|.*\.(?:rb|js|c|h|html|template))$/i
+
+COMMIT_MSG_FILE = 'commit-msg.txt'
+
+###
+### Subversion-specific Helpers
+###
+
+### Return a new tag for the given time
+def make_new_tag( time=Time.now )
+ return time.strftime( TAG_TIMESTAMP_FORMAT )
+end
+
+
+### Get the subversion information for the current working directory as
+### a hash.
+def get_svn_info( dir='.' )
+ info = IO.read( '|-' ) or exec 'svn', 'info', dir
+ return YAML.load( info ) # 'svn info' outputs valid YAML! Yay!
+end
+
+
+### Get a list of the objects registered with subversion under the specified directory and
+### return them as an Array of Pathame objects.
+def get_svn_filelist( dir='.' )
+ list = IO.read( '|-' ) or exec 'svn', 'st', '-v', '--ignore-externals', dir
+
+ # Split into lines, filter out the unknowns, and grab the filenames as Pathnames
+ # :FIXME: This will break if we ever put in a file with spaces in its name. This
+ # will likely be the least of our worries if we do so, however, so it's not worth
+ # the additional complexity to make it handle that case. If we do need that, there's
+ # always the --xml output for 'svn st'...
+ return list.split( $/ ).
+ reject {|line| line =~ /^\?/ }.
+ collect {|fn| Pathname(fn[/\S+$/]) }
+end
+
+### Return the URL to the repository root for the specified +dir+.
+def get_svn_repo_root( dir='.' )
+ info = get_svn_info( dir )
+ return info['Repository Root'] + '/thingfish'
+end
+
+
+### Return the Subversion URL to the given +dir+.
+def get_svn_url( dir='.' )
+ info = get_svn_info( dir )
+ return info['URL']
+end
+
+
+### Return the path of the specified +dir+ under the svn root of the
+### checkout.
+def get_svn_path( dir='.' )
+ root = get_svn_repo_root( dir )
+ url = get_svn_url( dir )
+
+ return url.sub( root + '/', '' )
+end
+
+
+### Return the keywords for the specified array of +files+ as a Hash keyed by filename.
+def get_svn_keyword_map( files )
+ cmd = ['svn', 'pg', 'svn:keywords', *files]
+
+ # trace "Executing: svn pg svn:keywords " + files.join(' ')
+ output = IO.read( '|-' ) or exec( 'svn', 'pg', 'svn:keywords', *files )
+
+ kwmap = {}
+ output.split( "\n" ).each do |line|
+ next if line !~ /\s+-\s+/
+ path, keywords = line.split( /\s+-\s+/, 2 )
+ kwmap[ path ] = keywords.split
+ end
+
+ return kwmap
+end
+
+
+### Return the latest revision number of the specified +dir+ as an Integer.
+def get_svn_rev( dir='.' )
+ info = get_svn_info( dir )
+ return info['Revision']
+end
+
+
+### Return a list of the entries at the specified Subversion url. If
+### no +url+ is specified, it will default to the list in the URL
+### corresponding to the current working directory.
+def svn_ls( url=nil )
+ url ||= get_svn_url()
+ list = IO.read( '|-' ) or exec 'svn', 'ls', url
+
+ trace 'svn ls of %s: %p' % [url, list] if $trace
+
+ return [] if list.nil? || list.empty?
+ return list.split( $INPUT_RECORD_SEPARATOR )
+end
+
+
+### Return the URL of the latest timestamp in the tags directory.
+def get_latest_svn_timestamp_tag
+ rooturl = get_svn_repo_root()
+ tagsurl = rooturl + '/tags'
+
+ tags = svn_ls( tagsurl ).grep( TAG_TIMESTAMP_PATTERN ).sort
+ return nil if tags.nil? || tags.empty?
+ return tagsurl + '/' + tags.last
+end
+
+
+### Get a subversion diff of the specified targets and return it. If no targets are
+### specified, the current directory will be diffed instead.
+def get_svn_diff( *targets )
+ targets << BASEDIR if targets.empty?
+ trace "Getting svn diff for targets: %p" % [targets]
+ log = IO.read( '|-' ) or exec 'svn', 'diff', *(targets.flatten)
+
+ return log
+end
+
+
+### Return the URL of the latest timestamp in the tags directory.
+def get_latest_release_tag
+ rooturl = get_svn_repo_root()
+ releaseurl = rooturl + '/releases'
+
+ tags = svn_ls( releaseurl ).grep( RELEASE_VERSION_PATTERN ).sort_by do |tag|
+ tag.split('.').collect {|i| Integer(i) }
+ end
+ return nil if tags.empty?
+
+ return releaseurl + '/' + tags.last
+end
+
+
+### Extract a diff from the specified subversion working +dir+, rewrite its
+### file lines as Trac links, and return it.
+def make_svn_commit_log( dir='.' )
+ editor_prog = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
+
+ diff = IO.read( '|-' ) or exec 'svn', 'diff'
+ fail "No differences." if diff.empty?
+
+ return diff
+end
+
+
+
+###
+### Tasks
+###
+
+desc "Subversion tasks"
+namespace :svn do
+
+ desc "Copy the HEAD revision of the current trunk/ to tags/ with a " +
+ "current timestamp."
+ task :tag do
+ svninfo = get_svn_info()
+ tag = make_new_tag()
+ svntrunk = svninfo['Repository Root'] + '/thingfish/trunk'
+ svntagdir = svninfo['Repository Root'] + '/thingfish/tags'
+ svntag = svntagdir + '/' + tag
+
+ desc = "Tagging trunk as #{svntag}"
+ ask_for_confirmation( desc ) do
+ msg = prompt_with_default( "Commit log: ", "Tagging for code push" )
+ run 'svn', 'cp', '-m', msg, svntrunk, svntag
+ end
+ end
+
+
+ desc "Copy the most recent tag to releases/#{PKG_VERSION}"
+ task :release do
+ last_tag = get_latest_svn_timestamp_tag()
+ svninfo = get_svn_info()
+ release = PKG_VERSION
+ svnrel = svninfo['Repository Root'] + '/thingfish/releases'
+ svnrelease = svnrel + '/' + release
+
+ if last_tag.nil?
+ error "There are no tags in the repository"
+ fail
+ end
+
+ releases = svn_ls( svnrel )
+ trace "Releases: %p" % [releases]
+ if releases.include?( release )
+ error "Version #{release} already has a branch (#{svnrelease}). Did you mean" +
+ "to increment the version in thingfish.rb?"
+ fail
+ else
+ trace "No #{svnrel} version currently exists"
+ end
+
+ desc = "Release tag\n #{last_tag}\nto\n #{svnrelease}"
+ ask_for_confirmation( desc ) do
+ msg = prompt_with_default( "Commit log: ", "Branching for release" )
+ run 'svn', 'cp', '-m', msg, last_tag, svnrelease
+ end
+ end
+
+ ### Task for debugging the #get_target_args helper
+ task :show_targets do
+ $stdout.puts "Targets from ARGV (%p): %p" % [ARGV, get_target_args()]
+ end
+
+
+ desc "Generate a commit log"
+ task :commitlog => [COMMIT_MSG_FILE]
+
+ desc "Show the (pre-edited) commit log for the current directory"
+ task :show_commitlog => [COMMIT_MSG_FILE] do
+ ask_for_confirmation( "Confirm? " ) do
+ args = get_target_args()
+ puts get_svn_diff( *args )
+ end
+ end
+
+
+ file COMMIT_MSG_FILE do
+ args = get_target_args()
+ diff = get_svn_diff( *args )
+
+ File.open( COMMIT_MSG_FILE, File::WRONLY|File::EXCL|File::CREAT ) do |fh|
+ fh.print( diff )
+ end
+
+ editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
+ system editor, COMMIT_MSG_FILE
+ unless $?.success?
+ fail "Editor exited uncleanly."
+ end
+ end
+
+
+ desc "Update from Subversion"
+ task :update do
+ run 'svn', 'up', '--ignore-externals'
+ end
+
+
+ desc "Check in all the changes in your current working copy"
+ task :checkin => ['svn:update', 'coverage:verify', 'svn:fix_keywords', COMMIT_MSG_FILE] do
+ targets = get_target_args()
+ $deferr.puts '---', File.read( COMMIT_MSG_FILE ), '---'
+ ask_for_confirmation( "Continue with checkin?" ) do
+ run 'svn', 'ci', '-F', COMMIT_MSG_FILE, targets
+ rm_f COMMIT_MSG_FILE
+ end
+ end
+ task :commit => :checkin
+ task :ci => :checkin
+
+
+ task :clean do
+ rm_f COMMIT_MSG_FILE
+ end
+
+
+ desc "Check and fix any missing keywords for any files in the project which need them"
+ task :fix_keywords do
+ log "Checking subversion keywords..."
+ paths = get_svn_filelist( BASEDIR ).
+ select {|path| path.file? && path.to_s =~ KEYWORDED_FILEPATTERN }
+
+ trace "Looking at %d paths for keywords:\n %p" % [paths.length, paths]
+ kwmap = get_svn_keyword_map( paths )
+
+ buf = ''
+ PP.pp( kwmap, buf, 132 )
+ trace "keyword map is: %s" % [buf]
+
+ files_needing_fixups = paths.find_all do |path|
+ (kwmap[path.to_s] & DEFAULT_KEYWORDS) != DEFAULT_KEYWORDS
+ end
+
+ unless files_needing_fixups.empty?
+ $deferr.puts "Files needing keyword fixes: ",
+ files_needing_fixups.collect {|f|
+ " %s: %s" % [f, kwmap[f] ? kwmap[f].join(' ') : "(no keywords)"]
+ }
+ ask_for_confirmation( "Will add default keywords to these files." ) do
+ run 'svn', 'ps', 'svn:keywords', DEFAULT_KEYWORDS.join(' '), *files_needing_fixups
+ end
+ else
+ log "Keywords are all up to date."
+ end
+ end
+
+
+ task :debug_helpers do
+ methods = [
+ :make_new_tag,
+ :get_svn_info,
+ :get_svn_repo_root,
+ :get_svn_url,
+ :get_svn_path,
+ :svn_ls,
+ :get_latest_svn_timestamp_tag,
+ ]
+ maxlen = methods.collect {|sym| sym.to_s.length }.max
+
+ methods.each do |meth|
+ res = send( meth )
+ puts "%*s => %p" % [ maxlen, colorize(meth.to_s, :cyan), res ]
+ end
+ end
+end
+
View
64 misc/rake/verifytask.rb
@@ -0,0 +1,64 @@
+#####################################################################
+### S U B V E R S I O N T A S K S A N D H E L P E R S
+#####################################################################
+
+require 'rake/tasklib'
+
+#
+# Work around the inexplicable behaviour of the original RDoc::VerifyTask, which
+# errors if your coverage isn't *exactly* the threshold.
+#
+
+# A task that can verify that the RCov coverage doesn't
+# drop below a certain threshold. It should be run after
+# running Spec::Rake::SpecTask.
+class VerifyTask < Rake::TaskLib
+
+ COVERAGE_PERCENTAGE_PATTERN =
+ %r{<tt class='coverage_code'>(\d+\.\d+)%</tt>}
+
+ # Name of the task. Defaults to :verify_rcov
+ attr_accessor :name
+
+ # Path to the index.html file generated by RCov, which
+ # is the file containing the total coverage.
+ # Defaults to 'coverage/index.html'
+ attr_accessor :index_html
+
+ # Whether or not to output details. Defaults to true.
+ attr_accessor :verbose
+
+ # The threshold value (in percent) for coverage. If the
+ # actual coverage is not equal to this value, the task will raise an
+ # exception.
+ attr_accessor :threshold
+
+ def initialize( name=:verify )
+ @name = name
+ @index_html = 'coverage/index.html'
+ @verbose = true
+ yield self if block_given?
+ raise "Threshold must be set" if @threshold.nil?
+ define
+ end
+
+ def define
+ desc "Verify that rcov coverage is at least #{threshold}%"
+
+ task @name do
+ total_coverage = nil
+ if match = File.read( index_html ).match( COVERAGE_PERCENTAGE_PATTERN )
+ total_coverage = Float( match[1] )
+ else
+ raise "Couldn't find the coverage percentage in #{index_html}"
+ end
+
+ puts "Coverage: #{total_coverage}% (threshold: #{threshold}%)" if verbose
+ if total_coverage < threshold
+ raise "Coverage must be at least #{threshold}% but was #{total_coverage}%"
+ end
+ end
+ end
+end
+
+# vim: set nosta noet ts=4 sw=4:
View
261 spec/linkage_spec.rb
@@ -270,199 +270,168 @@
@linkage.links[3].rword.should == 'was.v'
@linkage.links[3].label.should == 'Ss'
end
-
-
-end
-class BlahDeBlah
-
- #1 LEFT-WALL Xp <---Xp----> Xp .
- #2 (m) LEFT-WALL Wd <---Wd----> Wd flag.n
- #3+4 (m) the D <---Ds----> Ds flag.n
- #5 (m) flag.n Ss <---Ss----> Ss was.v
- #6 (m) was.v Pa <---Pa----> Pa wet.a
- def test_linkage_links_should_contain_link_structs_describing_the_linkage
- rval = nil
-
- assert_nothing_raised do
- rval = @linkage.links
- end
-
- assert_instance_of Array, rval
- assert_kind_of Struct, rval.first
- assert_equal 'LEFT-WALL', rval.first.lword, "left word of first link"
- assert_equal 'Xp', rval.first.label, "label of first link"
- assert_equal 'RIGHT-WALL', rval.last.rword, "right word of last link"
- assert_equal 'RW', rval.last.label, "label of last link"
- assert_equal 'flag.n', rval[3].lword, "left word of the fourth link"
- assert_equal 'was.v', rval[3].rword, "right word of the fourth link"
- assert_equal 'Ss', rval[3].label, "label of the fourth link"
+ it "knows what word is the verb in the sentence" do
+ @linkage.verb.should == "was"
end
- def test_linkage_verb_should_return_sentence_verb
- rval = nil
-
- assert_nothing_raised do
- rval = @linkage.verb
- end
-
- assert_equal "was", rval
+ it "knows when the sentence doesn't have a direct object" do
+ @linkage.object.should be_nil()
end
+
+ MODE1_C_TREE_STRING = "(S (NP The flag)\n (VP was\n (ADJP wet))\n .)\n"
+ MODE2_C_TREE_STRING = "[S [NP The flag NP] [VP was [ADJP wet ADJP] VP] . S] \n"
+ MODE3_C_TREE_STRING = "(S (NP The flag) (VP was (ADJP wet)) .)\n"
- # The ball rolled down the hill and bumped the curb.
- def test_linkage_verb_should_return_vword_of_current_sublinkage_of_conjunction
- rval = nil
- linkage = @conjunct_sentence.linkages.first
-
- assert_nothing_raised do
- rval = linkage.verb
- end
-
- assert_equal 'rolled', rval
-
- assert_nothing_raised do
- linkage.current_sublinkage = 1
- rval = linkage.verb
- end
-
- assert_equal 'bumped', rval
+ it "returns an indented sexps for the constituent tree string by default (mode 1)" do
+ @linkage.constituent_tree_string.should == MODE1_C_TREE_STRING
end
+
+ it "returns indented sexps for the constituent tree string if fetched with explicit mode '1'" do
+ @linkage.constituent_tree_string( 1 ).should == MODE1_C_TREE_STRING
+ end
+ it "returns bracketed constituents if constituent tree string is fetched in mode 2" do
+ @linkage.constituent_tree_string( 2 ).should == MODE2_C_TREE_STRING
+ end
- Mode1CTreeString = "(S (NP The flag)\n (VP was\n (ADJP wet))\n .)\n"
- Mode2CTreeString = "[S [NP The flag NP] [VP was [ADJP wet ADJP] VP] . S] \n"
- Mode3CTreeString = "(S (NP The flag) (VP was (ADJP wet)) .)\n"
+ it "returns unindented sexps for the constituent tree string if constituent tree string " +
+ "is fetched in mode 3" do
+ @linkage.constituent_tree_string( 3 ).should == MODE3_C_TREE_STRING
+ end
- def test_constituent_tree_string_without_mode_should_return_mode1_string
- rval = nil
-
- assert_nothing_raised do
- rval = @linkage.constituent_tree_string
- end
-
- assert_equal Mode1CTreeString, rval
+ it "raises an exception for any numeric constituent tree string mode greater than 3" do
+ lambda {
+ @linkage.constituent_tree_string( 4 )
+ }.should raise_error( ArgumentError, /illegal mode 4/i )
+ end
+
+ it "raises an exception for any numeric constituent tree string mode less than 1" do
+ lambda {
+ @linkage.constituent_tree_string( 0 )
+ }.should raise_error( ArgumentError, /illegal mode 0/i )
end
- def test_constituent_tree_string_with_mode1_should_return_mode1_string
- rval = nil
-
- assert_nothing_raised do
- rval = @linkage.constituent_tree_string( 1 )
- end
-
- assert_equal Mode1CTreeString, rval
+ it "raises an exception when a non-numeric constituent tree string mode is given" do
+ lambda {
+ @linkage.constituent_tree_string( 'glarg' )
+ }.should raise_error( TypeError )
end
-
- def test_constituent_tree_string_with_mode2_should_return_mode2_string
- rval = nil
-
- assert_nothing_raised do
- rval = @linkage.constituent_tree_string( 2 )
- end
+
+ it "returns an Array of CTree structs for its constituent tree" do
+ rval = @linkage.constituent_tree
- assert_equal Mode2CTreeString, rval
+ rval.should be_an_instance_of( Array )
+ rval.should have(1).members
+ rval.first.should be_a_kind_of( Struct )
+ rval.first.label.should == 'S'
+ rval.first.children.should have(3).members
+ rval.first.children.collect {|n| n.label }.should include( 'NP', 'VP', '.' )
end
-
- def test_constituent_tree_string_with_mode3_should_return_mode3_string
- rval = nil
-
- assert_nothing_raised do
- rval = @linkage.constituent_tree_string( 3 )
- end
-
- assert_equal Mode3CTreeString, rval
+
+ it "returns 0 as the number of the current sublinkage since it has no conjunctions" do
+ @linkage.current_sublinkage.should == 0
end
- def test_constituent_tree_string_with_mode4_should_raise_exception
- assert_raises( ArgumentError ) do
- @linkage.constituent_tree_string( 4 )
- end
- end
- def test_constituent_tree_string_with_nonnumeric_should_raise_exception
- assert_raises( TypeError ) do
- @linkage.constituent_tree_string( "Glah" )
- end
+ it "returns an informational string when inspected" do
+ @linkage.inspect.should =~ /Linkage:0x[[:xdigit:]]+: sublinkage 0: \[\d+ links\]/
end
+
+
+ describe "from a simple sentence with a direct object" do
+ before( :each ) do
+ @sentence = @dict.parse( "The dog ran home." )
+ @linkage = @sentence.linkages.first
+ end
- def test_constituent_tree_should_return_array_of_CTree_structs
- rval = nil
-
- assert_nothing_raised do
- rval = @linkage.constituent_tree
+ it "doesn't have any sublinkages" do
+ @linkage.num_sublinkages.should == 1
end
-
- assert_kind_of Array, rval
- assert_kind_of Struct, rval.first
- assert_equal "S", rval.first.label
- assert_equal "NP", rval.first.children.first.label
- assert_equal "The", rval.first.children.first.children.first.label
- end
- def test_linkage_current_sublinkage_should_return
- rval = nil
- assert_nothing_raised do
- rval = @linkage.current_sublinkage
+ it "doesn't change after computing its union" do
+ lambda {
+ @linkage.compute_union
+ }.should_not change( @linkage, :num_sublinkages )
end
- assert_kind_of(Fixnum, rval)
- end
-end
+ it "knows what word is the object in the sentence" do
+ @linkage.object.should == 'home'
+ end
+
+ end
-describe LinkParser::Linkage, " from a simple sentence" do
- before( :all ) do
- @dict = LinkParser::Dictionary.new( :verbosity => 0 )
+ it "knows that it doesn't have any conjunctions" do
+ @linkage.should_not have_conjunction()
end
+
- before( :each ) do
- @sentence = @dict.parse( "The dog ran home." )
- @linkage = @sentence.linkages.first
- end
+ describe "from a sentence with a conjunction" do
+ before( :each ) do
+ @sentence =
+ @dict.parse( "The ball rolled down the hill and bumped the curb." )
+ @linkage = @sentence.linkages.first
+ end
- it "doesn't have any sublinkages" do
- @linkage.num_sublinkages.should == 1
- end
+ it "knows that it has a conjunction" do
+ @linkage.should have_conjunction()
+ end
+
+ it "has two sublinkages" do
+ @linkage.num_sublinkages.should == 2
+ end
- it "doesn't change after computing its union" do
- lambda {
- @linkage.compute_union
- }.should_not change( @linkage, :num_sublinkages )
- end
-end
+ it "adds a sublinkage after computing its union" do
+ lambda {
+ @linkage.compute_union
+ }.should change( @linkage, :num_sublinkages ).from(2).to(3)
+ end
-describe LinkParser::Linkage, " with a conjunction" do
- before( :all ) do
- @dict = LinkParser::Dictionary.new( :verbosity => 0 )
- end
+ it "knows what word is the verb in the current sublinkage" do
+ @linkage.verb.should == 'rolled'
+ @linkage.current_sublinkage = 1
+ @linkage.verb.should == 'bumped'
+ end
+
+
+ it "knows what word is the object in the current sublinkage" do
+ @linkage.object.should == 'hill'
+ @linkage.current_sublinkage = 1
+ @linkage.object.should == 'curb'
+ end
- before( :each ) do
- @sentence =
- @dict.parse( "The ball rolled down the hill and bumped the curb." )
- @linkage = @sentence.linkages.first
end
- it "has two sublinkages" do
- @linkage.num_sublinkages.should == 2
+ it "should know that it's not an imperative sentence" do
+ @linkage.imperative?.should be_false()
end
- it "adds a sublinkage after computing its union" do
- lambda {
- @linkage.compute_union
- }.should change( @linkage, :num_sublinkages ).from(2).to(3)
+ describe "from an imperative sentence" do
+ before( :each ) do
+ @sentence = @dict.parse( "Go to the store!" )
+ @linkage = @sentence.linkages.first
+ end
+
+
+ it "knows that it's an imperative sentence" do
+ @linkage.imperative?.should be_true()
+ end
+
+
end
-end
+end
View
169 spec/sentence.tests.rb
@@ -1,169 +0,0 @@
-#!/usr/bin/ruby -w
-#
-# Unit tests for the LinkParser::Sentence class
-# $Id$
-#
-# Copyright (c) 2007, 2008 The FaerieMUD Consortium
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-
-BEGIN {
- require 'pathname'
- basedir = Pathname.new( __FILE__ ).dirname.parent
- require basedir + "linkparser-path.rb"
-}
-
-
-require 'test/unit'
-require 'linkparser'
-
-class LinkParser::Sentence::TestCase < Test::Unit::TestCase
-
- @dict = LinkParser::Dictionary.new( :verbosity => 0 )
- class << self; attr_accessor :dict; end
-
-
- def setup
- @dict = self.class.dict
- @sentence = LinkParser::Sentence.new( "The cat runs.", @dict )
- end
-
-
- def test_sentence_parse_returns_linkage_count
- rval = nil
-
- assert_nothing_raised do
- rval = @sentence.parse
- end
-
- assert_equal rval, 1, "'The cat runs.' should only have one linkage"
- end
-
-
- def test_sentence_parse_should_accept_parse_options
- rval = nil
-
- assert_nothing_raised do
- @sentence.parse( :verbosity => 0 )
- end
- end
-
-
- def test_sentence_length_should_return_word_count
- rval = nil
- assert_nothing_raised do
- rval = @sentence.length
- end
- assert_equal 6, rval, "'The cat runs.' should have a length of 6"
- end
-
-
- def test_sentence_delegates_linkage_methods_to_first_linkage
- rval = nil
-
- assert_nothing_raised do
- rval = @sentence.num_links
- end
-
- assert_equal 5, rval
- end
-
-
- def test_sentence_parsed_p_should_return_false_for_unparsed_sentences
- rval = nil
-
- assert_nothing_raised do
- rval = @sentence.parsed?
- end
-
- assert_equal false, rval
- end
-
-
- def test_sentence_parsed_p_should_return_true_for_parsed_sentences
- rval = nil
- @sentence.parse
-
- assert_nothing_raised do
- rval = @sentence.parsed?
- end
-
- assert_equal true, rval
- end
-
-
- def test_sentence_linkages_should_return_linkage_objects
- rval = nil
-
- assert_nothing_raised do
- rval = @sentence.linkages
- end
-
- assert_instance_of Array, rval
- rval.each do |obj|
- assert_instance_of LinkParser::Linkage, obj
- end
- end
-
-
- def test_sentence_length_should_return_number_of_words_in_sentence
- rval = nil
-
- assert_nothing_raised do
- rval = @sentence.length
- end
-
- assert_equal 6, rval
- end
-
-
- def test_sentence_word_returns_tokenized_word
- rval = nil
-
- assert_nothing_raised do
- rval = @sentence.word( 0 )
- end
-
- assert_equal "LEFT-WALL", rval
- end
-
- def test_sentence_bracketbracket_returns_tokenized_word
- rval = nil
-
- assert_nothing_raised do
- rval = @sentence[ -1 ]
- end
-
- assert_equal "RIGHT-WALL", rval
- end
-
- def test_sentence_null_count_should_return_count_of_null_links
- sent = @dict.parse( "This sentence contains a gravel superfluous word.")
- rval = nil
-
- assert_nothing_raised do
- rval = sent.null_count
- end
-
- rval = 1
- end
-
-end
-
View
130 spec/sentence_spec.rb
@@ -0,0 +1,130 @@
+#!/usr/bin/ruby -w
+#
+# Specification for the LinkParser::Sentence class
+# $Id$
+#
+# Copyright (c) 2007, 2008 The FaerieMUD Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+BEGIN {
+ require 'pathname'
+ basedir = Pathname.new( __FILE__ ).dirname.parent
+ require basedir + 'linkparser-path.rb'
+}
+
+require 'spec/runner'
+require 'linkparser'
+
+
+describe LinkParser::Sentence do
+
+
+ before( :all ) do
+ @dict = LinkParser::Dictionary.new( :verbosity => 0 )
+ end
+
+
+ before( :each ) do
+ @sentence = LinkParser::Sentence.new( "The cat runs.", @dict )
+ end
+
+
+ it "returns an informational string when inspected" do
+ @sentence.inspect.should =~ %r{
+ <
+ LinkParser::Sentence:0x[[:xdigit:]]+
+ \s
+ (?-x:"LEFT-WALL the cat runs . RIGHT-WALL")
+ /\d+\slinkages
+ /\d+\snulls
+ >
+ }x
+ end
+
+ it "can return itself as a tokenized string" do
+ @sentence.to_s.should == "LEFT-WALL the cat runs . RIGHT-WALL"
+ end
+
+
+ it "returns the linkage count as the result of parsing the sentence" do
+ @sentence.parse.should == 1
+ end
+
+
+ it "accepts parse options when parsing" do