Class: TaxonWorks::Vendor::Biodiversity::Result

Inherits:
Object
  • Object
show all
Defined in:
lib/vendor/biodiversity.rb

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Result) initialize(query_string: nil, project_id: nil, code: :iczn, match_mode: :groups)

query_string:

mode:

ranked: return names at that queried rank only (e.g. only match a subgenus to rank subgenus
groups: return names at Group level (species or genus), i.e. a subgenus name in query will match genus OR subgenus in database


69
70
71
72
73
74
75
76
# File 'lib/vendor/biodiversity.rb', line 69

def initialize(query_string: nil, project_id: nil, code: :iczn, match_mode: :groups)
  @project_id = project_id
  @name = query_string
  @nomenclature_code = code
  @mode = match_mode

  parse if !query_string.blank?
end

Instance Attribute Details

- (String) citation (readonly)

Returns the bit after ` in `

Returns:

  • (String)

    the bit after ` in `



46
47
48
# File 'lib/vendor/biodiversity.rb', line 46

def citation
  @citation
end

- (Combination) combination (readonly)

Returns ranks that are unambiguous have their Protonym set

Returns:

  • (Combination)

    ranks that are unambiguous have their Protonym set



62
63
64
# File 'lib/vendor/biodiversity.rb', line 62

def combination
  @combination
end

- (Combination) disambiguated_combination (readonly)

Returns a memoized result of disambiguated_combination

Returns:

  • (Combination)

    a memoized result of disambiguated_combination



58
59
60
# File 'lib/vendor/biodiversity.rb', line 58

def disambiguated_combination
  @disambiguated_combination
end

- (Object) mode

how to match



26
27
28
# File 'lib/vendor/biodiversity.rb', line 26

def mode
  @mode
end

- (Object) name

query string



23
24
25
# File 'lib/vendor/biodiversity.rb', line 23

def name
  @name
end

- (Object) nomenclature_code

one of :iczn, :icn, :icnb



32
33
34
# File 'lib/vendor/biodiversity.rb', line 32

def nomenclature_code
  @nomenclature_code
end

- (Object) parse_result

the result of a ScientificNameParser parse



35
36
37
# File 'lib/vendor/biodiversity.rb', line 35

def parse_result
  @parse_result
end

- (Boolean) parseable (readonly)

Returns:

  • (Boolean)


50
51
52
# File 'lib/vendor/biodiversity.rb', line 50

def parseable
  @parseable
end

- (Object) project_id

project to query against



29
30
31
# File 'lib/vendor/biodiversity.rb', line 29

def project_id
  @project_id
end

- (Hash) protonym_result (readonly)

Returns we inspect this internally, so it has to be decoupled

Returns:

  • (Hash)

    we inspect this internally, so it has to be decoupled



54
55
56
# File 'lib/vendor/biodiversity.rb', line 54

def protonym_result
  @protonym_result
end

- (Hash) result (readonly)

Returns summary for rendering purposes

Returns:

  • (Hash)

    summary for rendering purposes



43
44
45
# File 'lib/vendor/biodiversity.rb', line 43

def result
  @result
end

Instance Method Details

- (Array) ambiguous_ranks

Returns the ranks, as symbols, at which there are multiple (>1) Protonym matches !! subtly different than unambiguous_at, probably should use that?!

Returns:

  • (Array)

    the ranks, as symbols, at which there are multiple (>1) Protonym matches !! subtly different than unambiguous_at, probably should use that?!



245
246
247
248
249
250
251
# File 'lib/vendor/biodiversity.rb', line 245

def ambiguous_ranks
  a = [ ]
  protonym_result.each do |k, v|
    a.push k if v.count > 1
  end
  a 
end

- (String?) author

Returns:

  • (String, nil)


187
188
189
190
191
192
193
# File 'lib/vendor/biodiversity.rb', line 187

def author
  if a = authorship
    Utilities::Strings.authorship_sentence(a[:author])
  else
    nil
  end
end

- (Object) author_word_position



397
398
399
400
401
402
403
404
# File 'lib/vendor/biodiversity.rb', line 397

def author_word_position 
  if a = parse_result[:scientificName] 
    if b = a[:positions]
      c = b.select{|k,v| v[0] == 'author_word'}.keys.min
      p = [name.length, c].compact.min 
    end
  end
end

- (Object) author_year



195
196
197
# File 'lib/vendor/biodiversity.rb', line 195

def author_year
  [author, year].compact.join(', ')
end

- (Hash?) authorship

Returns the Biodiversity authorship hash

Returns:

  • (Hash, nil)

    the Biodiversity authorship hash



180
181
182
183
184
# File 'lib/vendor/biodiversity.rb', line 180

def authorship
  d = detail[RANK_MAP[finest_rank]]
  d = d.last if d.kind_of?(Array)
  d[:basionymAuthorTeam]
end

- (Scope) basic_scope(rank)

Parameters:

  • rank (Symbol)

    like `:genus` or `:species`

Returns:

  • (Scope)


282
283
284
285
286
287
# File 'lib/vendor/biodiversity.rb', line 282

def basic_scope(rank)
  Protonym.where(
    project_id: project_id,
    name: string(rank)
  )
end

- (Hash) build_result

Returns:

  • (Hash)


363
364
365
366
367
368
369
370
371
# File 'lib/vendor/biodiversity.rb', line 363

def build_result
  @result = {}
  @result[:protonyms] = protonym_result
  @result[:parse] = parse_values
  @result[:unambiguous] = is_unambiguous?
  @result[:existing_combination_id] = combination_exists?.try(:id)
  @result[:other_matches] = other_matches
  @result
end

- (Combination, false) combination_exists?

Returns the Combination, if it exists

Returns:

  • (Combination, false)

    the Combination, if it exists



389
390
391
392
393
394
395
# File 'lib/vendor/biodiversity.rb', line 389

def combination_exists?
  if is_unambiguous?
    Combination.match_exists?(combination.protonym_ids_params) # TODO: pass name?
  else
    false
  end
end

- (Hash) detail

Returns:

  • (Hash)


113
114
115
116
117
118
119
120
# File 'lib/vendor/biodiversity.rb', line 113

def detail
  if parseable 
    a = parse_result[:scientificName]
    a ||= parse_result[:uninomial]
    return a[:details].first if a[:details]                 
  end
  {}
end

- (Combination) disambiguate_combination(target_protonym_ids = {})

Parameters:

  • target_protonym_ids (Hash) (defaults to: {})

    like like `123, species: 345` Given a targeted list of ids checks to see if

    a) there is an *ambiguous* result at the rank AND
    b) there is a Protonym with the id provided in the ambiguous result

    If a and b are both true then the combination once ambiguous result is set to the id provided in targeted_protonym_ids

