taxonifi 0.2.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +59 -0
- data/.travis.yml +11 -0
- data/Gemfile +5 -17
- data/Gemfile.lock +22 -40
- data/README.md +192 -0
- data/Rakefile +35 -26
- data/lib/export/format/base.rb +1 -1
- data/lib/export/format/species_file.rb +154 -152
- data/lib/lumper/clump.rb +1 -1
- data/lib/lumper/lumper.rb +22 -18
- data/lib/lumper/lumps/parent_child_name_collection.rb +1 -2
- data/lib/lumper/name_index.rb +21 -0
- data/lib/{models → model}/author_year.rb +2 -2
- data/lib/{models → model}/base.rb +35 -5
- data/lib/{models → model}/collection.rb +8 -1
- data/lib/{models → model}/name.rb +128 -36
- data/lib/{models → model}/name_collection.rb +134 -33
- data/lib/{models → model}/person.rb +1 -1
- data/lib/{models → model}/ref.rb +4 -2
- data/lib/model/ref_collection.rb +171 -0
- data/lib/{models → model}/species_name.rb +24 -3
- data/lib/splitter/builder.rb +1 -1
- data/lib/splitter/parser.rb +5 -0
- data/lib/splitter/tokens.rb +54 -9
- data/lib/taxonifi/version.rb +3 -0
- data/lib/taxonifi.rb +5 -9
- data/taxonifi.gemspec +29 -99
- data/test/helper.rb +1 -1
- data/test/test_exporter.rb +1 -1
- data/test/test_lumper_names.rb +9 -9
- data/test/test_lumper_refs.rb +4 -4
- data/test/test_parser.rb +97 -26
- data/test/test_splitter_tokens.rb +25 -4
- data/test/test_taxonifi_base.rb +1 -1
- data/test/test_taxonifi_geog.rb +1 -1
- data/test/test_taxonifi_name.rb +13 -14
- data/test/test_taxonifi_name_collection.rb +11 -5
- data/test/test_taxonifi_ref.rb +1 -1
- data/test/test_taxonifi_ref_collection.rb +40 -3
- data/test/test_taxonifi_species_name.rb +51 -1
- data/travis/before_install.sh +2 -0
- metadata +96 -66
- data/README.rdoc +0 -154
- data/VERSION +0 -1
- data/lib/models/ref_collection.rb +0 -107
- /data/lib/{models → model}/generic_object.rb +0 -0
- /data/lib/{models → model}/geog.rb +0 -0
- /data/lib/{models → model}/geog_collection.rb +0 -0
- /data/lib/{models → model}/shared_class_methods.rb +0 -0
@@ -16,14 +16,14 @@ module Taxonifi
|
|
16
16
|
# Optionly store the row this came from
|
17
17
|
attr_accessor :row_number
|
18
18
|
|
19
|
-
# A general purpose
|
20
|
-
attr_accessor :
|
19
|
+
# A general purpose Hash populable as needed for related metadata
|
20
|
+
attr_accessor :properties
|
21
21
|
|
22
22
|
# TODO: Rethink this. See @@ATTRIBUTES in subclasses.
|
23
23
|
ATTRIBUTES = [:row_number]
|
24
24
|
|
25
25
|
def initialize(options = {})
|
26
|
-
@
|
26
|
+
@properties = {}
|
27
27
|
end
|
28
28
|
|
29
29
|
# Assign on new() all attributes for the ATTRIBUTES
|
@@ -35,6 +35,38 @@ module Taxonifi
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
# Add a set of properties (doesn't check for key collisions)
|
39
|
+
def add_properties(hash)
|
40
|
+
@properties.merge!(hash)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Add a key/value pair to @properties
|
44
|
+
def add_property(key, value)
|
45
|
+
if @properties[key]
|
46
|
+
return false
|
47
|
+
else
|
48
|
+
@properties.merge!(key => value)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Replace an existing key/value pair in @properties
|
53
|
+
def replace_property(key,value)
|
54
|
+
if !@properties[key]
|
55
|
+
return false
|
56
|
+
else
|
57
|
+
@properties.merge!(key => value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Delete an existing key/value pair in @properties
|
62
|
+
def delete_property(key)
|
63
|
+
if !@properties[key]
|
64
|
+
@properties.delete(key)
|
65
|
+
else
|
66
|
+
@properties.merge!(key => value)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
38
70
|
def id=(id)
|
39
71
|
raise Taxonifi::ModelError, "Base model objects must have Fixnum ids." if !id.nil? && id.class != Fixnum
|
40
72
|
@id = id
|
@@ -70,9 +102,7 @@ module Taxonifi
|
|
70
102
|
end
|
71
103
|
ancestors
|
72
104
|
end
|
73
|
-
|
74
105
|
end
|
75
106
|
|
76
|
-
|
77
107
|
end
|
78
108
|
end
|
@@ -89,8 +89,15 @@ module Taxonifi
|
|
89
89
|
|
90
90
|
# Returns an Array which respresents
|
91
91
|
# all the "root" objects.
|
92
|
+
# TODO: test
|
92
93
|
def objects_without_parents
|
93
|
-
collection.select{|o| o.parent.nil?}
|
94
|
+
@collection.select{|o| o.parent.nil?}
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns an Array of immediate children
|
98
|
+
# TODO: test
|
99
|
+
def children_of_object(o)
|
100
|
+
@collection.select{|i| i.parent == o}
|
94
101
|
end
|
95
102
|
|
96
103
|
protected
|
@@ -10,10 +10,10 @@ module Taxonifi
|
|
10
10
|
# String
|
11
11
|
attr_accessor :rank
|
12
12
|
|
13
|
-
# String
|
13
|
+
# String, authors as originally read
|
14
14
|
attr_accessor :author
|
15
15
|
|
16
|
-
# String,
|
16
|
+
# String, year as originally read
|
17
17
|
attr_accessor :year
|
18
18
|
|
19
19
|
# Boolean, true if parens present (i.e. _not_ in original combination)
|
@@ -22,16 +22,22 @@ module Taxonifi
|
|
22
22
|
# A Taxonifi::Model::Name
|
23
23
|
attr_accessor :parent
|
24
24
|
|
25
|
-
#
|
25
|
+
# A Taxonifi::Model::Name
|
26
|
+
# A general purpose relationship, typically used to indicate synonymy.
|
26
27
|
attr_accessor :related_name
|
27
28
|
|
28
|
-
#
|
29
|
-
|
29
|
+
# A Taxonifi::Model::Reference
|
30
|
+
# The original description.
|
31
|
+
attr_accessor :original_description_reference
|
30
32
|
|
31
|
-
#
|
33
|
+
# An Array, contains assignable properties in Taxonifi::Model::Name#new()
|
34
|
+
@@ATTRIBUTES = [:name, :rank, :year, :parens, :author, :related_name ]
|
35
|
+
|
36
|
+
# An Array of Taxonifi::Model::Person
|
37
|
+
# Optionally parsed/index
|
32
38
|
attr_accessor :authors
|
33
39
|
|
34
|
-
#
|
40
|
+
# Optionally parsed/index
|
35
41
|
attr_accessor :author_year_index
|
36
42
|
|
37
43
|
def initialize(options = {})
|
@@ -41,11 +47,16 @@ module Taxonifi
|
|
41
47
|
}.merge!(options)
|
42
48
|
|
43
49
|
@parent = nil
|
50
|
+
@authors ||= []
|
51
|
+
|
44
52
|
build(@@ATTRIBUTES, opts)
|
45
|
-
|
53
|
+
assign_author_year(opts)
|
54
|
+
|
55
|
+
|
56
|
+
@id = opts[:id]
|
46
57
|
@parent = opts[:parent] if (!opts[:parent].nil? && opts[:parent].class == Taxonifi::Model::Name)
|
47
|
-
@
|
48
|
-
|
58
|
+
@original_description_reference = opts[:original_description_reference] if (!opts[:original_description_reference].nil? && opts[:original_description_reference].class == Taxonifi::Model::Ref)
|
59
|
+
|
49
60
|
true
|
50
61
|
end
|
51
62
|
|
@@ -63,8 +74,8 @@ module Taxonifi
|
|
63
74
|
end
|
64
75
|
|
65
76
|
# Set the rank.
|
66
|
-
def rank=(
|
67
|
-
r =
|
77
|
+
def rank=(value)
|
78
|
+
r = value.to_s.downcase.strip
|
68
79
|
if !RANKS.include?(r)
|
69
80
|
raise NameError, "#{r} is not a valid rank."
|
70
81
|
end
|
@@ -76,7 +87,7 @@ module Taxonifi
|
|
76
87
|
# TODO: Family group extension; ICZN specific
|
77
88
|
def index_rank
|
78
89
|
case rank
|
79
|
-
when 'species', 'subspecies'
|
90
|
+
when 'species', 'subspecies', 'variety'
|
80
91
|
'species_group'
|
81
92
|
when 'genus', 'subgenus'
|
82
93
|
'genus_group'
|
@@ -88,6 +99,8 @@ module Taxonifi
|
|
88
99
|
end
|
89
100
|
|
90
101
|
# Set the parent (a Taxonifi::Model::Name)
|
102
|
+
# Passing "true" allows you to bypass the parent level restriction, do so
|
103
|
+
# with great caution.
|
91
104
|
def parent=(parent)
|
92
105
|
if @rank.nil?
|
93
106
|
raise Taxonifi::NameError, "Parent of name can not be set if rank of child is not set."
|
@@ -98,7 +111,8 @@ module Taxonifi
|
|
98
111
|
raise NameError, "Parent is not a Taxonifi::Model::Name."
|
99
112
|
end
|
100
113
|
|
101
|
-
if RANKS.index(parent.rank) >= RANKS.index(self.rank)
|
114
|
+
if (RANKS.index(parent.rank) >= RANKS.index(self.rank))
|
115
|
+
# warn "WARNING:: Assigning parent to Name at same or lower rank than self (#{rank})."
|
102
116
|
raise NameError, "Parent is same or lower rank than self (#{rank})."
|
103
117
|
end
|
104
118
|
|
@@ -113,13 +127,70 @@ module Taxonifi
|
|
113
127
|
(self.parens == true) ? "(#{au})" : au
|
114
128
|
end
|
115
129
|
|
130
|
+
|
116
131
|
# Return the author year string.
|
117
132
|
def author_year_string
|
118
|
-
|
133
|
+
# Build based on People
|
134
|
+
|
135
|
+
auth = nil
|
136
|
+
if authors.size > 0
|
137
|
+
case authors.size
|
138
|
+
when 1
|
139
|
+
auth = self.author
|
140
|
+
when 2
|
141
|
+
auth = authors.map(&:last_name).join(" & ")
|
142
|
+
when 2...100
|
143
|
+
auth = authors[0..-1].map(&:last_name).join(", ") + " & " + authors.last.last_name
|
144
|
+
end
|
145
|
+
# Build based on string
|
146
|
+
else
|
147
|
+
auth = self.author
|
148
|
+
end
|
149
|
+
au = [auth, self.year].compact.join(", ")
|
119
150
|
return nil if au.size == 0
|
120
151
|
au
|
121
152
|
end
|
122
153
|
|
154
|
+
# Return a String, the human readable version of this name (genus, subgenus, species, subspecies, variety author, year)
|
155
|
+
def display_name
|
156
|
+
[nomenclator_name, author_year].compact.join(" ")
|
157
|
+
end
|
158
|
+
|
159
|
+
# Return a String, the human readable version of this name (genus, subgenus, species, subspecies)
|
160
|
+
def nomenclator_name
|
161
|
+
case @rank
|
162
|
+
# TODO: update for infrasubspecifics if we start tracking those
|
163
|
+
when 'species', 'subspecies', 'genus', 'subgenus', 'variety'
|
164
|
+
nomenclator_array.compact.join(" ")
|
165
|
+
else
|
166
|
+
@name
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Return a Boolean, True if @rank is one of 'genus', 'subgenus', 'species', 'subspecies'
|
171
|
+
# TODO: update for infrasubspecifics if we start tracking those
|
172
|
+
def nomenclator_name?
|
173
|
+
%w{genus subgenus species subspecies variety}.include?(@rank)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Return an Array of lenght 4 of Names representing a Species or Genus group name
|
177
|
+
# [genus, subgenus, species, subspecies, infrasubspecific]
|
178
|
+
def nomenclator_array
|
179
|
+
case @rank
|
180
|
+
when 'variety'
|
181
|
+
return [parent_name_at_rank('genus'), (parent_name_at_rank('subgenus') ? "(#{parent_name_at_rank('subgenus')})" : nil), parent_name_at_rank('species'), parent_name_at_rank('subspecies'), "var. #{@name}"]
|
182
|
+
when 'species', 'subspecies'
|
183
|
+
return [parent_name_at_rank('genus'), (parent_name_at_rank('subgenus') ? "(#{parent_name_at_rank('subgenus')})" : nil), parent_name_at_rank('species'), parent_name_at_rank('subspecies'), nil]
|
184
|
+
when 'subgenus'
|
185
|
+
return [parent_name_at_rank('genus'), "(#{@name})", nil, nil, nil]
|
186
|
+
when 'genus'
|
187
|
+
return [@name, nil, nil, nil, nil]
|
188
|
+
else
|
189
|
+
return false
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
123
194
|
# Return a Taxonifi::Model::Name representing the finest genus_group_parent.
|
124
195
|
# TODO: ICZN specific(?)
|
125
196
|
def genus_group_parent
|
@@ -164,24 +235,7 @@ module Taxonifi
|
|
164
235
|
nil
|
165
236
|
end
|
166
237
|
|
167
|
-
|
168
|
-
def display_name
|
169
|
-
[nomenclator_name, author_year].compact.join(" ")
|
170
|
-
end
|
171
|
-
|
172
|
-
# Return the human readable version of this name, without author year (String)
|
173
|
-
def nomenclator_name
|
174
|
-
case @rank
|
175
|
-
when 'species', 'subspecies'
|
176
|
-
[parent_name_at_rank('genus'), (parent_name_at_rank('subgenus') ? "(#{parent_name_at_rank('subgenus')})" : nil), parent_name_at_rank('species'), parent_name_at_rank('subspecies')].compact.join(" ")
|
177
|
-
when 'subgenus'
|
178
|
-
[parent_name_at_rank('genus'), "(#{@name})"].compact.join(" ")
|
179
|
-
else
|
180
|
-
[@name].compact.join(" ")
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
# Return a dashed "vector" of ids representing the ancestor parent closure, like:
|
238
|
+
# Return a dashed "vector" of ids representing the ancestor parent closure, like:
|
185
239
|
# 0-1-14-29g-45s-99-100.
|
186
240
|
# Postfixed g means "genus", postifed s means "subgenus. As per SpecieFile usage.
|
187
241
|
# TODO: !! malformed because the valid name is not injected. Note that this can be generated internally post import.
|
@@ -197,26 +251,64 @@ module Taxonifi
|
|
197
251
|
ids.push a.id.to_s
|
198
252
|
end
|
199
253
|
end
|
200
|
-
|
201
254
|
ids.join("-")
|
202
255
|
end
|
203
256
|
|
204
|
-
# Return
|
257
|
+
# Return a Taxonifi::Model::AuthorYear representing author/year
|
258
|
+
# !! Identical to method in Taxonifi::Model::Ref
|
259
|
+
# !! *Not* necessarily unique.
|
205
260
|
def author_year_index
|
206
261
|
@author_year_index ||= generate_author_year_index
|
207
262
|
end
|
208
263
|
|
209
|
-
# Generate
|
264
|
+
# Generate and return (String) the author year index.
|
210
265
|
def generate_author_year_index
|
211
266
|
@author_year_index = Taxonifi::Model::AuthorYear.new(people: @authors, year: @year).compact_index
|
212
267
|
end
|
213
268
|
|
269
|
+
# TODO: test
|
270
|
+
# Returne True of False based on @rank
|
271
|
+
def species_group?
|
272
|
+
true if @rank == 'species' || @rank == 'subspecies'
|
273
|
+
end
|
274
|
+
|
275
|
+
# TODO: test
|
276
|
+
# Returne True of False based on @rank
|
277
|
+
def genus_group?
|
278
|
+
true if @rank == 'genus' || @rank == 'subgenus'
|
279
|
+
end
|
280
|
+
|
214
281
|
# Return a String of Prolog rules representing this Name
|
215
282
|
def prologify
|
216
283
|
"false"
|
284
|
+
end
|
217
285
|
|
286
|
+
protected
|
287
|
+
|
288
|
+
# Generate @authors = [People], @year = 1999 from incoming initialization options.
|
289
|
+
def assign_author_year(opts)
|
290
|
+
# If for some reason already set get out
|
291
|
+
raise NameError, "Name initialization error, @authors set prior to conversionf from @author_year." if @year && !@authors.nil? && @authors.size > 0
|
292
|
+
author_year = nil
|
293
|
+
if !opts[:author_year].nil? && (opts[:author_year].size > 0)
|
294
|
+
author_year = opts[:author_year]
|
295
|
+
elsif !opts[:author].nil? && !@year.nil? && (opts[:author].size > 0) && (@year.size > 0)
|
296
|
+
author_year = opts[:author] + ", " + @year.to_s
|
218
297
|
end
|
219
298
|
|
299
|
+
if !author_year.nil?
|
300
|
+
if ay = Taxonifi::Splitter::Builder.build_author_year(author_year)
|
301
|
+
@year = ay.year
|
302
|
+
@authors = ay.people
|
303
|
+
true
|
304
|
+
else
|
305
|
+
false
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
|
311
|
+
|
220
312
|
end
|
221
313
|
|
222
314
|
# ICZN specific sublassing of a taxonomic name.
|
@@ -5,28 +5,61 @@ module Taxonifi
|
|
5
5
|
# A collection of taxonomic names.
|
6
6
|
class NameCollection < Taxonifi::Model::Collection
|
7
7
|
|
8
|
-
# A
|
8
|
+
# A Hash. Keys are the name (String), values are ids of Names in the collection.
|
9
|
+
# { rank => { name => [ids] }}
|
10
|
+
# There are two special ranks "genus_group" and "species_group".
|
11
|
+
# E.g.: {'species_group' => {'bar' => [1,2,93]}})
|
9
12
|
attr_accessor :by_name_index
|
10
|
-
|
13
|
+
|
11
14
|
# A Taxonifi::Model::RefCollection, optionally generated from Author/Year strings
|
12
15
|
attr_accessor :ref_collection
|
13
16
|
|
14
17
|
# An optional collection of existing combinations of species names, as represented by
|
15
18
|
# individual arrays of Taxonifi::Model::Names. Note you can not use a Taxonifi::Model::SpeciesName
|
16
19
|
# for this purpose because getting/setting names therin will affect other combinations
|
20
|
+
# TODO: DEPRECATE? !?!
|
17
21
|
attr_accessor :combinations
|
18
22
|
|
23
|
+
# A Hash. Contains metadata when non-unique names are found in input parsing
|
24
|
+
# {unique row identifier => { redundant row identifier => {properties hash}}}
|
25
|
+
# TODO: reconsider, move to superclass or down to record base
|
26
|
+
# TODO: Test
|
27
|
+
attr_accessor :duplicate_entry_buffer
|
28
|
+
|
29
|
+
# A Hash. Index (keys) created by the collection, values are an Array of Strings
|
30
|
+
# representing the genus, subgenus, species, and subspecies name.
|
31
|
+
# Automatically populated when .add_object is used.
|
32
|
+
# Alternately populated with .add_nomenclator(Name)
|
33
|
+
# Nomenclator values are not repeated.
|
34
|
+
# Index is used in @citations.
|
35
|
+
# { @nomenclator_index => [genus_string, subgenus_string, species_string, subspecies_string, infrasubspecific_string (e.g. variety)], ... }
|
36
|
+
# !! The names represented in the Array of strings does *NOT* have to be represented in the NameCollection.
|
37
|
+
attr_accessor :nomenclators
|
38
|
+
|
39
|
+
# An Integer used for indexing nomenclator records in @nomenclators. Contains the next available index value.
|
40
|
+
attr_accessor :nomenclator_index
|
41
|
+
|
42
|
+
# TaxonNameID => [[ nomenclator_index, Ref ], ... []]
|
43
|
+
attr_accessor :citations
|
44
|
+
|
19
45
|
def initialize(options = {})
|
20
46
|
super
|
21
|
-
@by_name_index = {'genus_group' => {}, 'species_group' => {} }
|
22
|
-
|
23
|
-
|
24
|
-
@
|
25
|
-
@
|
26
|
-
@
|
47
|
+
@by_name_index = {'genus_group' => {}, 'species_group' => {}, 'unknown' => {}} # Lumping species and genus group names, unranked named are in 'unknown'
|
48
|
+
Taxonifi::RANKS[0..-5].inject(@by_name_index){|hsh, v| hsh.merge!(v => {})} # TODO: Still needed?!
|
49
|
+
@ref_collection = options[:ref_collection]
|
50
|
+
@citations = {}
|
51
|
+
@combinations = []
|
52
|
+
@nomenclators = {}
|
53
|
+
@nomenclator_index = options[:initial_nomenclator_index]
|
54
|
+
@nomenclator_index ||= 1
|
55
|
+
@duplicate_entry_buffer = {} # Move to Collection?!
|
27
56
|
true
|
28
57
|
end
|
29
58
|
|
59
|
+
def ref_collection=(ref_collection)
|
60
|
+
@ref_collection ||= ref_collection
|
61
|
+
end
|
62
|
+
|
30
63
|
def object_class
|
31
64
|
Taxonifi::Model::Name
|
32
65
|
end
|
@@ -70,7 +103,7 @@ module Taxonifi
|
|
70
103
|
by_name_index[rank][name.name_author_year_string].each do |id|
|
71
104
|
full_parent_vector = parent_id_vector(name.parent.id)
|
72
105
|
return id if full_parent_vector == parent_id_vector(id) # this hits species/genus group names
|
73
|
-
|
106
|
+
|
74
107
|
vector = parent_id_vector(id)
|
75
108
|
next if vector.last != name.parent.id # can stop looking at this possiblity
|
76
109
|
vector.pop # compare just parents
|
@@ -83,20 +116,60 @@ module Taxonifi
|
|
83
116
|
false
|
84
117
|
end
|
85
118
|
|
86
|
-
# Add an
|
119
|
+
# Add an individual Name instance, indexing it.
|
87
120
|
def add_object(obj)
|
88
121
|
super
|
89
122
|
index_by_name(obj)
|
123
|
+
derive_nomenclator(obj) if obj.nomenclator_name?
|
90
124
|
obj
|
91
125
|
end
|
92
126
|
|
93
|
-
# Add an individaul
|
127
|
+
# Add an individaul Name instance, without indexing it.
|
94
128
|
def add_object_pre_indexed(obj)
|
95
129
|
super
|
96
130
|
index_by_name(obj)
|
97
131
|
obj
|
98
132
|
end
|
99
133
|
|
134
|
+
# TODO: Test
|
135
|
+
def derive_nomenclator(obj)
|
136
|
+
if obj.nomenclator_name? && !obj.authors.nil? && !obj.year.nil?
|
137
|
+
add_nomenclator(obj.nomenclator_array)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Add a Nomenclator (Array) to the index.
|
142
|
+
# Returns the index of the Nomenclator added.
|
143
|
+
# TODO: Test
|
144
|
+
def add_nomenclator(nomenclator_array)
|
145
|
+
raise if (!nomenclator_array.class == Array) || (nomenclator_array.length != 5)
|
146
|
+
if @nomenclators.has_value?(nomenclator_array)
|
147
|
+
return @nomenclators.key(nomenclator_array)
|
148
|
+
else
|
149
|
+
@nomenclators.merge!(@nomenclator_index => nomenclator_array)
|
150
|
+
@nomenclator_index += 1
|
151
|
+
return @nomenclator_index - 1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Return the Integer (index) for a name
|
156
|
+
def nomenclator_id_for_name(name)
|
157
|
+
@nomenclators.key(name.nomenclator_array)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Add a Citation
|
161
|
+
# Returns the index of the Nomenclator added.
|
162
|
+
# TODO: Test/Validate
|
163
|
+
def add_citation(name, ref, nomenclator_index, properties)
|
164
|
+
if @citations[name.id]
|
165
|
+
return false if @citations[name.id].collect{|i| [i[0],i[1]] }.include?([ref.id, nomenclator_index])
|
166
|
+
@citations[name.id].push([ref.id, nomenclator_index, properties])
|
167
|
+
else
|
168
|
+
@citations[name.id] = [[ref.id, nomenclator_index, properties]]
|
169
|
+
end
|
170
|
+
true
|
171
|
+
end
|
172
|
+
|
100
173
|
# Add a Taxonifi::Model::SpeciesName object
|
101
174
|
# as individual objects.
|
102
175
|
def add_species_name(sn)
|
@@ -126,24 +199,17 @@ module Taxonifi
|
|
126
199
|
end
|
127
200
|
end
|
128
201
|
|
129
|
-
#
|
130
|
-
def name_string_array
|
131
|
-
collection.collect{|n| n.display_name}
|
132
|
-
end
|
133
|
-
|
134
|
-
|
135
|
-
# Take the author/years of these names and generate a reference collection.
|
202
|
+
# Take the author/years of these names and generate a RefCollection.
|
136
203
|
# Start the ids assigned to the references with initial_id.
|
137
204
|
def generate_ref_collection(initial_id = 0)
|
138
205
|
rc = Taxonifi::Model::RefCollection.new(:initial_id => initial_id)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
end
|
206
|
+
temp_index = {}
|
207
|
+
@collection.each do |n|
|
208
|
+
index = n.author_year_index
|
209
|
+
if !temp_index[index] && index.size > 0
|
210
|
+
temp_index.merge!(index => nil)
|
211
|
+
ref = Taxonifi::Model::Ref.new(authors: n.authors, year: n.year)
|
212
|
+
rc.add_object(ref)
|
147
213
|
end
|
148
214
|
end
|
149
215
|
@ref_collection = rc
|
@@ -152,10 +218,10 @@ module Taxonifi
|
|
152
218
|
# Assign a reference collection to this name collection.
|
153
219
|
# !! Overwrites existing reference collection, including ones built
|
154
220
|
# using generate_ref_collection.
|
155
|
-
def ref_collection=(ref_collection)
|
221
|
+
def ref_collection=(ref_collection = Taxonifi::Model::RefCollection)
|
156
222
|
@ref_collection = ref_collection if ref_collection.class == Taxonifi::Model::RefCollection
|
157
223
|
end
|
158
|
-
|
224
|
+
|
159
225
|
# Return an Array of "homonyms" within the rank
|
160
226
|
# provided. Useful for finding missmatched upper heirarchies,
|
161
227
|
# if nc is a name_collection:
|
@@ -169,7 +235,7 @@ module Taxonifi
|
|
169
235
|
# end
|
170
236
|
#
|
171
237
|
def homonyms_at_rank(rank)
|
172
|
-
|
238
|
+
raise if !RANKS.include?(rank)
|
173
239
|
uniques = {}
|
174
240
|
names_at_rank(rank).each do |n|
|
175
241
|
uniques.merge!(n.name => []) if !uniques[n.name]
|
@@ -179,12 +245,47 @@ module Taxonifi
|
|
179
245
|
uniques
|
180
246
|
end
|
181
247
|
|
248
|
+
# Add a record to @duplicate_entry_buffer
|
249
|
+
def add_duplicate_entry_metadata(name_id, row_identifier, data_hash)
|
250
|
+
@duplicate_entry_buffer[name_id] = Hash.new if !@duplicate_entry_buffer[name_id]
|
251
|
+
@duplicate_entry_buffer[name_id].merge!(row_identifier => data_hash)
|
252
|
+
end
|
253
|
+
|
254
|
+
# For all species group names, assigns to property 'original_genus_id' the id of the parent genus group name if parens are not set.
|
255
|
+
# Returns an Array of ids for those names for which the property has *NOT* been set.
|
256
|
+
def add_original_genus_id_property
|
257
|
+
not_added = []
|
258
|
+
by_name_index['species_group'].values.flatten.uniq.each do |id|
|
259
|
+
name = object_by_id(id)
|
260
|
+
if name.parens != true
|
261
|
+
name.add_property('original_genus_id', name.genus_group_parent.id)
|
262
|
+
else
|
263
|
+
not_added.push(name.id)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
not_added
|
267
|
+
end
|
268
|
+
|
269
|
+
# Return an Array of Strings
|
270
|
+
def genus_group_name_strings
|
271
|
+
by_name_index['genus_group'].keys
|
272
|
+
end
|
273
|
+
|
274
|
+
# Return an Array of Strings
|
275
|
+
def species_group_name_strings
|
276
|
+
by_name_index['species_group'].keys
|
277
|
+
end
|
278
|
+
|
279
|
+
# Return an array of the names in the collection
|
280
|
+
# DEPRECATE for name_strings
|
281
|
+
def name_string_array
|
282
|
+
collection.collect{|n| n.display_name}
|
283
|
+
end
|
284
|
+
|
182
285
|
protected
|
183
286
|
|
184
|
-
# Index the object by name into the
|
185
|
-
#
|
186
|
-
# {"Foo bar" => [1,2,93]})
|
187
|
-
# Pass a Taxonifi::Name
|
287
|
+
# Index the object by name into the @by_name_index variable
|
288
|
+
# Pass a Taxonifi::Name
|
188
289
|
def index_by_name(name)
|
189
290
|
rank = name.rank
|
190
291
|
rank = 'species_group' if %w{species subspecies variety}.include?(rank)
|
data/lib/{models → model}/ref.rb
RENAMED
@@ -71,12 +71,14 @@ module Taxonifi
|
|
71
71
|
s
|
72
72
|
end
|
73
73
|
|
74
|
-
# Return a
|
74
|
+
# Return a Taxonifi::Model::AuthorYear representing author/year
|
75
|
+
# !! Identical to method in Taxonifi::Model::Name
|
76
|
+
# !! *Not* necessarily unique.
|
75
77
|
def author_year_index
|
76
78
|
@author_year_index ||= generate_author_year_index
|
77
79
|
end
|
78
80
|
|
79
|
-
# (
|
81
|
+
# (Re-) generate the author year index.
|
80
82
|
def generate_author_year_index
|
81
83
|
@author_year_index = Taxonifi::Model::AuthorYear.new(people: @authors, year: @year).compact_index
|
82
84
|
end
|