• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / pdc_describe / 4e4e59fc-9df4-4838-9fd4-6c7ea33cdb7c

07 Apr 2025 06:36PM UTC coverage: 1.283% (-94.6%) from 95.862%
4e4e59fc-9df4-4838-9fd4-6c7ea33cdb7c

Pull #1994

circleci

hectorcorrea
Switched to use the autocomplete that we aleady use for ROR. Integrated it with the existing logic for creators
Pull Request #1994: Started adding auto complete to contributors

0 of 46 new or added lines in 2 files covered. (0.0%)

4806 existing lines in 74 files now uncovered.

65 of 5065 relevant lines covered (1.28%)

0.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/app/models/dataset_citation.rb
1
# frozen_string_literal: true
2

3
# Handles citations for datasets
4
# rubocop:disable Metrics/ParameterLists
5
# rubocop:disable Metrics/ClassLength
6
# rubocop:disable Style/NumericPredicate
7
# rubocop:disable Style/IfUnlessModifier
UNCOV
8
class DatasetCitation
×
UNCOV
9
  NEWLINE_INDENTED = "\r\n\t\t\t\t\t\t\t\t"
×
10

11
  # @param authors [<String>] Array of authors.
12
  # @param years [<String>] Array of years (expected 1 or 2 values).
13
  # @param title [String>] Title of the dataset
14
  # @param type [String] Type of the dataset (e.g. "Data set" or "Unpublished raw data")
15
  # @publisher [String] Publisher of the dataset
16
  # @doi [String] DOI URL
UNCOV
17
  def initialize(authors, years, title, type, publisher, doi)
×
UNCOV
18
    @authors = authors || []
×
UNCOV
19
    @years = years || []
×
UNCOV
20
    @title = title
×
UNCOV
21
    @type = type
×
UNCOV
22
    @publisher = publisher
×
UNCOV
23
    @doi = doi
×
UNCOV
24
  end
×
25

UNCOV
26
  def to_s(style)
×
UNCOV
27
    if style == "BibTeX"
×
UNCOV
28
      bibtex
×
UNCOV
29
    else
×
UNCOV
30
      apa
×
UNCOV
31
    end
×
UNCOV
32
  end
×
33

34
  # Returns a string with APA-ish citation for the dataset
35
  # Reference: https://libguides.usc.edu/APA7th/datasets#s-lg-box-22855503
UNCOV
36
  def apa
×
UNCOV
37
    apa_title = DatasetCitation.custom_strip(@title)
×
UNCOV
38
    apa_title += " [#{@type}]" if @type.present?
×
UNCOV
39
    apa_title = append_dot(apa_title)
×
40

UNCOV
41
    apa_publisher = append_dot(@publisher)
×
UNCOV
42
    apa_doi = @doi
×
43

UNCOV
44
    tokens = [append_dot(apa_author), append_dot(apa_year), apa_title, apa_publisher, apa_doi].compact_blank
×
UNCOV
45
    tokens.join(" ")
×
UNCOV
46
  rescue => ex
×
47
    Rails.logger.error "Error generating APA citation for (#{@title}): #{ex.message}"
×
48
    nil
×
UNCOV
49
  end
×
50

51
  # Returns a string with BibTeX citation for the dataset.
52
  #
53
  # There is no set standard for datasets and therefore the format we produce
54
  # was put together from a variety of sources including mimicking what Zotero
55
  # does and looking at examples from Zenodo (e.g. https://zenodo.org/record/6062882/export/hx#.Yiejad9OnUL)
56
  #
57
  # Notice that we use the @electronic{...} identifier instead of @dataset{...} since
58
  # Zotero does not recognize the later.
UNCOV
59
  def bibtex
×
UNCOV
60
    tokens = bibtex_checks
×
61

UNCOV
62
    text = "@electronic{#{bibtex_id},\r\n"
×
UNCOV
63
    text += tokens.map { |token| "\t#{token}" }.join(",\r\n") + "\r\n"
×
UNCOV
64
    text += "}"
×
UNCOV
65
    text
×
UNCOV
66
  rescue => ex
×
67
    Rails.logger.error "Error generating BibTex citation for (#{@title}): #{ex.message}"
×
68
    nil
×
UNCOV
69
  end
×
70

71
  # Returns an ID value for a BibTex citation
UNCOV
72
  def bibtex_id
×
UNCOV
73
    author_id = "unknown"
×
UNCOV
74
    if @authors.count > 0
×
UNCOV
75
      author_id = @authors.first.downcase.tr(" ", "_").gsub(/[^a-z0-9_]/, "")
×
UNCOV
76
    end
×
UNCOV
77
    year_id = @years.first&.to_s || "unknown"
×
UNCOV
78
    "#{author_id}_#{year_id}"
×
UNCOV
79
  end
×
80

81
  # Breaks a string into lines of at most max_length.
82
  # Returns an array with the lines.
UNCOV
83
  def bibtex_lines(string, max_length = 40)
