From: Markus Date: 2004-10-17T08:19:48+09:00 Subject: Re: Ruby programming styles and new program? So I'm just hanging out while my wife packs... I haven't been following this thread much (sorry) but here's a style suggestion: instead of doing a bunch of conditional return true/return false statements, you can make use of the fact that booleans are first class values and write: def move_to_archive(fname) Zip::ZipFile.open(@archive_zip_filename, 1) { | zfile | return nil if zfile.exist?(fname) zfile.add(fname, fname) } File.delete(fname) == 1 end def archiving_needed # check if we should do periodic archiving (up to daily) yday = Time.now.yday next_archive_day = @last_archive_day + @archive_days_interval yday != @last_archive_day and yday >= next_archive_day end I also note in this one that it does not seem to handle year-end-wrapping and also that IIRC yday will never be 0. You may want to look at using the raw Time.now (instead of the yday) and storing your intervals in seconds. Sorry that these are so late to the table... -- Markus On Sat, 2004-10-16 at 15:24, Bill wrote: > Okay--I think this is the last revision unless there's a feature > request. Thanks to all who helped with the Ruby/Smalltalk idioms. > > ========================== > #!/usr/bin/ruby -w > ######################################################### > # > # log_CID.rb > # > # Ruby CID logging script > # > # Logs all activity at a modem set to decipher CID > # (Caller ID) information. Archives the daily logs as well. > # > ########################################################## > > require 'zip/zip' > require 'serialport/serialport.so' > require 'yaml' > require 'getoptlong' > > ################################# > > class ModemCIDMonitor > def initialize(config, logger) > @port_name = config.port_name > @MAX_PORT_ERRORS = config.max_port_errors > @debug = config.debug > @log_blank_lines = config.log_blank_lines > @modem_init_string = config.modem_init_string > @logger = logger > @port_err_count = 0 > @port = SerialPort.new(@port_name) > @port.read_timeout = 0 > @port.puts(@modem_init_string) > end > > def log(txt) > print txt if @debug > @logger.log_text(txt) > end > > def run > print "Starting run with port ", @port_name, > " and logging to dir ", @logger.archive_dir, "\n" > loop do > @port.each_line do | text | > next unless text =~ /\S/ or @log_blank_lines > # squeeze double \r, etc to just \n > text.sub!(/[\r\n]+/, "\n") > log(text) > end > msg = > "#{Time.now.to_s}: dropped out of system call, restarting > loop.\n" > log(msg) if @debug > @port_err_count += 1 > if(@port_err_count > MAX_PORT_ERRORS) > errmsg = "Too many port errors...ending run\n" > log(errmsg) > return errmsg > end > end > end > end > > class CID_Config > attr_reader :config_file, :as_hash, :defaults > > def initialize(config_file) > @config_file = config_file > @as_hash = YAML::load( File.open(@config_file) ) > @defaults = { > 'archive_dir' => './', > 'base_log_name' => 'CID', > 'debug' => false, > 'archive_days_interval' => 1, > 'archive_zip_filename' => 'CID_archive.zip', > 'port_name' => 'COM1', > 'max_port_errors' => 100, > 'log_blank_lines' => false, > 'modem_init_string' => "AT+VCID=1\r\n", > } > @defaults.each do | k, v | > @as_hash[k] = v unless @as_hash.has_key?(k) > end > end > > def method_missing(method, *args) > method_key = method.to_s > if args.length == 0 and @as_hash.has_key?(method_key) > return @as_hash[method_key] > else > super > end > end > > end > > class DailyLogWithArchive > attr_reader :archive_dir, :base_log_name, :archive_zip_filename, > :archive_days_secs, :archive_days_interval > attr_accessor :debug > > def initialize(config) > @archive_dir = config.archive_dir > @base_log_name = config.base_log_name > @debug = config.debug > @archive_days_interval = config.archive_days_interval > @archive_zip_filename = config.archive_zip_filename > @last_archive_day = -1 > @secs_before_archive = 60 * 60 * 24 * config.days_before_archive > end > > def current_fname > "#{archive_dir}/#{base_log_name}#{Time.now.strftime('%Y%m%d')}.log" > end > > def logfile_needs_moving(logfile) > # check if the logfile mtime is old enough to archive the file > return false unless logfile.index(@base_log_name) == 0 > return false unless Time.now > > File.stat(logfile).mtime + @secs_before_archive > return true > end > > def archiving_needed > # check if we should do periodic archiving (up to daily) > yday = Time.now.yday > return false unless yday != @last_archive_day > return false unless > yday >= @last_archive_day + @archive_days_interval or > yday == 0 > return true > end > > def archive_old_to_zip > moved = 0 > Dir.chdir(@archive_dir) do > dir = Dir.open('.') > moved = dir.inject(0) do | move_count, logfile | > next unless logfile_needs_moving(logfile) > next unless move_to_archive(logfile) > log_text("LOGGER: Archiving file " + logfile + "\n") if > @debug > next move_count + 1 > end > end > return moved > end > > def move_to_archive(fname) > Zip::ZipFile.open(@archive_zip_filename, 1) { > | zfile | > return nil if zfile.exist?(fname) > zfile.add(fname, fname) > } > rc = File.delete(fname) > return true if rc and rc == 1 > return nil > end > > def log_text(txt) > Dir.chdir(@archive_dir) do > File.open(current_fname, "a") do | logfile | > logfile.print(txt) > end > if(archiving_needed) > archive_old_to_zip > @last_archive_day = Time.now.yday > end > end > end > > end > > ############################### > > config_yaml = 'log_CID.yml' # default config file > opts = GetoptLong.new( [ "--conf", "-c", GetoptLong::REQUIRED_ARGUMENT ] ) > opts.each do | opt, arg | > if(opt == "--conf" and arg.length > 0) > config_yaml = arg > last > end > end > > config = CID_Config.new(config_yaml) > logger = DailyLogWithArchive.new(config) > monitor = ModemCIDMonitor.new(config, logger) > > # no return from run unless abort on port timeouts or errors > errmsg = monitor.run > > print errmsg > > return 0 > > > > > ========================== > > ############################################ > # > # log_CID YAML config file. > # > > # name of archive file--daily logs are moved to this archive > archive_zip_filename: "CID_Data.zip" > > # modem initialization string. > # need to set to log verbose caller ID information (+VCID=1 or #CID=1, etc) > # also need to set to NOT answer, just monitor line (usually the default) > modem_init_string: "AT+VCID=1\r\n" > > # directory to kep log files > archive_dir: "c:/modemlog" > > # base log name for daily log files > # daily log file name is this, plus YYYYMMDD date, plus .log extension > # eg. CID20041004.log > base_log_name: CID > > # the comm port having the CID-capable modem > port_name: 'COM1:' > > # days that a daily log file is kept prior to archiving the file > days_before_archive: 7 > > # maximum port read errors allowed before aborting run > max_port_errors: 3000 > > # whether to log whitespace-only lines > log_blank_lines: false > > # debug on or off? > debug: true > > # > # end YAML config file. > # > ##################################################### > >