Returns:



259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/vendor/biodiversity.rb', line 259

def disambiguate_combination(target_protonym_ids = {})
  return nil unless target_protonym_ids.any?
  c = combination
  b = ambiguous_ranks

  target_protonym_ids.each do |rank, id|
    if b.include?(rank)
      c.send("#{rank}_id=", id) if protonym_result[rank].map(&:id).include?(id)
    end
  end
  @disambiguated_combination = c
end

- (Symbol?) finest_rank

Returns like `:genus`

Returns:

  • (Symbol, nil)

    like `:genus`



171
172
173
174
175
176
# File 'lib/vendor/biodiversity.rb', line 171

def finest_rank
  RANK_MAP.keys.reverse.each do |k|
    return k if send(k)
  end
  nil
end

- (String?) form

Returns:

  • (String, nil)


150
151
152
# File 'lib/vendor/biodiversity.rb', line 150

def form
  infraspecies('form')
end

- (String?) genus

Returns:

  • (String, nil)


123
124
125
# File 'lib/vendor/biodiversity.rb', line 123

def genus
  (detail[:genus] && detail[:genus][:string]) || (detail[:uninomial] && detail[:uninomial][:string])
end

- (Scope) grouped_protonyms(rank)

Parameters:

  • rank (Symbol)

    like `:genus` or `:species` Protonyms grouped by nomenclatural group, for a rank

