linkparser 1.1.4 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.simplecov +9 -0
- data/ChangeLog +40 -3
- data/History.md +55 -0
- data/Manifest.txt +6 -4
- data/{README.rdoc → README.md} +56 -53
- data/Rakefile +53 -21
- data/ext/dictionary.c +60 -65
- data/ext/extconf.rb +6 -3
- data/ext/linkage.c +117 -368
- data/ext/linkparser.c +56 -27
- data/ext/linkparser.h +14 -16
- data/ext/parseoptions.c +209 -680
- data/ext/sentence.c +62 -149
- data/lib/linkparser.rb +14 -7
- data/lib/linkparser/dictionary.rb +13 -0
- data/lib/linkparser/linkage.rb +277 -166
- data/lib/linkparser/mixins.rb +2 -2
- data/lib/linkparser/parseoptions.rb +58 -0
- data/lib/linkparser/sentence.rb +21 -34
- data/spec/bugfixes_spec.rb +23 -36
- data/spec/helpers.rb +35 -0
- data/spec/linkparser/dictionary_spec.rb +29 -48
- data/spec/linkparser/linkage_spec.rb +199 -268
- data/spec/linkparser/mixins_spec.rb +9 -24
- data/spec/linkparser/parseoptions_spec.rb +45 -59
- data/spec/linkparser/sentence_spec.rb +36 -56
- data/spec/linkparser_spec.rb +6 -25
- metadata +97 -85
- metadata.gz.sig +0 -0
- data/History.rdoc +0 -41
- data/examples/basic-api.rb +0 -65
- data/examples/readme-example.rb +0 -14
data/lib/linkparser/mixins.rb
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
require 'linkparser' unless defined?( LinkParser )
|
5
|
+
|
6
|
+
|
7
|
+
# LinkParser parse options class. Instances of this class are used to specify the different
|
8
|
+
# parameters that are used to parse sentences. Examples of the kinds of things that are
|
9
|
+
# controlled by ParseOptions include maximum parsing time and memory, whether to use
|
10
|
+
# null-links, and whether or not to use "panic" mode. This data structure is passed in to
|
11
|
+
# the various parsing and printing routines along with the sentence.
|
12
|
+
class LinkParser::ParseOptions
|
13
|
+
extend Loggability,
|
14
|
+
LinkParser::DeprecationUtilities
|
15
|
+
|
16
|
+
# Use LinkParser's logger
|
17
|
+
log_to :linkparser
|
18
|
+
|
19
|
+
|
20
|
+
### Return an Array of valid option names as Symbols.
|
21
|
+
def self::option_names
|
22
|
+
return @option_names ||= instance_methods( false ).
|
23
|
+
grep( /^[a-z].*=$/ ).map {|sym| sym.to_s.chomp('=').to_sym }
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
### Return a new LinkParser::ParseOptions with the values of the receiver merged with
|
28
|
+
### those from the +other+ object.
|
29
|
+
def merge( other )
|
30
|
+
new_options = self.dup
|
31
|
+
new_options.merge!( other )
|
32
|
+
return new_options
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
### Overwrite the option settings on the receiver with those from the +other+
|
37
|
+
### object.
|
38
|
+
def merge!( other )
|
39
|
+
other.to_hash.each do |key, val|
|
40
|
+
self.send( "#{key}=", val )
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
### Return the options as a Hash.
|
46
|
+
def to_hash
|
47
|
+
return self.class.option_names.each_with_object( {} ) do |optname, accum|
|
48
|
+
val = if self.respond_to?( "#{optname}?" )
|
49
|
+
self.send( "#{optname}?" )
|
50
|
+
else
|
51
|
+
self.send( optname )
|
52
|
+
end
|
53
|
+
|
54
|
+
accum[ optname ] = val
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end # class LinkParser::ParseOptions
|
data/lib/linkparser/sentence.rb
CHANGED
@@ -1,28 +1,20 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
2
3
|
|
3
4
|
require 'linkparser' unless defined?( LinkParser )
|
4
5
|
|
5
|
-
#
|
6
6
|
# A Sentence is the API's representation of an input string, tokenized
|
7
7
|
# and interpreted according to a specific Dictionary. After a Sentence
|
8
8
|
# is created and parsed, various attributes of the resulting set of
|
9
9
|
# linkages can be obtained.
|
10
|
-
#
|
11
|
-
# == Authors
|
12
|
-
#
|
13
|
-
# * Michael Granger <ged@FaerieMUD.org>
|
14
|
-
#
|
15
|
-
# == Version
|
16
|
-
#
|
17
|
-
# $Id: sentence.rb,v 23a39531870a 2011/01/11 18:18:12 ged $
|
18
|
-
#
|
19
|
-
# == License
|
20
|
-
#
|
21
|
-
# :include: LICENSE
|
22
|
-
#--
|
23
|
-
#
|
24
|
-
# See the LICENSE file for copyright/licensing information.
|
25
10
|
class LinkParser::Sentence
|
11
|
+
extend Loggability,
|
12
|
+
LinkParser::DeprecationUtilities
|
13
|
+
|
14
|
+
|
15
|
+
# Use LinkParser's logger
|
16
|
+
log_to :linkparser
|
17
|
+
|
26
18
|
|
27
19
|
######
|
28
20
|
public
|
@@ -41,7 +33,7 @@ class LinkParser::Sentence
|
|
41
33
|
contents = "(unparsed)"
|
42
34
|
end
|
43
35
|
|
44
|
-
return "#<%s
|
36
|
+
return "#<%s:%#x %s>" % [
|
45
37
|
self.class.name,
|
46
38
|
self.object_id / 2,
|
47
39
|
contents,
|
@@ -59,26 +51,21 @@ class LinkParser::Sentence
|
|
59
51
|
protected
|
60
52
|
#########
|
61
53
|
|
62
|
-
### Return the singleton class for this object
|
63
|
-
def singleton_class
|
64
|
-
class << self; self; end
|
65
|
-
end
|
66
|
-
|
67
|
-
|
68
54
|
### Proxy method -- auto-delegate calls to the first linkage.
|
69
|
-
def method_missing( sym, *args )
|
70
|
-
|
71
|
-
# Check both symbol and string for forward-compatibility with 1.9.x
|
72
|
-
return super unless
|
73
|
-
LinkParser::Linkage.instance_methods.include?( sym.to_s ) ||
|
74
|
-
LinkParser::Linkage.instance_methods.include?( sym )
|
55
|
+
def method_missing( sym, *args, &block )
|
56
|
+
return super unless LinkParser::Linkage.instance_methods.include?( sym )
|
75
57
|
|
76
|
-
|
58
|
+
linkage_method = LinkParser::Linkage.instance_method( sym )
|
59
|
+
meth = lambda do |*args, &block|
|
60
|
+
linkage = self.linkages.first or raise LinkParser::Error, "sentence has no linkages"
|
61
|
+
linkage_method.bind( linkage ).call( *args, &block )
|
62
|
+
end
|
77
63
|
|
78
|
-
|
79
|
-
|
64
|
+
self.singleton_class.instance_exec( sym, meth ) do |name, new_method|
|
65
|
+
define_method( name, &new_method )
|
66
|
+
end
|
80
67
|
|
81
|
-
meth.call( *args )
|
68
|
+
meth.call( *args, &block )
|
82
69
|
rescue => err
|
83
70
|
raise err, err.message, err.backtrace[ 0..-2 ]
|
84
71
|
end
|
data/spec/bugfixes_spec.rb
CHANGED
@@ -1,48 +1,35 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# Specification for various bugfixes to the LinkParser binding
|
4
|
-
# $Id: bugfixes_spec.rb,v 1eddd00723e6 2010/11/22 15:59:36 ged $
|
5
|
-
#
|
6
|
-
# See the LICENSE file in the distribution for information about copyright and licensing.
|
7
|
-
#
|
8
|
-
|
9
|
-
BEGIN {
|
10
|
-
require 'pathname'
|
11
|
-
basedir = Pathname.new( __FILE__ ).dirname.parent
|
12
|
-
|
13
|
-
libdir = basedir + 'lib'
|
14
|
-
extdir = basedir + 'ext'
|
15
|
-
|
16
|
-
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
17
|
-
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
18
|
-
$LOAD_PATH.unshift( extdir.to_s ) unless $LOAD_PATH.include?( extdir.to_s )
|
19
|
-
}
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
20
3
|
|
21
|
-
|
4
|
+
require_relative 'helpers'
|
22
5
|
|
6
|
+
require 'rspec'
|
23
7
|
require 'linkparser'
|
24
8
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
describe %{bugfix for #3: The first linkage for "The cat runs."} do
|
9
|
+
|
10
|
+
describe LinkParser do
|
11
|
+
|
29
12
|
before( :all ) do
|
30
|
-
|
13
|
+
@dict = LinkParser::Dictionary.new('en', verbosity: 0)
|
31
14
|
end
|
32
15
|
|
33
|
-
|
34
|
-
|
35
|
-
@sentence = @dict.parse( "The cat runs." )
|
36
|
-
@linkage = @sentence.linkages.first
|
37
|
-
end
|
16
|
+
let( :sentence ) { @dict.parse( text ) }
|
17
|
+
let( :linkage ) { sentence.linkages.first }
|
38
18
|
|
39
19
|
|
40
|
-
|
41
|
-
|
42
|
-
|
20
|
+
describe 'bugfix for #3: The first linkage for "The cat runs."' do
|
21
|
+
|
22
|
+
let( :text ) { "The cat runs." }
|
23
|
+
|
24
|
+
|
25
|
+
it "selects cat as the subject" do
|
26
|
+
expect( linkage.subject ).to eq( "cat" )
|
27
|
+
end
|
28
|
+
|
29
|
+
it "selects runs as the verb" do
|
30
|
+
expect( linkage.verb ).to eq( "runs" )
|
31
|
+
end
|
43
32
|
|
44
|
-
it "thinks runs is the verb" do
|
45
|
-
@linkage.verb.should == "runs"
|
46
33
|
end
|
47
|
-
end
|
48
34
|
|
35
|
+
end
|
data/spec/helpers.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
3
|
+
|
4
|
+
# SimpleCov test coverage reporting; enable this using the :coverage rake task
|
5
|
+
require 'simplecov' if ENV['COVERAGE']
|
6
|
+
require 'rspec'
|
7
|
+
|
8
|
+
require 'loggability/spechelpers'
|
9
|
+
|
10
|
+
require 'linkparser'
|
11
|
+
|
12
|
+
|
13
|
+
$DEBUG = true if ENV['DEBUG']
|
14
|
+
|
15
|
+
|
16
|
+
### RSpec helper functions.
|
17
|
+
module LinkParser::SpecHelpers
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
### Mock with RSpec
|
22
|
+
RSpec.configure do |config|
|
23
|
+
config.run_all_when_everything_filtered = true
|
24
|
+
config.filter_run :focus
|
25
|
+
config.order = 'random'
|
26
|
+
config.mock_with( :rspec ) do |mock|
|
27
|
+
mock.syntax = :expect
|
28
|
+
end
|
29
|
+
|
30
|
+
config.include( Loggability::SpecHelpers )
|
31
|
+
config.include( LinkParser::SpecHelpers )
|
32
|
+
end
|
33
|
+
|
34
|
+
# vim: set nosta noet ts=4 sw=4:
|
35
|
+
|
@@ -1,31 +1,15 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# Specification for the LinkParser::Dictionary class
|
4
|
-
# $Id: dictionary_spec.rb,v 54e4e2ff8899 2010/11/25 00:50:55 ged $
|
5
|
-
#
|
6
|
-
# See the LICENSE file in the distribution for information about copyright and licensing.
|
7
|
-
#
|
8
|
-
|
9
|
-
BEGIN {
|
10
|
-
require 'pathname'
|
11
|
-
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
12
|
-
|
13
|
-
libdir = basedir + 'lib'
|
14
|
-
extdir = basedir + 'ext'
|
15
|
-
|
16
|
-
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
17
|
-
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
18
|
-
$LOAD_PATH.unshift( extdir.to_s ) unless $LOAD_PATH.include?( extdir.to_s )
|
19
|
-
}
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
20
3
|
|
21
|
-
|
4
|
+
require_relative '../helpers'
|
22
5
|
|
6
|
+
require 'rspec'
|
23
7
|
require 'linkparser'
|
24
8
|
|
25
9
|
|
26
10
|
describe LinkParser::Dictionary do
|
27
11
|
|
28
|
-
###
|
12
|
+
### Tests expect English locale
|
29
13
|
before( :all ) do
|
30
14
|
$LANG = ENV['LANG']
|
31
15
|
ENV['LANG'] = 'en_US.UTF-8'
|
@@ -38,66 +22,63 @@ describe LinkParser::Dictionary do
|
|
38
22
|
|
39
23
|
|
40
24
|
it "can be instantiated using all default values" do
|
41
|
-
LinkParser::Dictionary.new.
|
25
|
+
expect( LinkParser::Dictionary.new ).to be_an_instance_of( LinkParser::Dictionary )
|
42
26
|
end
|
43
27
|
|
44
28
|
it "can be instantiated with an options hash" do
|
45
|
-
LinkParser::Dictionary.new( :verbosity => 2 )
|
29
|
+
dict = LinkParser::Dictionary.new( :verbosity => 2 )
|
30
|
+
expect( dict ).to be_a( LinkParser::Dictionary )
|
31
|
+
expect( dict.options[:verbosity] ).to eq( 2 )
|
46
32
|
end
|
47
33
|
|
48
34
|
it "raises an error when created with an bad number of arguments" do
|
49
|
-
|
35
|
+
expect {
|
50
36
|
LinkParser::Dictionary.new( "foo", "bar", "baz" )
|
51
|
-
}.
|
37
|
+
}.to raise_error( ArgumentError )
|
52
38
|
end
|
53
39
|
|
54
40
|
it "can be instantiated with a language argument" do
|
55
|
-
|
41
|
+
dict = LinkParser::Dictionary.new( 'en' )
|
42
|
+
expect( dict ).to be_a( LinkParser::Dictionary )
|
56
43
|
end
|
57
44
|
|
58
45
|
it "can be instantiated with both a language and an options hash" do
|
59
|
-
LinkParser::Dictionary.new('en', :verbosity => 2)
|
46
|
+
dict = LinkParser::Dictionary.new( 'en', :verbosity => 2 )
|
47
|
+
expect( dict.options[:verbosity] ).to eq( 2 )
|
60
48
|
end
|
61
49
|
|
62
|
-
it "raises an exception if created with unknown
|
63
|
-
|
64
|
-
LinkParser::Dictionary.new(
|
65
|
-
}.
|
50
|
+
it "raises an exception if created with an unknown language" do
|
51
|
+
expect {
|
52
|
+
LinkParser::Dictionary.new( 'ie' )
|
53
|
+
}.to raise_error( LinkParser::Error )
|
66
54
|
end
|
67
55
|
|
68
56
|
it "raises an exception if created with an unknown language" do
|
69
|
-
|
57
|
+
expect {
|
70
58
|
LinkParser::Dictionary.new('zz')
|
71
|
-
}.
|
59
|
+
}.to raise_error( LinkParser::Error )
|
72
60
|
end
|
73
61
|
|
62
|
+
|
74
63
|
context "instance" do
|
75
64
|
|
76
65
|
TEST_SENTENCE = "The dog plays with the ball."
|
77
66
|
|
78
|
-
before( :
|
79
|
-
@dict = LinkParser::Dictionary.new(
|
80
|
-
:verbosity => 0,
|
81
|
-
:max_null_count => 18,
|
82
|
-
:echo_on => true
|
83
|
-
)
|
67
|
+
before( :all ) do
|
68
|
+
@dict = LinkParser::Dictionary.new( verbosity: 0, max_null_count: 18, islands_ok: true )
|
84
69
|
end
|
85
70
|
|
86
71
|
|
87
|
-
it "knows what the total cost of its linkages are" do
|
88
|
-
@dict.max_cost.should be_an_instance_of(Fixnum)
|
89
|
-
end
|
90
|
-
|
91
72
|
it "can parse a sentence" do
|
92
|
-
@dict.parse( TEST_SENTENCE )
|
93
|
-
|
73
|
+
sentence = @dict.parse( TEST_SENTENCE )
|
74
|
+
expect( sentence ).to be_an_instance_of( LinkParser::Sentence )
|
94
75
|
end
|
95
76
|
|
96
77
|
it "passes on its options to the sentences it parses" do
|
97
78
|
sentence = @dict.parse( TEST_SENTENCE )
|
98
|
-
sentence.options.max_null_count.
|
99
|
-
sentence.options.verbosity.
|
100
|
-
sentence.options.
|
79
|
+
expect( sentence.options.max_null_count ).to eq( 18 )
|
80
|
+
expect( sentence.options.verbosity ).to eq( 0 )
|
81
|
+
expect( sentence.options.islands_ok? ).to eq( true )
|
101
82
|
end
|
102
83
|
end
|
103
84
|
|
@@ -1,420 +1,351 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# Specification for the LinkParser::Linkage class
|
4
|
-
# $Id: linkage_spec.rb,v 7af8c401b107 2010/12/30 18:00:05 ged $
|
5
|
-
#
|
6
|
-
# See the LICENSE file in the distribution for information about copyright and licensing.
|
7
|
-
#
|
8
|
-
|
9
|
-
BEGIN {
|
10
|
-
require 'pathname'
|
11
|
-
basedir = Pathname.new( __FILE__ ).dirname.parent.parent
|
12
|
-
|
13
|
-
libdir = basedir + 'lib'
|
14
|
-
extdir = basedir + 'ext'
|
15
|
-
|
16
|
-
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
17
|
-
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
18
|
-
$LOAD_PATH.unshift( extdir.to_s ) unless $LOAD_PATH.include?( extdir.to_s )
|
19
|
-
}
|
1
|
+
# -*- ruby -*-
|
2
|
+
#encoding: utf-8
|
20
3
|
|
21
|
-
|
4
|
+
require_relative '../helpers'
|
22
5
|
|
6
|
+
require 'rspec'
|
23
7
|
require 'linkparser'
|
24
8
|
|
25
9
|
|
26
10
|
describe LinkParser::Linkage do
|
27
11
|
|
28
12
|
before( :all ) do
|
29
|
-
@dict = LinkParser::Dictionary.new( 'en', :
|
30
|
-
$DEBUG = true if ENV['DEBUG']
|
13
|
+
@dict = LinkParser::Dictionary.new( 'en', verbosity: 0 )
|
31
14
|
end
|
32
15
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
16
|
+
|
17
|
+
let( :dict ) { @dict }
|
18
|
+
|
19
|
+
let( :text ) { "The flag was wet." }
|
20
|
+
let( :sentence ) { @dict.parse(text) }
|
21
|
+
let( :linkage ) { sentence.linkages.first }
|
37
22
|
|
38
23
|
|
39
|
-
# +-------------Xp-------------+
|
40
|
-
# +-----Wd-----+ |
|
41
|
-
# | +--Ds-+--Ss-+--Pa-+ |
|
42
|
-
# | | | | | |
|
43
|
-
# LEFT-WALL the flag.n was.v wet.a .
|
44
24
|
it "can build a diagram string for a sentence" do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
25
|
+
expect( linkage.diagram.each_line.to_a ).to include(
|
26
|
+
" +--------------Xp--------------+ \n",
|
27
|
+
" +-------->WV------->+ | \n",
|
28
|
+
" +-----Wd-----+ | | \n",
|
29
|
+
" | +Ds**c+--Ss--+--Pa--+ +--RW--+\n",
|
30
|
+
" | | | | | | |\n",
|
31
|
+
"LEFT-WALL the flag.n was.v-d wet.a . RIGHT-WALL \n",
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
50
35
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
36
|
+
it "can build a diagram string for a sentence wrapped to a screen width" do
|
37
|
+
diagram = linkage.diagram( max_width: 10 )
|
38
|
+
|
39
|
+
pending \
|
40
|
+
'link-grammar itself returns "wet.a . \n" as the second-to-last ' \
|
41
|
+
'line.'
|
42
|
+
expect( diagram.each_line.map(&:length) ).to all( be <= 11 )
|
56
43
|
end
|
57
44
|
|
58
45
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
# (m) was.v Pa <---Pa----> Pa wet.a
|
64
|
-
# . RW <---RW----> RW RIGHT-WALL
|
65
|
-
it "can build a 'links and domains' diagram" do
|
66
|
-
@linkage.links_and_domains.should =~ /LEFT-WALL/
|
67
|
-
@linkage.links_and_domains.should =~ /the/
|
68
|
-
@linkage.links_and_domains.should =~ /flag\.n/
|
69
|
-
@linkage.links_and_domains.should =~ /was\.v/
|
70
|
-
@linkage.links_and_domains.should =~ /wet\.a/
|
46
|
+
it "can build a diagram string without wall-words" do
|
47
|
+
expect( linkage.diagram(display_walls: false) ).to_not include( 'RIGHT-WALL' )
|
48
|
+
end
|
49
|
+
|
71
50
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
51
|
+
it "can build a 'links and domains' diagram" do
|
52
|
+
expect( linkage.links_and_domains.each_line ).to include(
|
53
|
+
" LEFT-WALL Xp ----Xp----- Xp .\n",
|
54
|
+
" (s) (v) LEFT-WALL hWV >---WV----> dWV was.v-d\n",
|
55
|
+
" LEFT-WALL Wd ----Wd----- Wd flag.n\n",
|
56
|
+
" (s) flag.n Ss ----Ss----- Ss was.v-d\n",
|
57
|
+
" (s) the D ----Ds**c-- Ds**c flag.n\n",
|
58
|
+
" (s) (v) was.v-d Pa ----Pa----- Pa wet.a\n",
|
59
|
+
" . RW ----RW----- RW RIGHT-WALL\n",
|
60
|
+
"\n"
|
61
|
+
)
|
77
62
|
end
|
78
63
|
|
79
64
|
|
80
65
|
it "knows how many words are in the sentence" do
|
81
66
|
# LEFT-WALL + words + '.' + RIGHT-WALL = 7
|
82
|
-
|
67
|
+
expect( linkage.num_words ).to eq( 7 )
|
83
68
|
end
|
84
69
|
|
85
70
|
|
86
71
|
it "can return a list of the tokenized words" do
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
72
|
+
expect( linkage.words ).to include("LEFT-WALL")
|
73
|
+
expect( linkage.words ).to include("the")
|
74
|
+
expect( linkage.words ).to include("flag.n")
|
75
|
+
expect( linkage.words ).to include("was.v-d")
|
76
|
+
expect( linkage.words ).to include("wet.a")
|
77
|
+
expect( linkage.words ).to include(".")
|
78
|
+
expect( linkage.words ).to include("RIGHT-WALL")
|
94
79
|
end
|
95
80
|
|
96
81
|
|
97
82
|
it "knows how many links are in the sentence" do
|
98
|
-
|
83
|
+
expect( linkage.num_links ).to eq( 7 )
|
99
84
|
end
|
100
85
|
|
101
86
|
|
102
87
|
it "can return the left word for any of its links" do
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# . RW <---RW----> RW RIGHT-WALL
|
119
|
-
@linkage.link_lword( 5 ).should == @linkage.words.index('.')
|
120
|
-
|
88
|
+
# LEFT-WALL Xp <---Xp----> Xp .
|
89
|
+
expect( linkage.link_lword(0) ).to eq( linkage.words.index('LEFT-WALL') )
|
90
|
+
# (m) LEFT-WALL WV <---WV----> WV was.v-d
|
91
|
+
expect( linkage.link_lword(1) ).to eq( linkage.words.index('LEFT-WALL') )
|
92
|
+
# (m) LEFT-WALL Wd <---Wd----> Wd flag.n
|
93
|
+
expect( linkage.link_lword(2) ).to eq( linkage.words.index('LEFT-WALL') )
|
94
|
+
# (m) flag.n Ss <---Ss----> Ss was.v-d
|
95
|
+
expect( linkage.link_lword(3) ).to eq( linkage.words.index('flag.n') )
|
96
|
+
# (m) the D <---Ds----> Ds flag.n
|
97
|
+
expect( linkage.link_lword(4) ).to eq( linkage.words.index('the') )
|
98
|
+
# (m) was.v-d Pa <---Pa----> Pa wet.a
|
99
|
+
expect( linkage.link_lword(5) ).to eq( linkage.words.index('was.v-d') )
|
100
|
+
# . RW <---RW----> RW RIGHT-WALL
|
101
|
+
expect( linkage.link_lword(6) ).to eq( linkage.words.index('.') )
|
121
102
|
end
|
122
103
|
|
123
104
|
it "can return the right word for any of its links" do
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
# . RW <---RW----> RW RIGHT-WALL
|
140
|
-
@linkage.link_rword( 5 ).should == @linkage.words.index('RIGHT-WALL')
|
141
|
-
|
105
|
+
# LEFT-WALL Xp <---Xp----> Xp .
|
106
|
+
expect( linkage.link_rword(0) ).to eq( linkage.words.index('.') )
|
107
|
+
# (m) LEFT-WALL WV <---WV----> WV was.v-d
|
108
|
+
expect( linkage.link_rword(1) ).to eq( linkage.words.index('was.v-d') )
|
109
|
+
# (m) LEFT-WALL Wd <---Wd----> Wd flag.n
|
110
|
+
expect( linkage.link_rword(2) ).to eq( linkage.words.index('flag.n') )
|
111
|
+
# (m) flag.n Ss <---Ss----> Ss was.v-d
|
112
|
+
expect( linkage.link_rword(3) ).to eq( linkage.words.index('was.v-d') )
|
113
|
+
# (m) the D <---Ds----> Ds flag.n
|
114
|
+
expect( linkage.link_rword(4) ).to eq( linkage.words.index('flag.n') )
|
115
|
+
# (m) was.v-d Pa <---Pa----> Pa wet.a
|
116
|
+
expect( linkage.link_rword(5) ).to eq( linkage.words.index('wet.a') )
|
117
|
+
# . RW <---RW----> RW RIGHT-WALL
|
118
|
+
expect( linkage.link_rword(6) ).to eq( linkage.words.index('RIGHT-WALL') )
|
142
119
|
end
|
143
120
|
|
144
121
|
|
145
122
|
it "can return the length of any of its links" do
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
123
|
+
expect( linkage.link_length(0) ).to eq( 5 )
|
124
|
+
expect( linkage.link_length(1) ).to eq( 3 )
|
125
|
+
expect( linkage.link_length(2) ).to eq( 2 )
|
126
|
+
expect( linkage.link_length(3) ).to eq( 1 )
|
127
|
+
expect( linkage.link_length(4) ).to eq( 1 )
|
128
|
+
expect( linkage.link_length(5) ).to eq( 1 )
|
129
|
+
expect( linkage.link_length(6) ).to eq( 1 )
|
152
130
|
|
153
131
|
# Out-of-bounds just returns -1
|
154
|
-
|
132
|
+
expect( linkage.link_length(11) ).to eq( -1 )
|
155
133
|
end
|
156
134
|
|
157
135
|
|
158
136
|
it "can return labels for any of its links" do
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
137
|
+
expect( linkage.link_label(0) ).to eq( "Xp" )
|
138
|
+
expect( linkage.link_label(1) ).to eq( "WV" )
|
139
|
+
expect( linkage.link_label(2) ).to eq( "Wd" )
|
140
|
+
expect( linkage.link_label(3) ).to eq( "Ss" )
|
141
|
+
expect( linkage.link_label(4) ).to eq( "Ds**c" )
|
142
|
+
expect( linkage.link_label(5) ).to eq( "Pa" )
|
143
|
+
expect( linkage.link_label(6) ).to eq( "RW" )
|
165
144
|
|
166
|
-
|
145
|
+
expect( linkage.link_label(7) ).to be_nil
|
167
146
|
end
|
168
147
|
|
169
148
|
|
170
149
|
it "can return left labels for any of its links" do
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
150
|
+
expect( linkage.link_llabel(0) ).to eq( "Xp" )
|
151
|
+
expect( linkage.link_llabel(1) ).to eq( "hWV" )
|
152
|
+
expect( linkage.link_llabel(2) ).to eq( "Wd" )
|
153
|
+
expect( linkage.link_llabel(3) ).to eq( "Ss" )
|
154
|
+
expect( linkage.link_llabel(4) ).to eq( "D" )
|
155
|
+
expect( linkage.link_llabel(5) ).to eq( "Pa" )
|
156
|
+
expect( linkage.link_llabel(6) ).to eq( "RW" )
|
177
157
|
|
178
|
-
|
158
|
+
expect( linkage.link_llabel(7) ).to be_nil
|
179
159
|
end
|
180
160
|
|
181
161
|
|
182
162
|
it "can return labels for any of its links" do
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
163
|
+
expect( linkage.link_rlabel(0) ).to eq( "Xp" )
|
164
|
+
expect( linkage.link_rlabel(1) ).to eq( "dWV" )
|
165
|
+
expect( linkage.link_rlabel(2) ).to eq( "Wd" )
|
166
|
+
expect( linkage.link_rlabel(3) ).to eq( "Ss" )
|
167
|
+
expect( linkage.link_rlabel(4) ).to eq( "Ds**c" )
|
168
|
+
expect( linkage.link_rlabel(5) ).to eq( "Pa" )
|
169
|
+
expect( linkage.link_rlabel(6) ).to eq( "RW" )
|
189
170
|
|
190
|
-
|
171
|
+
expect( linkage.link_rlabel(7) ).to be_nil
|
191
172
|
end
|
192
173
|
|
193
174
|
|
194
175
|
it "can return the number of domains for any link" do
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
176
|
+
expect( linkage.link_num_domains(0) ).to eq( 0 )
|
177
|
+
expect( linkage.link_num_domains(1) ).to eq( 2 )
|
178
|
+
expect( linkage.link_num_domains(2) ).to eq( 0 )
|
179
|
+
expect( linkage.link_num_domains(3) ).to eq( 1 )
|
180
|
+
expect( linkage.link_num_domains(4) ).to eq( 1 )
|
181
|
+
expect( linkage.link_num_domains(5) ).to eq( 2 )
|
182
|
+
expect( linkage.link_num_domains(6) ).to eq( 0 )
|
200
183
|
|
201
|
-
|
184
|
+
expect( linkage.link_num_domains(112) ).to eq( -1 )
|
202
185
|
end
|
203
186
|
|
204
187
|
|
205
188
|
it "can return the names of the domains of any of its links" do
|
206
|
-
|
207
|
-
|
189
|
+
expect( linkage.link_domain_names(0) ).to be_an_instance_of( Array )
|
190
|
+
expect( linkage.link_domain_names(0) ).to be_empty
|
208
191
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
192
|
+
expect( linkage.link_domain_names(1) ).to be_an_instance_of( Array )
|
193
|
+
expect( linkage.link_domain_names(1) ).to eq( ['s', 'v'] )
|
194
|
+
|
195
|
+
expect( linkage.link_domain_names(2) ).to be_an_instance_of( Array )
|
196
|
+
expect( linkage.link_domain_names(2) ).to be_empty
|
197
|
+
|
198
|
+
expect( linkage.link_domain_names(3) ).to be_an_instance_of( Array )
|
199
|
+
expect( linkage.link_domain_names(3) ).to eq( ["s"] )
|
200
|
+
|
201
|
+
expect( linkage.link_domain_names(4) ).to be_an_instance_of( Array )
|
202
|
+
expect( linkage.link_domain_names(4) ).to eq( ['s'] )
|
203
|
+
|
204
|
+
expect( linkage.link_domain_names(5) ).to be_an_instance_of( Array )
|
205
|
+
expect( linkage.link_domain_names(5) ).to eq( ['s', 'v'] )
|
213
206
|
|
214
|
-
|
215
|
-
|
207
|
+
expect( linkage.link_domain_names(6) ).to be_an_instance_of( Array )
|
208
|
+
expect( linkage.link_domain_names(6) ).to be_empty
|
216
209
|
|
217
|
-
|
218
|
-
|
210
|
+
expect( linkage.link_domain_names(12) ).to be_an_instance_of( Array )
|
211
|
+
expect( linkage.link_domain_names(12) ).to be_empty
|
219
212
|
end
|
220
213
|
|
221
214
|
|
222
215
|
it "can return the disjunct strings for any of its words" do
|
223
|
-
|
216
|
+
expect( linkage.disjunct_strings.length ).to eq( linkage.num_words )
|
224
217
|
end
|
225
218
|
|
226
219
|
|
227
220
|
it "can return parsed disjuncts for any of its words" do
|
228
|
-
|
221
|
+
expect( linkage.disjuncts.length ).to eq( linkage.num_words )
|
229
222
|
end
|
230
223
|
|
231
224
|
|
232
225
|
it "can report on the various cost metrics of the parse" do
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
@linkage.link_cost.should be_an_instance_of( Fixnum )
|
226
|
+
expect( linkage.unused_word_cost ).to be_an_instance_of( Fixnum )
|
227
|
+
expect( linkage.disjunct_cost ).to be_an_instance_of( Fixnum )
|
228
|
+
expect( linkage.link_cost ).to be_an_instance_of( Fixnum )
|
237
229
|
end
|
238
230
|
|
239
231
|
|
240
|
-
### :FIXME: I don't know what these do/mean yet, so for now just test to
|
232
|
+
### :FIXME: I don't know what these do/mean yet, so for now just test to
|
241
233
|
### make sure they're implemented. They should really be tested with
|
242
234
|
### sentences that have predictable results.
|
243
235
|
it "implements Link Grammar predicate methods" do
|
244
|
-
|
245
|
-
@linkage.should respond_to( :improper? )
|
246
|
-
@linkage.should respond_to( :has_inconsistent_domains? )
|
247
|
-
@linkage.should respond_to( :violation_name )
|
236
|
+
expect( linkage ).to respond_to( :violation_name )
|
248
237
|
end
|
249
238
|
|
250
239
|
|
251
240
|
# LEFT-WALL Xp <---Xp----> Xp .
|
241
|
+
# (m) LEFT-WALL WV <---WV----> WV was.v-d
|
252
242
|
# (m) LEFT-WALL Wd <---Wd----> Wd flag.n
|
243
|
+
# (m) flag.n Ss <---Ss----> Ss was.v-d
|
253
244
|
# (m) the D <---Ds----> Ds flag.n
|
254
|
-
# (m)
|
255
|
-
# (m) was.v Pa <---Pa----> Pa wet.a
|
245
|
+
# (m) was.v-d Pa <---Pa----> Pa wet.a
|
256
246
|
# . RW <---RW----> RW RIGHT-WALL
|
257
247
|
it "contains link structs describing the linkage" do
|
258
|
-
|
259
|
-
|
248
|
+
expect( linkage.links ).to be_an_instance_of( Array )
|
249
|
+
expect( linkage.links.length ).to eq( 7 )
|
260
250
|
|
261
|
-
|
262
|
-
link.
|
251
|
+
linkage.links.each do |link|
|
252
|
+
expect( link ).to be_a_kind_of( Struct )
|
263
253
|
end
|
264
254
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
255
|
+
expect( linkage.links.first.lword ).to eq( 'LEFT-WALL' )
|
256
|
+
expect( linkage.links.first.label ).to eq( 'Xp' )
|
257
|
+
expect( linkage.links.last.rword ).to eq( 'RIGHT-WALL' )
|
258
|
+
expect( linkage.links.last.label ).to eq( 'RW' )
|
259
|
+
expect( linkage.links[3].lword ).to eq( 'flag.n' )
|
260
|
+
expect( linkage.links[3].rword ).to eq( 'was.v-d' )
|
261
|
+
expect( linkage.links[3].label ).to eq( 'Ss' )
|
272
262
|
end
|
273
263
|
|
274
264
|
|
275
265
|
it "knows what word is the verb in the sentence" do
|
276
|
-
|
266
|
+
expect( linkage.verb ).to eq( "was" )
|
277
267
|
end
|
278
268
|
|
279
269
|
|
280
|
-
it "
|
281
|
-
|
270
|
+
it "can return the verb without stripping the subscript" do
|
271
|
+
expect( linkage.verb(keep_subscript: true) ).to eq( "was.v-d" )
|
282
272
|
end
|
283
273
|
|
284
274
|
|
285
|
-
it "knows
|
286
|
-
|
275
|
+
it "knows what word is the subject of the sentence" do
|
276
|
+
expect( linkage.subject ).to eq( "flag" )
|
287
277
|
end
|
288
278
|
|
289
279
|
|
290
|
-
it "
|
291
|
-
|
292
|
-
@linkage.nouns.should include( "flag" )
|
280
|
+
it "can return the subject without stripping the subscript" do
|
281
|
+
expect( linkage.subject(keep_subscript: true) ).to eq( "flag.n" )
|
293
282
|
end
|
294
283
|
|
295
284
|
|
296
|
-
|
297
|
-
MODE2_C_TREE_STRING = "[S [NP The flag NP] [VP was [ADJP wet ADJP] VP] . S] \n"
|
298
|
-
MODE3_C_TREE_STRING = "(S (NP The flag) (VP was (ADJP wet)) .)\n"
|
285
|
+
context "for sentences with a direct object" do
|
299
286
|
|
300
|
-
|
301
|
-
@linkage.constituent_tree_string.should == MODE1_C_TREE_STRING
|
302
|
-
end
|
287
|
+
let( :text ) { "The dog fetches the ball." }
|
303
288
|
|
304
289
|
|
305
|
-
|
306
|
-
|
307
|
-
|
290
|
+
it "knows what word is the object of the sentence" do
|
291
|
+
expect( linkage.object ).to eq( "ball" )
|
292
|
+
end
|
308
293
|
|
309
|
-
it "returns bracketed constituents if constituent tree string is fetched in mode 2" do
|
310
|
-
@linkage.constituent_tree_string( 2 ).should == MODE2_C_TREE_STRING
|
311
|
-
end
|
312
294
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
end
|
317
|
-
|
318
|
-
it "raises an exception for any numeric constituent tree string mode greater than 3" do
|
319
|
-
expect {
|
320
|
-
@linkage.constituent_tree_string( 4 )
|
321
|
-
}.to raise_error( ArgumentError, /illegal mode 4/i )
|
322
|
-
end
|
295
|
+
it "can return the object without stripping the subscript" do
|
296
|
+
expect( linkage.object(keep_subscript: true) ).to eq( "ball.n-u" )
|
297
|
+
end
|
323
298
|
|
324
|
-
it "raises an exception for any numeric constituent tree string mode less than 1" do
|
325
|
-
expect {
|
326
|
-
@linkage.constituent_tree_string( 0 )
|
327
|
-
}.to raise_error( ArgumentError, /illegal mode 0/i )
|
328
299
|
end
|
329
300
|
|
330
301
|
|
331
|
-
it "
|
332
|
-
expect
|
333
|
-
@linkage.constituent_tree_string( 'glarg' )
|
334
|
-
}.to raise_error( TypeError )
|
302
|
+
it "knows when the sentence doesn't have a direct object" do
|
303
|
+
expect( linkage.object ).to be_nil()
|
335
304
|
end
|
336
305
|
|
337
|
-
it "returns an Array of CTree structs for its constituent tree" do
|
338
|
-
rval = @linkage.constituent_tree
|
339
306
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
rval.first.label.should == 'S'
|
344
|
-
rval.first.children.should have(3).members
|
345
|
-
rval.first.children.collect {|n| n.label }.should include( 'NP', 'VP', '.' )
|
307
|
+
it "knows which of its words are nouns" do
|
308
|
+
expect( linkage.nouns.size ).to eq( 1 )
|
309
|
+
expect( linkage.nouns ).to include( "flag" )
|
346
310
|
end
|
347
311
|
|
312
|
+
|
348
313
|
it "returns an informational string when inspected" do
|
349
|
-
|
314
|
+
expect( linkage.inspect ).to match( /Linkage:0x[[:xdigit:]]+: \[\d+ links\]/ )
|
350
315
|
end
|
351
316
|
|
352
317
|
|
353
318
|
context "from a simple sentence with a direct object" do
|
354
|
-
before( :each ) do
|
355
|
-
@sentence = @dict.parse( "The dog ran home." )
|
356
|
-
@linkage = @sentence.linkages.first
|
357
|
-
end
|
358
319
|
|
320
|
+
let( :text ) { "The dog fetches the ball." }
|
359
321
|
|
360
|
-
it "knows what word is the object in the sentence" do
|
361
|
-
# This depends on the linkage:
|
362
|
-
# +---------------Xp---------------+
|
363
|
-
# +-----Wd----+ |
|
364
|
-
# | +-Ds-+--Ss--+---Ou---+ |
|
365
|
-
# | | | | | |
|
366
|
-
# LEFT-WALL the dog.n ran.v-d home.n-u .
|
367
|
-
@sentence.object.should == 'home'
|
368
322
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
@sentence = @dict.parse( "The ball rolled down the hill and bumped the curb." )
|
378
|
-
@linkage = @sentence.linkages.first
|
379
|
-
end
|
380
|
-
|
381
|
-
it "warns about deprecation if #num_sublinkages is called" do
|
382
|
-
@linkage.should_receive( :warn ).with( /deprecated/i )
|
383
|
-
@linkage.num_sublinkages
|
384
|
-
end
|
385
|
-
|
386
|
-
it "warns about deprecation if #compute_union is called" do
|
387
|
-
@linkage.should_receive( :warn ).with( /deprecated/i )
|
388
|
-
@linkage.compute_union
|
389
|
-
end
|
390
|
-
|
391
|
-
it "warn about deprecation if #current_sublinkage= is called" do
|
392
|
-
@linkage.should_receive( :warn ).with( /deprecated/i )
|
393
|
-
@linkage.current_sublinkage = 1
|
394
|
-
end
|
323
|
+
it "knows what word is the object in the sentence" do
|
324
|
+
# +------------------Xp------------------+
|
325
|
+
# +-------->WV------->+ |
|
326
|
+
# +-----Wd----+ +------Ou-----+ |
|
327
|
+
# | +Ds**+---Ss--+ +--Dmu-+ +--RW--+
|
328
|
+
# | | | | | | | |
|
329
|
+
# LEFT-WALL the dog.n fetches.v the ball.n-u . RIGHT-WALL
|
330
|
+
expect( sentence.object ).to eq( 'ball' )
|
395
331
|
|
396
|
-
it "warn about deprecation if #current_sublinkage is called" do
|
397
|
-
@linkage.should_receive( :warn ).with( /deprecated/i )
|
398
|
-
@linkage.current_sublinkage
|
399
332
|
end
|
400
333
|
|
401
334
|
end
|
402
335
|
|
403
336
|
|
404
337
|
it "should know that it's not an imperative sentence" do
|
405
|
-
|
338
|
+
expect( linkage.imperative? ).to be_falsey()
|
406
339
|
end
|
407
340
|
|
408
341
|
|
409
342
|
context "from an imperative sentence" do
|
410
|
-
|
411
|
-
|
412
|
-
@linkage = @sentence.linkages.first
|
413
|
-
end
|
343
|
+
|
344
|
+
let( :text ) { "Go to the store!" }
|
414
345
|
|
415
346
|
|
416
347
|
it "knows that it's an imperative sentence" do
|
417
|
-
|
348
|
+
expect( linkage.imperative? ).to be_truthy()
|
418
349
|
end
|
419
350
|
|
420
351
|
|
@@ -424,9 +355,9 @@ describe LinkParser::Linkage do
|
|
424
355
|
context "bugfixes" do
|
425
356
|
|
426
357
|
it "also strips off the '.p' from the subject and object when they are plural" do
|
427
|
-
sent =
|
428
|
-
sent.subject.
|
429
|
-
sent.object.
|
358
|
+
sent = dict.parse( 'People like goats.' )
|
359
|
+
expect( sent.subject ).to_not match( /people\.p/i )
|
360
|
+
expect( sent.object ).to_not match( /goats\.p/i )
|
430
361
|
end
|
431
362
|
|
432
363
|
end
|