Class: Optix

Inherits:
Object
  • Object
show all
Defined in:
lib/optix.rb,
lib/optix.rb,
lib/optix/version.rb

Defined Under Namespace

Classes: CLI, Cli, Command, Configurator, HelpNeeded

Constant Summary collapse

VERSION =
"2.0.0"
@@tree =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv = ARGV, scope = :default) ⇒ Optix

Returns a new instance of Optix.



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
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/optix.rb', line 35

def initialize(argv=ARGV, scope=:default)
  unless @@tree.include? scope
    raise RuntimeError, "Scope '#{scope}' is not defined"
  end
  o = @@tree[scope]

  parent_calls = o[:calls] || []
  filters = o[:filters] || []
  triggers = o[:triggers] || {}
  cmdpath = []
  while o.include? argv[0]
    cmdpath << cmd = argv.shift
    o = o[cmd]
    parent_calls += o[:calls] if o.include? :calls
    filters += o[:filters] if o.include? :filters
    triggers.merge! o[:triggers] if o.include? :triggers
  end

  o[:header] ||= "\n#{@@config[:text_header_usage]}\n"
  o[:params] ||= ''

  subcmds = o.keys.reject{|x| x.is_a? Symbol}

  if 0 < subcmds.length
    o[:params] = @@config[:text_param_subcommand]
  end

  text = o[:header].gsub('%0', File.basename($0)).gsub('%command', cmdpath.join(' ')).gsub('%params', o[:params]).gsub(/ +/, ' ')

  calls = []
  calls << [:nowrap, [text], nil]

  calls << [:banner, [' '], nil]
  unless o[:text].nil?
    calls << [:banner, [o[:text]], nil]
    calls << [:banner, [' '], nil]
  end

  # sort opts and move non-opt calls to the end
  non_opt = parent_calls.select {|x| x[0] != :opt }
  parent_calls = parent_calls.select {|x| x[0] == :opt }
  parent_calls.sort! {|a,b| ; a[1][0].to_s <=> b[1][0].to_s }
  parent_calls += non_opt
  parent_calls.unshift([:banner, [@@config[:text_header_options]], nil])
  calls += parent_calls

  unless @@config[:text_help].nil?
    calls << [:opt, [:help, @@config[:text_help]], nil]
  end

  if 0 < subcmds.length
    prefix = cmdpath.join(' ')

    text = ""
    wid = 0
    subcmds.each do |k|
      len = k.length + prefix.length + 1
      wid = len if wid < len
    end

    #calls << [:no_help_help, [], nil]

    subcmds.each do |k|
      cmd = "#{prefix} #{k}"
      text += "  #{cmd.ljust(wid)}"
      unless o[k][:description].nil?
        text += "   #{o[k][:description]}"
      end
      text += "\n"
    end

    if 0 < cmdpath.length
      calls << [:banner, ["\n#{@@config[:text_header_subcommands]}\n#{text}"], nil]
    else
      calls << [:banner, ["\n#{@@config[:text_header_topcommands]}\n#{text}"], nil]
    end
  end

  calls << [:banner, [" \n"], nil]

  parser = Trollop::Parser.new

  lastmeth = nil
  begin
    calls.each do |e|
      lastmeth = e[0]
      parser.send(e[0], *e[1])
    end
  rescue NoMethodError => e
    raise RuntimeError, "Unknown Optix command: '#{lastmeth}'"
  end

  # expose our goodies
  @parser = parser
  @node = o
  @filters = filters
  @triggers = triggers
  @command = cmdpath
  @subcommands = subcmds
end

Instance Attribute Details

#commandObject (readonly)

Returns the value of attribute command.



10
11
12
# File 'lib/optix.rb', line 10

def command
  @command
end

#filtersObject (readonly)

Returns the value of attribute filters.



10
11
12
# File 'lib/optix.rb', line 10

def filters
  @filters
end

#nodeObject (readonly)

Returns the value of attribute node.



10
11
12
# File 'lib/optix.rb', line 10

def node
  @node
end

#parserObject (readonly)

Returns the value of attribute parser.



10
11
12
# File 'lib/optix.rb', line 10

def parser
  @parser
end

#subcommandsObject (readonly)

Returns the value of attribute subcommands.



10
11
12
# File 'lib/optix.rb', line 10

def subcommands
  @subcommands
end

#triggersObject (readonly)

Returns the value of attribute triggers.



10
11
12
# File 'lib/optix.rb', line 10

def triggers
  @triggers
end

Class Method Details

.command(cmd = nil, scope = :default, &b) ⇒ Object



12
13
14
15
# File 'lib/optix.rb', line 12

def self.command cmd=nil, scope=:default, &b
  @@tree[scope] ||= {}
  Command.new(@@tree[scope], @@config, cmd, &b)
end

.configure(&b) ⇒ Object



31
32
33
# File 'lib/optix.rb', line 31

def self.configure &b
  Configurator.new(@@config, &b)
end

.invoke!(argv = ARGV, scope = :default) ⇒ Object



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
# File 'lib/optix.rb', line 136

def self.invoke!(argv=ARGV, scope=:default)
  optix = Optix.new(argv, scope)

  # If you need more flexibility than this block provides
  # then you may want to create your own Optix instance 
  # and perform the parsing manually.
  opts = Trollop::with_standard_exception_handling optix.parser do

    # Process triggers first
    triggers = optix.triggers
    opts = optix.parser.parse argv, triggers
    return if opts.nil?

    # Always show help-screen if the invoked command has subcommands.
    if 0 < optix.subcommands.length
      raise Trollop::HelpNeeded # show help screen
    end

    begin
      # Run filter-chain
      optix.filters.each do |filter|
        filter.call(optix.command, opts, argv)
      end

      # Run exec-block
      if optix.node[:exec].nil?
        raise RuntimeError, "Command '#{optix.command.join(' ')}' has no exec{}-block!"
      end
      optix.node[:exec].call(optix.command, opts, argv)
    rescue HelpNeeded
      raise Trollop::HelpNeeded
    end
  end
end

.reset!Object



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/optix.rb', line 17

def self.reset!
  @@config = {
    :text_help => 'Show this message', # set to nil to suppress help option
    :text_required => ' (required)',
    :text_header_usage => 'Usage: %0 %command %params',
    :text_header_subcommands => 'Subcommands:',
    :text_header_topcommands => 'Commands:',
    :text_header_options => 'Options:',
    :text_param_subcommand => '<command>'
  }
  @@tree = {}
end