class Cabrillo

Constants

CABRILLO_VERSION

Attributes

raise_on_invalid_data[RW]

Public Class Methods

new(options = {}) click to toggle source

Public: Creates an instance of Cabrillo from a Hash of log data

options - A Hash which contains data from a cabrillo log

Returns an instance of Cabrillo.

# File lib/cabrillo.rb, line 55
def initialize(options = {})
  # Let all the given entries automagically become instance variables.
  options.each do |key, value|
    instance_variable_set("@#{key}", value)
    this = class << self; self; end
    this.class_eval { attr_accessor key }
  end

  # Defaults and sanity checks can go here if they need to.
  @version = options[:version] || CABRILLO_VERSION
end
parse(log_contents) click to toggle source

Public: Parses a log (a string containing newlines) into a Cabrillo

instance.

log_contents - A String containing the entire to parse.

TODO: Use a parsing lib like Treetop maybe?

Returns an instance of Cabrillo.

# File lib/cabrillo.rb, line 89
def parse(log_contents)
  cabrillo_info = Hash.new { |h,k| h[k] = [] }
  log_contents.lines.each do |line|
    line = line.strip

    # Ignore comments. (See README.md for info.)
    next if line.start_with? '#' or line.start_with? '//' or line.empty?

    # Info that can only appear once.
    cabrillo_info.merge! split_basic_line(line, 'START-OF-LOG', :version)
    cabrillo_info.merge! split_basic_line(line, 'CALLSIGN', :callsign)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-ASSISTED', :category_assisted, ContestValidators::CATEGORY_ASSISTED)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-BAND', :category_band, ContestValidators::CATEGORY_BAND)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-MODE', :category_mode, ContestValidators::CATEGORY_MODE)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-OPERATOR', :category_operator, ContestValidators::CATEGORY_OPERATOR)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-POWER', :category_power, ContestValidators::CATEGORY_POWER)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-STATION', :category_station, ContestValidators::CATEGORY_STATION)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-TIME', :category_time, ContestValidators::CATEGORY_TIME)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-TRANSMITTER', :category_transmitter, ContestValidators::CATEGORY_TRANSMITTER)
    cabrillo_info.merge! split_basic_line(line, 'CATEGORY-OVERLAY', :category_overlay, ContestValidators::CATEGORY_OVERLAY)
    cabrillo_info.merge! split_basic_line(line, 'CLAIMED-SCORE', :claimed_score, ContestValidators::CLAIMED_SCORE)
    cabrillo_info.merge! split_basic_line(line, 'CLUB', :club)
    cabrillo_info.merge! split_basic_line(line, 'CONTEST', :contest, ContestValidators::CONTEST)
    cabrillo_info.merge! split_basic_line(line, 'CREATED-BY', :created_by)
    cabrillo_info.merge! split_basic_line(line, 'EMAIL', :email)
    cabrillo_info.merge! split_basic_line(line, 'LOCATION', :location)
    cabrillo_info.merge! split_basic_line(line, 'NAME', :name)
    cabrillo_info.merge! split_basic_line(line, 'ADDRESS-CITY', :address_city)
    cabrillo_info.merge! split_basic_line(line, 'ADDRESS-STATE-PROVINCE', :address_state_province)
    cabrillo_info.merge! split_basic_line(line, 'ADDRESS-POSTALCODE', :address_postalcode)
    cabrillo_info.merge! split_basic_line(line, 'ADDRESS-COUNTRY', :address_country)

    # TODO: It would be great to remove some of the redundancy here.
    address = split_basic_line(line, 'ADDRESS', :address)
    cabrillo_info[:address] << address[:address] unless address.empty?

    soapbox = split_basic_line(line, 'SOAPBOX', :soapbox)
    cabrillo_info[:soapbox] << soapbox[:soapbox] unless soapbox.empty?

    club = split_basic_line(line, 'CLUB', :club)
    cabrillo_info[:club] << club[:club] unless club.empty?

    operators = split_basic_line(line, 'OPERATORS', :operators)
    cabrillo_info[:operators] << club[:operators] unless operators.empty?

    # If we already parsed in a contest then we're good. If not, we don't
    # know what to parse as, so skip.
    if line.start_with? "QSO: " and cabrillo_info[:contest]
      cabrillo_info[:qsos] << parse_qso(line, cabrillo_info[:contest])
    end
  end
  Cabrillo.new(cabrillo_info)
end
parse_file(file_path) click to toggle source

Public: A wrapper to Cabrillo.parse() to parse a log from a file.

file_path - The path to the logfile to parse.

Returns what Cabrillo.parse() returns, an instance of Cabrillo.

