Class: HowIs::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/how_is/cli.rb

Defined Under Namespace

Classes: InvalidInputFileError, InvalidOutputFileError, NoRepositoryError, OptionsError

Constant Summary collapse

DEFAULT_REPORT_FILE =
"report.#{HowIs::DEFAULT_FORMAT}".freeze

Class Method Summary collapse

Class Method Details

.parse(argv) ⇒ Object

Parses argv to generate an options Hash to control the behavior of the library.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/how_is/cli.rb', line 29

def self.parse(argv)
  opts = Slop::Options.new

  # General usage information.
  opts.banner =
    <<-EOF.gsub(/ *\| ?/, '')
      | Usage: how_is REPOSITORY [--report REPORT_FILE] [--from JSON_FILE]
      |        how_is --config CONFIG_FILE
      |
      | Where REPOSITORY is <GitHub username or org>/<repository name>.
      | CONFIG_FILE defaults to how_is.yml.
      |
      | E.g., if you wanted to check https://github.com/how-is/how_is,
      | you'd run `how_is how-is/how_is`.
      |
    EOF

  opts.separator ""
  opts.separator "Options:"

  # The extra spaces make this a lot easier to comprehend, so we don't want
  # RuboCop to complain about them.
  #
  # Same for line length.
  #
  # rubocop:disable Style/SpaceBeforeFirstArg
  # rubocop:disable Metrics/LineLength

  # Allowed arguments:
  opts.bool   "-h", "--help",    "Print help text"
  opts.string       "--config",  "YAML config file, used to generate a group of reports"
  opts.string       "--from",    "JSON report file, used instead of fetching the data again"
  opts.string       "--report",  "output file for the report (valid extensions: #{HowIs.supported_formats.join(', ')}; default: #{DEFAULT_REPORT_FILE})"
  opts.bool   "-v", "--version", "prints the version"

  # rubocop:enable Style/SpaceBeforeFirstArg
  # rubocop:enable Metrics/LineLength

  # Parse the arguments.
  parser    = Slop::Parser.new(opts)
  result    = parser.parse(argv)

  # +options+ is a Hash of flags/values.
  options   = result.to_hash
  # +arguments+ is an Array of values that don't correspond to a flag.
  arguments = result.arguments

  # If --report isn't specified, default to DEFAULT_REPORT_FILE.
  options[:report] ||= DEFAULT_REPORT_FILE

  # The following are only useful if they're not nil or false.
  # Removing them here simplifies contracts and keyword args for
  # other APIs.
  options.delete(:config)   unless options[:config]
  options.delete(:help)     unless options[:help]
  options.delete(:version)  unless options[:version]

  # If we can't export to the specified file, raise an exception.
  unless HowIs.can_export_to?(options[:report])
    raise InvalidOutputFileError, "Invalid file: #{options[:report]}. Supported formats: #{HowIs.supported_formats.join(', ')}"
  end

  # If we pass --config, other options (excluding --help and
  # --version) are ignored. As such, when --config is passed,
  # everything in this `unless` block is irrelevant.
  unless options[:config]
    if options[:from]
      raise InvalidInputFileError, "No such file: #{options[:from]}" unless File.file?(options[:from])

      # Opening the file here is a bit gross, but I couldn't find a
      # better way to do it. -@duckinator
      options[:repository] = JSON.parse(open(options[:from]).read)['repository']

      raise InvalidInputFileError, "Invalid JSON report file." unless options[:repository]

    elsif argv.length >= 1
      options[:repository] = argv.delete_at(0)

    else
      raise NoRepositoryError, "No repository specified."
    end
  end

  # Return a Hash with:
  #   +opts+: the original Slop::Options object.
  #   +options+: the Hash of flags/values (e.g. +--foo bar+ becomes
  #     +options[:foo]+ with the value of +"bar"+).
  #   +arguments+: an Array of arguments that don't have a
  #     corresponding flags.
  {
    opts: opts,
    options: options,
    arguments: arguments,
  }
end