From b4ce4ec975b4d81c0c8348e8444653140a80df38 Mon Sep 17 00:00:00 2001 From: Daniel Uber Date: Fri, 11 Jun 2021 12:51:51 -0500 Subject: [PATCH] 15 minute fix: Shorten long titles from feed items if needed (#13961) * Shorten long titles from feed items if needed Fixes #13959 When the title is too long to create a valid article, put a shortened title in the generated article markdown. Added unit tests to cover the default case and the shortening case * Fix Struct initialization Rubocop suggested struct over openstruct because of performance, but Struct.new creates a "class" with a positional initializer, while Openstruct's new takes a hash like keyword set and builds an object from those directly. I mistakenly reused the openstruct syntax after the conversion. This changes the feed and item to use Struct's initializer. * Use String#truncate in place of custom trimming `separator` enables a natural break (preventing space between last character and ellipsis), and omission text "..." is the default behavior. * Use verifying doubles in test, use method access to members in code The instance_double for Feedjira::Parser::RSSEntry necessitated changing hash key access to reader method access for the data members (title, categories, summary, description). --- .../feeds/assemble_article_markdown.rb | 12 +++-- .../feeds/assemble_article_markdown_spec.rb | 50 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 spec/services/feeds/assemble_article_markdown_spec.rb diff --git a/app/services/feeds/assemble_article_markdown.rb b/app/services/feeds/assemble_article_markdown.rb index 51bab88aa..c183dbbac 100644 --- a/app/services/feeds/assemble_article_markdown.rb +++ b/app/services/feeds/assemble_article_markdown.rb @@ -6,8 +6,8 @@ module Feeds def initialize(item, user, feed, feed_source_url) @item = item - @title = item[:title].strip - @categories = item[:categories] || [] + @title = item.title.strip + @categories = item.categories || [] @user = user @feed = feed @feed_source_url = feed_source_url @@ -16,7 +16,7 @@ module Feeds def call body = <<~HEREDOC --- - title: #{@title} + title: #{processed_title} published: false date: #{@item.published} tags: #{get_tags} @@ -31,6 +31,10 @@ module Feeds private + def processed_title + @title.truncate(128, omission: "...", separator: " ") + end + def get_tags @categories.first(4).map do |tag| tag.delete(" ").gsub(/[^[:alnum:]]/i, "")[0..19] @@ -54,7 +58,7 @@ module Feeds end def get_content - @item[:content] || @item[:summary] || @item[:description] + @item.content || @item.summary || @item.description end def thorough_parsing(content, feed_url) diff --git a/spec/services/feeds/assemble_article_markdown_spec.rb b/spec/services/feeds/assemble_article_markdown_spec.rb new file mode 100644 index 000000000..af44fcacf --- /dev/null +++ b/spec/services/feeds/assemble_article_markdown_spec.rb @@ -0,0 +1,50 @@ +require "rails_helper" + +RSpec.describe Feeds::AssembleArticleMarkdown, type: :service do + let(:user) { create(:user, feed_mark_canonical: true) } + let(:feed_source_url) { "https://feed.source/url" } + let(:feed) { instance_double("Feedjira::Parser::RSS", url: "https://feed.source/") } + let(:title) { "A title" } + let(:content) { "Some content that came in with the item, should be the body" } + + let(:item) do + instance_double( + "Feedjira::Parser::RSSEntry", + title: title, + categories: %w[tag1 tag2 tag3 tag4 tag5], + published: "2020-12-20", + content: content, + ) + end + + let(:feeds_assemble_article_markdown) { described_class.new(item, user, feed, feed_source_url) } + + it "creates markdown head matter" do + body = feeds_assemble_article_markdown.call + + expect(body).to include("title: A title") + expect(body).to include("date: 2020-12-20") + end + + it "includes the content from the feed" do + body = feeds_assemble_article_markdown.call + + expect(body).to include(content) + end + + context "when item has a long title" do + let(:title) { "Words " * 25 } + + it "limits the title to 128 characters by truncation" do + body = feeds_assemble_article_markdown.call + + title_line = body.lines.detect { |line| line.starts_with?("title:") } + shortened_title = title_line.split(":").second.strip + # we expect 21 "Words" plus an ellipsis, total of 128 characters + expected_title = "Words Words Words Words Words Words Words Words Words Words Words Words Words Words Words Words Words Words Words Words Words..." # rubocop:disable Layout/LineLength + + expect(shortened_title.size).to eq(128) + expect(shortened_title).to eq(expected_title) + end + end +end