biodiversity 0.5.14

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.
@@ -0,0 +1,211 @@
1
+ # encoding: UTF-8
2
+ grammar ScientificNameDirty
3
+ include ScientificNameClean
4
+
5
+ rule root
6
+ super
7
+ end
8
+
9
+ rule scientific_name_5
10
+ a:scientific_name_4 garbage {
11
+ def value
12
+ a.value
13
+ end
14
+
15
+ def canonical
16
+ a.canonical
17
+ end
18
+
19
+ def pos
20
+ a.pos
21
+ end
22
+
23
+ def details
24
+ a.details
25
+ end
26
+ }
27
+ /
28
+ super
29
+ end
30
+
31
+ rule infraspecies
32
+ a:infraspecies_epitheton space b:year {
33
+ def value
34
+ a.value + " " + b.value
35
+ end
36
+
37
+ def canonical
38
+ a.canonical
39
+ end
40
+
41
+ def pos
42
+ a.pos.merge(b.pos)
43
+ end
44
+
45
+ def details
46
+ {:infraspecies => a.details[:infraspecies].merge(b.details)}
47
+ end
48
+ }
49
+ /
50
+ a:infraspecies_epitheton space epitheton_authorship_inconsistencies space b:authorship {
51
+ def value
52
+ a.value + " " + b.value
53
+ end
54
+
55
+ def canonical
56
+ a.canonical
57
+ end
58
+
59
+ def pos
60
+ a.pos.merge(b.pos)
61
+ end
62
+
63
+ def details
64
+ {:infraspecies => a.details[:infraspecies].merge(b.details)}
65
+ end
66
+ }
67
+ /
68
+ super
69
+ end
70
+
71
+ rule species
72
+ a:species_epitheton space b:year {
73
+ def value
74
+ a.value + " " + b.value
75
+ end
76
+
77
+ def canonical
78
+ a.canonical
79
+ end
80
+
81
+ def pos
82
+ a.pos.merge(b.pos)
83
+ end
84
+
85
+ def details
86
+ {:species => a.details[:species].merge(b.details)}
87
+ end
88
+ }
89
+ /
90
+ super
91
+ end
92
+
93
+ rule right_paren
94
+ ")" space ")"
95
+ /
96
+ super
97
+ end
98
+
99
+ rule left_paren
100
+ "(" space "("
101
+ /
102
+ super
103
+ end
104
+
105
+ rule year
106
+ a:year_number space b:approximate_year {
107
+ def value
108
+ a.value + " " + b.value
109
+ end
110
+
111
+ def pos
112
+ a.pos.merge(b.pos)
113
+ end
114
+
115
+ def details
116
+ {:year => a.value, :approximate_year => b.value}
117
+ end
118
+ }
119
+ /
120
+ a:year_number space page_number {
121
+ def value
122
+ a.text_value
123
+ end
124
+
125
+ def pos
126
+ {a.interval.begin => ['year', a.interval.end]}
127
+ end
128
+
129
+ def details
130
+ {:year => value}
131
+ end
132
+ }
133
+ /
134
+ year_number_with_punctuation
135
+ /
136
+ approximate_year
137
+ /
138
+ double_year
139
+ /
140
+ super
141
+ end
142
+
143
+ rule approximate_year
144
+ "[" space a:year_number space "]"+ {
145
+ def value
146
+ "(" + a.text_value + ")"
147
+ end
148
+
149
+ def pos
150
+ {a.interval.begin => ['year', a.interval.end]}
151
+ end
152
+
153
+ def details
154
+ {:approximate_year => value}
155
+ end
156
+ }
157
+ end
158
+
159
+
160
+ rule double_year
161
+ year_number "-" [0-9]+ [A-Za-z]? [\?]? {
162
+ def value
163
+ text_value
164
+ end
165
+
166
+ def pos
167
+ {interval.begin => ['year', interval.end]}
168
+ end
169
+
170
+ def details
171
+ {:year => value}
172
+ end
173
+ }
174
+ end
175
+
176
+ rule year_number_with_punctuation
177
+ a:year_number "." {
178
+ def value
179
+ a.text_value
180
+ end
181
+
182
+ def pos
183
+ {interval.begin => ['year', interval.end]}
184
+ end
185
+
186
+ def details
187
+ {:year => value}
188
+ end
189
+ }
190
+ end
191
+
192
+
193
+ rule page_number
194
+ ":" space [\d]+
195
+ {
196
+ def value
197
+ end
198
+ }
199
+ end
200
+
201
+ rule epitheton_authorship_inconsistencies
202
+ ("corrig.")
203
+ end
204
+
205
+ rule garbage
206
+ space (["',.]) space [^щ]*
207
+ /
208
+ space_hard [^ш]+
209
+ end
210
+
211
+ end
File without changes
@@ -0,0 +1,12 @@
1
+ dir = File.dirname("__FILE__")
2
+ require 'rubygems'
3
+ require 'spec'
4
+ require File.expand_path(dir + "../../conf/environment")
5
+ require File.expand_path(dir + "../../lib/biodiversity/guid")
6
+
7
+ describe LsidResolver do
8
+ it "should return RFD document from lsid" do
9
+ lsid = "urn:lsid:ubio.org:classificationbank:2232671"
10
+ LsidResolver.resolve(lsid).class.should == "".class
11
+ end
12
+ end
@@ -0,0 +1,35 @@
1
+ #NOTE: this spec needs compiled treetop files.
2
+ dir = File.dirname("__FILE__")
3
+ require File.expand_path(dir + '../../spec/parser/spec_helper')
4
+ require File.expand_path(dir + '../../lib/biodiversity/parser')
5
+
6
+ describe ScientificNameClean do
7
+ before(:all) do
8
+ set_parser(ScientificNameParser.new)
9
+ end
10
+
11
+ it 'should generate standardized json' do
12
+ read_test_file do |y|
13
+ JSON.load(json(y[:name])).should == JSON.load(y[:jsn]) unless y[:comment]
14
+ end
15
+ end
16
+
17
+ # it 'should generate new test_file' do
18
+ # new_test = open(File.expand_path(dir + "../../spec/parser/test_data_new.txt"),'w')
19
+ # read_test_file do |y|
20
+ # if y[:comment]
21
+ # new_test.write y[:comment]
22
+ # else
23
+ # name = y[:name]
24
+ # jsn = json(y[:name])# rescue puts(y[:name])
25
+ # new_test.write("#{name}|#{jsn}\n")
26
+ # end
27
+ # end
28
+ # end
29
+
30
+ it 'should generate reasonable output if parser failed' do
31
+ sn = 'ddd sljlkj 3223452432'
32
+ json(sn).should == '{"scientificName":{"parsed":false,"verbatim":"ddd sljlkj 3223452432"}}'
33
+ end
34
+
35
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+ dir = File.dirname("__FILE__")
3
+ require File.expand_path(dir + '../../spec/parser/spec_helper')
4
+
5
+ describe ScientificNameCanonical do
6
+ before(:all) do
7
+ set_parser(ScientificNameCanonicalParser.new)
8
+ end
9
+
10
+
11
+ it 'should parse names with valid name part and unparseable rest' do
12
+ [
13
+ ['Morea ssjjlajajaj324$33 234243242','Morea', [{:uninomial=>{:epitheton=>"Morea"}}], {0=>["uninomial", 5]}],
14
+ ['Morea (Morea) Burt 2342343242 23424322342 23424234', 'Morea (Morea)', [{:genus=>{:epitheton=>"Morea"}, :subgenus=>{:epitheton=>"Morea"}}], {0=>["genus", 5], 7=>["subgenus", 12]}],
15
+ ['Morea (Morea) burtius 2342343242 23424322342 23424234', 'Morea (Morea) burtius', [{:genus=>{:epitheton=>"Morea"}, :subgenus=>{:epitheton=>"Morea"}, :species=>{:epitheton=>"burtius"}}], {0=>["genus", 5], 7=>["subgenus", 12], 14=>["species", 21]}],
16
+ ['Moraea spathulata ( (L. f. Klatt','Moraea spathulata',[{:genus=>{:epitheton=>"Moraea"}, :species=>{:epitheton=>"spathulata"}}], {0=>["genus", 6], 7=>["species", 17]} ],
17
+ ['Verpericola megasoma ""Dall" Pils.','Verpericola megasoma',[{:genus=>{:epitheton=>"Verpericola"}, :species=>{:epitheton=>"megasoma"}}], {0=>["genus", 11], 12=>["species", 20]}]
18
+ ].each do |n|
19
+ parse(n[0]).should_not be_nil
20
+ value(n[0]).should == n[1]
21
+ details(n[0]).should == n[2]
22
+ pos(n[0]).should == n[3]
23
+ parse(n[0]).hybrid.should be_false
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,504 @@
1
+ # encoding: UTF-8
2
+ dir = File.dirname("__FILE__")
3
+ require File.expand_path(dir + '../../spec/parser/spec_helper')
4
+
5
+
6
+ describe ScientificNameClean do
7
+ before(:all) do
8
+ set_parser(ScientificNameCleanParser.new)
9
+ end
10
+
11
+ it 'should parse uninomial' do
12
+ sn = 'Pseudocercospora'
13
+ parse(sn).should_not be_nil
14
+ value(sn).should == 'Pseudocercospora'
15
+ canonical(sn).should == 'Pseudocercospora'
16
+ details(sn).should == [{:uninomial=>{:epitheton=>"Pseudocercospora"}}]
17
+ pos(sn).should == {0=>["uninomial", 16]}
18
+ end
19
+
20
+ it 'should parse uninomial with author and year' do
21
+ sn = 'Pseudocercospora Speg.'
22
+ parse(sn).should_not be_nil
23
+ details(sn).should == [{:uninomial=>{:epitheton=>"Pseudocercospora", :authorship=>"Speg.", :basionymAuthorTeam=>{:authorTeam=>"Speg.", :author=>["Speg."]}}}]
24
+ pos(sn).should == {0=>["uninomial", 16], 17=>["author_word", 22]}
25
+ sn = 'Pseudocercospora Spegazzini, 1910'
26
+ parse(sn).should_not be_nil
27
+ value(sn).should == 'Pseudocercospora Spegazzini 1910'
28
+ details(sn).should == [{:uninomial=>{:epitheton=>"Pseudocercospora", :authorship=>"Spegazzini, 1910", :basionymAuthorTeam=>{:authorTeam=>"Spegazzini", :author=>["Spegazzini"], :year=>"1910"}}}]
29
+ pos(sn).should == {0=>["uninomial", 16], 17=>["author_word", 27], 29=>["year", 33]}
30
+ end
31
+
32
+ it 'should parse names with a valid 2 letter genus' do
33
+ ["Ca Dyar 1914",
34
+ "Ea Distant 1911",
35
+ "Ge Nicéville 1895",
36
+ "Ia Thomas 1902",
37
+ "Io Lea 1831",
38
+ "Io Blanchard 1852",
39
+ "Ix Bergroth 1916",
40
+ "Lo Seale 1906",
41
+ "Oa Girault 1929",
42
+ "Ra Whitley 1931",
43
+ "Ty Bory de St. Vincent 1827",
44
+ "Ua Girault 1929",
45
+ "Aa Baker 1940",
46
+ "Ja Uéno 1955",
47
+ "Zu Walters & Fitch 1960",
48
+ "La Bleszynski 1966",
49
+ "Qu Durkoop",
50
+ "As Slipinski 1982",
51
+ "Ba Solem 1983"].each do |name|
52
+ parse(name).should_not be_nil
53
+ end
54
+ canonical('Quoyula').should == 'Quoyula'
55
+ end
56
+
57
+ it 'should parse canonical' do
58
+ sn = 'Pseudocercospora dendrobii'
59
+ parse(sn).should_not be_nil
60
+ value(sn).should == 'Pseudocercospora dendrobii'
61
+ canonical(sn).should == 'Pseudocercospora dendrobii'
62
+ details(sn).should == [{:genus=>{:epitheton=>"Pseudocercospora"}, :species=>{:epitheton=>"dendrobii"}}]
63
+ pos(sn).should == {0=>["genus", 16], 21=>["species", 30]}
64
+ end
65
+
66
+
67
+ it 'should parse species name with author and year' do
68
+ sn = "Platypus bicaudatulus Schedl 1935"
69
+ parse(sn).should_not be_nil
70
+ value(sn).should == "Platypus bicaudatulus Schedl 1935"
71
+ sn = "Platypus bicaudatulus Schedl, 1935h"
72
+ parse(sn).should_not be_nil
73
+ value(sn).should == "Platypus bicaudatulus Schedl 1935"
74
+ details(sn).should == [{:genus=>{:epitheton=>"Platypus"}, :species=>{:epitheton=>"bicaudatulus", :authorship=>"Schedl, 1935h", :basionymAuthorTeam=>{:authorTeam=>"Schedl", :author=>["Schedl"], :year=>"1935"}}}]
75
+ pos(sn).should == {0=>["genus", 8], 9=>["species", 21], 22=>["author_word", 28], 30=>["year", 35]}
76
+ parse("Platypus bicaudatulus Schedl, 1935B").should_not be_nil
77
+ sn = "Platypus bicaudatulus Schedl (1935h)"
78
+ parse(sn).should_not be_nil
79
+ details(sn).should == [{:genus=>{:epitheton=>"Platypus"}, :species=>{:epitheton=>"bicaudatulus", :authorship=>"Schedl (1935h)", :basionymAuthorTeam=>{:authorTeam=>"Schedl", :author=>["Schedl"], :year=>"1935"}}}]
80
+ parse("Platypus bicaudatulus Schedl 1935").should_not be_nil
81
+ end
82
+
83
+ it 'should parse genus with "?"' do
84
+ sn = "Ferganoconcha? oblonga"
85
+ parse(sn).should_not be_nil
86
+ value(sn).should == "Ferganoconcha oblonga"
87
+ details(sn).should == [{:genus=>{:epitheton=>"Ferganoconcha"}, :species=>{:epitheton=>"oblonga"}}]
88
+ pos(sn).should == {0=>["genus", 14], 15=>["species", 22]}
89
+ end
90
+
91
+ it 'should parse æ in the name' do
92
+ names = [
93
+ ["Læptura laetifica Dow, 1913", "Laeptura laetifica Dow 1913"],
94
+ ["Leptura lætifica Dow, 1913", "Leptura laetifica Dow 1913"],
95
+ ["Leptura leætifica Dow, 1913", "Leptura leaetifica Dow 1913"],
96
+ ["Leæptura laetifica Dow, 1913", "Leaeptura laetifica Dow 1913"],
97
+ ["Leœptura laetifica Dow, 1913", "Leoeptura laetifica Dow 1913"],
98
+ ['Ærenea cognata Lacordaire, 1872', 'Aerenea cognata Lacordaire 1872'],
99
+ ['Œdicnemus capensis', 'Oedicnemus capensis'],
100
+ ['Œnanthe œnanthe','Oenanthe oenanthe']
101
+ ]
102
+ names.each do |name_pair|
103
+ parse(name_pair[0]).should_not be_nil
104
+ value(name_pair[0]).should == name_pair[1]
105
+ end
106
+ end
107
+
108
+ it 'should parse names with "common" utf-8 charactes' do
109
+ names = ["Rühlella","Sténométope laevissimus Bibron 1855"].each do |name|
110
+ parse(name).should_not be_nil
111
+ end
112
+ sn = "Trematosphaeria phaeospora (E. Müll.) L. Holm 1957"
113
+ parse(sn).should_not be_nil
114
+ value(sn).should == "Trematosphaeria phaeospora (E. Müll.) L. Holm 1957"
115
+ canonical(sn).should == "Trematosphaeria phaeospora"
116
+ details(sn).should == [{:genus=>{:epitheton=>"Trematosphaeria"}, :species=>{:epitheton=>"phaeospora", :authorship=>"(E. Müll.) L. Holm 1957", :combinationAuthorTeam=>{:authorTeam=>"L. Holm", :author=>["L. Holm"], :year=>"1957"}, :basionymAuthorTeam=>{:authorTeam=>"E. Müll.", :author=>["E. Müll."]}}}]
117
+ pos(sn).should == {0=>["genus", 15], 16=>["species", 26], 28=>["author_word", 30], 31=>["author_word", 36], 46=>["author_word", 48], 61=>["author_word", 65], 66=>["year", 70]}
118
+
119
+ end
120
+
121
+ it 'should parse subgenus (ICZN code)' do
122
+ sn = "Hegeter (Hegeter) intercedens Lindberg H 1950"
123
+ parse(sn).should_not be_nil
124
+ value(sn).should == "Hegeter (Hegeter) intercedens Lindberg H 1950"
125
+ canonical(sn).should == "Hegeter intercedens"
126
+ details(sn).should == [{:genus=>{:epitheton=>"Hegeter"}, :subgenus=>{:epitheton=>"Hegeter"}, :species=>{:epitheton=>"intercedens", :authorship=>"Lindberg H 1950", :basionymAuthorTeam=>{:authorTeam=>"Lindberg H", :author=>["Lindberg H"], :year=>"1950"}}}]
127
+ pos(sn).should == {0=>["genus", 7], 9=>["subgenus", 16], 18=>["species", 29], 30=>["author_word", 38], 39=>["author_word", 40], 41=>["year", 45]}
128
+ end
129
+
130
+ it 'should parse several authors without a year' do
131
+ sn = "Pseudocercospora dendrobii U. Braun & Crous"
132
+ parse(sn).should_not be_nil
133
+ value(sn).should == "Pseudocercospora dendrobii U. Braun et Crous"
134
+ canonical(sn).should == "Pseudocercospora dendrobii"
135
+ details(sn).should == [{:genus=>{:epitheton=>"Pseudocercospora"}, :species=>{:epitheton=>"dendrobii", :authorship=>"U. Braun & Crous", :basionymAuthorTeam=>{:authorTeam=>"U. Braun & Crous", :author=>["U. Braun", "Crous"]}}}]
136
+ pos(sn).should == {0=>["genus", 16], 17=>["species", 26], 27=>["author_word", 29], 30=>["author_word", 35], 38=>["author_word", 43]}
137
+ sn = "Pseudocercospora dendrobii U. Braun and Crous"
138
+ parse(sn).should_not be_nil
139
+ value(sn).should == "Pseudocercospora dendrobii U. Braun et Crous"
140
+ pos(sn).should == {0=>["genus", 16], 17=>["species", 26], 27=>["author_word", 29], 30=>["author_word", 35], 40=>["author_word", 45]}
141
+ sn = "Pseudocercospora dendrobii U. Braun et Crous"
142
+ parse(sn).should_not be_nil
143
+ value(sn).should == "Pseudocercospora dendrobii U. Braun et Crous"
144
+ sn = "Arthopyrenia hyalospora(Nyl.)R.C. Harris"
145
+ parse(sn).should_not be_nil
146
+ value(sn).should == "Arthopyrenia hyalospora (Nyl.) R.C. Harris"
147
+ canonical(sn).should == "Arthopyrenia hyalospora"
148
+ details(sn).should == [{:genus=>{:epitheton=>"Arthopyrenia"}, :species=>{:epitheton=>"hyalospora", :authorship=>"(Nyl.)R.C. Harris", :combinationAuthorTeam=>{:authorTeam=>"R.C. Harris", :author=>["R.C. Harris"]}, :basionymAuthorTeam=>{:authorTeam=>"Nyl.", :author=>["Nyl."]}}}]
149
+ end
150
+
151
+
152
+
153
+ it 'should parse several authors with a year' do
154
+ sn = "Pseudocercospora dendrobii U. Braun & Crous 2003"
155
+ parse(sn).should_not be_nil
156
+ value(sn).should == "Pseudocercospora dendrobii U. Braun et Crous 2003"
157
+ canonical(sn).should == "Pseudocercospora dendrobii"
158
+ details(sn).should == [{:genus=>{:epitheton=>"Pseudocercospora"}, :species=>{:epitheton=>"dendrobii", :authorship=>"U. Braun & Crous 2003", :basionymAuthorTeam=>{:authorTeam=>"U. Braun & Crous", :author=>["U. Braun", "Crous"], :year=>"2003"}}}]
159
+ pos(sn).should == {0=>["genus", 16], 17=>["species", 26], 27=>["author_word", 29], 30=>["author_word", 35], 38=>["author_word", 43], 44=>["year", 48]}
160
+ sn = "Pseudocercospora dendrobii Crous, 2003"
161
+ parse(sn).should_not be_nil
162
+ end
163
+
164
+ it 'should parse basionym authors in parenthesis' do
165
+ sn = "Zophosis persis (Chatanay, 1914)"
166
+ parse(sn).should_not be_nil
167
+ details(sn).should == [{:genus=>{:epitheton=>"Zophosis"}, :species=>{:epitheton=>"persis", :authorship=>"(Chatanay, 1914)", :basionymAuthorTeam=>{:authorTeam=>"Chatanay", :author=>["Chatanay"], :year=>"1914"}}}]
168
+ sn = "Zophosis persis (Chatanay 1914)"
169
+ parse(sn).should_not be_nil
170
+ details(sn).should == [{:genus=>{:epitheton=>"Zophosis"}, :species=>{:epitheton=>"persis", :authorship=>"(Chatanay 1914)", :basionymAuthorTeam=>{:authorTeam=>"Chatanay", :author=>["Chatanay"], :year=>"1914"}}}]
171
+ sn = "Zophosis persis (Chatanay), 1914"
172
+ parse(sn).should_not be_nil
173
+ value(sn).should == "Zophosis persis (Chatanay 1914)"
174
+ details(sn).should == [{:genus=>{:epitheton=>"Zophosis"}, :species=>{:epitheton=>"persis", :authorship=>"(Chatanay), 1914", :basionymAuthorTeam=>{:author_team=>"(Chatanay), 1914", :author=>["Chatanay"], :year=>"1914"}}}]
175
+ pos(sn).should == {0=>["genus", 8], 9=>["species", 15], 17=>["author_word", 25], 28=>["year", 32]}
176
+ parse("Zophosis persis (Chatanay) 1914").should_not be_nil
177
+ #parse("Zophosis persis Chatanay (1914)").should_not be_nil
178
+ end
179
+
180
+ it 'should parse scientific name' do
181
+ sn = "Pseudocercospora dendrobii(H.C. Burnett)U. Braun & Crous 2003"
182
+ parse(sn).should_not be_nil
183
+ value(sn).should == "Pseudocercospora dendrobii (H.C. Burnett) U. Braun et Crous 2003"
184
+ canonical(sn).should == "Pseudocercospora dendrobii"
185
+ details(sn).should == [{:genus=>{:epitheton=>"Pseudocercospora"}, :species=>{:epitheton=>"dendrobii", :authorship=>"(H.C. Burnett)U. Braun & Crous 2003", :combinationAuthorTeam=>{:authorTeam=>"U. Braun & Crous", :author=>["U. Braun", "Crous"], :year=>"2003"}, :basionymAuthorTeam=>{:authorTeam=>"H.C. Burnett", :author=>["H.C. Burnett"]}}}]
186
+ sn = "Pseudocercospora dendrobii(H.C. Burnett,1873)U. Braun & Crous 2003"
187
+ parse(sn).should_not be_nil
188
+ value(sn).should == "Pseudocercospora dendrobii (H.C. Burnett 1873) U. Braun et Crous 2003"
189
+ details(sn).should == [{:genus=>{:epitheton=>"Pseudocercospora"}, :species=>{:epitheton=>"dendrobii", :authorship=>"(H.C. Burnett,1873)U. Braun & Crous 2003", :combinationAuthorTeam=>{:authorTeam=>"U. Braun & Crous", :author=>["U. Braun", "Crous"], :year=>"2003"}, :basionymAuthorTeam=>{:authorTeam=>"H.C. Burnett", :author=>["H.C. Burnett"], :year=>"1873"}}}]
190
+ end
191
+
192
+ it 'should parse several authors with several years' do
193
+ sn = "Pseudocercospora dendrobii (H.C. Burnett 1883) U. Braun & Crous 2003"
194
+ parse(sn).should_not be_nil
195
+ value(sn).should == "Pseudocercospora dendrobii (H.C. Burnett 1883) U. Braun et Crous 2003"
196
+ canonical(sn).should == "Pseudocercospora dendrobii"
197
+ details(sn).should == [{:genus=>{:epitheton=>"Pseudocercospora"}, :species=>{:epitheton=>"dendrobii", :authorship=>"(H.C. Burnett 1883) U. Braun & Crous 2003", :combinationAuthorTeam=>{:authorTeam=>"U. Braun & Crous", :author=>["U. Braun", "Crous"], :year=>"2003"}, :basionymAuthorTeam=>{:authorTeam=>"H.C. Burnett", :author=>["H.C. Burnett"], :year=>"1883"}}}]
198
+ pos(sn).should == {0=>["genus", 16], 17=>["species", 26], 28=>["author_word", 32], 33=>["author_word", 40], 41=>["year", 45], 47=>["author_word", 49], 50=>["author_word", 55], 58=>["author_word", 63], 64=>["year", 68]}
199
+ end
200
+
201
+ it "should parse name with subspecies without rank Zoological Code" do
202
+ sn = "Hydnellum scrobiculatum zonatum (Banker) D. Hall & D.E. Stuntz 1972"
203
+ parse(sn).should_not be_nil
204
+ value(sn).should == "Hydnellum scrobiculatum zonatum (Banker) D. Hall et D.E. Stuntz 1972"
205
+ canonical(sn).should == "Hydnellum scrobiculatum zonatum"
206
+ details(sn).should == [{:genus=>{:epitheton=>"Hydnellum"}, :species=>{:epitheton=>"scrobiculatum"}, :infraspecies=>[{:epitheton=>"zonatum", :rank=>"n/a", :authorship=>"(Banker) D. Hall & D.E. Stuntz 1972", :combinationAuthorTeam=>{:authorTeam=>"D. Hall & D.E. Stuntz", :author=>["D. Hall", "D.E. Stuntz"], :year=>"1972"}, :basionymAuthorTeam=>{:authorTeam=>"Banker", :author=>["Banker"]}}]}]
207
+ pos(sn).should == {0=>["genus", 9], 10=>["species", 23], 24=>["infraspecies", 31], 33=>["author_word", 39], 41=>["author_word", 43], 44=>["author_word", 48], 51=>["author_word", 55], 56=>["author_word", 62], 63=>["year", 67]}
208
+ sn = "Begonia pingbienensis angustior"
209
+ parse(sn).should_not be_nil
210
+ details(sn).should == [{:genus=>{:epitheton=>"Begonia"}, :species=>{:epitheton=>"pingbienensis"}, :infraspecies=>[{:epitheton=>"angustior", :rank=>"n/a"}]}]
211
+ pos(sn).should == {0=>["genus", 7], 8=>["species", 21], 22=>["infraspecies", 31]}
212
+ end
213
+
214
+ it 'should parse infraspecies with rank' do
215
+ sn = "Aus bus Linn. var. bus"
216
+ parse(sn).should_not be_nil
217
+ details(sn).should == [{:genus=>{:epitheton=>"Aus"}, :species=>{:epitheton=>"bus", :authorship=>"Linn.", :basionymAuthorTeam=>{:authorTeam=>"Linn.", :author=>["Linn."]}}, :infraspecies=>[{:epitheton=>"bus", :rank=>"var."}]}]
218
+ sn = "Agalinis purpurea (L.) Briton var. borealis (Berg.) Peterson 1987"
219
+ parse(sn).should_not be_nil
220
+ details(sn).should == [{:genus=>{:epitheton=>"Agalinis"}, :species=>{:epitheton=>"purpurea", :authorship=>"(L.) Briton", :combinationAuthorTeam=>{:authorTeam=>"Briton", :author=>["Briton"]}, :basionymAuthorTeam=>{:authorTeam=>"L.", :author=>["L."]}}, :infraspecies=>[{:epitheton=>"borealis", :rank=>"var.", :authorship=>"(Berg.) Peterson 1987", :combinationAuthorTeam=>{:authorTeam=>"Peterson", :author=>["Peterson"], :year=>"1987"}, :basionymAuthorTeam=>{:authorTeam=>"Berg.", :author=>["Berg."]}}]}]
221
+ pos(sn).should == {0=>["genus", 8], 9=>["species", 17], 19=>["author_word", 21], 23=>["author_word", 29], 35=>["infraspecies", 43], 45=>["author_word", 50], 52=>["author_word", 60], 61=>["year", 65]}
222
+ sn = "Phaeographis inusta var. macularis(Leight.) A.L. Sm. 1861"
223
+ parse(sn).should_not be_nil
224
+ value(sn).should == "Phaeographis inusta var. macularis (Leight.) A.L. Sm. 1861"
225
+ canonical(sn).should == "Phaeographis inusta macularis"
226
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 19], 25=>["infraspecies", 34], 35=>["author_word", 42], 44=>["author_word", 48], 49=>["author_word", 52], 53=>["year", 57]}
227
+ end
228
+
229
+ it 'should parse unknown original authors (auct.)/(hort.)/(?)' do
230
+ sn = "Tragacantha leporina (?) Kuntze"
231
+ parse(sn).should_not be_nil
232
+ value(sn).should == "Tragacantha leporina (?) Kuntze"
233
+ details(sn).should == [{:genus=>{:epitheton=>"Tragacantha"}, :species=>{:epitheton=>"leporina", :authorship=>"(?) Kuntze", :combinationAuthorTeam=>{:authorTeam=>"Kuntze", :author=>["Kuntze"]}, :basionymAuthorTeam=>{:authorTeam=>"(?)", :author=>["?"]}}}]
234
+ sn = "Lachenalia tricolor var. nelsonii (auct.) Baker"
235
+ parse(sn).should_not be_nil
236
+ value(sn).should == "Lachenalia tricolor var. nelsonii (auct.) Baker"
237
+ details(sn).should == [{:genus=>{:epitheton=>"Lachenalia"}, :species=>{:epitheton=>"tricolor"}, :infraspecies=>[{:epitheton=>"nelsonii", :rank=>"var.", :authorship=>"(auct.) Baker", :combinationAuthorTeam=>{:authorTeam=>"Baker", :author=>["Baker"]}, :basionymAuthorTeam=>{:authorTeam=>"auct.", :author=>["unknown"]}}]}]
238
+ pos(sn).should == {0=>["genus", 10], 11=>["species", 19], 25=>["infraspecies", 33], 35=>["unknown_author", 40], 42=>["author_word", 47]}
239
+ end
240
+
241
+ it 'should parse unknown authors auct./anon./hort./ht.' do
242
+ sn = "Puya acris ht."
243
+ parse(sn).should_not be_nil
244
+ pos(sn).should == {0=>["genus", 4], 5=>["species", 10], 11=>["unknown_author", 14]}
245
+ end
246
+
247
+ it 'shuould parse real world examples' do
248
+ sn = "Stagonospora polyspora M.T. Lucas & Sousa da Câmara 1934"
249
+ parse(sn).should_not be_nil
250
+ value(sn).should == "Stagonospora polyspora M.T. Lucas et Sousa da Câmara 1934"
251
+ details(sn).should == [{:genus=>{:epitheton=>"Stagonospora"}, :species=>{:epitheton=>"polyspora", :authorship=>"M.T. Lucas & Sousa da Câmara 1934", :basionymAuthorTeam=>{:authorTeam=>"M.T. Lucas & Sousa da Câmara", :author=>["M.T. Lucas", "Sousa da Câmara"], :year=>"1934"}}}]
252
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 22], 23=>["author_word", 27], 28=>["author_word", 33], 36=>["author_word", 41], 42=>["author_word", 44], 45=>["author_word", 51], 52=>["year", 56]}
253
+ parse("Cladoniicola staurospora Diederich, van den Boom & Aptroot 2001").should_not be_nil
254
+ sn = "Yarrowia lipolytica var. lipolytica (Wick., Kurtzman & E.A. Herrm.) Van der Walt & Arx 1981"
255
+ parse(sn).should_not be_nil
256
+ value(sn).should == "Yarrowia lipolytica var. lipolytica (Wick., Kurtzman et E.A. Herrm.) Van der Walt et Arx 1981"
257
+ pos(sn).should == {0=>["genus", 8], 9=>["species", 19], 25=>["infraspecies", 35], 37=>["author_word", 42], 44=>["author_word", 52], 55=>["author_word", 59], 60=>["author_word", 66], 68=>["author_word", 71], 72=>["author_word", 75], 76=>["author_word", 80], 83=>["author_word", 86], 87=>["year", 91]}
258
+ parse("Physalospora rubiginosa (Fr.) anon.").should_not be_nil
259
+ parse("Pleurotus ëous (Berk.) Sacc. 1887").should_not be_nil
260
+ parse("Lecanora wetmorei Śliwa 2004").should_not be_nil
261
+ # valid
262
+ # infraspecific
263
+ parse("Calicium furfuraceum * furfuraceum (L.) Pers. 1797").should_not be_nil
264
+ parse("Exobasidium vaccinii ** andromedae (P. Karst.) P. Karst. 1882").should_not be_nil
265
+ parse("Urceolaria scruposa **** clausa Flot. 1849").should_not be_nil
266
+ parse("Cortinarius angulatus B gracilescens Fr. 1838").should_not be_nil
267
+ parse("Cyathicula scelobelonium").should_not be_nil
268
+ # single quote that did not show
269
+ # parse("Phytophthora hedraiandra De Cock & Man in ?t Veld 2004"
270
+ # Phthora vastatrix d?Hérelle 1909
271
+ # author is exception
272
+ sn = "Tuber liui A S. Xu 1999"
273
+ parse(sn).should_not be_nil
274
+ details(sn).should == [{:genus=>{:epitheton=>"Tuber"}, :species=>{:epitheton=>"liui", :authorship=>"A S. Xu 1999", :basionymAuthorTeam=>{:authorTeam=>"A S. Xu", :author=>["A S. Xu"], :year=>"1999"}}}]
275
+ parse('Xylaria potentillae A S. Xu').should_not be_nil
276
+ parse("Agaricus squamula Berk. & M.A. Curtis 1860").should_not be_nil
277
+ parse("Peltula coriacea Büdel, Henssen & Wessels 1986").should_not be_nil
278
+ #had to add no dot rule for trinomials without a rank to make it to work
279
+ sn = "Saccharomyces drosophilae anon."
280
+ parse(sn).should_not be_nil
281
+ details(sn).should == [{:genus=>{:epitheton=>"Saccharomyces"}, :species=>{:epitheton=>"drosophilae", :authorship=>"anon.", :basionymAuthorTeam=>{:authorTeam=>"anon.", :author=>["unknown"]}}}]
282
+ pos(sn).should == {0=>["genus", 13], 14=>["species", 25], 26=>["unknown_author", 31]}
283
+ sn = "Abacetus laevicollis de Chaudoir, 1869"
284
+ parse(sn).should_not be_nil
285
+ canonical(sn).should == 'Abacetus laevicollis'
286
+ sn = "Gastrosericus eremorum van Beaumont 1955"
287
+ canonical(sn).should == 'Gastrosericus eremorum'
288
+ sn = "Gastrosericus eremorum von Beaumont 1955"
289
+ canonical(sn).should == 'Gastrosericus eremorum'
290
+ sn = "Cypraeovula (Luponia) amphithales perdentata"
291
+ canonical(sn).should == 'Cypraeovula Luponia amphithales perdentata'
292
+ details(sn).should == [{:genus=>{:epitheton=>"Cypraeovula"}, :subgenus=>{:epitheton=>"Luponia"}, :species=>{:epitheton=>"amphithales"}, :infraspecies=>[{:epitheton=>"perdentata", :rank=>"n/a"}]}]
293
+ sn = "Polyrhachis orsyllus nat musculus Forel 1901"
294
+ canonical(sn).should == "Polyrhachis orsyllus musculus"
295
+ sn = 'Latrodectus 13-guttatus Thorell, 1875'
296
+ canonical(sn).should == 'Latrodectus 13-guttatus'
297
+ value(sn).should == 'Latrodectus 13-guttatus Thorell 1875'
298
+ sn = 'Latrodectus 3guttatus Thorell, 1875'
299
+ canonical(sn).should == 'Latrodectus 3-guttatus'
300
+ value(sn).should == 'Latrodectus 3-guttatus Thorell 1875'
301
+ end
302
+
303
+ it "should parse name with morph." do
304
+ sn = "Callideriphus flavicollis morph. reductus Fuchs 1961"
305
+ parse(sn).should_not be_nil
306
+ value(sn).should == "Callideriphus flavicollis morph. reductus Fuchs 1961"
307
+ canonical(sn).should == "Callideriphus flavicollis reductus"
308
+ details(sn).should == [{:genus=>{:epitheton=>"Callideriphus"}, :species=>{:epitheton=>"flavicollis"}, :infraspecies=>[{:epitheton=>"reductus", :rank=>"morph.", :authorship=>"Fuchs 1961", :basionymAuthorTeam=>{:authorTeam=>"Fuchs", :author=>["Fuchs"], :year=>"1961"}}]}]
309
+ pos(sn).should == {0=>["genus", 13], 14=>["species", 25], 33=>["infraspecies", 41], 42=>["author_word", 47], 48=>["year", 52]}
310
+ end
311
+
312
+
313
+ it "should parse name with forma/fo./form./f." do
314
+ sn = "Caulerpa cupressoides forma nuda"
315
+ parse(sn).should_not be_nil
316
+ value(sn).should == "Caulerpa cupressoides f. nuda"
317
+ canonical(sn).should == "Caulerpa cupressoides nuda"
318
+ details(sn).should == [{:genus=>{:epitheton=>"Caulerpa"}, :species=>{:epitheton=>"cupressoides"}, :infraspecies=>[{:epitheton=>"nuda", :rank=>"f."}]}]
319
+ pos(sn).should == {0=>["genus", 8], 9=>["species", 21], 28=>["infraspecies", 32]}
320
+ sn = "Chlorocyperus glaber form. fasciculariforme (Lojac.) Soó"
321
+ parse(sn).should_not be_nil
322
+ value("Chlorocyperus glaber form. fasciculariforme (Lojac.) Soó").should == "Chlorocyperus glaber f. fasciculariforme (Lojac.) Soó"
323
+ canonical(sn).should == "Chlorocyperus glaber fasciculariforme"
324
+ details(sn).should == [{:genus=>{:epitheton=>"Chlorocyperus"}, :species=>{:epitheton=>"glaber"}, :infraspecies=>[{:epitheton=>"fasciculariforme", :rank=>"f.", :authorship=>"(Lojac.) Soó", :combinationAuthorTeam=>{:authorTeam=>"Soó", :author=>["Soó"]}, :basionymAuthorTeam=>{:authorTeam=>"Lojac.", :author=>["Lojac."]}}]}]
325
+ pos(sn).should == {0=>["genus", 13], 14=>["species", 20], 27=>["infraspecies", 43], 45=>["author_word", 51], 53=>["author_word", 56]}
326
+ sn = "Bambusa nana Roxb. fo. alphonse-karri (Mitford ex Satow) Makino ex Shiros."
327
+ parse(sn).should_not be_nil
328
+ value(sn).should == "Bambusa nana Roxb. f. alphonse-karri (Mitford ex Satow) Makino ex Shiros."
329
+ canonical(sn).should == "Bambusa nana alphonse-karri"
330
+ details(sn).should == [{:genus=>{:epitheton=>"Bambusa"}, :species=>{:epitheton=>"nana", :authorship=>"Roxb.", :basionymAuthorTeam=>{:authorTeam=>"Roxb.", :author=>["Roxb."]}}, :infraspecies=>[{:epitheton=>"alphonse-karri", :rank=>"f.", :authorship=>"(Mitford ex Satow) Makino ex Shiros.", :combinationAuthorTeam=>{:authorTeam=>"Makino", :author=>["Makino"], :exAuthorTeam=>{:authorTeam=>"Shiros.", :author=>["Shiros."]}}, :basionymAuthorTeam=>{:authorTeam=>"Mitford", :author=>["Mitford"], :exAuthorTeam=>{:authorTeam=>"Satow", :author=>["Satow"]}}}]}]
331
+ pos(sn).should == {0=>["genus", 7], 8=>["species", 12], 13=>["author_word", 18], 23=>["infraspecies", 37], 39=>["author_word", 46], 50=>["author_word", 55], 57=>["author_word", 63], 67=>["author_word", 74]}
332
+ sn = " Sphaerotheca fuliginea f. dahliae Movss. 1967 "
333
+ sn = "Sphaerotheca fuliginea f. dahliae Movss. 1967"
334
+ parse(sn).should_not be_nil
335
+ value(sn).should == "Sphaerotheca fuliginea f. dahliae Movss. 1967"
336
+ canonical(sn).should == "Sphaerotheca fuliginea dahliae"
337
+ details(sn).should == [{:genus=>{:epitheton=>"Sphaerotheca"}, :species=>{:epitheton=>"fuliginea"}, :infraspecies=>[{:epitheton=>"dahliae", :rank=>"f.", :authorship=>"Movss. 1967", :basionymAuthorTeam=>{:authorTeam=>"Movss.", :author=>["Movss."], :year=>"1967"}}]}]
338
+ pos(sn).should == {0=>["genus", 12], 16=>["species", 25], 36=>["infraspecies", 43], 47=>["author_word", 53], 58=>["year", 62]}
339
+ parse('Polypodium vulgare nothosubsp. mantoniae (Rothm.) Schidlay').should_not be_nil
340
+ end
341
+
342
+ it "should parse name with several subspecies names NOT BOTANICAL CODE BUT NOT INFREQUENT" do
343
+ sn = "Hydnellum scrobiculatum var. zonatum f. parvum (Banker) D. Hall & D.E. Stuntz 1972"
344
+ parse(sn).should_not be_nil
345
+ value(sn).should == "Hydnellum scrobiculatum var. zonatum f. parvum (Banker) D. Hall et D.E. Stuntz 1972"
346
+ details(sn).should == [{:genus=>{:epitheton=>"Hydnellum"}, :species=>{:epitheton=>"scrobiculatum"}, :infraspecies=>[{:epitheton=>"zonatum", :rank=>"var."}, {:epitheton=>"parvum", :rank=>"f.", :authorship=>"(Banker) D. Hall & D.E. Stuntz 1972", :combinationAuthorTeam=>{:authorTeam=>"D. Hall & D.E. Stuntz", :author=>["D. Hall", "D.E. Stuntz"], :year=>"1972"}, :basionymAuthorTeam=>{:authorTeam=>"Banker", :author=>["Banker"]}}]}]
347
+ pos(sn).should == {0=>["genus", 9], 10=>["species", 23], 29=>["infraspecies", 36], 40=>["infraspecies", 46], 48=>["author_word", 54], 56=>["author_word", 58], 59=>["author_word", 63], 66=>["author_word", 70], 71=>["author_word", 77], 78=>["year", 82]}
348
+ parse('Senecio fuchsii C.C.Gmel. subsp. fuchsii var. expansus (Boiss. & Heldr.) Hayek').should_not be_nil
349
+ parse('Senecio fuchsii C.C.Gmel. subsp. fuchsii var. fuchsii').should_not be_nil
350
+ end
351
+
352
+
353
+ it "should parse status BOTANICAL RARE" do
354
+ #it is always latin abbrev often 2 words
355
+ sn = "Arthopyrenia hyalospora (Nyl.) R.C. Harris comb. nov."
356
+ parse(sn).should_not be_nil
357
+ value(sn).should == "Arthopyrenia hyalospora (Nyl.) R.C. Harris comb. nov."
358
+ canonical(sn).should == "Arthopyrenia hyalospora"
359
+ details(sn).should == [{:genus=>{:epitheton=>"Arthopyrenia"}, :species=>{:epitheton=>"hyalospora", :authorship=>"(Nyl.) R.C. Harris", :combinationAuthorTeam=>{:authorTeam=>"R.C. Harris ", :author=>["R.C. Harris"]}, :basionymAuthorTeam=>{:authorTeam=>"Nyl.", :author=>["Nyl."]}}, :status=>"comb. nov."}]
360
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 23], 25=>["author_word", 29], 31=>["author_word", 35], 36=>["author_word", 42]}
361
+ end
362
+
363
+ it "should parse revised (ex) names" do
364
+ #invalidly published
365
+ sn = "Arthopyrenia hyalospora (Nyl. ex Banker) R.C. Harris"
366
+ parse(sn).should_not be_nil
367
+ value(sn).should == "Arthopyrenia hyalospora (Nyl. ex Banker) R.C. Harris"
368
+ canonical(sn).should == "Arthopyrenia hyalospora"
369
+ details(sn).should == [{:genus=>{:epitheton=>"Arthopyrenia"}, :species=>{:epitheton=>"hyalospora", :authorship=>"(Nyl. ex Banker) R.C. Harris", :combinationAuthorTeam=>{:authorTeam=>"R.C. Harris", :author=>["R.C. Harris"]}, :basionymAuthorTeam=>{:authorTeam=>"Nyl.", :author=>["Nyl."], :exAuthorTeam=>{:authorTeam=>"Banker", :author=>["Banker"]}}}}]
370
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 23], 25=>["author_word", 29], 33=>["author_word", 39], 41=>["author_word", 45], 46=>["author_word", 52]}
371
+ sn = "Arthopyrenia hyalospora Nyl. ex Banker"
372
+ parse(sn).should_not be_nil
373
+ details(sn).should == [{:genus=>{:epitheton=>"Arthopyrenia"}, :species=>{:epitheton=>"hyalospora", :authorship=>"Nyl. ex Banker", :basionymAuthorTeam=>{:authorTeam=>"Nyl.", :author=>["Nyl."], :exAuthorTeam=>{:authorTeam=>"Banker", :author=>["Banker"]}}}}]
374
+ sn = "Glomopsis lonicerae Peck ex C.J. Gould 1945"
375
+ parse(sn).should_not be_nil
376
+ details(sn).should == [{:genus=>{:epitheton=>"Glomopsis"}, :species=>{:epitheton=>"lonicerae", :authorship=>"Peck ex C.J. Gould 1945", :basionymAuthorTeam=>{:authorTeam=>"Peck", :author=>["Peck"], :exAuthorTeam=>{:authorTeam=>"C.J. Gould", :author=>["C.J. Gould"], :year=>"1945"}}}}]
377
+ pos(sn).should == {0=>["genus", 9], 10=>["species", 19], 20=>["author_word", 24], 28=>["author_word", 32], 33=>["author_word", 38], 39=>["year", 43]}
378
+ parse("Acanthobasidium delicatum (Wakef.) Oberw. ex Jülich 1979").should_not be_nil
379
+ sn = "Mycosphaerella eryngii (Fr. ex Duby) Johanson ex Oudem. 1897"
380
+ parse(sn).should_not be_nil
381
+ details(sn).should == [{:genus=>{:epitheton=>"Mycosphaerella"}, :species=>{:epitheton=>"eryngii", :authorship=>"(Fr. ex Duby) Johanson ex Oudem. 1897", :combinationAuthorTeam=>{:authorTeam=>"Johanson", :author=>["Johanson"], :exAuthorTeam=>{:authorTeam=>"Oudem.", :author=>["Oudem."], :year=>"1897"}}, :basionymAuthorTeam=>{:authorTeam=>"Fr.", :author=>["Fr."], :exAuthorTeam=>{:authorTeam=>"Duby", :author=>["Duby"]}}}}]
382
+ pos(sn).should == {0=>["genus", 14], 15=>["species", 22], 24=>["author_word", 27], 31=>["author_word", 35], 37=>["author_word", 45], 49=>["author_word", 55], 56=>["year", 60]}
383
+ #invalid but happens
384
+ parse("Mycosphaerella eryngii (Fr. Duby) ex Oudem. 1897").should_not be_nil
385
+ parse("Mycosphaerella eryngii (Fr.ex Duby) ex Oudem. 1897").should_not be_nil
386
+ sn = "Salmonella werahensis (Castellani) Hauduroy and Ehringer in Hauduroy 1937"
387
+ parse(sn).should_not be_nil
388
+ details(sn).should == [{:genus=>{:epitheton=>"Salmonella"}, :species=>{:epitheton=>"werahensis", :authorship=>"(Castellani) Hauduroy and Ehringer in Hauduroy 1937", :combinationAuthorTeam=>{:authorTeam=>"Hauduroy and Ehringer", :author=>["Hauduroy", "Ehringer"], :exAuthorTeam=>{:authorTeam=>"Hauduroy", :author=>["Hauduroy"], :year=>"1937"}}, :basionymAuthorTeam=>{:authorTeam=>"Castellani", :author=>["Castellani"]}}}]
389
+ pos(sn).should == {0=>["genus", 10], 11=>["species", 21], 23=>["author_word", 33], 35=>["author_word", 43], 48=>["author_word", 56], 60=>["author_word", 68], 69=>["year", 73]}
390
+ end
391
+
392
+ it 'should parse named hybrids' do
393
+ [
394
+ ["×Agropogon P. Fourn. 1934", [{:uninomial=>{:epitheton=>"Agropogon", :authorship=>"P. Fourn. 1934", :basionymAuthorTeam=>{:authorTeam=>"P. Fourn.", :author=>["P. Fourn."], :year=>"1934"}}}]],
395
+ ["xAgropogon P. Fourn.", [{:uninomial=>{:epitheton=>"Agropogon", :authorship=>"P. Fourn.", :basionymAuthorTeam=>{:authorTeam=>"P. Fourn.", :author=>["P. Fourn."]}}}]],
396
+ ["XAgropogon P.Fourn.", [{:uninomial=>{:epitheton=>"Agropogon", :authorship=>"P.Fourn.", :basionymAuthorTeam=>{:authorTeam=>"P.Fourn.", :author=>["P.Fourn."]}}}]],
397
+ ["× Agropogon", [{:uninomial=>{:epitheton=>"Agropogon"}}]],
398
+ ["x Agropogon", [{:uninomial=>{:epitheton=>"Agropogon"}}]],
399
+ ["X Agropogon", [{:uninomial=>{:epitheton=>"Agropogon"}}]],
400
+ ["X Cupressocyparis leylandii", [{:genus=>{:epitheton=>"Cupressocyparis"}, :species=>{:epitheton=>"leylandii"}}]],
401
+ ["×Heucherella tiarelloides", [{:genus=>{:epitheton=>"Heucherella"}, :species=>{:epitheton=>"tiarelloides"}}]],
402
+ ["xHeucherella tiarelloides", [{:genus=>{:epitheton=>"Heucherella"}, :species=>{:epitheton=>"tiarelloides"}}]],
403
+ ["x Heucherella tiarelloides", [{:genus=>{:epitheton=>"Heucherella"}, :species=>{:epitheton=>"tiarelloides"}}]],
404
+ ["×Agropogon littoralis (Sm.) C. E. Hubb. 1946", [{:genus=>{:epitheton=>"Agropogon"}, :species=>{:epitheton=>"littoralis", :authorship=>"(Sm.) C. E. Hubb. 1946", :combinationAuthorTeam=>{:authorTeam=>"C. E. Hubb.", :author=>["C. E. Hubb."], :year=>"1946"}, :basionymAuthorTeam=>{:authorTeam=>"Sm.", :author=>["Sm."]}}}]]
405
+ ].each do |res|
406
+ parse(res[0]).should_not be_nil
407
+ parse(res[0]).hybrid.should be_true
408
+ details(res[0]).should == res[1]
409
+ end
410
+ [
411
+ ['Asplenium X inexpectatum (E.L. Braun 1940) Morton (1956)',[{:genus=>{:epitheton=>"Asplenium"}, :species=>{:epitheton=>"inexpectatum", :authorship=>"(E.L. Braun 1940) Morton (1956)", :combinationAuthorTeam=>{:authorTeam=>"Morton", :author=>["Morton"], :year=>"1956"}, :basionymAuthorTeam=>{:authorTeam=>"E.L. Braun", :author=>["E.L. Braun"], :year=>"1940"}}}]],
412
+ ['Mentha ×smithiana R. A. Graham 1949',[{:genus=>{:epitheton=>"Mentha"}, :species=>{:epitheton=>"smithiana", :authorship=>"R. A. Graham 1949", :basionymAuthorTeam=>{:authorTeam=>"R. A. Graham", :author=>["R. A. Graham"], :year=>"1949"}}}]],
413
+ ['Salix ×capreola Andersson (1867)',[{:genus=>{:epitheton=>"Salix"}, :species=>{:epitheton=>"capreola", :authorship=>"Andersson (1867)", :basionymAuthorTeam=>{:authorTeam=>"Andersson", :author=>["Andersson"], :year=>"1867"}}}]],
414
+ ['Salix x capreola Andersson',[{:genus=>{:epitheton=>"Salix"}, :species=>{:epitheton=>"capreola", :authorship=>"Andersson", :basionymAuthorTeam=>{:authorTeam=>"Andersson", :author=>["Andersson"]}}}]]
415
+ ].each do |res|
416
+ parse(res[0]).should_not be_nil
417
+ parse(res[0]).hybrid.should be_true
418
+ details(res[0]).should == res[1]
419
+ end
420
+ end
421
+
422
+ it "should parse hybrid combination" do
423
+ sn = "Arthopyrenia hyalospora X Hydnellum scrobiculatum"
424
+ parse(sn).should_not be_nil
425
+ parse(sn).hybrid.should be_true
426
+ value(sn).should == "Arthopyrenia hyalospora \303\227 Hydnellum scrobiculatum"
427
+ canonical(sn).should == "Arthopyrenia hyalospora Hydnellum scrobiculatum"
428
+ details(sn).should == [{:genus=>{:epitheton=>"Arthopyrenia"}, :species=>{:epitheton=>"hyalospora"}}, {:genus=>{:epitheton=>"Hydnellum"}, :species=>{:epitheton=>"scrobiculatum"}}]
429
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 23], 26=>["genus", 35], 36=>["species", 49]}
430
+ sn = "Arthopyrenia hyalospora (Banker) D. Hall X Hydnellum scrobiculatum D.E. Stuntz"
431
+ parse(sn).should_not be_nil
432
+ parse(sn).hybrid.should be_true
433
+ value(sn).should == "Arthopyrenia hyalospora (Banker) D. Hall \303\227 Hydnellum scrobiculatum D.E. Stuntz"
434
+ canonical(sn).should == "Arthopyrenia hyalospora Hydnellum scrobiculatum"
435
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 23], 25=>["author_word", 31], 33=>["author_word", 35], 36=>["author_word", 40], 43=>["genus", 52], 53=>["species", 66], 67=>["author_word", 71], 72=>["author_word", 78]}
436
+ value("Arthopyrenia hyalospora X").should == "Arthopyrenia hyalospora \303\227 ?"
437
+ sn = "Arthopyrenia hyalospora x"
438
+ parse(sn).should_not be_nil
439
+ parse(sn).hybrid.should be_true
440
+ canonical(sn).should == "Arthopyrenia hyalospora"
441
+ details(sn).should == [{:genus=>{:epitheton=>"Arthopyrenia"}, :species=>{:epitheton=>"hyalospora"}}, "?"]
442
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 23]}
443
+ sn = "Arthopyrenia hyalospora × ?"
444
+ parse(sn).should_not be_nil
445
+ parse(sn).hybrid.should be_true
446
+ details(sn).should == [{:genus=>{:epitheton=>"Arthopyrenia"}, :species=>{:epitheton=>"hyalospora"}}, "?"]
447
+ pos(sn).should == {0=>["genus", 12], 13=>["species", 23]}
448
+ end
449
+
450
+ it 'should parse names with taxon concept' do
451
+ sn = "Sténométope laevissimus sec. Eschmeyer 2004"
452
+ val = @parser.failure_reason.to_s.match(/column [0-9]*/).to_s().gsub(/column /,'')
453
+ details(sn).should == [{:genus=>{:epitheton=>"Sténométope"}, :species=>{:epitheton=>"laevissimus"}, :taxon_concept=>{:authorship=>"Eschmeyer 2004", :basionymAuthorTeam=>{:authorTeam=>"Eschmeyer", :author=>["Eschmeyer"], :year=>"2004"}}}]
454
+ pos(sn).should == {0=>["genus", 11], 12=>["species", 23], 29=>["author_word", 38], 39=>["year", 43]}
455
+ sn = "Sténométope laevissimus Bibron 1855 sec. Eschmeyer 2004"
456
+ parse(sn).should_not be_nil
457
+ details(sn).should == [{:genus=>{:epitheton=>"Sténométope"}, :species=>{:epitheton=>"laevissimus", :authorship=>"Bibron 1855", :basionymAuthorTeam=>{:authorTeam=>"Bibron", :author=>["Bibron"], :year=>"1855"}}, :taxon_concept=>{:authorship=>"Eschmeyer 2004", :basionymAuthorTeam=>{:authorTeam=>"Eschmeyer", :author=>["Eschmeyer"], :year=>"2004"}}}]
458
+ pos(sn).should == {0=>["genus", 11], 12=>["species", 23], 24=>["author_word", 30], 31=>["year", 35], 41=>["author_word", 50], 51=>["year", 55]}
459
+ end
460
+
461
+ it 'should parse names with spaces inconsistencies at the start and the end and in the middle' do
462
+ parse(" Asplenium X inexpectatum (E.L. Braun 1940) Morton (1956) ").should_not be_nil
463
+ end
464
+
465
+ it 'should not parse serveral authors groups with several years NOT CORRECT' do
466
+ parse("Pseudocercospora dendrobii (H.C. Burnett 1883) (Leight.) (Movss. 1967) U. Braun & Crous 2003").should be_nil
467
+ end
468
+
469
+ it "should not parse unallowed utf-8 chars in name part" do
470
+ parse("Érematosphaeria phaespora").should be_nil
471
+ parse("Trematosphaeria phaeáapora").should be_nil
472
+ parse("Trematоsphaeria phaeáapora").should be_nil #cyrillic o
473
+ end
474
+
475
+ it "should parse new stuff" do
476
+ sn = 'Nesticus quelpartensis Paik & Namkung, in Paik, Yaginuma & Namkung, 1969'
477
+ details(sn).should == [{:genus=>{:epitheton=>"Nesticus"}, :species=>{:epitheton=>"quelpartensis", :authorship=>"Paik & Namkung, in Paik, Yaginuma & Namkung, 1969", :basionymAuthorTeam=>{:authorTeam=>"Paik & Namkung", :author=>["Paik", "Namkung"], :exAuthorTeam=>{:authorTeam=>"Paik, Yaginuma & Namkung", :author=>["Paik", "Yaginuma", "Namkung"], :year=>"1969"}}}}]
478
+ parse('Dipoena yoshidai Ono, in Ono et al., 1991').should_not be_nil
479
+ sn = 'Choriozopella trägårdhi Lawrence, 1947'
480
+ details(sn).should == [{:genus=>{:epitheton=>"Choriozopella"}, :species=>{:epitheton=>"trägårdhi", :authorship=>"Lawrence, 1947", :basionymAuthorTeam=>{:authorTeam=>"Lawrence", :author=>["Lawrence"], :year=>"1947"}}}]
481
+ sn = 'Latrodectus mactans bishopi Kaston, 1938'
482
+ details(sn).should == [{:genus=>{:epitheton=>"Latrodectus"}, :species=>{:epitheton=>"mactans"}, :infraspecies=>[{:epitheton=>"bishopi", :rank=>"n/a", :authorship=>"Kaston, 1938", :basionymAuthorTeam=>{:authorTeam=>"Kaston", :author=>["Kaston"], :year=>"1938"}}]}]
483
+ sn = 'Diplocephalus aff. procerus Thaler, 1972'
484
+ details(sn).should == [{:genus=>{:epitheton=>"Diplocephalus"}, :species=>{:epitheton=>"procerus", :authorship=>"Thaler, 1972", :basionymAuthorTeam=>{:authorTeam=>"Thaler", :author=>["Thaler"], :year=>"1972"}}}]
485
+ sn = 'Dyarcyops birói Kulczynski, 1908'
486
+ details(sn).should == [{:genus=>{:epitheton=>"Dyarcyops"}, :species=>{:epitheton=>"birói", :authorship=>"Kulczynski, 1908", :basionymAuthorTeam=>{:authorTeam=>"Kulczynski", :author=>["Kulczynski"], :year=>"1908"}}}]
487
+ sn = 'Sparassus françoisi Simon, 1898'
488
+ details(sn).should == [{:genus=>{:epitheton=>"Sparassus"}, :species=>{:epitheton=>"françoisi", :authorship=>"Simon, 1898", :basionymAuthorTeam=>{:authorTeam=>"Simon", :author=>["Simon"], :year=>"1898"}}}]
489
+ sn = 'Thiobacillus x Parker and Prisk 1953' #have to figure out black lists for this one
490
+ sn = 'Bacille de Plaut, Kritchevsky and Séguin 1921'
491
+ details(sn).should == [{:uninomial=>{:epitheton=>"Bacille", :authorship=>"de Plaut, Kritchevsky and Séguin 1921", :basionymAuthorTeam=>{:authorTeam=>"de Plaut, Kritchevsky and Séguin", :author=>["de Plaut", "Kritchevsky", "Séguin"], :year=>"1921"}}}]
492
+ sn = 'Araneus van bruysseli Petrunkevitch, 1911'
493
+ details(sn).should == [{:genus=>{:epitheton=>"Araneus"}, :species=>{:epitheton=>"van"}, :infraspecies=>[{:epitheton=>"bruysseli", :rank=>"n/a", :authorship=>"Petrunkevitch, 1911", :basionymAuthorTeam=>{:authorTeam=>"Petrunkevitch", :author=>["Petrunkevitch"], :year=>"1911"}}]}]
494
+ sn = 'Sapromyces laidlawi ab Sabin 1941'
495
+ details(sn).should == [{:genus=>{:epitheton=>"Sapromyces"}, :species=>{:epitheton=>"laidlawi", :authorship=>"ab Sabin 1941", :basionymAuthorTeam=>{:authorTeam=>"ab Sabin", :author=>["ab Sabin"], :year=>"1941"}}}]
496
+ sn = 'Nocardia rugosa di Marco and Spalla 1957'
497
+ details(sn).should == [{:genus=>{:epitheton=>"Nocardia"}, :species=>{:epitheton=>"rugosa", :authorship=>"di Marco and Spalla 1957", :basionymAuthorTeam=>{:authorTeam=>"di Marco and Spalla", :author=>["di Marco", "Spalla"], :year=>"1957"}}}]
498
+ sn = 'Flexibacter elegans Lewin 1969 non Soriano 1945'
499
+ details(sn).should == [{:genus=>{:epitheton=>"Flexibacter"}, :species=>{:epitheton=>"elegans", :authorship=>"Lewin 1969 non Soriano 1945", :basionymAuthorTeam=>{:authorTeam=>"Lewin", :author=>["Lewin"], :year=>"1969"}}}]
500
+ sn = 'Flexibacter elegans Soriano 1945, non Lewin 1969'
501
+ details(sn).should == [{:genus=>{:epitheton=>"Flexibacter"}, :species=>{:epitheton=>"elegans", :authorship=>"Soriano 1945, non Lewin 1969", :basionymAuthorTeam=>{:authorTeam=>"Soriano", :author=>["Soriano"], :year=>"1945"}}}]
502
+ end
503
+
504
+ end