Class: Source

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
Housekeeping::Timestamps, Housekeeping::Users, Shared::AlternateValues, Shared::DataAttributes, Shared::Documentation, Shared::HasRoles, Shared::Identifiable, Shared::IsData, Shared::Notable, Shared::SharedAcrossProjects, Shared::Taggable
Defined in:
app/models/source.rb

Overview

A Source is the metadata that identifies the origin of some information/data.

The primary purpose of Source metadata is to allow the user to find the source, that's all.

See en.wikipedia.org/wiki/BibTeX for a definition of attributes, in nearly all cases they are 1:1 with the TW model. We use this github.com/inukshuk/bibtex-ruby awesomeness. See github.com/inukshuk/bibtex-ruby/tree/master/lib/bibtex/entry, in particular rdf_converter.rb for the types of field managed.

Direct Known Subclasses

Bibtex, Human, Verbatim

Defined Under Namespace

Classes: Bibtex, Human, Verbatim

Constant Summary

ALTERNATE_VALUES_FOR =
[:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
:publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

Instance Attribute Summary (collapse)

Attributes included from Housekeeping::Users

#by

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods included from Housekeeping::Timestamps

#data_breakdown_for_chartkick_recent

Methods included from Housekeeping::Users

#set_created_by_id, #set_updated_by_id

Instance Attribute Details

- (String) abstract

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) address

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) annote

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) author

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) bibtex_type

Returns alias for “type” in the bibtex framework see en.wikipedia.org/wiki/BibTeX#Field_types

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) booktitle

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) cached

Returns calculated full citation, searched again in “full text”

Returns:

  • (String)

    calculated full citation, searched again in “full text”



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) cached_author_string

Returns calculated author string

Returns:

  • (String)

    calculated author string



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (DateTime) cached_nomenclature_date

Returns Date sensu nomenclature algorithm in TaxonWorks (see Utilities::Dates)

Returns:

  • (DateTime)

    Date sensu nomenclature algorithm in TaxonWorks (see Utilities::Dates)



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) chapter

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) crossref

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (Integer) day

TODO:

Returns:

  • (Integer)


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) doi

Returns When provided also cloned to an Identifier::Global. See en.wikipedia.org/wiki/BibTeX#Field_types

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) edition

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) editor

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) howpublished

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) institution

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) isbn

TODO:

Returns:

  • (String)


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) issn

TODO:

Returns:

  • (String)


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) journal

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) key

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) language

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (Integer) language_id

Returns The TaxonWorks normalization of language to Language.

Returns:

  • (Integer)

    The TaxonWorks normalization of language to Language.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) month

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) note

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) number

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) organization

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) pages

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) publisher

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) school

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (Integer) serial_id

Returns The TaxonWorks Serial

Returns:

  • (Integer)

    The TaxonWorks Serial



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) series

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) stated_year

TODO:

Returns:

  • (String)


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.new_from_bibtex(b)
    end
    false
  end

  def self.batch_preview(file: nil, ** args)
    bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
    @sources     = []
    bibliography.each do |record|
      a = Source::Bibtex.new_from_bibtex(record)
      # v = a.valid?
      a.soft_validate()
      @sources.push(a)
    end
    @sources
  end

  def self.batch_create(file: nil, ** args)
    @sources = []
    @valid   = 0
    begin
      error_msg = []
      Source.transaction do
        bibliography = BibTeX.parse(file.read.force_encoding('UTF-8'))
        bibliography.each do |record|
          a = Source::Bibtex.new_from_bibtex(record)
          if a.valid?
            if a.save
              @valid += 1
            end
            a.soft_validate()
          else
            error_msg = a.errors.messages.to_s
          end
          @sources.push(a)
        end
      end
    rescue
      return false
    end
    {records: @sources, count: @valid}
  end

  # TODO: remove and use code in  Shared::IsData::Levenshtein
  def nearest_by_levenshtein(compared_string: nil, column: 'cached', limit: 10)
    return Source.none if compared_string.nil?
    order_str = Source.send(:sanitize_sql_for_conditions, ["levenshtein(sources.#{column}, ?)", compared_string])
    Source.where('id <> ?', self.to_param).
      order(order_str).
      limit(limit)
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  def is_bibtex?
    type == 'Source::Bibtex'
  end

  protected

  def set_cached
    # in subclasses
  end

end

- (String) title

Returns:



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'app/models/source.rb', line 184

class Source < ActiveRecord::Base
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::HasRoles
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::Taggable
  include Shared::IsData
  include Shared::Documentation

  has_paper_trail

  ALTERNATE_VALUES_FOR = [:address, :annote, :booktitle, :edition, :editor, :institution, :journal, :note, :organization,
                          :publisher, :school, :title, :doi, :abstract, :language, :translator, :author, :url].freeze

  has_many :asserted_distributions, through: :citations, source: :citation_object, source_type: 'AssertedDistribution'
  has_many :citations, inverse_of: :source, dependent: :restrict_with_error 
  has_many :project_sources, dependent: :destroy
  has_many :projects, through: :project_sources

  before_save :set_cached

  validates_presence_of :type

  accepts_nested_attributes_for :project_sources, reject_if: :reject_project_sources
 
  def reject_project_sources(attributed)
    return true if attributed['project_id'].blank? 
    return true if ProjectSource.where(project_id: attributed['project_id'], source_id: id).any?
  end 

  def cited_objects
    self.citations.collect { |t| t.citation_object }
  end

  # Create a new Source instance from a full text citatation.  By default
  # try to resolve the citation against Crossref, use the returned
  # bibtex to populate the object if it successfully resolves.
  #
  # Once created followup with .create_related_people_and_roles to create related people.
  #
  # @param citation [String] the full text of the citation to convert
  # @param resolve [Boolean] whether to resolve against CrossRef, if false then creates a verbatim instance
  # @return [Source::BibTex.new] a new instance
  # @return [Source::Verbatim.new] a new instance
  # @return [false]
  def self.new_from_citation(citation: nil, resolve: true)
    return false if citation.length < 6
    bibtex_string = Ref2bibtex.get(citation) if resolve
    # check string encoding, if not UTF-8, check if compatible with UTF-8,
    # if so convert to UTF-8 and parse with latex, else use type verbatim
    if bibtex_string
      unless bibtex_string.encoding == Encoding::UTF_8
        x = 'test'.encode(Encoding::UTF_8)
        if Encoding.compatible?(x, bibtex_string)
          bibtex_string.force_encoding(Encoding::UTF_8)
        else
          return Source::Verbatim.new(verbatim: citation)
        end
      end

      bibliography = BibTeX.parse(bibtex_string).convert(:latex)
      b = bibliography.first
      return Source::Bibtex.new_from_bibtex(b)
    else
      return Source::Verbatim.new(verbatim: citation)
    end
  end

  def self.new_from_doi(doi: nil)
    return false unless doi
    bibtex_string = Ref2bibtex.get_bibtex(doi)
    if bibtex_string
      b = BibTeX.parse(bibtex_string).first
      return Source::Bibtex.