linkparser 1.1.4 → 2.0.0
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.
- 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
|