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



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

def parse()
  taking_options = true
  last_opt = nil
  refargs = @spec.get_args.clone

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

  @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
        args << word
        key = refargs.shift
        if key
          if key == @spec.get_variad
            named[key] = []
            named[key] << word
          else
            named[key] = word
          end
        elsif @spec.is_variadic?
          named[@spec.get_variad] << word
        else
          trailing << word
        end
      end
    end
  end
  if @spec.trailing_error && !trailing.empty?
    raise InterfaceError, "Error: got trailing option(s): #{trailing.join(', ')}"
  end
  @spec.get_opts.each do |name, opt|
    options[name] = opt.value
    counts[name]  = opt.count
  end
  @spec.get_args.each do |name|
    if named[name].nil?
      if @spec.has_default?(name)
        named[name] = @spec.get_default(name)
        args << named[name]
      else
        unless @spec.is_variadic? && @spec.get_variad == name
          raise InterfaceError, "Required argument '#{name.upcase}' was not given."
        end
      end
    end
  end
  if @spec.is_variadic?
    named[@spec.get_variad] ||= []
  end
  @report = Report.new(args, named, trailing, options, counts)
  if @report.opt(:help)
    self.print_usage()
  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

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

Rebuild the interface with a new spec and args

Yields:

  • (@spec)


31
32
33
34
35
36
37
# 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"
  self.parse
end

#usageObject

Construct usage information



131
132
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 131

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[0..-2].map do |a|
        if @spec.has_default?(a)
          a = "[#{a}]"
        end
        a.upcase
      end
      tb.push singles
      v = @spec.get_args.last.upcase
      tb.push "[#{v}1 #{v}2...]"
    else
      argmap = @spec.get_args.map do |a|
        if @spec.has_default?(a)
          a = "[#{a}]"
        end
        a.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:'
  tb.skip

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

  return tb.print
end