linguistics 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/rake/testing.rb ADDED
@@ -0,0 +1,187 @@
1
+ #
2
+ # Rake tasklib for testing tasks
3
+
4
+ #
5
+ # Authors:
6
+ # * Michael Granger <ged@FaerieMUD.org>
7
+ #
8
+
9
+ unless defined?( COVERAGE_MINIMUM )
10
+ if ENV['COVVERAGE_MINIMUM']
11
+ COVERAGE_MINIMUM = Float( ENV['COVERAGE_MINIMUM'] )
12
+ else
13
+ COVERAGE_MINIMUM = 85.0
14
+ end
15
+ end
16
+ SPEC_FILES = [] unless defined?( SPEC_FILES )
17
+ TEST_FILES = [] unless defined?( TEST_FILES )
18
+
19
+ COMMON_SPEC_OPTS = ['-Du'] unless defined?( COMMON_SPEC_OPTS )
20
+
21
+ COVERAGE_TARGETDIR = BASEDIR + 'coverage' unless defined?( COVERAGE_TARGETDIR )
22
+ RCOV_EXCLUDES = 'spec,tests,/Library/Ruby,/var/lib,/usr/local/lib' unless
23
+ defined?( RCOV_EXCLUDES )
24
+
25
+
26
+ desc "Run all defined tests"
27
+ task :test do
28
+ unless SPEC_FILES.empty?
29
+ log "Running specs"
30
+ Rake::Task['spec:quiet'].invoke
31
+ end
32
+
33
+ unless TEST_FILES.empty?
34
+ log "Running unit tests"
35
+ Rake::Task[:unittests].invoke
36
+ end
37
+ end
38
+
39
+
40
+ ### RSpec specifications
41
+ begin
42
+ gem 'rspec', '>= 1.1.3'
43
+
44
+ require 'spec'
45
+ require 'spec/rake/spectask'
46
+
47
+ ### Task: spec
48
+ desc "Run specs"
49
+ task :spec => 'spec:doc'
50
+
51
+ namespace :spec do
52
+ desc "Run rspec every time there's a change to one of the files"
53
+ task :autotest do
54
+ require 'autotest/rspec'
55
+
56
+ autotester = Autotest::Rspec.new
57
+ autotester.run
58
+ end
59
+
60
+ desc "Generate regular color 'doc' spec output"
61
+ Spec::Rake::SpecTask.new( :doc ) do |task|
62
+ task.spec_files = SPEC_FILES
63
+ task.spec_opts = COMMON_SPEC_OPTS + ['-f', 's', '-c']
64
+ end
65
+
66
+ desc "Generate spec output with profiling"
67
+ Spec::Rake::SpecTask.new( :profile ) do |task|
68
+ task.spec_files = SPEC_FILES
69
+ task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'o']
70
+ end
71
+
72
+ desc "Generate quiet non-colored plain-text output"
73
+ Spec::Rake::SpecTask.new( :quiet ) do |task|
74
+ task.spec_files = SPEC_FILES
75
+ task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'p']
76
+ end
77
+
78
+ desc "Generate HTML output"
79
+ Spec::Rake::SpecTask.new( :html ) do |task|
80
+ task.spec_files = SPEC_FILES
81
+ task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'h']
82
+ end
83
+
84
+ end
85
+ rescue LoadError => err
86
+ task :no_rspec do
87
+ $stderr.puts "Specification tasks not defined: %s" % [ err.message ]
88
+ end
89
+
90
+ task :spec => :no_rspec
91
+ namespace :spec do
92
+ task :autotest => :no_rspec
93
+ task :doc => :no_rspec
94
+ task :profile => :no_rspec
95
+ task :quiet => :no_rspec
96
+ task :html => :no_rspec
97
+ end
98
+ end
99
+
100
+
101
+ ### Test::Unit tests
102
+ begin
103
+ require 'rake/testtask'
104
+
105
+ Rake::TestTask.new( :unittests ) do |task|
106
+ task.libs += [LIBDIR]
107
+ task.test_files = TEST_FILES
108
+ task.verbose = true
109
+ end
110
+
111
+ rescue LoadError => err
112
+ task :no_test do
113
+ $stderr.puts "Test tasks not defined: %s" % [ err.message ]
114
+ end
115
+
116
+ task :unittests => :no_rspec
117
+ end
118
+
119
+
120
+ ### RCov (via RSpec) tasks
121
+ begin
122
+ gem 'rcov'
123
+ gem 'rspec', '>= 1.1.3'
124
+
125
+ require 'spec'
126
+ require 'rcov'
127
+
128
+ ### Task: coverage (via RCov)
129
+ desc "Build test coverage reports"
130
+ unless SPEC_FILES.empty?
131
+ Spec::Rake::SpecTask.new( :coverage ) do |task|
132
+ task.spec_files = SPEC_FILES
133
+ task.libs += [LIBDIR]
134
+ task.spec_opts = ['-f', 'p', '-b']
135
+ task.rcov_opts = RCOV_OPTS
136
+ task.rcov = true
137
+ end
138
+ end
139
+
140
+
141
+ ### Task: rcov
142
+ task :rcov => :coverage
143
+
144
+ ### Other coverage tasks
145
+ namespace :coverage do
146
+ desc "Generate a detailed text coverage report"
147
+ Spec::Rake::SpecTask.new( :text ) do |task|
148
+ task.spec_files = SPEC_FILES
149
+ task.rcov_opts = RCOV_OPTS + ['--text-report']
150
+ task.rcov = true
151
+ end
152
+
153
+ desc "Show differences in coverage from last run"
154
+ Spec::Rake::SpecTask.new( :diff ) do |task|
155
+ task.spec_files = SPEC_FILES
156
+ task.spec_opts = ['-f', 'p', '-b']
157
+ task.rcov_opts = RCOV_OPTS - ['--save'] + ['--text-coverage-diff']
158
+ task.rcov = true
159
+ end
160
+
161
+ desc "Run RCov in 'spec-only' mode to check coverage from specs"
162
+ Spec::Rake::SpecTask.new( :speconly ) do |task|
163
+ task.spec_files = SPEC_FILES
164
+ task.rcov_opts = ['--exclude', RCOV_EXCLUDES, '--text-report', '--save']
165
+ task.rcov = true
166
+ end
167
+ end
168
+
169
+ CLOBBER.include( COVERAGE_TARGETDIR )
170
+
171
+ rescue LoadError => err
172
+ task :no_rcov do
173
+ $stderr.puts "Coverage tasks not defined: RSpec+RCov tasklib not available: %s" %
174
+ [ err.message ]
175
+ end
176
+
177
+ task :coverage => :no_rcov
178
+ task :clobber_coverage
179
+ task :rcov => :no_rcov
180
+ namespace :coverage do
181
+ task :text => :no_rcov
182
+ task :diff => :no_rcov
183
+ end
184
+ task :verify => :no_rcov
185
+ end
186
+
187
+
@@ -0,0 +1,64 @@
1
+ #####################################################################
2
+ ### 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
3
+ #####################################################################
4
+
5
+ require 'rake/tasklib'
6
+
7
+ #
8
+ # Work around the inexplicable behaviour of the original RDoc::VerifyTask, which
9
+ # errors if your coverage isn't *exactly* the threshold.
10
+ #
11
+
12
+ # A task that can verify that the RCov coverage doesn't
13
+ # drop below a certain threshold. It should be run after
14
+ # running Spec::Rake::SpecTask.
15
+ class VerifyTask < Rake::TaskLib
16
+
17
+ COVERAGE_PERCENTAGE_PATTERN =
18
+ %r{<tt class='coverage_code'>(\d+\.\d+)%</tt>}
19
+
20
+ # Name of the task. Defaults to :verify_rcov
21
+ attr_accessor :name
22
+
23
+ # Path to the index.html file generated by RCov, which
24
+ # is the file containing the total coverage.
25
+ # Defaults to 'coverage/index.html'
26
+ attr_accessor :index_html
27
+
28
+ # Whether or not to output details. Defaults to true.
29
+ attr_accessor :verbose
30
+
31
+ # The threshold value (in percent) for coverage. If the
32
+ # actual coverage is not equal to this value, the task will raise an
33
+ # exception.
34
+ attr_accessor :threshold
35
+
36
+ def initialize( name=:verify )
37
+ @name = name
38
+ @index_html = 'coverage/index.html'
39
+ @verbose = true
40
+ yield self if block_given?
41
+ raise "Threshold must be set" if @threshold.nil?
42
+ define
43
+ end
44
+
45
+ def define
46
+ desc "Verify that rcov coverage is at least #{threshold}%"
47
+
48
+ task @name do
49
+ total_coverage = nil
50
+ if match = File.read( index_html ).match( COVERAGE_PERCENTAGE_PATTERN )
51
+ total_coverage = Float( match[1] )
52
+ else
53
+ raise "Couldn't find the coverage percentage in #{index_html}"
54
+ end
55
+
56
+ puts "Coverage: #{total_coverage}% (threshold: #{threshold}%)" if verbose
57
+ if total_coverage < threshold
58
+ raise "Coverage must be at least #{threshold}% but was #{total_coverage}%"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # vim: set nosta noet ts=4 sw=4:
data/rake/win32.rb ADDED
@@ -0,0 +1,190 @@
1
+ #
2
+ # Win32-specific tasks (cross-compiling, etc.)
3
+ #
4
+ # Thanks to some people that understand this stuff better than me for
5
+ # posting helpful blog posts. This stuff is an amalgam of stuff they did:
6
+ #
7
+ # * Mauricio Fernandez
8
+ # http://eigenclass.org/hiki/cross+compiling+rcovrt
9
+ #
10
+ # * Jeremy Hinegardner
11
+ # http://www.copiousfreetime.org/articles/2008/10/12/building-gems-for-windows.html
12
+ #
13
+ # * Aaron Patterson
14
+ # http://tenderlovemaking.com/2008/11/21/cross-compiling-ruby-gems-for-win32/
15
+
16
+ require 'rubygems'
17
+ require 'rake'
18
+ require 'pathname'
19
+ require 'rubygems/platform'
20
+ require 'rbconfig'
21
+ require 'uri'
22
+ require 'net/ftp'
23
+
24
+ HOMEDIR = Pathname( '~' ).expand_path
25
+ RUBYVERSION = '1.8.6-p287'
26
+ RUBYVERSION_MAJORMINOR = RUBYVERSION[/^\d+\.\d+/]
27
+
28
+ RUBY_DL_BASE = "ftp://ftp.ruby-lang.org/pub/ruby/#{RUBYVERSION_MAJORMINOR}/"
29
+ RUBY_DL_URI = URI( RUBY_DL_BASE + "ruby-#{RUBYVERSION}.tar.gz" )
30
+
31
+ XCOMPILER_DIR = HOMEDIR + '.ruby_mingw32'
32
+
33
+ XCOMPILER_DL = XCOMPILER_DIR + "ruby-#{RUBYVERSION}.tar.gz"
34
+ XCOMPILER_SRC = XCOMPILER_DIR + "ruby-#{RUBYVERSION}"
35
+
36
+ XCOMPILER_BIN = XCOMPILER_DIR + 'bin'
37
+ XCOMPILER_LIB = XCOMPILER_DIR + 'lib'
38
+ XCOMPILER_RUBY = XCOMPILER_BIN + 'ruby.exe'
39
+
40
+ XCOMPILER_LOAD_PATH = XCOMPILER_LIB + "ruby/#{RUBYVERSION_MAJORMINOR}/i386-mingw32"
41
+
42
+ TAR_OPTS = { :compression => :gzip }
43
+
44
+ WIN32_GEMSPEC = GEMSPEC.dup
45
+ WIN32_GEMSPEC.files += FileList[ EXTDIR + '**.{dll,so}' ]
46
+ WIN32_GEMSPEC.platform = Gem::Platform.new( 'i386-mingw32' )
47
+ WIN32_GEMSPEC.extensions = []
48
+
49
+
50
+ CONFIGURE_CMD = %W[
51
+ env
52
+ ac_cv_func_getpgrp_void=no
53
+ ac_cv_func_setpgrp_void=yes
54
+ rb_cv_negative_time_t=no
55
+ ac_cv_func_memcmp_working=yes
56
+ rb_cv_binary_elf=no
57
+ ./configure
58
+ --host=i386-mingw32
59
+ --target=i386-mingw32
60
+ --build=#{Config::CONFIG['build']}
61
+ --prefix=#{XCOMPILER_DIR}
62
+ ]
63
+
64
+ ### Archive::Tar::Reader#extract (as of 0.9.0) is broken w.r.t.
65
+ ### permissions, so we have to do this ourselves.
66
+ def untar( tarfile, targetdir )
67
+ targetdir = Pathname( targetdir )
68
+ raise "No such directory: #{targetdir}" unless targetdir.directory?
69
+
70
+ reader = Archive::Tar::Reader.new( tarfile.to_s, TAR_OPTS )
71
+
72
+ mkdir_p( targetdir )
73
+ reader.each( true ) do |header, body|
74
+ path = targetdir + header[:path]
75
+ # trace "Header is: %p" % [ header ]
76
+
77
+ case header[:type]
78
+ when :file
79
+ trace " #{path}"
80
+ path.open( File::WRONLY|File::EXCL|File::CREAT|File::TRUNC, header[:mode] ) do |fio|
81
+ bytesize = header[:size]
82
+ fio.write( body[0,bytesize] )
83
+ end
84
+
85
+ when :directory
86
+ trace " #{path}"
87
+ path.mkpath
88
+
89
+ when :link
90
+ linktarget = targetdir + header[:dest]
91
+ trace " #{path} => #{linktarget}"
92
+ path.make_link( linktarget.to_s )
93
+
94
+ when :symlink
95
+ linktarget = targetdir + header[:dest]
96
+ trace " #{path} -> #{linktarget}"
97
+ path.make_symlink( linktarget )
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+
104
+ begin
105
+ require 'archive/tar'
106
+
107
+ namespace :win32 do
108
+ directory XCOMPILER_DIR.to_s
109
+
110
+ file XCOMPILER_DL => XCOMPILER_DIR do
111
+ # openuri can't handle this -- passive ftp required?
112
+ # run 'wget', '-O', XCOMPILER_DL, RUBY_DL_URI
113
+ log "Downloading ruby distro from %s" % [ RUBY_DL_URI ]
114
+ ftp = Net::FTP.new( RUBY_DL_URI.host )
115
+ ftp.login
116
+ ftp.getbinaryfile( RUBY_DL_URI.path, XCOMPILER_DL, 4096 )
117
+ ftp.close
118
+ end
119
+
120
+ directory XCOMPILER_SRC.to_s
121
+ task XCOMPILER_SRC => [ XCOMPILER_DIR, XCOMPILER_DL ] do
122
+ if XCOMPILER_SRC.exist?
123
+ trace "Rake fails. #{XCOMPILER_SRC} already exists."
124
+ else
125
+ untar( XCOMPILER_DL, XCOMPILER_DIR )
126
+ end
127
+ end
128
+
129
+ file XCOMPILER_RUBY => XCOMPILER_SRC do
130
+ Dir.chdir( XCOMPILER_SRC ) do
131
+ unless File.exist?( 'Makefile.in.orig' )
132
+ File.open( 'Makefile.in.new', IO::CREAT|IO::WRONLY|IO::EXCL ) do |ofh|
133
+ IO.readlines( 'Makefile.in' ).each do |line|
134
+ next if line.include?( 0.chr )
135
+ trace " copying line: %p" % [ line ]
136
+ line.sub!( /ALT_SEPARATOR = ".*?"/, "ALT_SEPARATOR = 92.chr" )
137
+ ofh.write( line )
138
+ end
139
+ end
140
+
141
+ mv 'Makefile.in', 'Makefile.in.orig'
142
+ mv 'Makefile.in.new', 'Makefile.in'
143
+ end
144
+
145
+ run *CONFIGURE_CMD
146
+ run 'make', 'ruby'
147
+ run 'make', 'rubyw.exe'
148
+ run 'make', 'install'
149
+ end
150
+ end
151
+
152
+ file XCOMPILER_LOAD_PATH => XCOMPILER_RUBY
153
+
154
+ desc "Cross-compile the library for Win32 systems, installing a cross-" +
155
+ "compiled Ruby if necessary"
156
+ task :build => [ EXTDIR, XCOMPILER_LOAD_PATH.to_s ] do
157
+ in_subdirectory( EXTDIR ) do
158
+ ruby "-I#{XCOMPILER_LOAD_PATH}", 'extconf.rb'
159
+ sh 'make'
160
+ end
161
+ end
162
+
163
+ desc "Build a binary gem for win32 systems"
164
+ task :gem => ['win32:build', PKGDIR.to_s] + WIN32_GEMSPEC.files do
165
+ when_writing( "Creating win32 GEM" ) do
166
+ pkgname = WIN32_GEMSPEC.file_name
167
+ builder = Gem::Builder.new( WIN32_GEMSPEC )
168
+ builder.build
169
+ mv pkgname, PKGDIR + pkgname, :verbose => $trace
170
+ end
171
+ end
172
+ end
173
+
174
+ rescue LoadError => err
175
+ trace "Couldn't load the win32 tasks: %s: %s" % [ err.class.name, err.message ]
176
+
177
+ task :no_win32_build do
178
+ abort "No win32 build: %s: %s" % [ err.class.name, err.message ]
179
+ end
180
+
181
+ namespace :win32 do
182
+ desc "Build a binary Gem for Win32 systems, installing a cross " +
183
+ "compiled Ruby if necessary"
184
+ task :gem => :no_win32_build
185
+ task :build => :no_win32_build
186
+ end
187
+
188
+ end
189
+
190
+
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env spec -cfs
2
+
3
+ BEGIN {
4
+ require 'pathname'
5
+ basedir = Pathname.new( __FILE__ ).dirname.parent.parent
6
+
7
+ libdir = basedir + "lib"
8
+
9
+ $LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
10
+ }
11
+
12
+ begin
13
+ require 'spec/runner'
14
+ require 'linguistics'
15
+ require 'linguistics/en'
16
+ rescue LoadError
17
+ unless Object.const_defined?( :Gem )
18
+ require 'rubygems'
19
+ retry
20
+ end
21
+ raise
22
+ end
23
+
24
+
25
+ describe Linguistics::EN do
26
+
27
+ before( :all ) do
28
+ Linguistics::use( :en )
29
+ include Linguistics::EN
30
+ end
31
+
32
+
33
+ describe "conjunctions with an Array of a single element" do
34
+
35
+ before( :each ) do
36
+ @array = ['cat']
37
+ end
38
+
39
+ it "results in a phrase with indefinite article" do
40
+ @array.en.conjunction.should == "a cat"
41
+ end
42
+
43
+ end
44
+
45
+
46
+ describe "conjunction with an Array of two different words" do
47
+
48
+ before( :each ) do
49
+ @array = ['cat', 'dog']
50
+ end
51
+
52
+ it "results in a phrase joined with 'and' with default options" do
53
+ @array.en.conjunction.should == "a cat and a dog"
54
+ end
55
+
56
+ it "results in a phrase joined with 'plus' if 'plus' is set as the conjunctive" do
57
+ @array.en.conjunction(:conjunctive => 'plus').should == "a cat plus a dog"
58
+ end
59
+
60
+ it "results in a phrase joined with a space if an empty string is set as the conjunctive" do
61
+ @array.en.conjunction(:conjunctive => '').should == "a cat a dog"
62
+ end
63
+
64
+ end
65
+
66
+
67
+ describe "conjunction with an Array of two words that differ only in case" do
68
+
69
+ before( :each ) do
70
+ @array = ['cat', 'Cat']
71
+ end
72
+
73
+ it "combines them into their downcased equivalents with default options" do
74
+ @array.en.conjunction.should == "two cats"
75
+ end
76
+
77
+ it "lists them separately if :combine is set to false" do
78
+ @array.en.conjunction(:combine => false).should == "a cat and a Cat"
79
+ end
80
+
81
+ it "doesn't combine them if :casefold is turned off" do
82
+ @array.en.conjunction(:casefold => false).should == "a cat and a Cat"
83
+ end
84
+
85
+ it "combines and lists them with a non-specific count if :generalize is set" do
86
+ @array.en.conjunction(:generalize => true).should == "several cats"
87
+ end
88
+
89
+ end
90
+
91
+
92
+ describe "conjunction with an Array of many (more than two) words of varying cases" do
93
+
94
+ before( :each ) do
95
+ @array = %w{cat dog fox dog chicken chicken Fox chicken goose Dog goose}
96
+ end
97
+
98
+ it "combines them into their downcased equivalents and lists them in order of amount " +
99
+ "with default options" do
100
+ @array.en.conjunction.should ==
101
+ 'three dogs, three chickens, two foxes, two geese, and a cat'
102
+ end
103
+
104
+ it "lists them separately if :combine is set to false" do
105
+ @array.en.conjunction(:combine => false).should ==
106
+ 'a cat, a dog, a fox, a dog, a chicken, a chicken, a Fox, a '\
107
+ 'chicken, a goose, a Dog, and a goose'
108
+ end
109
+
110
+ it "doesn't combine the differently-cased ones if :casefold is turned off" do
111
+ @array.en.conjunction(:casefold => false).should ==
112
+ 'three chickens, two dogs, two geese, a cat, a fox, a Fox, '\
113
+ 'and a Dog'
114
+ end
115
+
116
+ it "combines and lists them with a non-specific count if :generalize is set" do
117
+ @array.en.conjunction(:generalize => true).should ==
118
+ 'several dogs, several chickens, several foxes, several '\
119
+ 'geese, and a cat'
120
+ end
121
+
122
+ end
123
+
124
+
125
+ describe "conjunction with an object-transform block" do
126
+
127
+ it "doesn't still have #6: #conjunction doesn't invoke supplied block under some conditions"
128
+ before( :each ) do
129
+ # Create a new class, as we need to guarantee that this will be the
130
+ # first #conjunction call to it.
131
+ @collection = Class::new {
132
+ include Enumerable, Linguistics
133
+ def initialize( *ary )
134
+ @ary = ary.flatten
135
+ end
136
+
137
+ # Delegate #each to the contained Array
138
+ def each( &block )
139
+ @ary.each( &block )
140
+ end
141
+ }
142
+
143
+ @obj = @collection.new( 'foo', 'bar', 'baz', 'tree', 'node', 'sonogram' )
144
+ end
145
+
146
+ it "uses supplied block for object transform on first invocation" do
147
+ @obj.en.conjunction {|word| "%s-letter word" % word.length.en.numwords }.should ==
148
+ "three three-letter words, two four-letter words, and an eight-letter word"
149
+ end
150
+ end
151
+
152
+
153
+
154
+ def test_conjunction_should_use_supplied_block_for_object_transform
155
+ rval = nil
156
+
157
+ assert_nothing_raised do
158
+ rval = Items.en.conjunction {|word| "%s-word" % word[0,1]}
159
+ end
160
+
161
+ assert_equal "three c-words and a b-word", rval
162
+ end
163
+
164
+
165
+ def test_conjunction_should_use_supplied_block_for_object_transform_through_autoproxy
166
+ rval = nil
167
+
168
+ assert_nothing_raised do
169
+ rval = Items.conjunction {|word| "%s-word" % word[0,1]}
170
+ end
171
+
172
+ assert_equal "three c-words and a b-word", rval
173
+ end
174
+
175
+ def test_conjunction_with_penultimate_separator_turned_off_should_not_use_one
176
+ rval = nil
177
+
178
+ assert_nothing_raised do
179
+ rval = Items.en.conjunction( :penultimate => false )
180
+ end
181
+
182
+ assert_equal "a cow, a chicken, a blancmange and a cyclist", rval
183
+ end
184
+
185
+ def test_three_item_conjunction_should_honor_penultimate_setting
186
+ rval = nil
187
+
188
+ assert_nothing_raised do
189
+ rval = %w{duck cow dog}.en.conjunction( :penultimate => false )
190
+ end
191
+
192
+ assert_equal "a duck, a cow and a dog", rval
193
+ end
194
+
195
+ def test_conjunction_uses_alt_separator_if_phrases_include_the_primary_one
196
+ rval = nil
197
+ scene_items = [
198
+ "desk with stamps, paper, and envelopes on it",
199
+ "basket containing milk, eggs, and broccoli",
200
+ "chair",
201
+ "wooden chest",
202
+ "hat rack",
203
+ ]
204
+
205
+ assert_nothing_raised do
206
+ rval = scene_items.conjunction
207
+ end
208
+
209
+ assert_equal "a desk with stamps, paper, and envelopes on it; " +
210
+ "a basket containing milk, eggs, and broccoli; " +
211
+ "a chair; a wooden chest; and a hat rack", rval
212
+ end
213
+
214
+ end
215
+