×
UNCOV
84
    string = string.to_s # handles non-string values gracefully
×
UNCOV
85
    lines = []
×
UNCOV
86
    until string.nil?
×
87
      # TODO: it would be nice it we break on spaces rather than in the middle of a word.
UNCOV
88
      lines << string[0..max_length - 1]
×
UNCOV
89
      string = string[max_length..-1]
×
UNCOV
90
    end
×
UNCOV
91
    lines
×
UNCOV
92
  end
×
93

94
  # Creates a line to represent a BibTex field.
95
  # Breaks long lines into smaller lines.
96
  # Examples:
97
  #
98
  #     field_name = {{ short value }}
99
  #     field_name = {{ very very very
100
  #                 very very very very
101
  #                 long value }}
102
  #
UNCOV
103
  def bibtex_field(name, value, open_tag = "", close_tag = "")
×
UNCOV
104
    return nil if value.blank?
×
105

UNCOV
106
    value_trim = bibtex_lines(value).join(NEWLINE_INDENTED)
×
UNCOV
107
    name.ljust(12) + "= " + open_tag + value_trim + close_tag
×
UNCOV
108
  end
×
109

110
  # Creates a line to represent multiple authors in a BibTex field
111
  # https://en.wikibooks.org/wiki/LaTeX/Bibliography_Management#Authors
112
  #
113
  # Example:
114
  #
115
  #     author = { author1 and
116
  #              author2 and
117
  #              author3 }
118
  #
UNCOV
119
  def bibtex_field_author(name, authors, open_tag = "{", close_tag = "}")
×
UNCOV
120
    return nil if @authors.count <= 0
×
121

UNCOV
122
    value_trim = authors.join(" and #{NEWLINE_INDENTED}")
×
UNCOV
123
    name.ljust(12) + "= " + open_tag + value_trim + close_tag
×
UNCOV
124
  end
×
125

126
  # Appends a dot to a string if it does not end with one.
UNCOV
127
  def append_dot(value)
×
UNCOV
128
    return nil if value.nil?
×
UNCOV
129
    return "" if value.empty?
×
UNCOV
130
    DatasetCitation.custom_strip(value) + "."
×
UNCOV
131
  end
×
132

133
  # Strip a few specific characters that tend to mess up citations (e.g. trailing periods, commas, et cetera)
UNCOV
134
  def self.custom_strip(value)
×
UNCOV
135
    return nil if value.nil?
×
UNCOV
136
    return "" if value.empty?
×
UNCOV
137
    while true
×
UNCOV
138
      last_char = value[-1]
×
UNCOV
139
      break if last_char.nil? || !last_char.in?(". ,")
×
UNCOV
140
      value = value.chomp(last_char)
×
UNCOV
141
    end
×
UNCOV
142
    value
×
UNCOV
143
  end
×
144

UNCOV
145
  private
×
146

UNCOV
147
    def apa_author
×
UNCOV
148
      apa_author = ""
×
UNCOV
149
      case @authors.count
×
UNCOV
150
      when 0
×
151
        # do nothing
UNCOV
152
      when 1
×
UNCOV
153
        apa_author += @authors.first
×
UNCOV
154
      when 2
×
UNCOV
155
        apa_author += @authors.join(" & ")
×
UNCOV
156
      else
×
UNCOV
157
        apa_author += @authors[0..-2].join(", ") + ", & " + @authors[-1]
×
UNCOV
158
      end
×
UNCOV
159
      apa_author
×
UNCOV
160
    end
×
161

UNCOV
162
    def apa_year
×
UNCOV
163
      apa_year = ""
×
UNCOV
164
      case @years.count
×
UNCOV
165
      when 0
×
166
        # do nothing
UNCOV
167
      when 1
×
UNCOV
168
        apa_year += "(#{@years.first})"
×
UNCOV
169
      else
×
UNCOV
170
        apa_year += "(#{@years.join('-')})"
×
UNCOV
171
      end
×
UNCOV
172
      apa_year
×
UNCOV
173
    end
×
174

UNCOV
175
    def bibtex_checks
×
UNCOV
176
      tokens = []
×
177

UNCOV
178
      tokens << bibtex_field_author("author", @authors)
×
179

UNCOV
180
      tokens << bibtex_field("title", @title, "{{", "}}")
×
181

UNCOV
182
      tokens << bibtex_field("publisher", @publisher, "{{", "}}")
×
183

UNCOV
184
      tokens << bibtex_field("year", @years.first)
×
185

UNCOV
186
      tokens << bibtex_field("url", @doi, "{", "}")
×
187

UNCOV
188
      tokens.compact # remove nil values
×
UNCOV
189
    end
×
UNCOV
190
end
×
191
# rubocop:enable Metrics/ParameterLists
192
# rubocop:enable Metrics/ClassLength
193
# rubocop:enable Style/NumericPredicate
194
# rubocop:enable Style/IfUnlessModifier
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc