0

I'm trying to DRY up my code and wondering if many people have experience with CSV's and ruby.

My code is below. It works just... Its awful.

I'm wondering if anyone has any ideas on how I could do the following:

1 - How could I use a loop rather than explicit 1..10 that I've done. I did try a few ways but couldn't get them to work with CSV. 2 - Is there a nicer way to do headers in CSV? 3 - Any other ideas on how to make CSV code nicer?

I initially went with this

(1..10).each do |number| 
end 

However the csv system didn't like that one! It was thinking my end statements were incorrect however, I don't think this was the case.

Here's my code. If you have any bright ideas you're awesome! Yes I know it's awful, just wondering how I could do it better!

require 'csv'

class CampagignsCsv
  class << self
    HEADERS = [
      'Job Title',
      'Business Name',
      'Business Contact Name',
      'Location',
      'Job Status',
      'Created date',
      'Last Modified date',
      '# Positions',
      'Description',
      'Std/Prem',
      'Referral code (To discuss)',
      'Coupon code (To discuss)',
      'Question1',
      'Knockout?1',
      'Correct Answer1',
      'Question2',
      'Knockout?2',
      'Correct Answer2',
      'Question3',
      'Knockout?3',
      'Correct Answer3',
      'Question4',
      'Knockout?4',
      'Correct Answer4',
      'Question5',
      'Knockout?5',
      'Correct Answer5',
      'Question6',
      'Knockout?6',
      'Correct Answer6',
      'Question7',
      'Knockout?7',
      'Correct Answer7',
      'Question8',
      'Knockout?8',
      'Correct Answer8',
      'Question9',
      'Knockout?9',
      'Correct Answer9',
      'Question10',
      'Knockout?10',
      'Correct Answer10'
    ].freeze

    def report
      puts 'campaigns_report.csv created in reporting_output folder'
      CSV.open("reporting_output/campagins_report.csv", "wb") do |csv|
        csv << HEADERS
        Paddl::Models::Job.all.each do |job|
          csv << [
            job.title,
            job.employer.business_name,
            job.employer.profile.full_name,
            job.address,
            job.status,
            job.created_at,
            job.updated_at,
            job.num_of_positions,
            job.description,
            job.employer.account_type,
            'null',
            'null',
            job.job_questions.map { |item| item[:question] }[1],
            job.job_questions.map { |item| item[:knockout] }[1],
            job.job_questions.map { |item| item[:correct_answer] }[1],
            job.job_questions.map { |item| item[:question] }[2],
            job.job_questions.map { |item| item[:knockout] }[2],
            job.job_questions.map { |item| item[:correct_answer] }[2],
            job.job_questions.map { |item| item[:question] }[3],
            job.job_questions.map { |item| item[:knockout] }[3],
            job.job_questions.map { |item| item[:correct_answer] }[3],
            job.job_questions.map { |item| item[:question] }[4],
            job.job_questions.map { |item| item[:knockout] }[4],
            job.job_questions.map { |item| item[:correct_answer] }[4],
            job.job_questions.map { |item| item[:question] }[5],
            job.job_questions.map { |item| item[:knockout] }[5],
            job.job_questions.map { |item| item[:correct_answer] }[5],
            job.job_questions.map { |item| item[:question] }[6],
            job.job_questions.map { |item| item[:knockout] }[6],
            job.job_questions.map { |item| item[:correct_answer] }[6],
            job.job_questions.map { |item| item[:question] }[7],
            job.job_questions.map { |item| item[:knockout] }[7],
            job.job_questions.map { |item| item[:correct_answer] }[7],
            job.job_questions.map { |item| item[:question] }[8],
            job.job_questions.map { |item| item[:knockout] }[8],
            job.job_questions.map { |item| item[:correct_answer] }[8],
            job.job_questions.map { |item| item[:question] }[9],
            job.job_questions.map { |item| item[:knockout] }[9],
            job.job_questions.map { |item| item[:correct_answer] }[9],
            job.job_questions.map { |item| item[:question] }[10],
            job.job_questions.map { |item| item[:knockout] }[10],
            job.job_questions.map { |item| item[:correct_answer] }[10]
          ]
        end
      end
    end
  end
end
0

2 Answers 2

1

How's this?

...
job.employer.account_type,
'null',
'null',
*1.upto(10).flat_map {|i|
  jq = job.job_questions[i]
  [jq[:question], jq[:knockout], jq[:correct_answer]]
}
...
Sign up to request clarification or add additional context in comments.

1 Comment

smart. Put it into an array an then flatten it :)
1

Here's an approach that organizes things better, plus cuts way down on duplication:

require 'csv'

class CampagignsCsv
  HEADERS = [
    'Job Title',
    'Business Name',
    'Business Contact Name',
    'Location',
    'Job Status',
    'Created date',
    'Last Modified date',
    '# Positions',
    'Description',
    'Std/Prem',
    'Referral code (To discuss)',
    'Coupon code (To discuss)'
  ] + (1..10).flat_map do |n|
    "Question#{n}",
    "Knockout?#{n}",
    "Correct Answer#{n}",
  end

  SECTIONS = [
    :question,
    :knockout,
    :correct_answer
  ]

  def self.report
    puts 'campaigns_report.csv created in reporting_output folder'

    CSV.open("reporting_output/campagins_report.csv", "wb") do |csv|
      csv << HEADERS

      Paddl::Models::Job.all.each do |job|
        csv << [
          job.title,
          job.employer.business_name,
          job.employer.profile.full_name,
          job.address,
          job.status,
          job.created_at,
          job.updated_at,
          job.num_of_positions,
          job.description,
          job.employer.account_type,
          'null',
          'null'
        ] + SECTIONS.flat_map do |section|
          (1..10).map do |n|
            job.job_questions[section][n]
          end
        end
      end
    end
  end
end

Normally you declare constants at the very top level of your class, not inside a class << self block. That's also not necessary since declaring a methods as self.x automatically makes it a class method.

Using flat_map can help convert array-of-array type results to a flat array, very handy in this case.

4 Comments

flat_map, huh, I recall you like it? :) There is DRY candidate in (1..10).flat_map { |n| SECTIONS.map { |s| "#{s.gsub(/(?<=\A|_)\w/, &:upcase).gsub('_', ' ')}" } }.
@mudasobwa Deriving the labels from the name is a good plan, though with Rails/ActiveSupport and titleize it's a lot easier.
No rails tag ⇒ no titleize :(
Thanks for the answer! I thought id give it to pocari being the first to suggest flat_map which is definiately what I needed. Thanks though :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.