Class: Whedon::Paper

Inherits:
Object
  • Object
show all
Includes:
GitHub
Defined in:
lib/whedon.rb

Constant Summary collapse

EXPECTED_MARKDOWN_FIELDS =
%w{
  title
  tags
  authors
  affiliations
  date
  bibliography
}
EXPECTED_LATEX_FIELDS =
%w{
  title
  keywords
  authors
  affiliations
  date
  bibliography
}

Constants included from GitHub

GitHub::MEDIA_TYPE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from GitHub

#client

Constructor Details

#initialize(review_issue_id, custom_path = nil, paper_path = nil) ⇒ Paper

Initialized with JOSS paper including YAML header e.g. joss.theoj.org/about#paper_structure Optionally return early if no paper_path is set



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/whedon.rb', line 85

def initialize(review_issue_id, custom_path=nil, paper_path=nil)
  @review_issue_id = review_issue_id
  @review_repository = ENV['REVIEW_REPOSITORY']
  @custom_path = custom_path

  return if paper_path.nil?

  parsed = load_yaml(paper_path)

  check_fields(parsed, paper_path)
  check_orcids(parsed)

  @paper_path = paper_path
  @authors = parse_authors(parsed)
  @title = parsed['title']
  @languages = detect_languages
  @tags = parsed['tags']
  @date = parsed['date']
  @bibliography_path = parsed['bibliography']
  # Probably a much nicer way to do this...
  @current_year = ENV["CURRENT_YEAR"].nil? ? Time.new.year : ENV["CURRENT_YEAR"]
  @current_volume = ENV["CURRENT_VOLUME"].nil? ? Time.new.year - (Time.parse(ENV['JOURNAL_LAUNCH_DATE']).year - 1) : ENV["CURRENT_VOLUME"]
  @current_issue = ENV["CURRENT_ISSUE"].nil? ? 1 + ((Time.new.year * 12 + Time.new.month) - (Time.parse(ENV['JOURNAL_LAUNCH_DATE']).year * 12 + Time.parse(ENV['JOURNAL_LAUNCH_DATE']).month)) : ENV["CURRENT_ISSUE"]
end

Instance Attribute Details

#authorsObject

Returns the value of attribute authors.



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

def authors
  @authors
end

#bibliography_pathObject

Returns the value of attribute bibliography_path.



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

def bibliography_path
  @bibliography_path
end

#current_issueObject

Returns the value of attribute current_issue.



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

def current_issue
  @current_issue
end

#current_volumeObject

TODO: work out how to resolve this code duplication with lib/processor.rb



51
52
53
# File 'lib/whedon.rb', line 51

def current_volume
  @current_volume
end

#current_yearObject

Returns the value of attribute current_year.



53
54
55
# File 'lib/whedon.rb', line 53

def current_year
  @current_year
end

#custom_pathObject

Returns the value of attribute custom_path.



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

def custom_path
  @custom_path
end

#dateObject

Returns the value of attribute date.



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

def date
  @date
end

#editorObject

Returns the value of attribute editor.



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

def editor
  @editor
end

#languagesObject

Returns the value of attribute languages.



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

def languages
  @languages
end

#paper_pathObject

Returns the value of attribute paper_path.



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

def paper_path
  @paper_path
end

#review_issue_bodyObject

Returns the value of attribute review_issue_body.



47
48
49
# File 'lib/whedon.rb', line 47

def review_issue_body
  @review_issue_body
end

#review_issue_idObject

Returns the value of attribute review_issue_id.



45
46
47
# File 'lib/whedon.rb', line 45

def review_issue_id
  @review_issue_id
end

#review_repositoryObject

Returns the value of attribute review_repository.



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

def review_repository
  @review_repository
end

#reviewersObject

Returns the value of attribute reviewers.



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

def reviewers
  @reviewers
end

#tagsObject

Returns the value of attribute tags.



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

def tags
  @tags
end

#titleObject

Returns the value of attribute title.



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

def title
  @title
end

Class Method Details

.listObject



73
74
75
76
77
78
79
80
# File 'lib/whedon.rb', line 73

def self.list
  reviews = Whedon::Reviews.new(ENV['REVIEW_REPOSITORY']).list_current
  return "No open reviews" if reviews.nil?

  reviews.each do |issue_id, vals|
    puts "#{issue_id}: #{vals[:url]} (#{vals[:opened_at]})"
  end
end

Instance Method Details

#auditObject



381
382
383
384
# File 'lib/whedon.rb', line 381

def audit
  review_issue if review_issue_body.nil?
  Whedon::Auditor.new(review_issue_body).audit
end

#authors_stringObject



279
280
281
282
283
284
285
286
287
# File 'lib/whedon.rb', line 279

def authors_string
  authors_array = []

  authors.each_with_index do |author, index|
    authors_array << "#{author.name}"
  end

  return authors_array.join(', ')
end

#bibtex_pathObject



257
258
259
# File 'lib/whedon.rb', line 257

def bibtex_path
  "#{directory}/#{bibliography_path}"
end

#check_fields(parsed, paper_path) ⇒ Object

Check that the paper has the expected YAML header. Raise if missing fields



