Class: Ark::CLI::Interface

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

Overview

Main class for ark-cli. Defines a Spec, parses the command line and returns Report objects.

Defined Under Namespace

Classes: InterfaceError, SyntaxError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args, &block) ⇒ Interface

:call-seq: rebuild(input=ARGV) { |spec| … } => Interface

Initialize an Interface instance.

args must be an array of strings, like ARGV



22
23
24
# File 'lib/ark/cli/interface.rb', line 22

def initialize(args, &block)
  self.rebuild(args, &block)
end

Instance Attribute Details

#reportObject (readonly)

The Report object for this interface, for inspecting information parsed from the command line.



28
29
30
# File 'lib/ark/cli/interface.rb', line 28

def report
  @report
end

Instance Method Details

#parseObject

Parse the command line



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
124
125
126
127
128
129
130
# File 'lib/ark/cli/interface.rb', line 43

def parse()
  taking_options = true
  last_opt = nil

  args = []
  trailing = []
  named = {}
  options = {}
  counts = {}
  arg_index = 0

  @input.each do |word|
    dbg "Parsing '#{word}'"
    if last_opt && last_opt.has_args? && !last_opt.full?
      dbg "Got argument '#{word}' for '#{last_opt}'", 1
      last_opt.push(word)
    else
      if word[/^-/] && taking_options
        if word[/^-[^-]/]
          dbg "Identified short option(s)", 1
          shorts = word[/[^-]+$/].split('')
          shorts.each_with_index do |short, i|
            last_short = i == (shorts.length - 1)
            opt = @spec.get_opt(short)
            last_opt = opt
            if opt.has_args? && shorts.length > 1 && !last_short
              raise SyntaxError, "Error: -#{short} in compound option '#{word}' expects an argument"
            elsif opt.flag?
              opt.toggle()
              dbg "Toggled flag '#{opt}'", 1
            end
          end
        elsif word[/^--/]
          dbg "Identified long option", 1
          key = word[/[^-]+$/]
          opt = @spec.get_opt(key)
          last_opt = opt
          if opt.flag?
            opt.toggle()
            dbg "Toggled #{opt}", 1
          end
        end
      else
        dbg "Parsed output arg", 1
        taking_options = false
        arg = @spec.get_args.values[arg_index]
        arg_index += 1
        if arg && !arg.variadic?
          arg.set(word)
        elsif @spec.is_variadic?
          @spec.get_variad.push(word)
        else
          trailing << word
        end
      end
    end
  end

  @spec.get_opts.each do |name, opt|
    options[name] = opt.value
    counts[name]  = opt.count
  end

  @spec.get_args.each do |name, arg|
    args << arg.value
    named[name] = arg.value
  end
  args.flatten!
  args += trailing

  @report = Report.new(args, named, trailing, options, counts)

  if @report.opt(:help)
    self.print_usage
  end

  if @report.opt(:version)
    self.print_version
  end

  unless @spec.get_args.values.all? {|arg| arg.fulfilled? }
    raise InterfaceError, "Required argument '#{name.upcase}' was not given."
  end

  if @spec.trailing_error && !@report.trailing.empty?
    raise InterfaceError, "Error: got trailing argument(s): #{trailing.join(', ')}"
  end
end

Print usage information and exit



192
193
194
195
# File 'lib/ark/cli/interface.rb', line 192

def print_usage
  puts self.usage
  exit 0
end


197
198
199
200
# File 'lib/ark/cli/interface.rb', line 197

def print_version
  puts @spec.get_version
  exit 0
end

#rebuild(input = ARGV) {|@spec| ... } ⇒ Object

Rebuild the interface with a new spec and args

Yields:

  • (@spec)


31
32
33
34
35
36
37
38
39
40
# File 'lib/ark/cli/interface.rb', line 31

def rebuild(input=ARGV, &block)
  @input = input
  @spec = Spec.new
  yield @spec
  @spec.opt :help, :h, desc: "Print usage information and exit"
  if @spec.get_version
    @spec.opt :version, :V, desc: "Print version information and exit"
  end
  self.parse
end

#usageObject

Construct usage information



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/ark/cli/interface.rb', line 133

def usage()
  tb = TextBuilder.new()

  tb.next('USAGE:')
  tb.push(@spec.get_name) if @spec.get_name

  if @spec.get_opts.values.uniq.length < 5 || @spec.option_listing
    @spec.get_opts.values.uniq.each do |opt|
      tb.push("[#{opt.header}]")
    end
  else
    tb.push('[OPTION...]')
  end

  if @spec.has_args?
    if @spec.is_variadic?
      singles = @spec.get_args.values[0..-2].map do |a|
        name = a.name
        if a.has_default?
          name = "[#{name}]"
        end
        name.upcase
      end
      tb.push(singles)
      v = @spec.get_variad.name.upcase
      tb.push("[#{v}1 #{v}2...]")
    else
      argmap = @spec.get_args.values.map do |a|
        name = a.name
        if a.has_default?
          name = "[#{name}]"
        end
        name.upcase
      end
      tb.push(argmap)
    end
  end

  tb.wrap(indent: 7, indent_after: true, segments: true)

  if @spec.get_desc
    tb.skip(@spec.get_desc)
    tb.wrap(indent: 4)
  end

  tb.skip('OPTIONS:').skip

  @spec.get_opts.values.uniq.each do |opt|
    tb.indent(4).push(opt.header)
    if opt.desc
      tb.next.indent(8).push(opt.desc)
    end
    tb.skip
  end

  return tb.to_s
end