odin 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.rvmrc +1 -0
- data/.travis.yml +2 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +26 -0
- data/HISTORY.md +102 -0
- data/LICENSE.md +10 -0
- data/README.md +46 -0
- data/Rakefile +69 -0
- data/app/controllers/grammar_checker.rb +51 -0
- data/check_grammar.rb +24 -0
- data/configure +9 -0
- data/images/atn_diagram.graffle +0 -0
- data/images/atn_diagram.pdf +0 -0
- data/images/odin-ff6.gif +0 -0
- data/lang/en/adjectives.rb +388 -0
- data/lang/en/atn.rb +102 -0
- data/lang/en/closed_class_words.rb +206 -0
- data/lang/en/data.rb +1086 -0
- data/lang/en/noun_inflections.rb +76 -0
- data/lang/en/noun_inflector_test_cases.rb +235 -0
- data/lang/en/pronoun_inflector_test_cases.rb +14 -0
- data/lang/en/verbs.rb +648 -0
- data/lang/iso639.rb +405 -0
- data/lib/array.rb +15 -0
- data/lib/atn.rb +82 -0
- data/lib/augmented_transition_network.rb +146 -0
- data/lib/dumper.rb +44 -0
- data/lib/noun_inflector.rb +283 -0
- data/lib/odin.rb +3 -0
- data/lib/odin/version.rb +3 -0
- data/lib/parts_of_speech.rb +402 -0
- data/lib/star.rb +23 -0
- data/lib/string.rb +99 -0
- data/lib/string_bracketing.rb +100 -0
- data/lib/word.rb +69 -0
- data/lib/word_net.rb +265 -0
- data/odin.gemspec +27 -0
- data/simple_atn/README.md +45 -0
- data/simple_atn/Rakefile +9 -0
- data/simple_atn/array.rb +15 -0
- data/simple_atn/augmented_transition_network.rb +146 -0
- data/simple_atn/augmented_transition_network_test.rb +113 -0
- data/simple_atn/english.rb +161 -0
- data/simple_atn/string.rb +63 -0
- data/test/fixtures/alice.txt +3594 -0
- data/test/fixtures/art.txt +7 -0
- data/test/fixtures/both.txt +1 -0
- data/test/fixtures/existing.txt +0 -0
- data/test/fixtures/existing.txt.checked.html +0 -0
- data/test/fixtures/grammar_checker.css +4 -0
- data/test/fixtures/grammatical.txt +1 -0
- data/test/fixtures/ungrammatical.txt +1 -0
- data/test/functional/grammar_checker_test.rb +64 -0
- data/test/integration/en/word_and_noun_inflector_test.rb +29 -0
- data/test/test_helper.rb +82 -0
- data/test/unit/atn_test.rb +240 -0
- data/test/unit/noun_inflector_test.rb +249 -0
- data/test/unit/pronoun_inflector_test.rb +17 -0
- data/test/unit/star_test.rb +24 -0
- data/test/unit/string_bracketing_test_module.rb +70 -0
- data/test/unit/string_test.rb +92 -0
- data/test/unit/word_test.rb +15 -0
- metadata +223 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
All of the great ancient civilizations, such as Ancient Egypt, India, China, Greece, Rome or Arabia had works and styles of art. In the Middle Ages, most of the art in Europe showed Biblical stories in paintings, stained glass windows, and mosaic tile floors and walls.
|
2
|
+
|
3
|
+
Islamic art includes geometric patterns, Islamic calligraphy, and architecture. In India and Tibet, painted sculptures, dance, and religious painting were done. In China, arts included jade carving, bronzework, pottery, poetry, calligraphy, music, painting, drama, and fiction. There are many Chinese artistic styles, which are usually named after the ruling dynasty.
|
4
|
+
|
5
|
+
In Europe, after the Middle Ages, (which some people call the Mediaeval Period or the "Dark Ages") there was a "Renaissance" which means "rebirth". People rediscovered science and artists were allowed to paint subjects other than religious subjects. People like Michelangelo and Leonardo da Vinci still painted religious pictures, but they also now could paint mythological pictures too. These artists also invented linear perspective where things in the distance look smaller than things close up in the picture. This was new because in the Middle Ages people would paint all the figures close up and just overlapping each other.
|
6
|
+
|
7
|
+
In the late 1800s, artists in Europe, responding to Modernity created many new painting styles such as Classicism, Romanticism, Realism, and Impressionism. The history of twentieth century art includes Expressionism, Fauvism, Cubism, Dadaism, and Surrealism, and Minimalism.
|
@@ -0,0 +1 @@
|
|
1
|
+
I love. She loves you. She loves apples. I love the girl. I love ripe apples. I love the pretty girl. I love the pretty, sweet girl. Man loves. Man loves apples. Man loves the apples. Man loves sweet apples. Man loves the sweet apples. Man loves the sweet, pretty apples. The man loves. The man loves apples. The man loves the apples. The man loves sweet apples. The man loves the sweet apples. The man loves the sweet, pretty apples. The woman in house loves you. The woman in pretty house loves you. The woman in the house loves you. The woman in the pretty house loves you. Old men love. Old men love apples. Old men love the apples. Old men love sweet apples. Old men love the sweet apples. Old men love the sweet, pretty apples. The old man loves. The old man loves apples. The old man loves the apples. The old man loves sweet apples. The old man loves the sweet apples. The old man loves the sweet, pretty apples. The old, old man loves. The old, old man loves apples. The old, old man loves the apples. The old, old man loves sweet apples. The old, old man loves the sweet apples. The old, old man loves the sweet, pretty apples. She loves you. Men love you. The man loves you. Sweet men love you. The sweet man loves you. The sweet, handsome man loves you. I. The. The apple. The sweet apple. In. In the. In the house. Man in. Man in the. Man in the house. Man in the walk. Loves. Loves you. Loves apples. Loves the. Loves the apples. Loves sweet apples. Loves the sweet. Loves the sweet apples. The the man loves you. The the man loves apples. The the man loves the apples. The the man loves sweet apples. The the man loves the sweet apples. Man the loves apples. The man the loves apples. The man the apples. Handsome loves.
|
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
I love. She loves you. She loves apples. I love the girl. I love ripe apples. I love the pretty girl. I love the pretty, sweet girl. Man loves. Man loves apples. Man loves the apples. Man loves sweet apples. Man loves the sweet apples. Man loves the sweet, pretty apples. The man loves. The man loves apples. The man loves the apples. The man loves sweet apples. The man loves the sweet apples. The man loves the sweet, pretty apples. The woman in house loves you. The woman in pretty house loves you. The woman in the house loves you. The woman in the pretty house loves you. Old men love. Old men love apples. Old men love the apples. Old men love sweet apples. Old men love the sweet apples. Old men love the sweet, pretty apples. The old man loves. The old man loves apples. The old man loves the apples. The old man loves sweet apples. The old man loves the sweet apples. The old man loves the sweet, pretty apples. The old, old man loves. The old, old man loves apples. The old, old man loves the apples. The old, old man loves sweet apples. The old, old man loves the sweet apples. The old, old man loves the sweet, pretty apples. She loves you. Men love you. The man loves you. Sweet men love you. The sweet man loves you. The sweet, handsome man loves you.
|
@@ -0,0 +1 @@
|
|
1
|
+
I. The. The apple. The sweet apple. In. In the. In the house. Man in. Man in the. Man in the house. Man in the walk. Loves. Loves you. Loves apples. Loves the. Loves the apples. Loves sweet apples. Loves the sweet. Loves the sweet apples. The the man loves you. The the man loves apples. The the man loves the apples. The the man loves sweet apples. The the man loves the sweet apples. Man the loves apples. The man the loves apples. The man the apples. Handsome loves.
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.dirname(__FILE__)/'..'/'test_helper'
|
2
|
+
require File.dirname(__FILE__)/'..'/'..'/'app'/'controllers'/'grammar_checker.rb'
|
3
|
+
require "find"
|
4
|
+
|
5
|
+
class GrammarCheckerTest < Test::Unit::TestCase
|
6
|
+
def teardown
|
7
|
+
Find.find(@@FixturesDirectory) do |file_name|
|
8
|
+
if file_name.match(/.*\.#{GrammarChecker.suffix}$/) and not file_name.match(/existing/)
|
9
|
+
File.delete(file_name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_fail_when_given_no_file
|
15
|
+
assert_raise(ArgumentError) do
|
16
|
+
GrammarChecker.check(nil)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_fail_when_given_nonexistent_file
|
21
|
+
assert_raise(Errno::ENOENT) do
|
22
|
+
GrammarChecker.check("nonexistent_file.txt")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_fail_when_given_existing_out_file
|
27
|
+
assert_raise(Errno::EEXIST) do
|
28
|
+
GrammarChecker.check(@@FixturesDirectory/"existing.txt")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_fail_when_given_directory
|
33
|
+
assert_raise(Errno::EISDIR) do
|
34
|
+
GrammarChecker.check(@@FixturesDirectory)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Regression test: the output of GrammarChecker used to differ from the output of the unit tests
|
39
|
+
# when used from the command line because word.rb wasn't imported before string.rb
|
40
|
+
def test_no_ungrammatical_when_checking_grammatical
|
41
|
+
file_name = @@FixturesDirectory/"grammatical.txt"
|
42
|
+
GrammarChecker.check(file_name)
|
43
|
+
|
44
|
+
File.open("#{file_name}.#{GrammarChecker.suffix}") do |file|
|
45
|
+
while line = file.gets
|
46
|
+
assert(!contains_ungrammatical?(line))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_ungrammatical_when_checking_ungrammatical
|
52
|
+
# TODO
|
53
|
+
# Would have to check each sentence
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def contains_ungrammatical?(string)
|
58
|
+
if string.match(/<[a-z="]*?ungrammatical[a-z="]*?>/)
|
59
|
+
return true
|
60
|
+
else
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__)/'..'/'..'/'test_helper'
|
2
|
+
|
3
|
+
class WordAndNounInflectorTest < Test::Unit::TestCase
|
4
|
+
include NounInflectorTestCases
|
5
|
+
|
6
|
+
PluralToSingular.each do |plural, singular|
|
7
|
+
define_method "test_#{plural}_plural" do
|
8
|
+
assert(Word.new(plural).plural?)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
SingularToPlural.each do |singular, plural|
|
13
|
+
define_method "test_#{singular}_singular" do
|
14
|
+
assert(Word.new(singular).singular?)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# PluralToSingular.each do |plural, singular|
|
19
|
+
# define_method "test_#{singular}_not_plural" do
|
20
|
+
# assert(!Word.new(singular).plural?)
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# PluralToSingular.each do |plural, singular|
|
25
|
+
# define_method "test_#{plural}_not_singular" do
|
26
|
+
# assert(!Word.new(plural).singular?)
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
class Test::Unit::TestCase
|
2
|
+
# Add helper methods to be used by all tests here...
|
3
|
+
@@FixturesDirectory = File.dirname(__FILE__) + '/fixtures'
|
4
|
+
end
|
5
|
+
|
6
|
+
module Test::Unit::Assertions
|
7
|
+
# Add assertions to be used by all tests here...
|
8
|
+
|
9
|
+
# The built in assert_raise doesn't work for subclasses, etc. That is, if I have
|
10
|
+
# UngrammaticalException and FragmentException < UngrammaticalException assert_raise
|
11
|
+
# UngrammaticalException will fail if the method throws FragmentException. It will only pass for
|
12
|
+
# UngrammaticalException.
|
13
|
+
#
|
14
|
+
# This code is basically the same as the original assert_raise (which, in my opinion, should make
|
15
|
+
# the above work). _expected_exception? just needed to be modified. I'm tempted to just change that
|
16
|
+
# method itself, but I don't want clients of these modifications to have unexpected behavior.
|
17
|
+
#
|
18
|
+
#
|
19
|
+
# Original:
|
20
|
+
#
|
21
|
+
# File test/unit/assertions.rb, line 111
|
22
|
+
# def assert_raise(*args)
|
23
|
+
# _wrap_assertion do
|
24
|
+
# if Module === args.last
|
25
|
+
# message = ""
|
26
|
+
# else
|
27
|
+
# message = args.pop
|
28
|
+
# end
|
29
|
+
# exceptions, modules = _check_exception_class(args)
|
30
|
+
# expected = args.size == 1 ? args.first : args
|
31
|
+
# actual_exception = nil
|
32
|
+
# full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
|
33
|
+
# assert_block(full_message) do
|
34
|
+
# begin
|
35
|
+
# yield
|
36
|
+
# rescue Exception => actual_exception
|
37
|
+
# break
|
38
|
+
# end
|
39
|
+
# false
|
40
|
+
# end
|
41
|
+
# full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
|
42
|
+
# assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
|
43
|
+
# actual_exception
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
def assert_raise_kind_of(*args)
|
47
|
+
_wrap_assertion do
|
48
|
+
if Module === args.last
|
49
|
+
message = ""
|
50
|
+
else
|
51
|
+
message = args.pop
|
52
|
+
end
|
53
|
+
exceptions, modules = _check_exception_class(args)
|
54
|
+
expected = args.size == 1 ? args.first : args
|
55
|
+
actual_exception = nil
|
56
|
+
full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
|
57
|
+
assert_block(full_message) do
|
58
|
+
begin
|
59
|
+
yield
|
60
|
+
rescue Exception => actual_exception
|
61
|
+
break
|
62
|
+
end
|
63
|
+
false
|
64
|
+
end
|
65
|
+
full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
|
66
|
+
assert_block(full_message) {_expected_kind_of_exception?(actual_exception, exceptions, modules)}
|
67
|
+
actual_exception
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Original:
|
72
|
+
#
|
73
|
+
# # File test/unit/assertions.rb, line 97
|
74
|
+
# def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
|
75
|
+
# exceptions.include?(actual_exception.class) or
|
76
|
+
# modules.any? {|mod| actual_exception.is_a?(mod)}
|
77
|
+
# end
|
78
|
+
def _expected_kind_of_exception?(actual_exception, exceptions, modules) # :nodoc:
|
79
|
+
exceptions.any? {|exception| actual_exception.kind_of?(exception)} or
|
80
|
+
modules.any? {|mod| actual_exception.is_a?(mod)}
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require File.dirname(__FILE__)/'..'/'test_helper'
|
2
|
+
|
3
|
+
class ATNTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@atn = ATN.new
|
6
|
+
@grammatical_sentences = []
|
7
|
+
|
8
|
+
# TODO move this to an English specific test file?
|
9
|
+
# Sentences named according to structure
|
10
|
+
#
|
11
|
+
# Key:
|
12
|
+
#
|
13
|
+
# a: adjective
|
14
|
+
# d: determiner
|
15
|
+
# n: noun
|
16
|
+
# P: preposition
|
17
|
+
# p: pronoun
|
18
|
+
# v: verb
|
19
|
+
#
|
20
|
+
@grammatical_sentences << @pv = "I love."
|
21
|
+
@grammatical_sentences << @pvp = "She loves you."
|
22
|
+
@grammatical_sentences << @pvn = "She loves apples."
|
23
|
+
@grammatical_sentences << @pvdn = "I love the girl."
|
24
|
+
@grammatical_sentences << @pvan = "I love ripe apples."
|
25
|
+
@grammatical_sentences << @pvdan = "I love the pretty girl."
|
26
|
+
@grammatical_sentences << @pvdaan = "I love the pretty, sweet girl."
|
27
|
+
|
28
|
+
@grammatical_sentences << @nv = "Man loves."
|
29
|
+
@grammatical_sentences << @nvn = "Man loves apples."
|
30
|
+
@grammatical_sentences << @nvdn = "Man loves the apples."
|
31
|
+
@grammatical_sentences << @nvan = "Man loves sweet apples."
|
32
|
+
@grammatical_sentences << @nvdan = "Man loves the sweet apples."
|
33
|
+
@grammatical_sentences << @nvdaan = "Man loves the sweet, pretty apples."
|
34
|
+
|
35
|
+
@grammatical_sentences << @dnv = "The man loves."
|
36
|
+
@grammatical_sentences << @dnvn = "The man loves apples."
|
37
|
+
@grammatical_sentences << @dnvdn = "The man loves the apples."
|
38
|
+
@grammatical_sentences << @dnvan = "The man loves sweet apples."
|
39
|
+
@grammatical_sentences << @dnvdan = "The man loves the sweet apples."
|
40
|
+
@grammatical_sentences << @dnvdaan = "The man loves the sweet, pretty apples."
|
41
|
+
|
42
|
+
@grammatical_sentences << @dnPnvp = "The woman in house loves you."
|
43
|
+
@grammatical_sentences << @dnPanvp = "The woman in pretty house loves you."
|
44
|
+
@grammatical_sentences << @dnPdnvp = "The woman in the house loves you."
|
45
|
+
@grammatical_sentences << @dnPdanvp = "The woman in the pretty house loves you."
|
46
|
+
|
47
|
+
@grammatical_sentences << @anv = "Old men love."
|
48
|
+
@grammatical_sentences << @anvn = "Old men love apples."
|
49
|
+
@grammatical_sentences << @anvdn = "Old men love the apples."
|
50
|
+
@grammatical_sentences << @anvan = "Old men love sweet apples."
|
51
|
+
@grammatical_sentences << @anvdan = "Old men love the sweet apples."
|
52
|
+
@grammatical_sentences << @anvdaan = "Old men love the sweet, pretty apples."
|
53
|
+
|
54
|
+
@grammatical_sentences << @danv = "The old man loves."
|
55
|
+
@grammatical_sentences << @danvn = "The old man loves apples."
|
56
|
+
@grammatical_sentences << @danvdn = "The old man loves the apples."
|
57
|
+
@grammatical_sentences << @danvan = "The old man loves sweet apples."
|
58
|
+
@grammatical_sentences << @danvdan = "The old man loves the sweet apples."
|
59
|
+
@grammatical_sentences << @danvdaan = "The old man loves the sweet, pretty apples."
|
60
|
+
|
61
|
+
@grammatical_sentences << @daanv = "The old, old man loves."
|
62
|
+
@grammatical_sentences << @daanvn = "The old, old man loves apples."
|
63
|
+
@grammatical_sentences << @daanvdn = "The old, old man loves the apples."
|
64
|
+
@grammatical_sentences << @daanvan = "The old, old man loves sweet apples."
|
65
|
+
@grammatical_sentences << @daanvdan = "The old, old man loves the sweet apples."
|
66
|
+
@grammatical_sentences << @daanvdaan = "The old, old man loves the sweet, pretty apples."
|
67
|
+
|
68
|
+
@grammatical_sentences << @pvp = "She loves you."
|
69
|
+
@grammatical_sentences << @nvp = "Men love you."
|
70
|
+
@grammatical_sentences << @dnvp = "The man loves you."
|
71
|
+
@grammatical_sentences << @anvp = "Sweet men love you."
|
72
|
+
@grammatical_sentences << @danvp = "The sweet man loves you."
|
73
|
+
@grammatical_sentences << @daanvp = "The sweet, handsome man loves you."
|
74
|
+
|
75
|
+
@word = /'[a-z]+'/i
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_grammatical_pv__parse
|
79
|
+
# TODO switch to match?
|
80
|
+
# assert_match(/S\(NP\(N\(#{@word}\)\)VP\(V\(#{@word}\)\)\)/i, @atn.parse(@pv))
|
81
|
+
# /S<NP<N<#{@word}>VP<V<#{@word}>>>/i would be easier
|
82
|
+
assert_equal("S(NP(N('I'))VP(V('love')))", @atn.parse(@pv))
|
83
|
+
assert_equal("S(NP(N('She'))VP(V('loves')NP(N('you'))))", @atn.parse(@pvp))
|
84
|
+
assert_equal("S(NP(N('She'))VP(V('loves')NP(N('apples'))))", @atn.parse(@pvn))
|
85
|
+
assert_equal("S(NP(N('I'))VP(V('love')NP(D('the')N('girl'))))", @atn.parse(@pvdn))
|
86
|
+
assert_equal("S(NP(N('I'))VP(V('love')NP(A('ripe')N('apples'))))", @atn.parse(@pvan))
|
87
|
+
assert_equal("S(NP(N('I'))VP(V('love')NP(D('the')A('pretty')N('girl'))))", @atn.parse(@pvdan))
|
88
|
+
assert_equal("S(NP(N('I'))VP(V('love')NP(D('the')A('pretty')A('sweet')N('girl'))))", @atn.parse(@pvdaan))
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_grammatical_nv__parse
|
92
|
+
assert_equal("S(NP(N('Man'))VP(V('loves')))", @atn.parse(@nv))
|
93
|
+
assert_equal("S(NP(N('Man'))VP(V('loves')NP(N('apples'))))", @atn.parse(@nvn))
|
94
|
+
assert_equal("S(NP(N('Man'))VP(V('loves')NP(D('the')N('apples'))))", @atn.parse(@nvdn))
|
95
|
+
assert_equal("S(NP(N('Man'))VP(V('loves')NP(A('sweet')N('apples'))))", @atn.parse(@nvan))
|
96
|
+
assert_equal("S(NP(N('Man'))VP(V('loves')NP(D('the')A('sweet')N('apples'))))", @atn.parse(@nvdan))
|
97
|
+
assert_equal("S(NP(N('Man'))VP(V('loves')NP(D('the')A('sweet')A('pretty')N('apples'))))", @atn.parse(@nvdaan))
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_grammatical_dnv__parse
|
101
|
+
assert_equal("S(NP(D('The')N('man'))VP(V('loves')))", @atn.parse(@dnv))
|
102
|
+
assert_equal("S(NP(D('The')N('man'))VP(V('loves')NP(N('apples'))))", @atn.parse(@dnvn))
|
103
|
+
assert_equal("S(NP(D('The')N('man'))VP(V('loves')NP(D('the')N('apples'))))", @atn.parse(@dnvdn))
|
104
|
+
assert_equal("S(NP(D('The')N('man'))VP(V('loves')NP(A('sweet')N('apples'))))", @atn.parse(@dnvan))
|
105
|
+
assert_equal("S(NP(D('The')N('man'))VP(V('loves')NP(D('the')A('sweet')N('apples'))))", @atn.parse(@dnvdan))
|
106
|
+
assert_equal("S(NP(D('The')N('man'))VP(V('loves')NP(D('the')A('sweet')A('pretty')N('apples'))))", @atn.parse(@dnvdaan))
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_grammatical_anv__parse
|
110
|
+
assert_equal("S(NP(A('Old')N('men'))VP(V('love')))", @atn.parse(@anv))
|
111
|
+
assert_equal("S(NP(A('Old')N('men'))VP(V('love')NP(N('apples'))))", @atn.parse(@anvn))
|
112
|
+
assert_equal("S(NP(A('Old')N('men'))VP(V('love')NP(D('the')N('apples'))))", @atn.parse(@anvdn))
|
113
|
+
assert_equal("S(NP(A('Old')N('men'))VP(V('love')NP(A('sweet')N('apples'))))", @atn.parse(@anvan))
|
114
|
+
assert_equal("S(NP(A('Old')N('men'))VP(V('love')NP(D('the')A('sweet')N('apples'))))", @atn.parse(@anvdan))
|
115
|
+
assert_equal("S(NP(A('Old')N('men'))VP(V('love')NP(D('the')A('sweet')A('pretty')N('apples'))))", @atn.parse(@anvdaan))
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_grammatical_danv__parse
|
119
|
+
assert_equal("S(NP(D('The')A('old')N('man'))VP(V('loves')))", @atn.parse(@danv))
|
120
|
+
assert_equal("S(NP(D('The')A('old')N('man'))VP(V('loves')NP(N('apples'))))", @atn.parse(@danvn))
|
121
|
+
assert_equal("S(NP(D('The')A('old')N('man'))VP(V('loves')NP(D('the')N('apples'))))", @atn.parse(@danvdn))
|
122
|
+
assert_equal("S(NP(D('The')A('old')N('man'))VP(V('loves')NP(A('sweet')N('apples'))))", @atn.parse(@danvan))
|
123
|
+
assert_equal("S(NP(D('The')A('old')N('man'))VP(V('loves')NP(D('the')A('sweet')N('apples'))))", @atn.parse(@danvdan))
|
124
|
+
assert_equal("S(NP(D('The')A('old')N('man'))VP(V('loves')NP(D('the')A('sweet')A('pretty')N('apples'))))", @atn.parse(@danvdaan))
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_grammatical_daanv__parse
|
128
|
+
assert_equal("S(NP(D('The')A('old')A('old')N('man'))VP(V('loves')))", @atn.parse(@daanv))
|
129
|
+
assert_equal("S(NP(D('The')A('old')A('old')N('man'))VP(V('loves')NP(N('apples'))))", @atn.parse(@daanvn))
|
130
|
+
assert_equal("S(NP(D('The')A('old')A('old')N('man'))VP(V('loves')NP(D('the')N('apples'))))", @atn.parse(@daanvdn))
|
131
|
+
assert_equal("S(NP(D('The')A('old')A('old')N('man'))VP(V('loves')NP(A('sweet')N('apples'))))", @atn.parse(@daanvan))
|
132
|
+
assert_equal("S(NP(D('The')A('old')A('old')N('man'))VP(V('loves')NP(D('the')A('sweet')N('apples'))))", @atn.parse(@daanvdan))
|
133
|
+
assert_equal("S(NP(D('The')A('old')A('old')N('man'))VP(V('loves')NP(D('the')A('sweet')A('pretty')N('apples'))))", @atn.parse(@daanvdaan))
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_grammatical__vp_parse
|
137
|
+
assert_equal("S(NP(N('She'))VP(V('loves')NP(N('you'))))", @atn.parse(@pvp))
|
138
|
+
assert_equal("S(NP(N('Men'))VP(V('love')NP(N('you'))))", @atn.parse(@nvp))
|
139
|
+
assert_equal("S(NP(D('The')N('man'))VP(V('loves')NP(N('you'))))", @atn.parse(@dnvp))
|
140
|
+
assert_equal("S(NP(A('Sweet')N('men'))VP(V('love')NP(N('you'))))", @atn.parse(@anvp))
|
141
|
+
assert_equal("S(NP(D('The')A('sweet')N('man'))VP(V('loves')NP(N('you'))))", @atn.parse(@danvp))
|
142
|
+
assert_equal("S(NP(D('The')A('sweet')A('handsome')N('man'))VP(V('loves')NP(N('you'))))", @atn.parse(@daanvp))
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_grammatical__P__phrase
|
146
|
+
assert_equal("S(NP(D('The')N('woman')PP(P('in')NP(N('house'))))VP(V('loves')NP(N('you'))))", @atn.parse(@dnPnvp))
|
147
|
+
assert_equal("S(NP(D('The')N('woman')PP(P('in')NP(A('pretty')N('house'))))VP(V('loves')NP(N('you'))))", @atn.parse(@dnPanvp))
|
148
|
+
assert_equal("S(NP(D('The')N('woman')PP(P('in')NP(D('the')N('house'))))VP(V('loves')NP(N('you'))))", @atn.parse(@dnPdnvp))
|
149
|
+
assert_equal("S(NP(D('The')N('woman')PP(P('in')NP(D('the')A('pretty')N('house'))))VP(V('loves')NP(N('you'))))", @atn.parse(@dnPdanvp))
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_words_match
|
153
|
+
# There were some issues with this before, when using instance variables
|
154
|
+
# No good reason to remove the test now that it's here.
|
155
|
+
@grammatical_sentences.each do |sentence|
|
156
|
+
assert_equal(sentence.words.collect { |i| "'#{i}'"}, @atn.parse(sentence).matches_for(/'[a-z]+'/i))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_ungrammatical_identified
|
161
|
+
ungrammatical_sentences = []
|
162
|
+
|
163
|
+
ungrammatical_sentences << p = "I."
|
164
|
+
ungrammatical_sentences << d = "The."
|
165
|
+
ungrammatical_sentences << dn = "The apple."
|
166
|
+
ungrammatical_sentences << dan = "The sweet apple."
|
167
|
+
|
168
|
+
# Underscore because initial P would be a constant
|
169
|
+
# TODO
|
170
|
+
ungrammatical_sentences << _P = "In."
|
171
|
+
ungrammatical_sentences << _Pd = "In the."
|
172
|
+
ungrammatical_sentences << _Pdn = "In the house."
|
173
|
+
|
174
|
+
ungrammatical_sentences << nP = "Man in."
|
175
|
+
ungrammatical_sentences << nPd = "Man in the."
|
176
|
+
ungrammatical_sentences << nPdn = "Man in the house."
|
177
|
+
|
178
|
+
ungrammatical_sentences << nPdv = "Man in the walk."
|
179
|
+
|
180
|
+
ungrammatical_sentences << v = "Loves."
|
181
|
+
ungrammatical_sentences << vp = "Loves you."
|
182
|
+
ungrammatical_sentences << vn = "Loves apples."
|
183
|
+
ungrammatical_sentences << vd = "Loves the."
|
184
|
+
ungrammatical_sentences << vdn = "Loves the apples."
|
185
|
+
ungrammatical_sentences << van = "Loves sweet apples."
|
186
|
+
ungrammatical_sentences << vda = "Loves the sweet."
|
187
|
+
ungrammatical_sentences << vdan = "Loves the sweet apples."
|
188
|
+
|
189
|
+
# Nearly grammatical
|
190
|
+
|
191
|
+
ungrammatical_sentences << ddnvp = "The the man loves you."
|
192
|
+
ungrammatical_sentences << ddnvn = "The the man loves apples."
|
193
|
+
ungrammatical_sentences << ddnvdn = "The the man loves the apples."
|
194
|
+
ungrammatical_sentences << ddnvan = "The the man loves sweet apples."
|
195
|
+
ungrammatical_sentences << ddnvdan = "The the man loves the sweet apples."
|
196
|
+
|
197
|
+
ungrammatical_sentences << ndvn = "Man the loves apples."
|
198
|
+
ungrammatical_sentences << dndvn = "The man the loves apples."
|
199
|
+
ungrammatical_sentences << dndn = "The man the apples."
|
200
|
+
|
201
|
+
ungrammatical_sentences << av = "Handsome loves."
|
202
|
+
|
203
|
+
ungrammatical_sentences.each do |sentence|
|
204
|
+
assert_raise_kind_of(UngrammaticalException) do
|
205
|
+
@atn.parse(sentence)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
ungrammatical_sentences.each do |sentence|
|
210
|
+
assert(!sentence.grammatical?)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_grammatical_identified
|
215
|
+
@grammatical_sentences.each do |sentence|
|
216
|
+
assert_nothing_raised(UngrammaticalException) do
|
217
|
+
@atn.parse(sentence)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
@grammatical_sentences.each do |sentence|
|
222
|
+
assert(sentence.grammatical?)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_corpus_grammatical
|
227
|
+
corpus = @grammatical_sentences.join(" ")
|
228
|
+
sentences = corpus.sentences
|
229
|
+
|
230
|
+
sentences.each do |sentence|
|
231
|
+
assert_nothing_raised(UngrammaticalException) do
|
232
|
+
@atn.parse(sentence)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
sentences.each do |sentence|
|
237
|
+
assert(sentence.grammatical?)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
require File.dirname(__FILE__)/'..'/'test_helper'
|
2
|
+
# require File.dirname(__FILE__) + '/abstract_unit'
|
3
|
+
require File.dirname(__FILE__)/'..'/'..'/'lang'/'en'/'noun_inflector_test_cases.rb' # TODO no "en"
|
4
|
+
|
5
|
+
module Ace
|
6
|
+
module Base
|
7
|
+
class Case
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class NounInflectorTest < Test::Unit::TestCase
|
13
|
+
include NounInflectorTestCases
|
14
|
+
|
15
|
+
def test_pluralize_plurals
|
16
|
+
assert_equal "plurals", NounInflector.pluralize("plurals")
|
17
|
+
assert_equal "Plurals", NounInflector.pluralize("Plurals")
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_pluralize_empty_string
|
21
|
+
assert_equal "", NounInflector.pluralize("")
|
22
|
+
end
|
23
|
+
|
24
|
+
SingularToPlural.each do |singular, plural|
|
25
|
+
define_method "test_pluralize_#{singular}" do
|
26
|
+
assert_equal(plural, NounInflector.pluralize(singular))
|
27
|
+
assert_equal(plural.capitalize, NounInflector.pluralize(singular.capitalize))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
SingularToPlural.each do |singular, plural|
|
32
|
+
define_method "test_singularize_#{plural}" do
|
33
|
+
assert_equal(singular, NounInflector.singularize(plural))
|
34
|
+
assert_equal(singular.capitalize, NounInflector.singularize(plural.capitalize))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
MixtureToTitleCase.each do |before, titleized|
|
39
|
+
define_method "test_titleize_#{before}" do
|
40
|
+
assert_equal(titleized, NounInflector.titleize(before))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_camelize
|
45
|
+
CamelToUnderscore.each do |camel, underscore|
|
46
|
+
assert_equal(camel, NounInflector.camelize(underscore))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_underscore
|
51
|
+
CamelToUnderscore.each do |camel, underscore|
|
52
|
+
assert_equal(underscore, NounInflector.underscore(camel))
|
53
|
+
end
|
54
|
+
CamelToUnderscoreWithoutReverse.each do |camel, underscore|
|
55
|
+
assert_equal(underscore, NounInflector.underscore(camel))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_camelize_with_module
|
60
|
+
CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
|
61
|
+
assert_equal(camel, NounInflector.camelize(underscore))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_underscore_with_slashes
|
66
|
+
CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
|
67
|
+
assert_equal(underscore, NounInflector.underscore(camel))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_demodulize
|
72
|
+
assert_equal "Account", NounInflector.demodulize("MyApplication::Billing::Account")
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_foreign_key
|
76
|
+
ClassNameToForeignKeyWithUnderscore.each do |klass, foreign_key|
|
77
|
+
assert_equal(foreign_key, NounInflector.foreign_key(klass))
|
78
|
+
end
|
79
|
+
|
80
|
+
ClassNameToForeignKeyWithoutUnderscore.each do |klass, foreign_key|
|
81
|
+
assert_equal(foreign_key, NounInflector.foreign_key(klass, false))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_tableize
|
86
|
+
ClassNameToTableName.each do |class_name, table_name|
|
87
|
+
assert_equal(table_name, NounInflector.tableize(class_name))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_classify
|
92
|
+
ClassNameToTableName.each do |class_name, table_name|
|
93
|
+
assert_equal(class_name, NounInflector.classify(table_name))
|
94
|
+
assert_equal(class_name, NounInflector.classify("table_prefix." + table_name))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_classify_with_symbol
|
99
|
+
assert_nothing_raised do
|
100
|
+
assert_equal 'FooBar', NounInflector.classify(:foo_bars)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_classify_with_leading_schema_name
|
105
|
+
assert_equal 'FooBar', NounInflector.classify('schema.foo_bar')
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_humanize
|
109
|
+
UnderscoreToHuman.each do |underscore, human|
|
110
|
+
assert_equal(human, NounInflector.humanize(underscore))
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_constantize
|
115
|
+
assert_nothing_raised { assert_equal Ace::Base::Case, NounInflector.constantize("Ace::Base::Case") }
|
116
|
+
assert_nothing_raised { assert_equal Ace::Base::Case, NounInflector.constantize("::Ace::Base::Case") }
|
117
|
+
assert_nothing_raised { assert_equal NounInflectorTest, NounInflector.constantize("NounInflectorTest") }
|
118
|
+
assert_nothing_raised { assert_equal NounInflectorTest, NounInflector.constantize("::NounInflectorTest") }
|
119
|
+
assert_raises(NameError) { NounInflector.constantize("UnknownClass") }
|
120
|
+
assert_raises(NameError) { NounInflector.constantize("An invalid string") }
|
121
|
+
assert_raises(NameError) { NounInflector.constantize("InvalidClass\n") }
|
122
|
+
end
|
123
|
+
|
124
|
+
if RUBY_VERSION < '1.9.0'
|
125
|
+
def test_constantize_does_lexical_lookup
|
126
|
+
assert_raises(NameError) { NounInflector.constantize("Ace::Base::NounInflectorTest") }
|
127
|
+
end
|
128
|
+
else
|
129
|
+
def test_constantize_does_dynamic_lookup
|
130
|
+
assert_equal self.class, NounInflector.constantize("Ace::Base::NounInflectorTest")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_ordinal
|
135
|
+
OrdinalNumbers.each do |number, ordinalized|
|
136
|
+
assert_equal(ordinalized, NounInflector.ordinalize(number))
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_dasherize
|
141
|
+
UnderscoresToDashes.each do |underscored, dasherized|
|
142
|
+
assert_equal(dasherized, NounInflector.dasherize(underscored))
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_underscore_as_reverse_of_dasherize
|
147
|
+
UnderscoresToDashes.each do |underscored, dasherized|
|
148
|
+
assert_equal(underscored, NounInflector.underscore(NounInflector.dasherize(underscored)))
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_underscore_to_lower_camel
|
153
|
+
UnderscoreToLowerCamel.each do |underscored, lower_camel|
|
154
|
+
assert_equal(lower_camel, NounInflector.camelize(underscored, false))
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
%w{plurals singulars uncountables}.each do |inflection_type|
|
159
|
+
class_eval "
|
160
|
+
def test_clear_#{inflection_type}
|
161
|
+
cached_values = NounInflector.inflections.#{inflection_type}
|
162
|
+
NounInflector.inflections.clear :#{inflection_type}
|
163
|
+
assert NounInflector.inflections.#{inflection_type}.empty?, \"#{inflection_type} inflections should be empty after clear :#{inflection_type}\"
|
164
|
+
NounInflector.inflections.instance_variable_set :@#{inflection_type}, cached_values
|
165
|
+
end
|
166
|
+
"
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_clear_all
|
170
|
+
cached_values = NounInflector.inflections.plurals, NounInflector.inflections.singulars, NounInflector.inflections.uncountables
|
171
|
+
NounInflector.inflections.clear :all
|
172
|
+
assert NounInflector.inflections.plurals.empty?
|
173
|
+
assert NounInflector.inflections.singulars.empty?
|
174
|
+
assert NounInflector.inflections.uncountables.empty?
|
175
|
+
NounInflector.inflections.instance_variable_set :@plurals, cached_values[0]
|
176
|
+
NounInflector.inflections.instance_variable_set :@singulars, cached_values[1]
|
177
|
+
NounInflector.inflections.instance_variable_set :@uncountables, cached_values[2]
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_clear_with_default
|
181
|
+
cached_values = NounInflector.inflections.plurals, NounInflector.inflections.singulars, NounInflector.inflections.uncountables
|
182
|
+
NounInflector.inflections.clear
|
183
|
+
assert NounInflector.inflections.plurals.empty?
|
184
|
+
assert NounInflector.inflections.singulars.empty?
|
185
|
+
assert NounInflector.inflections.uncountables.empty?
|
186
|
+
NounInflector.inflections.instance_variable_set :@plurals, cached_values[0]
|
187
|
+
NounInflector.inflections.instance_variable_set :@singulars, cached_values[1]
|
188
|
+
NounInflector.inflections.instance_variable_set :@uncountables, cached_values[2]
|
189
|
+
end
|
190
|
+
|
191
|
+
Irregularities.each do |irregularity|
|
192
|
+
singular, plural = *irregularity
|
193
|
+
NounInflector.inflections do |inflect|
|
194
|
+
define_method("test_irregularity_between_#{singular}_and_#{plural}") do
|
195
|
+
inflect.irregular(singular, plural)
|
196
|
+
assert_equal singular, NounInflector.singularize(plural)
|
197
|
+
assert_equal plural, NounInflector.pluralize(singular)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
[ :all, [] ].each do |scope|
|
203
|
+
NounInflector.inflections do |inflect|
|
204
|
+
define_method("test_clear_inflections_with_#{scope.kind_of?(Array) ? "no_arguments" : scope}") do
|
205
|
+
# save all the inflections
|
206
|
+
singulars, plurals, uncountables = inflect.singulars, inflect.plurals, inflect.uncountables
|
207
|
+
|
208
|
+
# clear all the inflections
|
209
|
+
inflect.clear(*scope)
|
210
|
+
|
211
|
+
assert_equal [], inflect.singulars
|
212
|
+
assert_equal [], inflect.plurals
|
213
|
+
assert_equal [], inflect.uncountables
|
214
|
+
|
215
|
+
# restore all the inflections
|
216
|
+
singulars.reverse.each { |singular| inflect.singular(*singular) }
|
217
|
+
plurals.reverse.each { |plural| inflect.plural(*plural) }
|
218
|
+
inflect.uncountable(uncountables)
|
219
|
+
|
220
|
+
assert_equal singulars, inflect.singulars
|
221
|
+
assert_equal plurals, inflect.plurals
|
222
|
+
assert_equal uncountables, inflect.uncountables
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
{ :singulars => :singular, :plurals => :plural, :uncountables => :uncountable }.each do |scope, method|
|
228
|
+
NounInflector.inflections do |inflect|
|
229
|
+
define_method("test_clear_inflections_with_#{scope}") do
|
230
|
+
# save the inflections
|
231
|
+
values = inflect.send(scope)
|
232
|
+
|
233
|
+
# clear the inflections
|
234
|
+
inflect.clear(scope)
|
235
|
+
|
236
|
+
assert_equal [], inflect.send(scope)
|
237
|
+
|
238
|
+
# restore the inflections
|
239
|
+
if scope == :uncountables
|
240
|
+
inflect.send(method, values)
|
241
|
+
else
|
242
|
+
values.reverse.each { |value| inflect.send(method, *value) }
|
243
|
+
end
|
244
|
+
|
245
|
+
assert_equal values, inflect.send(scope)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|