145
146
147
148
149
150
151
152
153
# File 'lib/whedon.rb', line 145

def check_fields(parsed, paper_path)
  if paper_path.include?('.tex')
    expected_fields = EXPECTED_LATEX_FIELDS
  else
    expected_fields = EXPECTED_MARKDOWN_FIELDS
  end
  fields = expected_fields - parsed.keys
  raise "Paper YAML header is missing expected fields: #{fields.join(', ')}" if !fields.empty?
end

#check_orcids(parsed) ⇒ Object

Check that the user-defined ORCIDs look valid



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

def check_orcids(parsed)
  authors = parsed['authors']
  authors.each do |author|
    next unless author.has_key?('orcid')
    raise "Problem with ORCID (#{author['orcid']}) for #{author['name']}" unless OrcidValidator.new(author['orcid']).validate
  end
end

#citation_authorObject

User when generating the citation snipped, returns either: ‘Smith et al’ for multiple authors or ‘Smith’ for a single author



268
269
270
271
272
273
274
275
276
277
# File 'lib/whedon.rb', line 268

def citation_author
  surname = authors.first.last_name
  initials = authors.first.initials

  if authors.size > 1
    return "#{surname} et al."
  else
    return "#{surname}, #{initials}"
  end
end

#compileObject



391
392
393
394
# File 'lib/whedon.rb', line 391

def compile
  review_issue if review_issue_body.nil?
  processor = Whedon::Processor.new(review_issue_id, review_issue_body)
end

#crossref_authorsObject

Returns an XML snippet to be included in the Crossref XML



321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/whedon.rb', line 321

def crossref_authors
  builder = Nokogiri::XML::Builder.new do |xml|
    xml.contributors {
      authors.each_with_index do |author, index|
        given_name = author.given_name
        surname = author.last_name
        orcid = author.orcid
        if index == 0
          sequence = "first"
        else
          sequence = "additional"
        end
        xml.person_name(:sequence => sequence, :contributor_role => "author") {
        xml.given_name given_name.encode(:xml => :text)
        if surname.nil?
          xml.surname "No Last Name".encode(:xml => :text)
        else
          xml.surname surname.encode(:xml => :text)
        end
        xml.ORCID "http://orcid.org/#{author.orcid}" if !orcid.nil?
        }
      end
    }
  end

  return builder.doc.xpath('//contributors').to_xml
end

#deposit_payloadObject

Create the payload that we’re going to use to post back to JOSS/JOSE



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/whedon.rb', line 175

def deposit_payload
  review_issue if review_issue_body.nil?
  payload = {
    'paper' => {}
  }

  %w(title tags languages).each { |var| payload['paper'][var] = self.send(var) }
  payload['paper']['authors'] = authors.collect { |a| a.to_h }
  payload['paper']['doi'] = formatted_doi
  payload['paper']['repository_doi'] = review_issue_body[ARCHIVE_REPOSITORY_REGEX].gsub('"', '')
  payload['paper']['data_doi'] = review_issue_body[ARCHIVE_DATA_REGEX].gsub('"', '')
  payload['paper']['book_doi'] = review_issue_body[ARCHIVE_BOOK_REGEX].gsub('"', '')
  payload['paper']['docker_doi'] = review_issue_body[ARCHIVE_DOCKER_REGEX].gsub('"', '')
  payload['paper']['book_exec_url'] = review_issue_body[BOOK_EXEC_REGEX].gsub('"', '')
  payload['paper']['repository_address'] = review_issue_body[REPO_REGEX].gsub('"', '')
  payload['paper']['editor'] = "@#{editor}"
  payload['paper']['reviewers'] = reviewers.collect(&:strip)
  payload['paper']['volume'] = current_volume
  payload['paper']['issue'] = current_issue
  payload['paper']['year'] = current_year
  payload['paper']['page'] = review_issue_id

  return payload
end

#detect_languagesObject



164
165
166
167
168
169
170
171
172
# File 'lib/whedon.rb', line 164

def detect_languages
  path = custom_path ? custom_path : "tmp/#{review_issue_id}"

  repo = Rugged::Repository.new("#{path}")
  project = Linguist::Repository.new(repo, repo.head.target_id)

  # Take top five languages from Linguist
  project.languages.keys.take(5)
end

#directoryObject



253
254
255
# File 'lib/whedon.rb', line 253

def directory
  File.dirname(paper_path)
end

#downloadObject



386
387
388
389
# File 'lib/whedon.rb', line 386

def download
  review_issue if review_issue_body.nil?
  Whedon::Processor.new(review_issue_id, review_issue_body, custom_path).clone
end

#filename_doiObject

A slightly modified DOI string for writing out files 10.21105/00001 -> 10.21105.00001



364
365
366
# File 'lib/whedon.rb', line 364

def filename_doi
  formatted_doi.gsub('/', '.')
end

#formatted_doiObject

The full DOI e.g. 10.21105/00001



262
263
264
# File 'lib/whedon.rb', line 262

def formatted_doi
  "#{ENV['DOI_PREFIX']}/#{joss_id}"
end

#google_scholar_authorsObject



