Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 53 additions & 26 deletions _layouts/bib.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -160,44 +160,71 @@
{% endif %}
</div>

<!-- Journal/Book title and date -->
<!-- Venue, date, and publication metadata -->
{% assign proceedings = 'inproceedings,incollection' | split: ',' %}
{% assign thesis = 'thesis,mastersthesis,phdthesis' | split: ',' %}
{% if entry.type == 'article' %}
{% capture entrytype %}<em>{{ entry.journal }}</em>{% endcapture %}
{% elsif proceedings contains entry.type %}
{% capture entrytype %}<em>In {{ entry.booktitle }}</em>{% endcapture %}
{% elsif thesis contains entry.type %}
{% capture entrytype %}<em>{{ entry.school }}</em>{% endcapture %}
{% else %}
{% capture entrytype %}{% endcapture %}
{% endif %}
{% if entry.month %}
{% capture entrymonth %}{{ " " }}{{ entry.month | capitalize }}{% endcapture %}
{% endif %}
{% if entry.year %}
{% capture entryyear %}{{ " " }}{{ entry.year }}{% endcapture %}
{% endif %}
{% if entry.location %}
{% capture entrytype %}{{ entrytype }}{{ ", " }}{{ entry.location }}{% endcapture %}
{% endif -%}
{% if entry.additional_info %}
{% capture entrytype %}{{ entrytype }}{{ entry.additional_info | markdownify | remove: '<p>' | remove: '</p>' }}{% endcapture %}
{% assign abbr_text = entry.abbr | default: '' | strip %}
{% assign location_text = entry.location | default: '' | strip %}
{% assign status_text = entry.status | default: '' | strip %}
{% assign additional_info_text = entry.additional_info | default: '' | strip %}
{% assign note_text = entry.note | default: '' | strip %}
{% assign award_text = entry.award | default: '' | strip %}
{% assign award_name_downcase = entry.award_name | default: '' | downcase %}
{% if award_text != '' and award_name_downcase contains 'oral' %}
{% assign status_text = '' %}
{% endif %}
{% assign abbreviated_months = 'jan,feb,mar,apr,aug,sep,sept,oct,nov,dec' | split: ',' %}
{% assign month_text = entry.month | default: '' | strip %}
{% assign month_downcase = month_text | downcase %}
{% capture publication_date -%}
{%- if month_text != '' -%}{{ month_text | capitalize }}{%- if abbreviated_months contains month_downcase -%}.{%- endif %} {% endif -%}{{ entry.year }}
{%- endcapture %}
{% assign publication_date_text = publication_date | strip %}
{% capture periodical -%}
{%- if abbr_text == '' -%}
{%- if entry.type == 'article' and entry.journal != blank -%}<em>{{ entry.journal }}</em>{%- assign has_full_venue = true -%}
{%- elsif proceedings contains entry.type and entry.booktitle != blank -%}<em>In {{ entry.booktitle }}</em>{%- assign has_full_venue = true -%}
{%- elsif thesis contains entry.type and entry.school != blank -%}<em>{{ entry.school }}</em>{%- assign has_full_venue = true -%}
{%- endif -%}
{%- endif -%}
{%- if has_full_venue and publication_date_text != '' -%}, {% endif -%}{{ publication_date_text }}
{%- if location_text != '' -%}{%- if has_full_venue or publication_date_text != '' -%}, {% endif -%}{{ entry.location }}{%- endif -%}
{%- if status_text != '' -%}{%- if has_full_venue or publication_date_text != '' or location_text != '' -%}, {% endif -%}{{ entry.status }}{%- endif -%}
{%- if additional_info_text != '' -%}
{%- assign additional_info_first_character = additional_info_text | slice: 0, 1 -%}
{%- unless additional_info_first_character == '.' or additional_info_first_character == '!' or additional_info_first_character == '?' or additional_info_first_character == ',' or additional_info_first_character == ';' or additional_info_first_character == ':' -%}
{%- if has_full_venue or publication_date_text != '' or location_text != '' or status_text != '' -%}. {% endif -%}
{%- endunless -%}
{{- entry.additional_info | markdownify | remove: '<p>' | remove: '</p>' -}}
{%- endif -%}
{%- endcapture %}
{% assign periodical_text = periodical | strip_html | strip %}
{% assign periodical_last_character = periodical_text | slice: -1, 1 %}
{% assign note_last_character = note_text | slice: -1, 1 %}

{% capture hook_exists %}{% file_exists _includes/hook/bib.liquid %}{% endcapture %}
{% if hook_exists == 'true' %}
{% include hook/bib.liquid %}
{% endif %}
{% assign entrytype_text = entrytype | strip_html | strip %}
{% capture periodical %}{{ entrytype }}{% if entrytype_text != "" and entryyear != "" %}, {% endif %}{{ entrymonth }}{{ entryyear }}{% endcapture %}

