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


63
64
65
66
67
68
69
70
# File 'lib/vendor/biodiversity.rb', line 63

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 `



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

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



56
57
58
# File 'lib/vendor/biodiversity.rb', line 56

def combination
  @combination
end

- (Combination) disambiguated_combination (readonly)

Returns a memoized result of disambiguated_combination

Returns:

  • (Combination)

    a memoized result of disambiguated_combination



52
53
54
# File 'lib/vendor/biodiversity.rb', line 52

def disambiguated_combination
  @disambiguated_combination
end

- (Object) mode

how to match



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

def mode
  @mode
end

- (Object) name

query string



19
20
21
# File 'lib/vendor/biodiversity.rb', line 19

def name
  @name
end

- (Object) nomenclature_code

one of :iczn, :icn, :icnb



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

def nomenclature_code
  @nomenclature_code
end

- (Object) parse_result

the result of a ScientificNameParser parse



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

def parse_result
  @parse_result
end

- (Boolean) parseable (readonly)

Returns:

  • (Boolean)


95
96
97
# File 'lib/vendor/biodiversity.rb', line 95

def parseable
  @parseable
end

- (Object) project_id

project to query against



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

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



48
49
50
# File 'lib/vendor/biodiversity.rb', line 48

def protonym_result
  @protonym_result
end

- (Hash) result (readonly)

Returns summary for rendering purposes

Returns:

  • (Hash)

    summary for rendering purposes



39
40
41
# File 'lib/vendor/biodiversity.rb', line 39

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?!



237
238
239
240
241
242
243
# File 'lib/vendor/biodiversity.rb', line 237

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)


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

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

- (Object) author_word_position



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

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



187
188
189
# File 'lib/vendor/biodiversity.rb', line 187

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

- (Hash?) authorship

Returns the Biodiversity authorship hash

Returns:

  • (Hash, nil)

    the Biodiversity authorship hash



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

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)


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

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

- (Hash) build_result

Returns:

  • (Hash)


354
355
356
357
358
359
360
361
362
# File 'lib/vendor/biodiversity.rb', line 354

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



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

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

- (Hash) detail

Returns:

  • (Hash)


107
108
109
110
111
112
113
114
# File 'lib/vendor/biodiversity.rb', line 107

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:



251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/vendor/biodiversity.rb', line 251

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`



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

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

- (String?) form

Returns:

  • (String, nil)


142
143
144
# File 'lib/vendor/biodiversity.rb', line 142

def form
  infraspecies('form')
end

- (String?) genus

Returns:

  • (String, nil)


117
118
119
# File 'lib/vendor/biodiversity.rb', line 117

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)


302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/vendor/biodiversity.rb', line 302

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)


147
148
149
150
151
152
153
154
# File 'lib/vendor/biodiversity.rb', line 147

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)


216
217
218
# File 'lib/vendor/biodiversity.rb', line 216

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



206
207
208
209
210
211
212
213
# File 'lib/vendor/biodiversity.rb', line 206

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



158
159
160
# File 'lib/vendor/biodiversity.rb', line 158

def name_count 
  detail.keys.count
end

- (Object) name_without_author_year



397
398
399
# File 'lib/vendor/biodiversity.rb', line 397

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



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/vendor/biodiversity.rb', line 405

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 = ?', 
    Utilities::Strings.nil_wrap('<i>', name_without_author_year, '</i>')
  ).all.to_a if parseable

  h
end

- (@parse_result) parse

Returns a Biodiversity name parser result

Returns:

  • (@parse_result)

    a Biodiversity name parser result



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/vendor/biodiversity.rb', line 74

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)


336
337
338
339
340
341
342
343
344
345
# File 'lib/vendor/biodiversity.rb', line 336

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



102
103
104
# File 'lib/vendor/biodiversity.rb', line 102

def preparse
  name.split(' in ')
end

- (Scope) protonyms(rank)

Parameters:

  • rank (Symbol)

    like `:genus` or `:species`

Returns:

  • (Scope)


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

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



295
296
297
# File 'lib/vendor/biodiversity.rb', line 295

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


318
319
320
321
# File 'lib/vendor/biodiversity.rb', line 318

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



370
371
372
373
374
375
376
# File 'lib/vendor/biodiversity.rb', line 370

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)


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

def species
  detail[:species] && detail[:species][:string]
end

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

Parameters:

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

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

Returns:

  • (String, false)


267
268
269
# File 'lib/vendor/biodiversity.rb', line 267

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

- (String?) subgenus

Returns:

  • (String, nil)


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

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

- (String?) subspecies

Returns:

  • (String, nil)


132
133
134
# File 'lib/vendor/biodiversity.rb', line 132

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



223
224
225
226
227
228
229
230
231
232
# File 'lib/vendor/biodiversity.rb', line 223

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)


137
138
139
# File 'lib/vendor/biodiversity.rb', line 137

def variety
  infraspecies('var.')
end

- (String?) year

Returns:

  • (String, nil)


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

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