Returns:

  • (Scope)


311
312
313
314
315
316
317
318
319
320
321
322
# File 'lib/vendor/biodiversity.rb', line 311

def grouped_protonyms(rank)
  s = case rank
      when :genus, :subgenus
        basic_scope(rank).is_genus_group
      when :species, :subspecies, :variety, :form
        basic_scope(rank).is_species_group
      else
        Protonym.none
      end

  (is_authored? && finest_rank == rank) ? scope_to_author_year(s) : s
end

- (String?) infraspecies(biodiversity_rank)

Returns:

  • (String, nil)


155
156
157
158
159
160
161
162
# File 'lib/vendor/biodiversity.rb', line 155

def infraspecies(biodiversity_rank)
  if m = detail[:infraspecies]
    m.each do |n|
      return n[:string] if n[:rank] == biodiversity_rank
    end
  end
  nil 
end

- (Boolean) is_authored?

Returns:

  • (Boolean)


224
225
226
# File 'lib/vendor/biodiversity.rb', line 224

def is_authored?
  author_year.size > 0
end

- (Boolean) is_unambiguous?

Returns true if for each parsed piece of there name there is 1 and only 1 result

Returns:

  • (Boolean)

    true if for each parsed piece of there name there is 1 and only 1 result



214
215
216
217
218
219
220
221
# File 'lib/vendor/biodiversity.rb', line 214

def is_unambiguous?
  RANK_MAP.each_key do |r|
    if !send(r).nil?
      return false unless !send(r).nil? && !unambiguous_at?(r).nil?
    end
  end
  true
end

- (Integer) name_count

Returns the total monomials in the epithet

Returns:

  • (Integer)

    the total monomials in the epithet



166
167
168
# File 'lib/vendor/biodiversity.rb', line 166

def name_count 
  detail.keys.count
end

- (Object) name_without_author_year



406
407
408
# File 'lib/vendor/biodiversity.rb', line 406

def name_without_author_year
  name[0..author_word_position - 1].strip 
end

- (Hash) other_matches

Returns `:verbatim` - names that have verbatim supplied, these should be the only names NOT parsed that user is interested in `:subgenus` - names that exactly match a subgenus, these are potential new combinations as Genus alone `:original_combination` - names that exactly match the original combination

Returns:

  • (Hash)

    `:verbatim` - names that have verbatim supplied, these should be the only names NOT parsed that user is interested in `:subgenus` - names that exactly match a subgenus, these are potential new combinations as Genus alone `:original_combination` - names that exactly match the original combination



414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/vendor/biodiversity.rb', line 414

def other_matches
  h = { 
    verbatim: [],
    subgenus: [], 
    original: []
  }

  h[:verbatim] = TaxonName.where(project_id: project_id, cached: name_without_author_year).
    where('verbatim_name is not null').order(:cached).all.to_a if parseable
  
  h[:subgenus] = Protonym.where(
    project_id: project_id, 
    name: genus, 
    rank_class: Ranks.lookup(nomenclature_code, :subgenus)
  ).all.to_a

  h[:original_combination] = Protonym.where(project_id: project_id). 
    where( cached_original_combination: name_without_author_year
         ).all.to_a if parseable

  h
end

- (@parse_result) parse

Returns a Biodiversity name parser result

Returns:

  • (@parse_result)

    a Biodiversity name parser result



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/vendor/biodiversity.rb', line 80

def parse
  @combination = nil
  @disambiguated_combination = nil

  n, @citation = preparse

  begin
    @parse_result ||= ScientificNameParser.new.parse(n)
  rescue NoMethodError => e
    case e.message
    when /canonical/
      @parseable = false 
    else
      raise
    end
  end

  @parse_result
end

- (Hash) parse_values

Returns:

  • (Hash)


345
346
347
348
349
350
351
352
353
354
# File 'lib/vendor/biodiversity.rb', line 345

def parse_values
  h = {
    author: author,
    year: year
  }
  RANK_MAP.each_key do |r|
    h[r] = send(r)
  end
  h
end

- (Array) preparse

Returns TODO: deprecate

Returns:

  • (Array)

    TODO: deprecate



108
109
110
# File 'lib/vendor/biodiversity.rb', line 108

def preparse
  name.split(' in ')
end

- (Scope) protonyms(rank)

Parameters:

  • rank (Symbol)

    like `:genus` or `:species`

Returns:

  • (Scope)


291
292
293
294
295
296
297
298
299
300
# File 'lib/vendor/biodiversity.rb', line 291

def protonyms(rank)
  case mode
  when :ranked
    ranked_protonyms(rank)
  when :groups
    grouped_protonyms(rank)
  else
    Protonym.none
  end
end

- (Scope) ranked_protonyms(rank)

Returns Protonyms at a given rank

Returns:

  • (Scope)

    Protonyms at a given rank



304
305
306
# File 'lib/vendor/biodiversity.rb', line 304

def ranked_protonyms(rank)
  basic_scope(rank).where(rank_class: Ranks.lookup(nomenclature_code, rank))
end

- (Scope) scope_to_author_year(scope)

Returns if there is an exact author year match scope it to that match, otherwise

ignore the author year

Returns:

  • (Scope)

    if there is an exact author year match scope it to that match, otherwise

    ignore the author year


327
328
329
330
# File 'lib/vendor/biodiversity.rb', line 327

def scope_to_author_year(scope)
  t = scope.where('(cached_author_year = ? OR cached_author_year = ?)', author_year, author_year.gsub(' & ', ' and '))
  t.count > 0 ? t : scope
end

- (Object) set_combination



379
380
381
382
383
384
385
# File 'lib/vendor/biodiversity.rb', line 379

def set_combination
  c = Combination.new
  RANK_MAP.each_key do |r|
    c.send("#{r}=", unambiguous_at?(r))
  end
  c
end

- (String?) species

Returns:

  • (String, nil)


133
134
135
136
137
# File 'lib/vendor/biodiversity.rb', line 133

def species
  a = detail
  (a[:species] && a[:species][:string]) ||
    (a[:annotation_identification] && a[:species] && a[:species][:species] && a[:species][:species][:string]) || nil
end

- (String, false) string(rank = nil)

Returns a wrapper on string returning methods

Parameters:

  • rank (Symbol, String) (defaults to: nil)

    rank is one of `genus`, `subgenus`, `species, `subspecies`, `variety`, `form`

Returns:

  • (String, false)

    a wrapper on string returning methods



276
277
278
# File 'lib/vendor/biodiversity.rb', line 276

def string(rank = nil)
  send(rank)
end

- (String?) subgenus

Returns:

  • (String, nil)


128
129
130
# File 'lib/vendor/biodiversity.rb', line 128

def subgenus
  detail[:infragenus] && detail[:infragenus][:string]
end

- (String?) subspecies

Returns:

  • (String, nil)


140
141
142
# File 'lib/vendor/biodiversity.rb', line 140

def subspecies
  infraspecies('n/a')
end

- (Protonym?) unambiguous_at?(rank)

Returns true if there is a single matching result or nominotypical subs

Parameters:

  • rank (Symbol)

    like `:genus` or `:species`

Returns:

  • (Protonym, nil)

    true if there is a single matching result or nominotypical subs



231
232
233
234
235
236
237
238
239
240
# File 'lib/vendor/biodiversity.rb', line 231

def unambiguous_at?(rank)
  return protonym_result[rank].first if protonym_result[rank].size == 1
  if protonym_result[rank].size == 2
    n1 = protonym_result[rank].first
    n2 = protonym_result[rank].last
    return n2 if n2.nominotypical_sub_of?(n1) 
    return n1 if n1.nominotypical_sub_of?(n2) 
  end
  nil 
end

- (String?) variety

Returns:

  • (String, nil)


145
146
147
# File 'lib/vendor/biodiversity.rb', line 145

def variety
  infraspecies('var.')
end

- (String?) year

Returns:

  • (String, nil)


200
201
202
203
204
205
# File 'lib/vendor/biodiversity.rb', line 200

def year
  if a = authorship
    return a[:year]
  end
  nil
end