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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +59 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +5 -17
  5. data/Gemfile.lock +22 -40
  6. data/README.md +192 -0
  7. data/Rakefile +35 -26
  8. data/lib/export/format/base.rb +1 -1
  9. data/lib/export/format/species_file.rb +154 -152
  10. data/lib/lumper/clump.rb +1 -1
  11. data/lib/lumper/lumper.rb +22 -18
  12. data/lib/lumper/lumps/parent_child_name_collection.rb +1 -2
  13. data/lib/lumper/name_index.rb +21 -0
  14. data/lib/{models → model}/author_year.rb +2 -2
  15. data/lib/{models → model}/base.rb +35 -5
  16. data/lib/{models → model}/collection.rb +8 -1
  17. data/lib/{models → model}/name.rb +128 -36
  18. data/lib/{models → model}/name_collection.rb +134 -33
  19. data/lib/{models → model}/person.rb +1 -1
  20. data/lib/{models → model}/ref.rb +4 -2
  21. data/lib/model/ref_collection.rb +171 -0
  22. data/lib/{models → model}/species_name.rb +24 -3
  23. data/lib/splitter/builder.rb +1 -1
  24. data/lib/splitter/parser.rb +5 -0
  25. data/lib/splitter/tokens.rb +54 -9
  26. data/lib/taxonifi/version.rb +3 -0
  27. data/lib/taxonifi.rb +5 -9
  28. data/taxonifi.gemspec +29 -99
  29. data/test/helper.rb +1 -1
  30. data/test/test_exporter.rb +1 -1
  31. data/test/test_lumper_names.rb +9 -9
  32. data/test/test_lumper_refs.rb +4 -4
  33. data/test/test_parser.rb +97 -26
  34. data/test/test_splitter_tokens.rb +25 -4
  35. data/test/test_taxonifi_base.rb +1 -1
  36. data/test/test_taxonifi_geog.rb +1 -1
  37. data/test/test_taxonifi_name.rb +13 -14
  38. data/test/test_taxonifi_name_collection.rb +11 -5
  39. data/test/test_taxonifi_ref.rb +1 -1
  40. data/test/test_taxonifi_ref_collection.rb +40 -3
  41. data/test/test_taxonifi_species_name.rb +51 -1
  42. data/travis/before_install.sh +2 -0
  43. metadata +96 -66
  44. data/README.rdoc +0 -154
  45. data/VERSION +0 -1
  46. data/lib/models/ref_collection.rb +0 -107
  47. /data/lib/{models → model}/generic_object.rb +0 -0
  48. /data/lib/{models → model}/geog.rb +0 -0
  49. /data/lib/{models → model}/geog_collection.rb +0 -0
  50. /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 hash populable as needed for related metadata
20
- attr_accessor :related
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
- @related = {}
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, authors as originally read
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
- # A Taxonifi::Model::Name General purpose relationship, typically used to indicate synonymy.
25
+ # A Taxonifi::Model::Name
26
+ # A general purpose relationship, typically used to indicate synonymy.
26
27
  attr_accessor :related_name
27
28
 
28
- # Array, contains properties assignable in Taxonifi::Model::Name#new()
29
- @@ATTRIBUTES = [:name, :rank, :year, :parens, :parent, :author, :related_name]
29
+ # A Taxonifi::Model::Reference
30
+ # The original description.
31
+ attr_accessor :original_description_reference
30
32
 
31
- # optionally parsed/index
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
- # optionally parsed/index
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
- add_author_year(opts[:author_year]) if !opts[:author_year].nil? && opts[:author_year].size > 0
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
- @id = opts[:id] # if !opts[:id].nil? && opts[:id].size != 0
48
- @authors ||= []
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=(rank)
67
- r = rank.to_s.downcase.strip
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
- au = [self.author, self.year].compact.join(", ")
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
- # Return the human readable version of this name with author year (String)
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 names indexed by author_year.
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/return the author year index.
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 by-name (string index)
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' => {} } # "foo => [1,2,3]"
22
- Taxonifi::RANKS[0..-5].inject(@by_name_index){|hsh, v| hsh.merge!(v => {})} # Lumping species and genus group names
23
-
24
- @by_name_index['unknown'] = {} # unranked names get dumped in here
25
- @ref_collection = nil
26
- @combinations = []
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 individaul name object, indexing it.
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 name object, without indexing it.
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
- # Return an array of the names in the collection
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
- if collection.size > 0
140
- uniques = collection.inject({}){|hsh, n| hsh.merge!(n.author_year_string => nil)}.keys.compact
141
- if uniques.size > 0
142
- uniques.sort.each_with_index do |r, i|
143
- next if r.size == 0
144
- ref = Taxonifi::Model::Ref.new(:author_year => r)
145
- rc.add_object(ref)
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
- raise if !RANKS.include?(rank)
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
- # @by_name_index variable (this looks like:
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)
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "../models/base.rb"))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "../model/base.rb"))
2
2
 
3
3
  module Taxonifi
4
4
  module Model
@@ -71,12 +71,14 @@ module Taxonifi
71
71
  s
72
72
  end
73
73
 
74
- # Return a by author_year index.
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
- # (re-) generate the author year index.
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