Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! /usr/bin/env ruby
- # Usage: ruby bill_generator.rb data.yml 2008-1-1 2008-12-31
- # Params: data file, begin date, end date
- # begin and end date is in the format yyyy-mm-dd
- # Sample data.yml file entries
- # Date format is [yyyy, mm, dd]
- #
- # # Paid every two weeks
- # Income1:
- # amount: 1000
- # start: [2008, 1, 18]
- # repeat: daily
- # freq: 14
- #
- # # Paid twice a month on the 15th and the last day
- # Income2:
- # amount: 1000
- # start: [ [2008, 1, 15], [2008, 1, -1] ]
- # repeat: monthly
- # freq: 1
- #
- # # Weekly food expense
- # Food:
- # amount: -100
- # start: [2008, 1, 6]
- # repeat: weekly
- # freq: 1
- #
- # # Quarterly bill
- # Water:
- # amount: -100
- # start: [2008, 1, 20]
- # repeat: monthly
- # freq: 3
- #
- # # Monthly bill
- # Home:
- # amount: -1000
- # start: [2008, 1, 1]
- # repeat: monthly
- # freq: 1
- # v0.1
- # TODO: Date parser for better dates in the yaml file
- # TODO: Extract bill class out into separate file
- # TODO: Use command line params lib
- require 'yaml'
- require 'date'
- class Bill
- def initialize(name, params)
- @name = name
- @amount = params['amount']
- @start_dates = params['start']
- @repeat = params['repeat']
- @freq = params['freq'].to_i
- end
- attr_accessor :name, :amount
- def due?(current_date)
- due = false
- if @start_dates[0].is_a? Array
- @start_dates.each do |start_date|
- # No need to check others if it matches
- next if due == true
- due = check_for_repeat_type(current_date, start_date)
- end
- else
- due = check_for_repeat_type(current_date, @start_dates)
- end
- due
- end
- private
- def check_for_repeat_type(current_date, start_date)
- case @repeat
- when "daily"
- compare_daily(current_date, start_date)
- when "weekly"
- compare_daily(current_date, start_date, @freq * 7)
- when "monthly"
- compare_monthly(current_date, start_date)
- when "yearly"
- compare_yearly(current_date, start_date)
- else
- raise ArgumentError, "Invalid repeat option. Must be one of daily, weekly, monthly, or yearly"
- end
- end
- def compare_daily(current_date, start_date, freq = @freq)
- # Custom freq allows us to convert weekly to daily
- start_date = convert_date(start_date)
- ((current_date - start_date) % freq) == 0
- end
- def compare_monthly(current_date, start_date)
- # Check for end of month comparison
- if start_date[2].to_i == -1
- start_date = convert_date(start_date)
- ((current_date.month - start_date.month) % @freq == 0) && current_date.day == end_of_month_day(current_date)
- else
- start_date = convert_date(start_date)
- ((current_date.month - start_date.month) % @freq == 0) && current_date.day == start_date.day
- end
- end
- def compare_yearly(current_date, start_date)
- ((current_date.year - start_date.year) % @freq == 0) && current_date.month == start_date.month && current_date.day == start_date.day
- end
- # Accepts format of [year, month, day]
- def convert_date(date)
- Date.new(*date)
- end
- def end_of_month_day(current_date)
- Date.new(current_date.year, current_date.month, -1).day
- end
- end
- # Begin script
- file = ARGV[0]
- date_start = Date.parse(ARGV[1].to_s)
- date_end = Date.parse(ARGV[2].to_s)
- bills = YAML.load_file(file)
- (date_start..date_end).each do |date|
- bills.each do |name, info|
- bill = Bill.new(name, info)
- puts "#{bill.name}, #{date.to_s.strip}, #{bill.amount}" if bill.due? date
- end
- end
Add Comment
Please, Sign In to add comment