davetron5000 / gli

Make awesome command-line applications the easy way
http://davetron5000.github.io/gli
Apache License 2.0
1.26k stars 102 forks source link

Do the actions outside of the `GLI::App` #292

Closed paul-mesnilgrente closed 4 years ago

paul-mesnilgrente commented 4 years ago

I started to use the GLI gem thinking I could have it behaving like OptionParser. But I am struggling on 1 point. With OptionParser, you can define an object like options = {} and modify it in the block.

I don't find any way to get an object out of my ArgumentParser. In clear: I don't want to do my actions in the ArgumentParser.

#!/usr/bin/env ruby

require 'gli'

class Action
  def initialize(global_options, options, args)
    @global_options = global_options
    @options = options
    @args = args
  end
end

class AddAction < Action
  def call
    # do my stuff on the database
    return "Your item has been added"
  end
end

class HelpAction < Action
  def call
    # how do I return the help text?
  end
end

class ArgumentParser
  extend GLI::App

  program_desc 'My command'
  command :add do |c|
    c.action do |global_options, options, args|
      add_action = AddAction.new(global_options, options, args)
      puts "list action"
      # How do I return `add_action`?
    end
  end
end

exit ArgumentParser.run(ARGV)
# is there an alternative to `run`?
# I want to get an instance of `Action` instead

The reason is that I am using GLI in a web server context and I don't to print logs but return strings as a JSON response.

davetron5000 commented 4 years ago

Not sure I totally understand the use case, but GLI is not designed to be persistent so I'm not sure what global state might get screwed up if you use it to parse CLI options in a long-running process.

That all said, you can call run directly. AppSupport is mixed into App and so those methods are public.

The block given to the action method works like any other ruby block, so this would work:

add_action = nil

class ArgumentParser
  extend GLI::App

  program_desc 'My command'
  command :add do |c|
    c.action do |global_options, options, args|
      add_action = AddAction.new(global_options, options, args)
    end
  end
end

exit_code = ArgumentParser.run

# add_action should not be nil if the `add` command was triggered

Also note that GLI's internals create instances of the Command class so you might be duplicating effort by creating your own actions.

In terms of accessing the help text - I'm not sure. Like I said above, GLI is designed to build command line programs which only experience a single "parse the CLI options" once per run. The help text is designed to be output not captured, but you can use the Help command directly and pass in a different stream than stdout and stderr.

As a final "warning", this would all rely on internal APIs that could change (though I don't have any plans to re-architect GLI so likely none of the internals will change)

paul-mesnilgrente commented 4 years ago

Ok, thanks for you quick answer. As far as I understand, the library doesn't fit my needs. I'll try to find another way :)