Module: Rubikon::Application::InstanceMethods

Included in:
Base
Defined in:
lib/rubikon/application/instance_methods.rb

Overview

This module contains internal instance methods of Application::Base and its subclasses.

See Also:

Author:

  • Sebastian Staudt

Since:

  • 0.2.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object (private)

This is used to determine the receiver of a method call inside the application code.

This is used to have a convenient way to access e.g. paramter arguments.

This will delegate a method call to the currently executed parameter if the receiving object exists and responds to the desired method. Currently executed means the application’s execution is inside a parameter’s code block at the moment, i.e. a call to a missing method inside a parameter’s code block will trigger this behavior.

Examples:

Access a command’s arguments

command :args, [:one, :two] do
  puts "One: #{one}, Two: #{two}"
end

Since:

  • 0.4.0



332
333
334
335
336
337
338
339
340
# File 'lib/rubikon/application/instance_methods.rb', line 332

def method_missing(name, *args, &block)
  receiver = @current_param || @current_command
  if receiver.nil? || (!receiver.respond_to?(name) &&
     !receiver.public_methods(false).include?(name))
    super
  else
    receiver.send(name, *args, &block)
  end
end

Instance Attribute Details

#current_paramParameter

Returns The parameter that’s currently executed.

Returns:

  • (Parameter)

    The parameter that’s currently executed

Since:

  • 0.2.0



33
34
35
# File 'lib/rubikon/application/instance_methods.rb', line 33

def current_param
  @current_param
end

#sandboxApplication::Sandbox (readonly)

Returns The sandbox this application runs in.

Returns:

Since:

  • 0.2.0



36
37
38
# File 'lib/rubikon/application/instance_methods.rb', line 36

def sandbox
  @sandbox
end

Instance Method Details

#base_file=(file) ⇒ Object (private)

Sets the (first) file this application has been defined in.

This also sets the path of the application used to load external command code and the default banner for the help screen.

Parameters:

  • file (String)

    The (first) file of the class definition

See Also:

Since:

  • 0.4.0



149
150
151
152
153
154
# File 'lib/rubikon/application/instance_methods.rb', line 149

def base_file=(file)
  @base_file = file
  @path      = File.dirname(file)

  @settings[:help_banner] ||= "Usage: #{Pathname.new(file).relative_path_from(Pathname.new(Dir.getwd))}"
end

#debug_flagFlag (private)

Defines a global Flag for enabling debug output

This will define a Flag --debug (with alias -d) to enable debug output. Using it sets Ruby’s global variable $DEBUG to true.

Returns:

  • (Flag)

    The debug flag

Since:

  • 0.2.0



163
164
165
166
167
168
# File 'lib/rubikon/application/instance_methods.rb', line 163

def debug_flag
  global_flag :debug do
    $DEBUG = true
  end
  global_flag :d => :debug
end

#estream=(estream) ⇒ Object (private)

Sets the error output stream of the application

If colors are enabled, this checks if the stream supports the color_filter method and enables the ColoredIO if not.

Parameters:

  • estream (IO)

    The output stream to use

See Also:

Since:

  • 0.6.0



178
179
180
181
182
183
# File 'lib/rubikon/application/instance_methods.rb', line 178

def estream=(estream)
  if !estream.respond_to?(:color_filter)
    ColoredIO.add_color_filter(estream, @settings[:colors])
  end
  @settings[:estream] = estream
end

#help(info = nil) ⇒ Object (private)

Prints a help screen for this application

Parameters:

  • info (String) (defaults to: nil)

    A additional information string to be displayed right after usage information

Since:

  • 0.6.0



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/rubikon/application/instance_methods.rb', line 190

def help(info = nil)
  help = {}
  @commands.each_value do |command|
    help[command.name.to_s] = command.description
  end
  help.delete('__default')

  if @commands.key? :__default
    puts " [command] [args]\n\n"
  else
    puts " command [args]\n\n"
  end

  puts "#{info}\n\n" unless info.nil?

  puts 'Commands:'
  max_command_length = help.keys.max_by { |a| a.size }.size
  help.sort_by { |name, description| name }.each do |name, description|
    puts "  #{name.ljust(max_command_length)}    #{description}"
  end

  if @commands.key?(:__default) &&
     @commands[:__default].description != '<hidden>'
    put "\nYou can also call this application without a command:"
    puts @commands[:__default].help(false) + "\n"
  end
end

#help_commandObject (private)

Defines a command for displaying a help screen

This takes any defined commands and it’s corresponding options and descriptions and displays them in a user-friendly manner.

Since:

  • 0.2.0



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/rubikon/application/instance_methods.rb', line 222

def help_command
  commands = @commands
  global_parameters = @global_parameters
  settings = @settings

  command :help, 'Show help for the application or a single command',
          :cmd => :optional do
    put settings[:help_banner]

    global_params = ''
    global_parameters.values.uniq.sort_by { |a| a.name.to_s }.each do |param|
      global_params << ' ['
      ([param.name] + param.aliases).each_with_index do |name, index|
        name = name.to_s
        global_params << '|' if index > 0
        global_params << '-' if name.size > 1
        global_params << "-#{name}"
      end
      global_params << ' ...' if param.is_a?(Option)
      global_params << ']'
    end
    put global_params

    app_help = lambda { |info| @__app__.instance_eval { help(info) } }

    unless cmd.nil?
      name = cmd.to_sym
      if commands.key? name
        puts commands[name].help
      else
        app_help.call("The command \"#{cmd}\" is undefined. The following commands are available:")
      end
    else
      app_help.call(nil)
    end
  end
end

#hidden_output(&block) ⇒ Object (private)

Hide output inside the given block and print it after the block has finished

If the block needs to print to the real IO stream, it can access it using its first parameter.

Parameters:

  • block (Proc)

    The block that should not print output while it’s running

Since:

  • 0.2.0



268
269
270
271
272
273
274
275
276
# File 'lib/rubikon/application/instance_methods.rb', line 268

def hidden_output(&block)
  current_ostream = ostream
  self.ostream = StringIO.new

  block.call(current_ostream)

  current_ostream << ostream.string
  self.ostream = current_ostream
end

#hook(name) ⇒ Object (private)

Executes the hook with the secified name

Parameters:

  • name (Symbol)

    The name of the hook to execute

Since:

  • 0.4.0



282
283
284
# File 'lib/rubikon/application/instance_methods.rb', line 282

def hook(name)
  @sandbox.instance_eval(&@hooks[name]) unless @hooks[name].nil?
end

#initObject (private)

This method is called once for each application and is used to initialize anything that needs to be ready before the application is run, but after the application is setup, i.e. after the user has defined the application class.

Since:

  • 0.2.0



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'lib/rubikon/application/instance_methods.rb', line 290

def init
  return if @initialized

  hook = InstanceMethods.instance_method(:hook).bind(self)

  @current_command      = nil
  @current_param        = nil
  @current_global_param = nil

  hook.call(:pre_init)

  InstanceMethods.instance_method(:debug_flag).bind(self).call
  InstanceMethods.instance_method(:help_command).bind(self).call
  InstanceMethods.instance_method(:verbose_flag).bind(self).call

  if @settings[:help_as_default] && @commands.key?(:help) &&
     !@commands.key?(:__default)
    default :help
  end

  @initialized = true

  hook.call(:post_init)
end

#initializeObject

Initialize with default settings

If you really need to override this in your application class, be sure to call super

See Also:

  • #set

Since:

  • 0.2.0



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
# File 'lib/rubikon/application/instance_methods.rb', line 44

def initialize
  @commands          = {}
  @current_command   = nil
  @current_param     = nil
  @default_config    = {}
  @global_parameters = {}
  @hooks             = {}
  @initialized       = false
  @parameters        = []
  @sandbox           = Sandbox.new(self)
  @settings          = {
    :autohelp        => true,
    :autorun         => true,
    :colors          => true,
    :config_file     => "#{self.class.to_s.downcase}.yml",
    :help_as_default => true,
    :istream         => $stdin,
    :name            => self.class.to_s,
    :raise_errors    => false
  }

  if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
    global_config_path = ENV['ALLUSERSPROFILE']
  else
    global_config_path = '/etc'
  end

  @settings[:config_paths] = [
    global_config_path, File.expand_path('~'), File.expand_path('.')
  ]

  self.estream = $stderr
  self.ostream = $stdout
end

#ostream=(ostream) ⇒ Object (private)

Sets the output stream of the application

If colors are enabled, this checks if the stream supports the color_filter method and enables the ColoredIO if not.

