在CSV对象上调用多个方法

时间:2013-06-22 17:26:44

标签: ruby csv

我构建了一个Event Manager类,它对CSV文件执行解析操作,并使用erb生成html字母。它是快速启动实验室tutorial

的一部分

该程序运行正常,但如果没有先前的方法干扰后面的方法,我无法在对象上调用多个方法。结果,我选择创建多个对象来调用实例方法,这似乎是一个笨重的不优雅的解决方案。有没有更好的方法来做到这一点,我可以创建一个新对象并在其上调用方法?

像这样:

eventmg = EventManager.new("event_attendees.csv")

eventmg.print_valid_phone_numbers

eventmg_2 = EventManager.new("event_attendees.csv")

eventmg_2.print_zipcodes

eventmg_3 = EventManager.new("event_attendees.csv")

eventmg_3.time_targeter

eventmg_4 = EventManager.new("event_attendees.csv")

eventmg_4.day_of_week

eventmg_5 = EventManager.new("event_attendees.csv")

eventmg_5.create_thank_you_letters

完整的代码如下

    require 'csv'
    require 'sunlight/congress'
    require 'erb'

    class EventManager

      INVALID_PHONE_NUMBER = "0000000000"

    Sunlight::Congress.api_key = "e179a6973728c4dd3fb1204283aaccb5"

    def initialize(file_name, list_selections = [])
     puts "EventManager Initialized."

     @file = CSV.open(file_name, {:headers => true, 
       :header_converters => :symbol} )

     @list_selections = list_selections
    end

    def clean_zipcode(zipcode)
      zipcode.to_s.rjust(5,"0")[0..4]
    end

    def print_zipcodes
       puts "Valid Participant Zipcodes"
      @file.each do |line|
        zipcode = clean_zipcode(line[:zipcode])
        puts zipcode
      end
    end

    def clean_phone(phone_number)
      converted = phone_number.scan(/\d/).join('').split('')
      if converted.count == 10
        phone_number
      elsif phone_number.to_s.length < 10
    INVALID_PHONE_NUMBER 
      elsif phone_number.to_s.length == 11 && converted[0] == 1
        phone_number.shift
        phone_number.join('')
      elsif phone_number.to_s.length == 11 && converted[0] != 1
    INVALID_PHONE_NUMBER
    else 
      phone_number.to_s.length > 11
      INVALID_PHONE_NUMBER
    end
    end

    def print_valid_phone_numbers
      puts "Valid Participant Phone Numbers"
    @file.each do |line|
    clean_number = clean_phone(line[:homephone])
    puts clean_number
    end
    end

    def time_targeter
      busy_times = Array.new(24) {0}
      @file.each do |line|
        registration = line[:regdate]
        prepped_time = DateTime.strptime(registration, "%m/%d/%Y %H:%M")
        prepped_time = prepped_time.hour.to_i
        # inserts filtered hour into the array 'list_selections'
        @list_selections << prepped_time
      end
      # tallies number of registrations for each hour
      i = 0
      while i < @list_selections.count
        busy_times[@list_selections[i]] += 1
        i+=1
      end
      # delivers a result showing the hour and the number of registrations
      puts "Number of Registered Participants by Hour:"
      busy_times.each_with_index {|counter, hours| puts "#{hours}\t#{counter}"}
    end


    def day_of_week
      busy_day = Array.new(7) {0}
      d_of_w = ["Monday:", "Tuesday:", "Wednesday:", "Thursday:", "Friday:", "Saturday:",         "Sunday:"]
      @file.each do |line|
        registration = line[:regdate]
        # you have to reformat date because of parser format
        prepped_date = Date.strptime(registration, "%m/%d/%y")
        prepped_date = prepped_date.wday
        # adds filtered day of week into array 'list selections'
        @list_selections << prepped_date  
      end
      i = 0
      while i < @list_selections.count
        # i is minus one since days of week begin at '1' and arrays begin at '0'
        busy_day[@list_selections[i-1]] += 1
        i+=1
      end
      #busy_day.each_with_index {|counter, day| puts "#{day}\t#{counter}"}
      prepared = d_of_w.zip(busy_day)
      puts "Number of Registered Participants by Day of Week"
      prepared.each{|date| puts date.join(" ")}
    end


    def legislators_by_zipcode(zipcode)
      Sunlight::Congress::Legislator.by_zipcode(zipcode)
    end


    def save_thank_you_letters(id,form_letter)
      Dir.mkdir("output") unless Dir.exists?("output")

      filename = "output/thanks_#{id}.html"

      File.open(filename,'w') do |file|
        file.puts form_letter
      end
    end


    def create_thank_you_letters
      puts "Thank You Letters Available in Output Folder"
      template_letter = File.read "form_letter.erb"
      erb_template = ERB.new template_letter

    @file.each do |line|
    id = line[0]
    name = line[:first_name]
    zipcode = clean_zipcode(line[:zipcode])
    legislators = legislators_by_zipcode(zipcode)

    form_letter = erb_template.result(binding)

    save_thank_you_letters(id,form_letter)
    end
    end

    end

2 个答案:

答案 0 :(得分:1)

您遇到此问题的原因是,当您将each应用于CSV.open的结果时,您每次都会移动文件指针。当您使用某种方法到达文件末尾时,其他任何人都无法阅读。

另一种方法是在初始化时使用readlines将文件内容读入实例变量。您将获得一组数组,您可以使用each轻松操作。

答案 1 :(得分:0)

  

“有没有更好的方法来实现这一点,我可以创建一个新对象并在其上调用方法?”

可能。如果您的方法相互干扰,则意味着您正在更改管理器中的状态,而不是处理局部变量。

有时,这是正确的做法(例如Array#<<);有时候没有(例如Fixnum#+)...看到你的方法名称,它可能不是。

将违法者钉死并相应调整代码。 (我只扫描了你的代码,但对实例变量的那些Array#<<调用,特别是看起来很可疑。)