<div class="publication-meta">
{% if entry.abbr %}
{% if abbr_text != '' %}
<abbr class="publication-venue">{{ entry.abbr }}</abbr>
{% endif %}
<span class="periodical">{{ periodical | strip }}</span>
<span class="periodical">
{{- periodical | strip -}}
{%- unless periodical_text == ''
or periodical_last_character == '.'
or periodical_last_character == '!'
or periodical_last_character == '?'
-%}
.
{%- endunless -%}
</span>
</div>
<div class="periodical">
{{ entry.note | strip }}
{{ entry.note | strip -}}
{%- unless note_text == '' or note_last_character == '.' or note_last_character == '!' or note_last_character == '?' %}.{% endunless %}
</div>

<!-- Links/Buttons -->
Expand Down
80 changes: 80 additions & 0 deletions test/publication_metadata_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# frozen_string_literal: true

require 'digest'
require 'minitest/autorun'
require 'liquid'

class FileExistsTag < Liquid::Tag
def render(_context)
'false'
end
end
Liquid::Template.register_tag('file_exists', FileExistsTag)

class PublicationMetadataTest < Minitest::Test
TEMPLATE_PATH = File.expand_path('../_layouts/bib.liquid', __dir__)
TEMPLATE_SOURCE = File.read(TEMPLATE_PATH)
METADATA_SOURCE = TEMPLATE_SOURCE[/ <!-- Venue, date, and publication metadata -->.*?(?= <!-- Links\/Buttons -->)/m]
BUTTON_SOURCE = TEMPLATE_SOURCE[/ <!-- Links\/Buttons -->.*?(?= \{% if site\.enable_publication_badges %\})/m]
MASTER_BUTTON_SHA256 = 'e066afb79731deff79de68a946081564c007cdccde8642749a8f2915909d6edd'

def render_metadata(entry)
Liquid::Template.parse(METADATA_SOURCE, error_mode: :strict).render!('entry' => entry)
end

def visible_text(entry)
render_metadata(entry).gsub(/<[^>]*>/, ' ').gsub(/\s+/, ' ').strip
end

def test_nonblank_abbr_unconditionally_suppresses_full_venue
article = visible_text('type' => 'article', 'abbr' => 'OOPSLA', 'journal' => 'Proc. ACM Program. Lang.', 'year' => '2025')
proceedings = visible_text('type' => 'inproceedings', 'abbr' => 'WWW', 'booktitle' => 'ACM Web Conference', 'year' => '2024')

assert_equal 'OOPSLA 2025.', article
assert_equal 'WWW 2024.', proceedings
end

def test_year_ended_line_has_one_terminal_period_and_preserves_month_style
assert_equal 'OOPSLA Oct. 2025.', visible_text('type' => 'article', 'abbr' => 'OOPSLA', 'month' => 'oct', 'year' => '2025')
assert_equal 'Test July 2025.', visible_text('type' => 'misc', 'abbr' => 'Test', 'month' => 'July', 'year' => '2025')
end

def test_non_year_metadata_lines_also_end_with_one_period
location = visible_text('type' => 'inproceedings', 'abbr' => 'WWW', 'year' => '2024', 'location' => 'Singapore')
additional_info = visible_text(
'type' => 'article', 'abbr' => 'OOPSLA', 'month' => 'oct', 'year' => '2025',
'additional_info' => ' [Site](https://example.com), the ArXiv version'
)
note = visible_text('type' => 'misc', 'abbr' => 'ArXiv', 'year' => '2025', 'note' => 'Useful note')

assert_equal 'WWW 2024, Singapore.', location
assert_equal 'OOPSLA Oct. 2025. [Site](https://example.com), the ArXiv version.', additional_info
assert_equal 'ArXiv 2025. Useful note.', note
end

def test_prepunctuated_metadata_is_not_double_punctuated
{ '.' => 'Final.', '!' => 'Final!', '?' => 'Final?' }.each do |punctuation, info|
text = visible_text('type' => 'misc', 'abbr' => 'Test', 'year' => '2025', 'additional_info' => ". #{info}")

assert text.end_with?(punctuation), text
refute_match(/[.!?]{2}\z/, text)
end
end

def test_oral_rule_and_nonvenue_metadata_are_preserved
text = visible_text(
'type' => 'inproceedings', 'abbr' => 'ICLR', 'year' => '2026',
'award' => "ICLR'26 oral paper.", 'award_name' => 'ORAL',
'status' => 'Selected for oral presentation', 'additional_info' => '. Oral paper (literal).'
)

refute_includes text, 'Selected for oral presentation'
assert_includes text, 'Oral paper (literal).'
end

def test_publication_buttons_are_byte_for_byte_unchanged_from_master
assert_equal MASTER_BUTTON_SHA256, Digest::SHA256.hexdigest(BUTTON_SOURCE)
%w[Abs arXiv Bib PAPER PDF Supp Video Blog Code Poster Slides Website].each { |label| assert_includes BUTTON_SOURCE, ">#{label}<" }
assert_includes BUTTON_SOURCE, '{%- if entry.award_name %}{{ entry.award_name }}{% else %}Awarded{% endif -%}'
end
end
Loading