# File lib/cabrillo.rb, line 148
def parse_file(file_path)
  Cabrillo.parse(IO.read(file_path))
end

Private Class Methods

parse_qso(qso_line, contest) click to toggle source

Private: Parses a QSO: line based on the contest type.

qso_line - The Strnig containing the line of the logfile that we are

parsing. Starts with "QSO:"

contest - A String, the name of the contest that we are parsing.

Returns a Hash containing the parsed result.

# File lib/cabrillo.rb, line 195
def parse_qso(qso_line, contest)
  if @raise_on_invalid_data
    raise InvalidDataError, "Invalid contest: #{contest}" unless ContestValidators::CONTEST.include? contest
    raise InvalidDataError, "Line does not start with 'QSO: '" unless qso_line.start_with? "QSO: "
  end
  qso_line.gsub!(/^QSO: /, "")

  # Basic structure
  qso = {
    :exchange => {
      :sent     => {},
      :received => {}
    }
  }

  # In any and all cases, the first fields are: frequency, mode, date, time.
  # Store the exchange/everything else into an array (using splat) for
  #   later.
  qso[:frequency], qso[:mode], date, time, *exchange = qso_line.split

  # Parse the date and time into a Time object.
  qso[:time] = Time.parse(DateTime.strptime("#{date} #{time}", '%Y-%m-%d %H%M').to_s)

  # Transmitted callsign always comes first.
  qso[:exchange][:sent][:callsign] = exchange.shift

  # Parse the rest of the exchange
  case contest
  when 'CQ-160-CW', 'CQ-160-SSB', 'CQ-WPX-RTTY', 'CQ-WPX-CW', 'CQ-WPX-SSB', 'CQ-WW-RTTY', 'CQ-WW-CW', 'CQ-WW-SSB', 'ARRL-DX-CW', 'ARRL-DX-SSB', 'IARU-HF', 'ARRL-10', 'ARRL-160', 'JIDX-CW', 'JIDX-SSB', 'STEW-PERRY', 'OCEANIA-XD-CW', 'OCEANIA-DX-SSB', 'AP-SPRINT', 'NEQP', 'ARRL-FIELD-DAY'
    qso[:exchange][:sent][:rst] = exchange.shift
    qso[:exchange][:sent][:exchange] = exchange.shift

    qso[:exchange][:received][:callsign] = exchange.shift
    qso[:exchange][:received][:rst] = exchange.shift
    qso[:exchange][:received][:exchange] = exchange.shift
    qso[:exchange][:received][:transmitter_id] = exchange.shift
  when 'ARRL-SS-CW', 'ARRL-SS-SSB'
    qso[:exchange][:sent][:serial_number] = exchange.shift
    qso[:exchange][:sent][:precedence] = exchange.shift
    qso[:exchange][:sent][:check] = exchange.shift
    qso[:exchange][:sent][:arrl_section] = exchange.shift

    qso[:exchange][:received][:callsign] = exchange.shift
    qso[:exchange][:received][:serial_number] = exchange.shift
    qso[:exchange][:received][:precedence] = exchange.shift
    qso[:exchange][:received][:check] = exchange.shift
    qso[:exchange][:received][:arrl_section] = exchange.shift
  end

  qso
end
split_basic_line(line, key, hash_key, validators = []) click to toggle source

Private: Parses a specific line of the log, in most cases.

line - The String of log line to parse. key - The key to look for in the line. hash_key - The key to use in the resulting Hash.

Throws an Exception if validators are given but the data does not match

one of them.

Returns a Hash of {:hash_key => value_from_parsed_line} or nil if the key

wasn't found.
# File lib/cabrillo.rb, line 165
def split_basic_line(line, key, hash_key, validators = [])
  line_key, line_value = line.split(/:\s+/, 2)

  if line_key == key
    okay = true
    unless validators.empty?
      okay = false
      validators.each do |v|
        okay = true and break if v.class.to_s == 'Regexp' and line_value =~ v
        okay = true and break if v.class.to_s == 'String' and line_value == v
      end
    end

    if okay || !@raise_on_invalid_data
      { hash_key => line_value.strip }
    elsif !validators.empty? && @raise_on_invalid_data
      raise InvalidDataError, "Invalid value given for key `#{line_key}`."
    end
  else
    { }
  end
end

Public Instance Methods

to_hash() click to toggle source

Public: Return the collected data as a Hash.

Returns the data that was parsed (or given) as a Hash.

# File lib/cabrillo.rb, line 70
def to_hash
  h = {}
  self.instance_variables.each do |variable|
    h[variable[1..-1].to_sym] = self.instance_variable_get(variable)
  end
  h
end