Parameters:

  • ostream (IO)

    The output stream to use

See Also:

Since:

  • 0.2.0



349
350
351
352
353
354
# File 'lib/rubikon/application/instance_methods.rb', line 349

def ostream=(ostream)
  if !ostream.respond_to?(:color_filter)
    ColoredIO.add_color_filter(ostream, @settings[:colors])
  end
  @settings[:ostream] = ostream
end

#parse_arguments(argv) ⇒ Array<Parameter>, Command (private)

Parses the command-line arguments given to the application by the user. This distinguishes between commands, global flags and command flags

Parameters:

  • argv (String)

    The command-line arguments

Returns:

  • (Array<Parameter>)

    one All global parameters that have been supplied

  • (Command)

    two The command to execute, the parameters of this command that have been supplied

  • (Array<Parameter>)

    three All parameters of that command that have been supplied

Raises:

Since:

  • 0.2.0



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
# File 'lib/rubikon/application/instance_methods.rb', line 371

def parse_arguments(argv)
  argv.extend ArgumentVector

  argv.expand!

  command, command_index = argv.command! @commands
  raise NoDefaultCommandError if command.nil?

  command_params = argv.params! command.params, command_index
  global_params  = argv.params! @global_parameters

  argv.scoped_args! command

  unless argv.empty?
    first = argv.first
    if first.start_with? '-'
      raise UnknownParameterError.new(first)
    else
      raise UnknownCommandError.new(first)
    end
  end

  return global_params, command, command_params
end

#resetObject (private)

Resets this application to its initial state

This rewinds the output stream, removes the color features from the and resets all commands and global parameters.

See Also:

Since:

  • 0.4.0



407
408
409
410
411
412
413
414
415
# File 'lib/rubikon/application/instance_methods.rb', line 407

def reset
  [estream, ostream].each do |stream|
    stream.rewind if stream.is_a? StringIO || !stream.stat.chardev?
    ColoredIO.remove_color_filter(estream)
  end
  (@commands.values + @global_parameters.values).uniq.each do |param|
    param.send :reset
  end
end

#run(args = ARGV) ⇒ Object

Run this application

Calling this method explicitly is not required when you want to create a simple application (having one main class inheriting from Rubikon::Application). But it’s useful for testing or if you want to have some sort of sub-applications.

Parameters:

  • args (Array<String>) (defaults to: ARGV)

    The command line arguments that should be given to the application as options

Since:

  • 0.2.0



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
135
136
# File 'lib/rubikon/application/instance_methods.rb', line 88

def run(args = ARGV)
  hook = InstanceMethods.instance_method(:hook).bind(self)

  begin
    InstanceMethods.instance_method(:init).bind(self).call
    global_params, command, command_params = InstanceMethods.
      instance_method(:parse_arguments).bind(self).call(args)

    @config_factory = Config::Factory.new(@settings[:config_file],
      @settings[:config_paths], @settings[:config_format])
    @config = @default_config.merge @config_factory.config

    global_params.each do |param|
      @current_param = param
      param.send :active!
      @current_param = nil
    end

    @current_command = command
    hook.call(:pre_execute)

    command_params.each do |param|
      @current_param = param
      param.send :active!
      @current_param = nil
    end

    result = command.send(:run)
    hook.call(:post_execute)
    @current_command = nil

    result
  rescue Interrupt
    error "\nInterrupted... exiting."
  rescue
    raise $! if @settings[:raise_errors]

    if @settings[:autohelp] && @commands.key?(:help) &&
       $!.is_a?(UnknownCommandError)
      call :help, $!.command
    else
      error "r{Error:}\n    #{$!.message}"
      error "     at #{$!.backtrace.join("\n     at ")}" if $DEBUG
      exit 1
    end
  ensure
    InstanceMethods.instance_method(:reset).bind(self).call
  end
end

#verbose_flagFlag (private)

Defines a global Flag for enabling verbose output

This will define a Flag --verbose and -v to enable verbose output. Using it sets Ruby’s global variable $VERBOSE to true.

Returns:

  • (Flag)

    The verbose Flag object

Since:

  • 0.2.0



424
425
426
427
428
429
# File 'lib/rubikon/application/instance_methods.rb', line 424

def verbose_flag
  global_flag :verbose do
    $VERBOSE = true
  end
  global_flag :v => :verbose
end