class Calrom::OptionParser

Parses command line options, produces Config.

Public Class Methods

call(argv) click to toggle source
# File lib/calrom/option_parser.rb, line 15
def self.call(argv)
  self.new.call(argv)
end

Public Instance Methods

call(argv) click to toggle source
# File lib/calrom/option_parser.rb, line 19
    def call(argv)
      config = Config.new

      today = config.today
      year = today.year
      month = today.month
      day = nil
      another_day = nil

      range_type = nil

      opt_parser = CustomizedOptionParser.new do |opts|
        opts.banner = <<~EOS
        Usage: calrom [options] [arg1 [arg2]]

        Specifying date range (cal/ncal-compatible):

          calrom             - current month
          calrom -m 5        - May of the current year
          calrom -m 5p       - May of the previous year
          calrom -m 5f       - May of the following year
          calrom -m 5 2000   - May 2000
          calrom 5 2000      - also May 2000
          calrom 2000        - whole year 2000
          calrom -y 2000     - also whole year 2000
          calrom -y          - whole current year

        Specifying date range (not cal-compatible):

          calrom 2000-05-31              - specified day (only)
          calrom 2000-05-31 2000-07-01   - arbitrary date range
          calrom (--yesterday|--today|--tomorrow)

        EOS

        opts.separator 'Configuration files'

        opts.on('--config=CONFIG', 'load configuration from file (may be used multiple times, all specified files will be loaded)') do |value|
          config.configs << value
        end

        opts.separator 'Options selecting date range'

        # cal
        opts.on('-m MONTH', '--month=MONTH', 'display the specified month. \'f\' or \'p\' can be appended to display the same month of the following or previous year respectively') do |value|
          range_type = :month
          if value =~ /^(\d+)([pf])$/
            month = $1
            year = validate_year(year) + ($2 == 'f' ? 1 : -1)
          else
            month = value
          end
        end

        # cal
        opts.on('-y', '--year', 'display specified (or current) year') do |value|
          range_type = :year
        end

        opts.on('--yesterday', 'display previous day') do |value|
          day = Date.today - 1
          range_type = :day
        end

        opts.on('--today', 'display current day') do |value|
          day = Date.today
          range_type = :day
        end

        opts.on('--tomorrow', 'display following day') do |value|
          day = Date.today + 1
          range_type = :day
        end

        opts.separator "Options configuring liturgical calendar"

        opts.on('-c CAL', '--calendar=CAL', 'specify (sanctorale) calendar to use. If repeated, layers all specified calendars one over another') do |value|
          config.sanctorale << value
        end

        locales_help = I18n.available_locales.join(', ')
        opts.on('--locale=LOCALE', "override language in which temporale celebration titles are rendered (supported: #{locales_help})") do |value|
          config.locale = value.to_sym
        end

        opts.separator 'Options affecting presentation'

        opts.on('-l', '--list', 'display detailed listing of days and celebrations (synonym to --format=list)') do
          config.formatter = :list
        end

        supported_formats = %i(overview list csv json)
        formats_help = supported_formats.join(', ')
        opts.on('--format=FORMAT', supported_formats, "specify output format (supported: #{formats_help})") do |value|
          config.formatter = value
        end

        # cal
        opts.on('-e', '--easter', 'display date of Easter (only)') do
          config.formatter = :easter
        end

        opts.on('--calendars', 'list bundled calendars') do |value|
          config.formatter = :calendars
        end

        opts.on('--[no-]color', 'enable/disable colours (enabled by default)') do |value|
          config.colours = value
        end

        opts.separator 'Debugging options'

        # cal
        opts.on('-d YM', '--current-month=YM', 'use given month (YYYY-MM) as the current month (for debugging of date range selection)') do |value|
          year, month = value.split '-'
        end

        # cal
        opts.on('-H DATE', '--highlight-date=DATE', 'use given date as the current date (for debugging of highlighting)') do |value|
          config.today = validate_day value
        end

        opts.separator 'Information regarding calrom'

        opts.on('-V', '--version', 'display calrom version') do
          puts 'calrom v' + Calrom::VERSION
          exit
        end

        # Normally optparse defines this option by default, but once -H option is added,
        # for some reason -h (if not defined explicitly) is treated as -H.
        opts.on('-h', '--help', 'display this help') do
          puts opts
          exit
        end
      end

      arguments = opt_parser.parse argv

      iso_date_regexp = /^(\d{4}-\d{2}-\d{2})$/
      match(arguments) do
        with(_[iso_date_regexp.(date)]) do
          range_type = :day
          day = date
        end

        with(_[iso_date_regexp.(date), iso_date_regexp.(another_date)]) do
          range_type = :free
          day = date
          another_day = another_date
        end

        with(_[y]) do
          range_type ||= :year
          year = y
        end

        with(_[m, y]) do
          range_type = :month
          month, year = m, y
        end

        with([]) {}

        with(_) do
          raise InputError.new('too many arguments')
        end
      end

      config.date_range =
        build_date_range(
          range_type,
          validate_year(year),
          validate_month(month),
          day && validate_day(day),
          another_day && validate_day(another_day)
        )

      config.freeze
    end

Protected Instance Methods

build_date_range(range_type, year, month, day, another_day=nil) click to toggle source
# File lib/calrom/option_parser.rb, line 227
def build_date_range(range_type, year, month, day, another_day=nil)
  range =
    case range_type
    when :year
      Year.new(year)
    when :day
      Day.new(day)
    when :free
      DateRange.new(day, another_day)
    else
      Month.new(year, month)
    end

  beginning = CR::Calendar::EFFECTIVE_FROM
  if range.first < beginning
    raise InputError.new("implemented calendar system in use only since #{beginning}")
  end

  range
end
validate_day(day) click to toggle source
# File lib/calrom/option_parser.rb, line 219
def validate_day(day)
  return day if day.is_a? Date

  Date.parse(day)
rescue ArgumentError
  raise InputError.new("not a valid date #{day}")
end
validate_month(month) click to toggle source
# File lib/calrom/option_parser.rb, line 210
def validate_month(month)
  unless month.is_a?(Integer) ||
         (month =~ /^\d+$/ && (1..12).include?(month.to_i))
    raise InputError.new("not a valid month #{month}")
  end

  month.to_i
end
validate_year(year) click to toggle source
# File lib/calrom/option_parser.rb, line 202
def validate_year(year)
  unless year.is_a?(Integer) || year =~ /^\d+$/
    raise InputError.new("not a valid year #{year}")
  end

  year.to_i
end