349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/whedon.rb', line 349

def google_scholar_authors
  authors_string = ""

  authors.each_with_index do |author, index|
    given_name = author.given_name
    surname = author.last_name

    authors_string << "<meta name=\"citation_author\" content=\"#{surname}, #{given_name}\">"
  end

  return authors_string
end

#jats_affiliationsObject



311
312
313
314
315
316
317
318
# File 'lib/whedon.rb', line 311

def jats_affiliations
  affiliations = ""
  authors.each_with_index do |author, index|
    affiliations << "<aff id=\"aff-#{index+1}\">#{author.affiliation}</aff>\n"
  end

  return affiliations
end

#jats_authorsObject



289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/whedon.rb', line 289

def jats_authors
  builder = Nokogiri::XML::Builder.new do |xml|
    xml.send(:'contrib-group', "content-type" => "authors") {
      authors.each_with_index do |author, index|
        given_name = author.given_name
        surname = author.last_name
        orcid = author.orcid
        xml.contrib("contrib-type" => "author", "id" => "author-#{index+1}") {
          xml.send(:'contrib-id', orcid, "contrib-id-type" => "orcid")
          xml.name {
            xml.surname surname.encode(:xml => :text)
            xml.send(:'given-names', given_name.encode(:xml => :text))
          }
          xml.xref("ref-type" => "aff", "rid" => "aff-#{index+1}")
        }
      end
    }
  end

  return builder.doc.xpath('//contrib-group').to_xml
end

#joss_idObject

A 5-figure integer used to produce the JOSS DOI Note, this doesn’t actually include the string ‘joss’ in the DOI any longer (it’s now generalized) but the method name remains



232
233
234
235
# File 'lib/whedon.rb', line 232

def joss_id
  id = "%05d" % review_issue_id
  "#{ENV['JOURNAL_ALIAS']}.#{id}"
end

#joss_resource_urlObject

The JOSS site url for a paper e.g. joss.theoj.org/papers/10.21105/00001



370
371
372
# File 'lib/whedon.rb', line 370

def joss_resource_url
  "#{ENV['JOURNAL_URL']}/papers/#{formatted_doi}"
end

#latex_source?Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/whedon.rb', line 136

def latex_source?
  paper_path.end_with?('.tex')
end

#load_yaml(paper_path) ⇒ Object



128
129
130
131
132
133
134
# File 'lib/whedon.rb', line 128

def load_yaml(paper_path)
  if paper_path.include?('.tex')
    return YAML.load_file(paper_path.gsub('.tex', '.yml'))
  else
    return YAML.load_file(paper_path)
  end
end

#markdown_source?Boolean

Returns:

  • (Boolean)


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

def markdown_source?
  paper_path.end_with?('.md')
end

#paper_orgObject



241
242
243
# File 'lib/whedon.rb', line 241

def paper_org
  ENV['PAPER_REPOSITORY'].split('/').first
end

#paper_repoObject



245
246
247
# File 'lib/whedon.rb', line 245

def paper_repo
  ENV['PAPER_REPOSITORY'].split('/').last
end

#parse_affiliations(affliations_yaml) ⇒ Object



220
221
222
223
224
225
226
227
# File 'lib/whedon.rb', line 220

def parse_affiliations(affliations_yaml)
  returned = {}
  affliations_yaml.each do |affiliation|
    returned[affiliation['index']] = affiliation['name']
  end

  returned
end

#parse_authors(yaml) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/whedon.rb', line 205

def parse_authors(yaml)
  returned = []
  authors_yaml = yaml['authors']
  affiliations = parse_affiliations(yaml['affiliations'])

  # Loop through the authors block and build up the affiliation
  authors_yaml.each do |author|
    affiliation_index = author['affiliation']
    raise "Author (#{author['name']}) is missing affiliation" if affiliation_index.nil?
    returned << Author.new(author['name'], author['orcid'], affiliation_index, affiliations)
  end

  returned
end

#pdf_urlObject



237
238
239
# File 'lib/whedon.rb', line 237

def pdf_url
  "http://neurolibre.org/#{paper_repo}/#{joss_id}/#{ENV['DOI_PREFIX']}.#{joss_id}.pdf"
end

#plain_titleObject



200
201
202
203
# File 'lib/whedon.rb', line 200

def plain_title
  renderer = Redcarpet::Markdown.new(Redcarpet::Render::StripDown)
  return renderer.render(self.title).strip
end

#review_issueObject

Return the Review object associated with the Paper



375
376
377
378
379
# File 'lib/whedon.rb', line 375

def review_issue
  review = Whedon::Review.new(review_issue_id, review_repository)
  @review_issue_body = review.issue_body
  return review
end

#review_issue_urlObject



249
250
251
# File 'lib/whedon.rb', line 249

def review_issue_url
  "https://github.com/#{ENV['REVIEW_REPOSITORY']}/issues/#{review_issue_id}"
end

#reviewers_without_handlesObject



115
116
117
# File 'lib/whedon.rb', line 115

def reviewers_without_handles
  reviewers.map { |reviewer_name| reviewer_name.sub(/^@/, "") }
end