0
\$\begingroup\$

I'm currently working on building a class to create a PDF form application with attached documents and sending that file to an endpoint in Box Api. I have found extremely difficult managing dependencies in this class. For example, I'm making use of a gem combine_pdf.

This gem has the following capabilities, load into a pdf and parse a file. However this are classes on their own. So instantiating an object pdf = CombinePdf.new will not give me access to pdf.parse(file) or pdf.load(file). This will not work and therefore I'm there having create a dependency on CombinePDF.parse and CombinePdf.load.

Same goes for using prawn. If I pass @pdf_prawn = Prawn::Document.new If I where to try to add @pdf_prawn(page_size: 'LETTER', margin: 0) this will not work and therefore I'll have to have a dependency of an external class within my class.

Here is the class I'm trying to get rid of dependencies:

class PDFProducer
  attr_reader :box, :pdf_prawn, :pdf, :formstack

  FORMSTACK_NAME_PATTERN  = /first \= (.*)\nlast \= (.*)/
  PATH_OF_PARSED_PDF_FILE = '/app/tmp/pdfs/'.freeze
  PDF_PAGE_WIDTH          = 612
  PDF_PAGE_LENGTH         = 792

  def initialize(args)
    @box       = args.fetch(:box, BoxApi.new)
    @pdf_prawn = args.fetch(:pdf_prawn, Prawn::Document.new)
    @pdf       = args.fetch(:pdf, CombinePDF.new )
    @formstack = args.fetch(:formstack, FormStack::Form.new)
  end

  # Retrive submission IDs & metadata as JSON array of objects.
  # TODO add formstack_submissions_ids and approved_submission
  def formstack_submissions
    unless @formstack.submissions['status'] == 'error'
      submissions = @formstack.submissions['submissions']
      approved_submission(submissions).map { |submission| submission.fetch('id') }
    else
      raise "Formstack: #{@formstack.submissions['error']}"
    end
  end

  def approved_submission(submissions)
    submissions.select do |submission|
      submission['approval_status'] == 'Approved'
    end
  end

  def parse_into_scrie_pdf
    formstack_submissions_from_id
      .map { |submission| pdf_scrie_application(submission) }
  end

  def formstack_submissions_from_id
    formstack_submissions.map { |id| formstack_submission(id) }
  end

  # GET user data by submission ID
  def formstack_submission(submission_id)
    @formstack.submission(submission_id)
  end

  def formstack_fields
    @formstack.create_form
  end

  # Using user Submission JSON, populate PDF form with the user's data.
  # Create a CombinePDF object to create a PDF package application
  # get attachements from submission by downloading from Box.
  # convert image into string using StringIO to be able to use Prawn.
  # With Prawn convert the image to PDF and add to PDF package (CombinePDF).
  def pdf_scrie_application(submission)
    user_data = submission['data']
    file_name = name_file(submission)
    pdf_path = PdfScrie.new(user_data, formstack_fields).export(file_name)
    @pdf << CombinePDF.load(pdf_path)
    application_notes = notes(user_data)

    @box.attach_docs_from_submission(user_data).each do |file|
      data = @box.client.download_file(file)
      is_pdf = (data =~ /\%PDF-\d+\.?\d+/) == 0
      package = ""

      unless is_pdf
        format_image = StringIO.new(data)
        package = pdf_document_package(format_image)
      end

      @pdf << CombinePDF.parse(package)
    end

    add_notes_page_to_pdf_package(@pdf, application_notes) if application_notes

    @pdf.save pdf_path
    @box.upload_file_to_box(pdf_path, pdf_path)
  end

  def parse_name(name)
    name.match(FORMSTACK_NAME_PATTERN).captures.join(' ')
  end

  def format_name(name)
    name.parameterize.underscore
  end

  def name_from_submission(submission)
    submission["data"].detect { |field_set|
      field_set["field"] == name_field }["value"]
  end

  def name_file(submission)
    unparsed_name = name_from_submission(submission)
    parsed_name = parse_name(unparsed_name)

    format_name(parsed_name)
  end

  def name_pdf_file(pdf_file_path)
    pdf_file_path.gsub(PATH_OF_PARSED_PDF_FILE, '')
  end

  def add_path_to_file_name(file_name)
    "#{PATH_OF_PARSED_PDF_FILE}#{file_name}"
  end

  def name_field
    formstack_fields.find {|f| f["label"] == "Client Name"}.fetch("id") || ""
  end

  def notes(user_submission)
    notes_field = user_submission.find { |field| field['field'] == notes_section_id}
    notes_field&.fetch('value')
  end

  def notes_section_id
    notes = "use_the_space_below_to_add_notes_to_this_application"
     formstack_fields.find {|field| field["name"] == notes }.fetch("id")
  end

  def add_notes_page_to_pdf_package(pdf, notes)
    @pdf_prawn.text notes
    @pdf << CombinePDF.parse(@pdf_prawn.render)
  end

  def pdf_document_package(string_image)
    pdf_blank_pages.image(
      string_image,
      fit: [
        PDF_PAGE_WIDTH,
        PDF_PAGE_LENGTH
      ],
      position: :center
    )
    pdf_blank_pages.render
  end

  def pdf_blank_pages
    Prawn::Document.new(page_size: 'LETTER', margin: 0)
  end
end

Is there something I'm missing? What style violations am I committing? How can I get rid of these dependencies?

\$\endgroup\$
  • \$\begingroup\$ This class is doing too much. Re: your question about dependencies, just pass them in the same way you are the others. you might consider creating wrapper classes over them too. but the main thing though is to break this down properly into objects with one responsibility each \$\endgroup\$ – Jonah Feb 13 at 13:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.