odin 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +19 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +2 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +26 -0
  6. data/HISTORY.md +102 -0
  7. data/LICENSE.md +10 -0
  8. data/README.md +46 -0
  9. data/Rakefile +69 -0
  10. data/app/controllers/grammar_checker.rb +51 -0
  11. data/check_grammar.rb +24 -0
  12. data/configure +9 -0
  13. data/images/atn_diagram.graffle +0 -0
  14. data/images/atn_diagram.pdf +0 -0
  15. data/images/odin-ff6.gif +0 -0
  16. data/lang/en/adjectives.rb +388 -0
  17. data/lang/en/atn.rb +102 -0
  18. data/lang/en/closed_class_words.rb +206 -0
  19. data/lang/en/data.rb +1086 -0
  20. data/lang/en/noun_inflections.rb +76 -0
  21. data/lang/en/noun_inflector_test_cases.rb +235 -0
  22. data/lang/en/pronoun_inflector_test_cases.rb +14 -0
  23. data/lang/en/verbs.rb +648 -0
  24. data/lang/iso639.rb +405 -0
  25. data/lib/array.rb +15 -0
  26. data/lib/atn.rb +82 -0
  27. data/lib/augmented_transition_network.rb +146 -0
  28. data/lib/dumper.rb +44 -0
  29. data/lib/noun_inflector.rb +283 -0
  30. data/lib/odin.rb +3 -0
  31. data/lib/odin/version.rb +3 -0
  32. data/lib/parts_of_speech.rb +402 -0
  33. data/lib/star.rb +23 -0
  34. data/lib/string.rb +99 -0
  35. data/lib/string_bracketing.rb +100 -0
  36. data/lib/word.rb +69 -0
  37. data/lib/word_net.rb +265 -0
  38. data/odin.gemspec +27 -0
  39. data/simple_atn/README.md +45 -0
  40. data/simple_atn/Rakefile +9 -0
  41. data/simple_atn/array.rb +15 -0
  42. data/simple_atn/augmented_transition_network.rb +146 -0
  43. data/simple_atn/augmented_transition_network_test.rb +113 -0
  44. data/simple_atn/english.rb +161 -0
  45. data/simple_atn/string.rb +63 -0
  46. data/test/fixtures/alice.txt +3594 -0
  47. data/test/fixtures/art.txt +7 -0
  48. data/test/fixtures/both.txt +1 -0
  49. data/test/fixtures/existing.txt +0 -0
  50. data/test/fixtures/existing.txt.checked.html +0 -0
  51. data/test/fixtures/grammar_checker.css +4 -0
  52. data/test/fixtures/grammatical.txt +1 -0
  53. data/test/fixtures/ungrammatical.txt +1 -0
  54. data/test/functional/grammar_checker_test.rb +64 -0
  55. data/test/integration/en/word_and_noun_inflector_test.rb +29 -0
  56. data/test/test_helper.rb +82 -0
  57. data/test/unit/atn_test.rb +240 -0
  58. data/test/unit/noun_inflector_test.rb +249 -0
  59. data/test/unit/pronoun_inflector_test.rb +17 -0
  60. data/test/unit/star_test.rb +24 -0
  61. data/test/unit/string_bracketing_test_module.rb +70 -0
  62. data/test/unit/string_test.rb +92 -0
  63. data/test/unit/word_test.rb +15 -0
  64. 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
@@ -0,0 +1,4 @@
1
+ .ungrammatical
2
+ {
3
+ border-bottom: 2px dotted green;
4
+ }
@@ -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
@@ -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