Class: NewspaperWorks::IssuePDFComposer

Inherits:
Object
  • Object
show all
Defined in:
lib/newspaper_works/issue_pdf_composer.rb

Overview

Adapter class composes a PDF derivative for issue, if it requires one.

Constant Summary collapse

CMD_BASE =
"gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(issue) ⇒ IssuePDFComposer

Returns a new instance of IssuePDFComposer.

Parameters:



12
13
14
15
16
# File 'lib/newspaper_works/issue_pdf_composer.rb', line 12

def initialize(issue)
  @issue = issue
  # paths to page PDFs
  @page_pdfs = []
end

Instance Attribute Details

#issueObject

Returns the value of attribute issue.



7
8
9
# File 'lib/newspaper_works/issue_pdf_composer.rb', line 7

def issue
  @issue
end

#page_pdfsObject

Returns the value of attribute page_pdfs.



7
8
9
# File 'lib/newspaper_works/issue_pdf_composer.rb', line 7

def page_pdfs
  @page_pdfs
end

Instance Method Details

#composeObject



18
19
20
21
22
23
24
25
26
27
# File 'lib/newspaper_works/issue_pdf_composer.rb', line 18

def compose
  # we will not step on any existing PDF
  return if issue_pdf_exists?
  # we can not compose a multi-page issue PDF if constituent page PDFs
  #   do not exist (yet == not ready, possibly waiting on an async job).
  @page_pdfs = validated_page_pdfs
  # Compose a Ghostscript command to merge all paths in @page_pdfs into
  #   a single output document, execute:
  compose_from_pages
end

#compose_from_pagesObject



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/newspaper_works/issue_pdf_composer.rb', line 29

def compose_from_pages
  outfile = File.join(Dir.mktmpdir, output_filename)
  sources = @page_pdfs.join(' ')
  cmd = "#{CMD_BASE} -sOutputFile=#{outfile} #{sources}"
  # rubocop:disable Lint/UnusedBlockArgument
  Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
    unless wait_thr.value.success?
      e = "Ghostscript Error: \n#{stderr.read}"
      raise NewspaperWorks::DataError, e
    end
  end
  # rubocop:enable Lint/UnusedBlockArgument
  # at this point, something should exist and validate at path `outfile`:
  raise NewspaperWorks::DataError, "Generated PDF invalid" unless validate_pdf(outfile)
  # Assign for attachment to issue, commit:
  attach_to_issue(outfile)
end

#output_filenameObject



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

def output_filename
  "#{@issue.id}_full-issue.pdf"
end

#validate_pdf(path) ⇒ Boolean

Validate PDF with poppler ‘pdfinfo` command, which will detect

error conditions in cases like truncated PDF, and only in those
error conditions will write to stderr.

Parameters:

  • path (String)

    path to PDF file

Returns:

  • (Boolean)

    true or false



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/newspaper_works/issue_pdf_composer.rb', line 56

def validate_pdf(path)
  return false if path.nil? || !File.exist?(path)
  return false if File.size(path).zero?
  result = ''
  cmd = "pdfinfo #{path}"
  # rubocop:disable Lint/UnusedBlockArgument
  Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
    result = stderr.read
  end
  # rubocop:enable Lint/UnusedBlockArgument
  # only zero bytes stderr output from `pdfinfo` considered valid PDF:
  result.size.zero?
end