matheusmoreira / acclaim

Command-line option parsing and command interface.
https://rubygems.org/gems/acclaim
6 stars 1 forks source link

[feature request] add arbitrary text to the help message #1

Open jtprince opened 11 years ago

jtprince commented 11 years ago

[I've used and played around with lots of commandline utilties (optparse, trollop, micro-optparse, commander, optitron) and I think acclaim is shaping up to be really awesome. I like the way you've organized the code--very clean. There are a few features that I would really like to see, and perhaps they would also fit into your vision.]

In structuring a help message, it is very useful to be able to add notes, examples, or groupings. This means that a user should be able to add any arbitrary text to the help message. Some of the command line utilities I write have dozens of options, so I need to be able to group them.

e.g., Optparse has "separator", Trollop has "text". I personally like the method name "text"

Thanks!

matheusmoreira commented 11 years ago

Thanks for your suggestions! I did my best to design a natural and readable API.

This is a nice feature. Help is documentation, and as such, it should contain notes and examples. It should be straightforward for commands. What do you think of the following DSL?

class Application::Command < Acclaim::Command

  # Strings can contain multiple lines if needed
  # Proc support is for internationalized applications

  example string
  example '$ application file1 file2 file3'
  example { proc_that_returns_string }

  note string
  note 'This command is dangerous if given the force option!'   # Possible aliases: notice
  note { proc_that_returns_string }

  description string
  description 'Creates a new project'
  description { proc_that_returns_string }

  text string
  text 'This will be appended to the end of the help text'
  text { proc_that_returns_string }

end

Separate contexts are useful when writing templates; so that different information can be formatted differently. These methods would be implemented in a new module named Acclaim::Command::DSL::Help.

Regarding option grouping, I need more details, since I'm not sure about the complexity it will require. Do you mean something like:

class Application::Command < Acclaim::Command

  option_set :experimental do
    description 'These options have not been tested.'
    note "If problems occur, please file a bug report at #{Application::Gem.homepage}"
    option :threads, 'Number of threads to spawn', Integer, arity: [1, 0], default: 1
  end

end

Again, thanks! I'll go take a look at the other issues now.

jtprince commented 11 years ago

I really like your idea to use different methods (e.g., example, note, description) to document various aspects of the help message. It also makes the whole thing generic so that a different backend (e.g., html) could be swapped in with little effort.

I think you have the right idea with the grouping example you gave. Here is the exact example I'm trying to convert over from Trollop. As you can see, I need to be able to group these, or at least add headers in the help because there are just too many options to list in one clump:

text "\ngeneral:"
  opt :config, "read a config file for default values. Command line

options overide those from the config file ", :type => :string opt :print_config, "print current options to #{default_config} and exit" opt :omit_zeros, "remove zero values" opt :combine, "combine all files and set the base name of resulting imzML and ibd files", :type => String opt :outfile, "use a specific basename for the resulting file. Acts like --combine for multiple files", :type => String

  text "\nimaging:"
  opt :continuous, "assumes m/z values are the same for every scan. The

'processed' storage format is used unless this flag is given." opt :scan_pattern, scan_patterns.join('|'), :default => scan_patterns.first opt :scan_type, scan_types.join('|'), :default => scan_types.first opt :linescan_direction, scan_direction.join('|'), :default => scan_direction.first opt :linescan_sequence, scan_sequence.join('|'), :default => scan_sequence.first opt :max_dimensions_pixels, "maximum X by Y pixels (e.g. 300x100)", :default => default_dims opt :shots_per_position, "number of spectra per position", :default => 1 opt :pixel_size, "X by Y of a single pixel in microns (ìm)", :default => default_pixel_size opt :max_dimensions_microns, "maximum X by Y in microns (e.g. 25x20)", :default => default_dims

  text "\ncontact: "
  opt :name, "name of the person or organization", :type => :string
  opt :address, "address of the person or organization", :type =>

:string opt :url, "url of person or organization", :type => :string opt :email, "email of person or organization", :type => :string opt :organization, "home institution of contact", :type => :string

  text "\nDESI: "
  opt :solvent, "the solvent used", :type => :string
  opt :solvent_flowrate, "flowrate of the solvent (ml/min)", :type =>

:float opt :spray_voltage, "spray voltage in kV", :type => :float opt :target_material, "the material the target is made of", :type => :string

  text "\nMALDI: "
  opt :matrix_application_types, "#{matrix_application_types.join('|')}

(comma separated)", :type => :string opt :matrix_solution_concentration, "in grams per liter", :type => :float opt :matrix_solution, "the chemical solution used as matrix (e.g., DHB)", :type => :string

best regards, John

matheusmoreira commented 11 years ago

By the way, full configuration file support is planned. Here's what I plan to do:

jtprince commented 11 years ago

awesome--config file support will be essential for many apps. XDG dir spec looks to be the one to follow for location. Maybe --config-file is better than --configuration-file (it's debatable)?