diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..536ea0e --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +custom/zsh + +vim/backups +vim/view +*un~ +vim/.netrwhist +vim/tmp +vim/spell +vim/after/.vimrc.after +vim/.vundles.local +vim/bundle +vim/sessions +.netrwhist +bin/subl +tags diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9952f59 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "zsh/prezto"] + path = zsh/prezto + url = https://github.com/sorin-ionescu/prezto.git + ignore = dirty diff --git a/.moda b/.moda new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1cea662 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2011-2012, Yan Pritzker +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8f62145 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ + __ __ _____ ____ __ + ( \/ )( _ )( _ \ /__\ + ) ( )(_)( )(_) )/(__)\ + (_/\/\_)(_____)(____/(__)(__) + _ _ _ + # MODA dotfile repo + + sh -c "`curl -fsSL https://raw.github.com/fmoda3/dotfiles/master/install.sh`" + +**Always be sure to run `rake update` after pulling to ensure plugins are updated** + +## Installation + +To get started please run: + +```bash +sh -c "`curl -fsSL https://raw.github.com/fmoda3/dotfiles/master/install.sh`" +``` + +**Note:** MODA will automatically install all of its subcomponents. If you want to be asked +about each one, use: +```bash +sh -c "`curl -fsSL https://raw.github.com/fmoda3/dotfiles/master/install.sh`" -s ask +``` + +* Install iTerm Solarized Colors - MODA will install Solarized colorschemes into your iTerm. Go to Profiles => Colors => Load Presets to pick Solarized Dark. +* [Remap caps-lock to escape with PCKeyboardHack](http://pqrs.org/macosx/keyremap4macbook/pckeyboardhack.html) - The escape key is the single most used key in vim. Old keyboards used to have Escape where Tab is today. Apple keyboards are the worst with their tiny Esc keys. But all this is fixed by remapping Caps to Escape. If you're hitting a small target in the corner, you are slowing yourself down considerably, and probably damaging your hands with repetitive strain injuries. +* Remap your Alfred or Spotlight to `Ctrl-Cmd-Space`, so that you can use `Cmd-Space` to autocomplete in vim. This is much more friendly for your fingers than `Ctrl-n`. + +### Upgrading + +Upgrading is easy. + +```bash +cd ~/.moda +git pull --rebase +rake update +``` + +### Credits + +This is a modification for personal use of the YADR repo found here https://github.com/skwp/dotfiles diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..cdc7a0c --- /dev/null +++ b/Rakefile @@ -0,0 +1,340 @@ +require 'rake' +require 'fileutils' +require File.join(File.dirname(__FILE__), 'bin', 'moda', 'vundle') + +desc "Hook our dotfiles into system-standard positions." +task :install => [:submodule_init, :submodules] do + puts + puts "======================================================" + puts "Welcome to MODA Installation." + puts "======================================================" + puts + + install_homebrew if RUBY_PLATFORM.downcase.include?("darwin") + + # this has all the runcoms from this directory. + file_operation(Dir.glob('zsh/config/*')) if want_to_install?('zsh configs') + file_operation(Dir.glob('git/*')) if want_to_install?('git configs (color, aliases)') + file_operation(Dir.glob('tmux/*')) if want_to_install?('tmux config') + if want_to_install?('vim configuration (highly recommended)') + file_operation(Dir.glob('{vim,vimrc}')) + Rake::Task["install_vundle"].execute + end + + Rake::Task["install_prezto"].execute + + install_tmuxinator + + install_fonts if RUBY_PLATFORM.downcase.include?("darwin") + + install_term_theme if RUBY_PLATFORM.downcase.include?("darwin") + + success_msg("installed") +end + +task :install_prezto do + if want_to_install?('zsh enhancements & prezto') + install_prezto + end +end + +task :update do + Rake::Task["vundle_migration"].execute if needs_migration_to_vundle? + Rake::Task["install"].execute + #TODO: for now, we do the same as install. But it would be nice + #not to clobber zsh files +end + +task :submodule_init do + unless ENV["SKIP_SUBMODULES"] + run %{ git submodule update --init --recursive } + end +end + +desc "Init and update submodules." +task :submodules do + unless ENV["SKIP_SUBMODULES"] + puts "======================================================" + puts "Downloading MODA submodules...please wait" + puts "======================================================" + + run %{ + cd $HOME/.moda + git submodule update --recursive + git clean -df + } + puts + end +end + +desc "Performs migration from pathogen to vundle" +task :vundle_migration do + puts "======================================================" + puts "Migrating from pathogen to vundle vim plugin manager. " + puts "This will move the old .vim/bundle directory to" + puts ".vim/bundle.old and replacing all your vim plugins with" + puts "the standard set of plugins. You will then be able to " + puts "manage your vim's plugin configuration by editing the " + puts "file .vim/vundles.vim" + puts "======================================================" + + Dir.glob(File.join('vim', 'bundle','**')) do |sub_path| + run %{git config -f #{File.join('.git', 'config')} --remove-section submodule.#{sub_path}} + # `git rm --cached #{sub_path}` + FileUtils.rm_rf(File.join('.git', 'modules', sub_path)) + end + FileUtils.mv(File.join('vim','bundle'), File.join('vim', 'bundle.old')) +end + +desc "Runs Vundle installer in a clean vim environment" +task :install_vundle do + puts "======================================================" + puts "Installing and updating vundles." + puts "The installer will now proceed to run BundleInstall." + puts "======================================================" + + puts "" + + vundle_path = File.join('vim','bundle', 'vundle') + unless File.exists?(vundle_path) + run %{ + cd $HOME/.moda + git clone https://github.com/gmarik/vundle.git #{vundle_path} + } + end + + Vundle::update_vundle +end + +task :default => 'install' + + +private +def run(cmd) + puts "[Running] #{cmd}" + `#{cmd}` unless ENV['DEBUG'] +end + +def install_homebrew + run %{which brew} + unless $?.success? + puts "======================================================" + puts "Installing Homebrew, the OSX package manager...If it's" + puts "already installed, this will do nothing." + puts "======================================================" + run %{ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"} + end + + puts + puts + puts "======================================================" + puts "Updating Homebrew." + puts "======================================================" + run %{brew update} + puts + puts + puts "======================================================" + puts "Installing Homebrew packages...There may be some warnings." + puts "======================================================" + run %{brew install zsh git tmux reattach-to-user-namespace} + run %{brew install macvim --custom-icons --override-system-vim --with-lua --with-luajit} + puts + puts +end + +def install_tmuxinator + run %{which tmuxinator} + puts "======================================================" + puts "Installing Tmuxinator...If it's already installed, " + puts "it will update it." + puts "======================================================" + unless $?.success? + run %{gem install tmuxinator} + else + run %{gem update tmuxinator} + end +end + +def install_fonts + puts "======================================================" + puts "Installing patched fonts for Powerline/Lightline." + puts "======================================================" + run %{ cp -f $HOME/.moda/fonts/* $HOME/Library/Fonts } + puts +end + +def install_term_theme + puts "======================================================" + puts "Installing iTerm2 solarized theme." + puts "======================================================" + run %{ /usr/libexec/PlistBuddy -c "Add :'Custom Color Presets':'Solarized Light' dict" ~/Library/Preferences/com.googlecode.iterm2.plist } + run %{ /usr/libexec/PlistBuddy -c "Merge 'iTerm2/Solarized Light.itermcolors' :'Custom Color Presets':'Solarized Light'" ~/Library/Preferences/com.googlecode.iterm2.plist } + run %{ /usr/libexec/PlistBuddy -c "Add :'Custom Color Presets':'Solarized Dark' dict" ~/Library/Preferences/com.googlecode.iterm2.plist } + run %{ /usr/libexec/PlistBuddy -c "Merge 'iTerm2/Solarized Dark.itermcolors' :'Custom Color Presets':'Solarized Dark'" ~/Library/Preferences/com.googlecode.iterm2.plist } + + # If iTerm2 is not installed or has never run, we can't autoinstall the profile since the plist is not there + if !File.exists?(File.join(ENV['HOME'], '/Library/Preferences/com.googlecode.iterm2.plist')) + puts "======================================================" + puts "To make sure your profile is using the solarized theme" + puts "Please check your settings under:" + puts "Preferences> Profiles> [your profile]> Colors> Load Preset.." + puts "======================================================" + return + end + + # Ask the user which theme he wants to install + message = "Which theme would you like to apply to your iTerm2 profile?" + color_scheme = ask message, iTerm_available_themes + color_scheme_file = File.join('iTerm2', "#{color_scheme}.itermcolors") + + # Ask the user on which profile he wants to install the theme + profiles = iTerm_profile_list + message = "I've found #{profiles.size} #{profiles.size>1 ? 'profiles': 'profile'} on your iTerm2 configuration, which one would you like to apply the Solarized theme to?" + profiles << 'All' + selected = ask message, profiles + + if selected == 'All' + (profiles.size-1).times { |idx| apply_theme_to_iterm_profile_idx idx, color_scheme_file } + else + apply_theme_to_iterm_profile_idx profiles.index(selected), color_scheme_file + end +end + +def iTerm_available_themes + Dir['iTerm2/*.itermcolors'].map { |value| File.basename(value, '.itermcolors')} +end + +def iTerm_profile_list + profiles=Array.new + begin + profiles << %x{ /usr/libexec/PlistBuddy -c "Print :'New Bookmarks':#{profiles.size}:Name" ~/Library/Preferences/com.googlecode.iterm2.plist 2>/dev/null} + end while $?.exitstatus==0 + profiles.pop + profiles +end + +def ask(message, values) + puts message + while true + values.each_with_index { |val, idx| puts " #{idx+1}. #{val}" } + selection = STDIN.gets.chomp + if (Float(selection)==nil rescue true) || selection.to_i < 0 || selection.to_i > values.size+1 + puts "ERROR: Invalid selection.\n\n" + else + break + end + end + selection = selection.to_i-1 + values[selection] +end + +def install_prezto + puts + puts "Installing Prezto (ZSH Enhancements)..." + + unless File.exists?(File.join(ENV['ZDOTDIR'] || ENV['HOME'], ".zprezto")) + run %{ ln -nfs "$HOME/.moda/zsh/prezto" "${ZDOTDIR:-$HOME}/.zprezto" } + + # The prezto runcoms are only going to be installed if zprezto has never been installed + file_operation(Dir.glob('zsh/prezto/runcoms/z*'), :copy) + end + + puts + puts "Overriding prezto ~/.zpreztorc with MODA's zpreztorc to enable additional modules..." + run %{ ln -nfs "$HOME/.moda/zsh/prezto-override/zpreztorc" "${ZDOTDIR:-$HOME}/.zpreztorc" } + + puts + puts "Creating directories for your customizations" + run %{ mkdir -p $HOME/.zsh.before } + run %{ mkdir -p $HOME/.zsh.after } + + if ENV["SHELL"].include? 'zsh' then + puts "Zsh is already configured as your shell of choice. Restart your session to load the new settings" + else + puts "Setting zsh as your default shell" + if File.exists?("/usr/local/bin/zsh") + if File.readlines("/private/etc/shells").grep("/usr/local/bin/zsh").empty? + puts "Adding zsh to standard shell list" + run %{ echo "/usr/local/bin/zsh" | sudo tee -a /private/etc/shells } + end + run %{ chsh -s /usr/local/bin/zsh } + else + run %{ chsh -s /bin/zsh } + end + end +end + +def want_to_install? (section) + if ENV["ASK"]=="true" + puts "Would you like to install configuration files for: #{section}? [y]es, [n]o" + STDIN.gets.chomp == 'y' + else + true + end +end + +def file_operation(files, method = :symlink) + files.each do |f| + file = f.split('/').last + source = "#{ENV["PWD"]}/#{f}" + target = "#{ENV["HOME"]}/.#{file}" + + puts "======================#{file}==============================" + puts "Source: #{source}" + puts "Target: #{target}" + + if File.exists?(target) && (!File.symlink?(target) || (File.symlink?(target) && File.readlink(target) != source)) + puts "[Overwriting] #{target}...leaving original at #{target}.backup..." + run %{ mv "$HOME/.#{file}" "$HOME/.#{file}.backup" } + end + + if method == :symlink + run %{ ln -nfs "#{source}" "#{target}" } + else + run %{ cp -f "#{source}" "#{target}" } + end + + # Temporary solution until we find a way to allow customization + # This modifies zshrc to load all of moda's zsh extensions. + # Eventually moda's zsh extensions should be ported to prezto modules. + if file == 'zshrc' + File.open(target, 'a') do |zshrc| + zshrc.puts('for config_file ($HOME/.moda/zsh/*.zsh) source $config_file') + end + end + + puts "==========================================================" + puts + end +end + +def needs_migration_to_vundle? + File.exists? File.join('vim', 'bundle', 'tpope-vim-pathogen') +end + + +def list_vim_submodules + result=`git submodule -q foreach 'echo $name"||"\`git remote -v | awk "END{print \\\\\$2}"\`'`.select{ |line| line =~ /^vim.bundle/ }.map{ |line| line.split('||') } + Hash[*result.flatten] +end + +def apply_theme_to_iterm_profile_idx(index, color_scheme_path) + values = Array.new + 16.times { |i| values << "Ansi #{i} Color" } + values << ['Background Color', 'Bold Color', 'Cursor Color', 'Cursor Text Color', 'Foreground Color', 'Selected Text Color', 'Selection Color'] + values.flatten.each { |entry| run %{ /usr/libexec/PlistBuddy -c "Delete :'New Bookmarks':#{index}:'#{entry}'" ~/Library/Preferences/com.googlecode.iterm2.plist } } + + run %{ /usr/libexec/PlistBuddy -c "Merge '#{color_scheme_path}' :'New Bookmarks':#{index}" ~/Library/Preferences/com.googlecode.iterm2.plist } +end + +def success_msg(action) + puts "" + puts " __ __ ____ _____ " + puts " | \/ |/ __ \| __ \ /\ " + puts " | \ / | | | | | | | / \ " + puts " | |\/| | | | | | | |/ /\ \ " + puts " | | | | |__| | |__| / ____ \ " + puts " |_| |_|\____/|_____/_/ \_\ " + puts "" + puts "MODA has been #{action}. Please restart your terminal and vim." +end diff --git a/bin/moda/default_libs.rb b/bin/moda/default_libs.rb new file mode 100755 index 0000000..fca5e12 --- /dev/null +++ b/bin/moda/default_libs.rb @@ -0,0 +1,4 @@ +Dir[File.join(File.dirname(__FILE__),"lib/**/lib")].each {|dir| $LOAD_PATH << dir} +require 'git-style-binary/command' + +$moda = File.join(ENV['HOME'], ".moda") diff --git a/bin/moda/lib/git-style-binaries-0.1.11/README.markdown b/bin/moda/lib/git-style-binaries-0.1.11/README.markdown new file mode 100644 index 0000000..b63fa39 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/README.markdown @@ -0,0 +1,280 @@ +git-style-binaries +================== + +Ridiculously easy git-style binaries. + +This gem uses [`trollop`](http://trollop.rubyforge.org/) for option parsing + +## Installation + + gem install jashmenn-git-style-binaries --source=http://gems.github.com + +## Screencast + +Checkout the new screencast! + + + +## Try it out + + cd `gem env gemdir`/gems/jashmenn-git-style-binaries-0.1.4/test/fixtures + ./wordpress -h + ./wordpress help post + +## Goal + +Lets use the imaginary `wordpress` gem. Let's say we have three different +actions we want to specify: + +* categories +* list +* post + +Each command has its own binary in a directory structure like this: + + bin/ + |-- wordpress + |-- wordpress-categories + |-- wordpress-list + `-- wordpress-post + +The goal is to be able to call commands in this manner: + + wordpress -h # gives help summary of all commands + wordpress-list -h # gives long help of wordpress-list + wordpress list -h # ditto + echo "about me" | wordpress-post --title="new post" # posts a new post with that title + +## Example code +Our `bin/wordpress` binary is called the *primary* . Our primary only needs to contain the following line: + + #!/usr/bin/env ruby + require 'git-style-binary/command' + +`git-style-binary` will automatically make this command the primary. + +The `bin/wordpress-post` binary could contain the following: + + #!/usr/bin/env ruby + require 'git-style-binary/command' + + GitStyleBinary.command do + short_desc "create a blog post" + banner <<-EOS + Usage: #{command.full_name} #{all_options_string} {content|STDIN} + + Posts content to a wordpress blog + + EOS + opt :blog, "short name of the blog to use", :default => 'default' + opt :category, "tag/category. specify multiple times for multiple categories", :type => String, :multi => true + opt :title, "title for the post", :required => true, :type => String + opt :type, "type of the content [html|xhtml|text]", :default => 'html', :type => String + + run do |command| + command.die :type, "type must be one of [html|xhtml|text]" unless command.opts[:type] =~ /^(x?html|text)$/i + + puts "Subcommand name: #{command.name.inspect}" + puts "Options: #{command.opts.inspect}" + puts "Remaining arguments: #{command.argv.inspect}" + end + end + +And so on with the other binaries. + +## Running the binaries + +Now if we run `wordpress -h` we get the following output: + + NAME + wordpress + + VERSION + 0.0.1 (c) 2009 Nate Murray - local + + SYNOPSIS + wordpress [--version] [--test-primary] [--help] [--verbose] COMMAND [ARGS] + + SUBCOMMANDS + wordpress-categories + do something with categories + + wordpress-help + get help for a specific command + + wordpress-list + list blog postings + + wordpress-post + create a blog post + + + See 'wordpress help COMMAND' for more information on a specific command. + + OPTIONS + -v, --verbose + verbose + + + -t, --test-primary= + test an option on the primary + + + -e, --version + Print version and exit + + + -h, --help + Show this message + + + +Default **options**, **version string**, and **usage banner** are automatically selected for you. +The subcommands and their short descriptions are loaded automatically! + +You can pass the `-h` flag to any one of the subcommands (with or without the +connecting `-`) or use the built-in `help` subcommand for the same effect. For instance: + + $ wordpress help post + + NAME + wordpress-post - create a blog post + + VERSION + 0.0.1 (c) 2009 Nate Murray - local + + SYNOPSIS + wordpress-post [--type] [--version] [--test-primary] [--blog] [--help] [--verbose] [--category] + [--title] COMMAND [ARGS] {content|STDIN} + + OPTIONS + -v, --verbose + verbose + + + -t, --test-primary= + test an option on the primary + + + -b, --blog= + short name of the blog to use (default: default) + + + -c, --category= + tag/category. specify multiple times for multiple + categories + + + -i, --title= + title for the post + + + -y, --type= + type of the content [html|xhtml|text] (default: html) + + + -e, --version + Print version and exit + + + -h, --help + Show this message + + +For more examples, see the binaries in `test/fixtures/`. + +## Primary options + +Often you may *want* the primary to have its own set of options. Simply call `GitStyleBinary.primary` with a block like so: + + #!/usr/bin/env ruby + require 'git-style-binary/command' + GitStyleBinary.primary do + version "#{command.full_name} 0.0.1 (c) 2009 Nate Murray - local" + opt :test_primary, "a primary string option", :type => String + + run do |command| + puts "Primary Options: #{command.opts.inspect}" + end + end + +Primary options are **inherited** by all subcommands. That means in this case +all subcommands will now get the `--test-primary` option available to them as +well as this new `version` string. + +## Option parsing + +Option parsing is done by [trollop](http://trollop.rubyforge.org/). +`git-style-binary` uses this more-or-less exactly. See the [trollop +documentation](http://trollop.rubyforge.org/) for information on how to setup +the options and flags. + +## Callbacks + +Callbacks are available on the primary and subcommands. Available callbacks currently +are before/after_run. These execute before the run block of the command parser and take +take one argument, which is the command itself + +## The `run` block + +To get the 'introspection' on the individual binaries every binary is `load`ed +on `primary help`. We need a way to get that information while not running +every command when calling `primary help`. To achieve that you need to put what +will be run in the `run` block. + +`run` `yields` a `Command` object which contains a number of useful options +such as `name`, `full_name`, `opts`, and `argv`. + +* `command.opts` is a hash of the options parsed +* `command.argv` is an array of the remaining arguments + +## Features +* automatic colorization +* automatic paging + +## To Learn more + +Play with the examples in the `test/fixtures` directory. + +## Credits +* `git-style-binary` was written by Nate Murray `` +* `trollop` was written by [William Morgan](http://trollop.rubyforge.org/) +* Inspiration comes from Ari Lerner's [git-style-binaries](http://blog.xnot.org/2008/12/16/git-style-binaries/) for [PoolParty.rb](http://poolpartyrb.com) +* [`colorize.rb`](http://colorize.rubyforge.org) by Michal Kalbarczyk +* Automatic less paging by [Nathan Weizenbaum](http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby) +* Color inspiration from [Brian Henderson](http://xcombinator.com) teaching me how to get `man git` colors using `less` on MacOSX + +## TODO +* automagic tab completion - Automatic for subcommands and options for any library that uses this + +## Known Bugs/Problems +* Young +* A few places of really ugly code +* A feeling that this could be done in 1/2 lines of code + +## Authors +By Nate Murray and Ari Lerner + +## Copyright + +The MIT License + +Copyright (c) 2009 Nate Murray. See LICENSE for details. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/bin/moda/lib/git-style-binaries-0.1.11/Rakefile b/bin/moda/lib/git-style-binaries-0.1.11/Rakefile new file mode 100644 index 0000000..2d0d50b --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/Rakefile @@ -0,0 +1,65 @@ +require 'rubygems' +require 'rake' + +begin + require 'jeweler' + Jeweler::Tasks.new do |gem| + gem.name = "git-style-binaries" + gem.description = %Q{Ridiculously easy git-style binaries} + gem.summary =<<-EOF + Add git-style binaries to your project easily. + EOF + gem.email = "nate@natemurray.com" + gem.homepage = "http://github.com/jashmenn/git-style-binaries" + gem.authors = ["Nate Murray"] + gem.add_dependency 'trollop' + gem.add_dependency 'shoulda' # for running the tests + + excludes = /(README\.html)/ + gem.files = (FileList["[A-Z]*.*", "{bin,examples,generators,lib,rails,spec,test,vendor}/**/*", 'Rakefile', 'LICENSE*']).delete_if{|f| f =~ excludes} + gem.extra_rdoc_files = FileList["README*", "ChangeLog*", "LICENSE*"].delete_if{|f| f =~ excludes} + end +rescue LoadError + puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" +end + +require 'rake/testtask' +Rake::TestTask.new(:test) do |test| + test.libs << 'lib' << 'test' + test.pattern = 'test/**/*_test.rb' + test.verbose = true +end + +begin + require 'rcov/rcovtask' + Rcov::RcovTask.new do |test| + test.libs << 'test' + test.pattern = 'test/**/*_test.rb' + test.verbose = true + end +rescue LoadError + task :rcov do + abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov" + end +end + + +task :default => :test + +require 'rake/rdoctask' +require 'yaml' +Rake::RDocTask.new do |rdoc| + if File.exist?('VERSION.yml') + config = YAML.load(File.read('VERSION.yml')) + version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}" + else + version = "" + end + + rdoc.rdoc_dir = 'rdoc' + rdoc.title = "git-style-binaries #{version}" + rdoc.rdoc_files.include('README*') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +task :bump => ['version:bump:patch', 'gemspec', 'build'] diff --git a/bin/moda/lib/git-style-binaries-0.1.11/VERSION.yml b/bin/moda/lib/git-style-binaries-0.1.11/VERSION.yml new file mode 100644 index 0000000..43ec547 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/VERSION.yml @@ -0,0 +1,4 @@ +--- +:patch: 10 +:major: 0 +:minor: 1 diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/ext/colorize.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/ext/colorize.rb new file mode 100644 index 0000000..c4d695a --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/ext/colorize.rb @@ -0,0 +1,198 @@ +# +# Colorize String class extension. +# +class String + + # + # Version string + # + COLORIZE_VERSION = '0.5.6' + + # + # Colors Hash + # + COLORS = { + :black => 0, + :red => 1, + :green => 2, + :yellow => 3, + :blue => 4, + :magenta => 5, + :cyan => 6, + :white => 7, + :default => 9, + + :light_black => 10, + :light_red => 11, + :light_green => 12, + :light_yellow => 13, + :light_blue => 14, + :light_magenta => 15, + :light_cyan => 16, + :light_white => 17 + } + + # + # Modes Hash + # + MODES = { + :default => 0, # Turn off all attributes + #:bright => 1, # Set bright mode + :underline => 4, # Set underline mode + :blink => 5, # Set blink mode + :swap => 7, # Exchange foreground and background colors + :hide => 8 # Hide text (foreground color would be the same as background) + } + + protected + + # + # Set color values in new string intance + # + def set_color_parameters( params ) + if (params.instance_of?(Hash)) + @color = params[:color] + @background = params[:background] + @mode = params[:mode] + @uncolorized = params[:uncolorized] + self + else + nil + end + end + + public + + # + # Change color of string + # + # Examples: + # + # puts "This is blue".colorize( :blue ) + # puts "This is light blue".colorize( :light_blue ) + # puts "This is also blue".colorize( :color => :blue ) + # puts "This is blue with red background".colorize( :color => :light_blue, :background => :red ) + # puts "This is blue with red background".colorize( :light_blue ).colorize( :background => :red ) + # puts "This is blue text on red".blue.on_red + # puts "This is red on blue".colorize( :red ).on_blue + # puts "This is red on blue and underline".colorize( :red ).on_blue.underline + # puts "This is blue text on red".blue.on_red.blink + # + def colorize( params ) + + unless STDOUT.use_color + return self unless STDOUT.isatty + end + return self if ENV['NO_COLOR'] + + begin + require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/ + rescue LoadError + raise 'You must gem install win32console to use color on Windows' + end + + color_parameters = {} + + if (params.instance_of?(Hash)) + color_parameters[:color] = COLORS[params[:color]] + color_parameters[:background] = COLORS[params[:background]] + color_parameters[:mode] = MODES[params[:mode]] + elsif (params.instance_of?(Symbol)) + color_parameters[:color] = COLORS[params] + end + + color_parameters[:color] ||= @color || 9 + color_parameters[:background] ||= @background || 9 + color_parameters[:mode] ||= @mode || 0 + + color_parameters[:uncolorized] ||= @uncolorized || self.dup + + # calculate bright mode + color_parameters[:color] += 50 if color_parameters[:color] > 10 + + color_parameters[:background] += 50 if color_parameters[:background] > 10 + + return "\033[#{color_parameters[:mode]};#{color_parameters[:color]+30};#{color_parameters[:background]+40}m#{color_parameters[:uncolorized]}\033[0m".set_color_parameters( color_parameters ) + end + + + # + # Return uncolorized string + # + def uncolorize + return @uncolorized || self + end + + # + # Return true if sting is colorized + # + def colorized? + return !@uncolorized.nil? + end + + # + # Make some color and on_color methods + # + COLORS.each_key do | key | + eval <<-"end_eval" + def #{key.to_s} + return self.colorize( :color => :#{key.to_s} ) + end + def on_#{key.to_s} + return self.colorize( :background => :#{key.to_s} ) + end + end_eval + end + + # + # Methods for modes + # + MODES.each_key do | key | + eval <<-"end_eval" + def #{key.to_s} + return self.colorize( :mode => :#{key.to_s} ) + end + end_eval + end + + class << self + + # + # Return array of available modes used by colorize method + # + def modes + keys = [] + MODES.each_key do | key | + keys << key + end + keys + end + + # + # Return array of available colors used by colorize method + # + def colors + keys = [] + COLORS.each_key do | key | + keys << key + end + keys + end + + # + # Display color matrix with color names. + # + def color_matrix( txt = "[X]" ) + size = String.colors.length + String.colors.each do | color | + String.colors.each do | back | + print txt.colorize( :color => color, :background => back ) + end + puts " < #{color}" + end + String.colors.reverse.each_with_index do | back, index | + puts "#{"|".rjust(txt.length)*(size-index)} < #{back}" + end + end + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/ext/core.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/ext/core.rb new file mode 100644 index 0000000..70bbf3d --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/ext/core.rb @@ -0,0 +1,16 @@ +class Object + def returning(value) + yield(value) + value + end unless Object.respond_to?(:returning) +end + +class Symbol + def to_proc + Proc.new { |*args| args.shift.__send__(self, *args) } + end +end + +class IO + attr_accessor :use_color +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary.rb new file mode 100644 index 0000000..fa853c9 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary.rb @@ -0,0 +1,88 @@ +$:.unshift(File.dirname(__FILE__)) +require 'rubygems' + +# Load the vendor gems +$:.unshift(File.dirname(__FILE__) + "/../vendor/gems") +%w(trollop).each do |library| + begin + require "#{library}/lib/#{library}" + rescue LoadError + begin + require 'trollop' + rescue LoadError + puts "There was an error loading #{library}. Try running 'gem install #{library}' to correct the problem" + end + end +end + +require 'ext/core' +require 'ext/colorize' +require 'git-style-binary/autorunner' +Dir[File.dirname(__FILE__) + "/git-style-binary/helpers/*.rb"].each {|f| require f} + +module GitStyleBinary + + class << self + include Helpers::NameResolver + attr_accessor :current_command + attr_accessor :primary_command + attr_writer :known_commands + + # If set to false GitStyleBinary will not automatically run at exit. + attr_writer :run + + # Automatically run at exit? + def run? + @run ||= false + end + + def parser + @p ||= Parser.new + end + + def known_commands + @known_commands ||= {} + end + + def load_primary + unless @loaded_primary + @loaded_primary = true + primary_file = File.join(binary_directory, basename) + load primary_file + + if !GitStyleBinary.primary_command # you still dont have a primary load a default + GitStyleBinary.primary do + run do |command| + educate + end + end + end + end + end + + def load_subcommand + unless @loaded_subcommand + @loaded_subcommand = true + cmd_file = GitStyleBinary.binary_filename_for(GitStyleBinary.current_command_name) + load cmd_file + end + end + + def load_command_file(name, file) + self.name_of_command_being_loaded = name + load file + self.name_of_command_being_loaded = nil + end + + # UGLY eek + attr_accessor :name_of_command_being_loaded + + end +end + +at_exit do + unless $! || GitStyleBinary.run? + command = GitStyleBinary::AutoRunner.run + exit 0 + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/autorunner.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/autorunner.rb new file mode 100644 index 0000000..be769c9 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/autorunner.rb @@ -0,0 +1,21 @@ +require 'git-style-binary/parser' + +module GitStyleBinary +class AutoRunner + + def self.run(argv=ARGV) + r = new + r.run + end + + def run + unless GitStyleBinary.run? + if !GitStyleBinary.current_command + GitStyleBinary.load_primary + end + GitStyleBinary.current_command.run + end + end + +end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/command.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/command.rb new file mode 100644 index 0000000..296588f --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/command.rb @@ -0,0 +1,204 @@ +require 'git-style-binary' + +module GitStyleBinary + def self.command(&block) + returning Command.new(:constraints => [block]) do |c| + c.name ||= (GitStyleBinary.name_of_command_being_loaded || GitStyleBinary.current_command_name) + GitStyleBinary.known_commands[c.name] = c + + if !GitStyleBinary.current_command || GitStyleBinary.current_command.is_primary? + GitStyleBinary.current_command = c + end + end + end + + def self.primary(&block) + returning Primary.new(:constraints => [block]) do |c| + c.name ||= (GitStyleBinary.name_of_command_being_loaded || GitStyleBinary.current_command_name) + GitStyleBinary.known_commands[c.name] = c + + GitStyleBinary.primary_command = c unless GitStyleBinary.primary_command + GitStyleBinary.current_command = c unless GitStyleBinary.current_command + end + end + + class Command + class << self + def defaults + lambda do + name_desc "#{command.full_name}\#{command.short_desc ? ' - ' + command.short_desc : ''}" # eval jit + version_string = defined?(VERSION) ? VERSION : "0.0.1" + version "#{version_string} (c) #{Time.now.year}" + banner <<-EOS +#{"SYNOPSIS".colorize(:red)} + #{command.full_name.colorize(:light_blue)} #{all_options_string} + +#{"SUBCOMMANDS".colorize(:red)} + \#{GitStyleBinary.pretty_known_subcommands.join("\n ")} + + See '#{command.full_name} help COMMAND' for more information on a specific command. + EOS + + opt :verbose, "verbose", :default => false + end + end + end + + attr_reader :constraints + attr_reader :opts + attr_accessor :name + + def initialize(o={}) + o.each do |k,v| + eval "@#{k.to_s}= v" + end + end + + def parser + @parser ||= begin + p = Parser.new + p.command = self + p + end + end + + def constraints + @constraints ||= [] + end + + def run + GitStyleBinary.load_primary unless is_primary? + GitStyleBinary.load_subcommand if is_primary? && running_subcommand? + load_all_parser_constraints + @opts = process_args_with_subcmd + call_parser_run_block + self + end + + def running_subcommand? + GitStyleBinary.valid_subcommand?(GitStyleBinary.current_command_name) + end + + def load_all_parser_constraints + @loaded_all_parser_constraints ||= begin + load_parser_default_constraints + load_parser_primary_constraints + load_parser_local_constraints + true + end + end + + def load_parser_default_constraints + parser.consume_all([self.class.defaults]) + end + + def load_parser_primary_constraints + parser.consume_all(GitStyleBinary.primary_command.constraints) + end + + def load_parser_local_constraints + cur = GitStyleBinary.current_command # see, why isn't 'this' current_command? + + unless self.is_primary? && cur == self + # TODO TODO - the key lies in this function. figure out when you hav emore engergy + # soo UGLY. see #process_parser! unify with that method + # parser.consume_all(constraints) rescue ArgumentError + parser.consume_all(cur.constraints) + end + end + + def call_parser_run_block + runs = GitStyleBinary.current_command.parser.runs + + parser.run_callbacks(:before_run, self) + parser.runs.last.call(self) # ... not too happy with this + parser.run_callbacks(:after_run, self) + end + + def process_args_with_subcmd(args = ARGV, *a, &b) + cmd = GitStyleBinary.current_command_name + vals = process_args(args, *a, &b) + parser.leftovers.shift if parser.leftovers[0] == cmd + vals + end + + # TOOooootally ugly! why? bc load_parser_local_constraints doesn't work + # when loading the indivdual commands because it depends on + # #current_command. This really sucks and is UGLY. + # the todo is to put in 'load_all_parser_constraints' and this works + def process_parser! + # load_all_parser_constraints + + load_parser_default_constraints + load_parser_primary_constraints + # load_parser_local_constraints + parser.consume_all(constraints) + + # hack + parser.consume { + opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"] + opt :help, "Show this message" unless @specs[:help] || @long["help"] + resolve_default_short_options + } # hack + end + + def process_args(args = ARGV, *a, &b) + p = parser + begin + vals = p.parse args + args.clear + p.leftovers.each { |l| args << l } + vals # ugly todo + rescue Trollop::CommandlineError => e + $stderr.puts "Error: #{e.message}." + $stderr.puts "Try --help for help." + exit(-1) + rescue Trollop::HelpNeeded + p.educate + exit + rescue Trollop::VersionNeeded + puts p.version + exit + end + end + + def is_primary? + false + end + + def argv + parser.leftovers + end + + def short_desc + parser.short_desc + end + + def full_name + # ugly, should be is_primary? + GitStyleBinary.primary_name == name ? GitStyleBinary.primary_name : GitStyleBinary.primary_name + "-" + name + end + + def die arg, msg=nil + p = parser # create local copy + Trollop.instance_eval { @p = p } + Trollop::die(arg, msg) + end + + # Helper to return the option + def [](k) + opts[k] + end + + end + + class Primary < Command + def is_primary? + true + end + def primary + self + end + end + +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/commands/help.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/commands/help.rb new file mode 100644 index 0000000..5c1f70b --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/commands/help.rb @@ -0,0 +1,32 @@ +module GitStyleBinary + module Commands + class Help + # not loving this syntax, but works for now + GitStyleBinary.command do + short_desc "get help for a specific command" + run do |command| + + # this is slightly ugly b/c it has to muck around in the internals to + # get information about commands other than itself. This isn't a + # typical case + self.class.send :define_method, :educate_about_command do |name| + load_all_commands + if GitStyleBinary.known_commands.has_key?(name) + cmd = GitStyleBinary.known_commands[name] + cmd.process_parser! + cmd.parser.educate + else + puts "Unknown command '#{name}'" + end + end + + if command.argv.size > 0 + command.argv.first == "help" ? educate : educate_about_command(command.argv.first) + else + educate + end + end + end + end + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/helpers/name_resolver.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/helpers/name_resolver.rb new file mode 100644 index 0000000..e6edbd6 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/helpers/name_resolver.rb @@ -0,0 +1,78 @@ +module GitStyleBinary +module Helpers + module NameResolver + + def basename(filename=zero) + File.basename(filename).match(/(.*?)(\-|$)/).captures.first + end + alias_method :primary_name, :basename + + # checks the bin directory for all files starting with +basename+ and + # returns an array of strings specifying the subcommands + def subcommand_names(filename=zero) + subfiles = Dir[File.join(binary_directory, basename + "-*")] + cmds = subfiles.collect{|file| File.basename(file).sub(/^#{basename}-/, '')}.sort + cmds += built_in_command_names + cmds.uniq + end + + def binary_directory(filename=zero) + File.dirname(filename) + end + + def built_in_commands_directory + File.dirname(__FILE__) + "/../commands" + end + + def built_in_command_names + Dir[built_in_commands_directory + "/*.rb"].collect{|f| File.basename(f.sub(/\.rb$/,''))} + end + + def list_subcommands(filename=zero) + subcommand_names(filename).join(", ") + end + + # load first from users binary directory. then load built-in commands if + # available + def binary_filename_for(name) + user_file = File.join(binary_directory, "#{basename}-#{name}") + return user_file if File.exists?(user_file) + built_in = File.join(built_in_commands_directory, "#{name}.rb") + return built_in if File.exists?(built_in) + user_file + end + + def current_command_name(filename=zero,argv=ARGV) + current = File.basename(zero) + first_arg = ARGV[0] + return first_arg if valid_subcommand?(first_arg) + return basename if basename == current + current.sub(/^#{basename}-/, '') + end + + # returns the command name with the prefix if needed + def full_current_command_name(filename=zero,argv=ARGV) + cur = current_command_name(filename, argv) + subcmd = cur == basename(filename) ? false : true # is this a subcmd? + "%s%s%s" % [basename(filename), subcmd ? "-" : "", subcmd ? current_command_name(filename, argv) : ""] + end + + def valid_subcommand?(name) + subcommand_names.include?(name) + end + + def zero + $0 + end + + def pretty_known_subcommands(theme=:long) + GitStyleBinary.known_commands.collect do |k,cmd| + next if k == basename + cmd.process_parser! + ("%-s%s%-10s" % [basename, '-', k]).colorize(:light_blue) + ("%s " % [theme == :long ? "\n" : ""]) + ("%s" % [cmd.short_desc]) + "\n" + end.compact.sort + end + + end +end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/helpers/pager.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/helpers/pager.rb new file mode 100644 index 0000000..1fa1cff --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/helpers/pager.rb @@ -0,0 +1,37 @@ +module GitStyleBinary + module Helpers + module Pager + + # by Nathan Weizenbaum - http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby + def run_pager + return if RUBY_PLATFORM =~ /win32/ + return unless STDOUT.tty? + STDOUT.use_color = true + + read, write = IO.pipe + + unless Kernel.fork # Child process + STDOUT.reopen(write) + STDERR.reopen(write) if STDERR.tty? + read.close + write.close + return + end + + # Parent process, become pager + STDIN.reopen(read) + read.close + write.close + + ENV['LESS'] = 'FSRX' # Don't page if the input is short enough + + Kernel.select [STDIN] # Wait until we have input before we start the pager + pager = ENV['PAGER'] || 'less -erXF' + exec pager rescue exec "/bin/sh", "-c", pager + end + + module_function :run_pager + + end + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/parser.rb b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/parser.rb new file mode 100644 index 0000000..4e03d5c --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/lib/git-style-binary/parser.rb @@ -0,0 +1,223 @@ +module GitStyleBinary +class Parser < Trollop::Parser + attr_reader :runs, :callbacks + attr_reader :short_desc + attr_accessor :command + + def initialize *a, &b + super + @runs = [] + setup_callbacks + end + + def setup_callbacks + @callbacks = {} + %w(run).each do |event| + %w(before after).each do |time| + @callbacks["#{time}_#{event}".to_sym] = [] + instance_eval "def #{time}_#{event}(&block);@callbacks[:#{time}_#{event}] << block;end" + end + end + end + + def run_callbacks(at, from) + @callbacks[at].each {|c| c.call(from) } + end + + def banner s=nil; @banner = s if s; @banner end + def short_desc s=nil; @short_desc = s if s; @short_desc end + def name_desc s=nil; @name_desc = s if s; @name_desc end + + # Set the theme. Valid values are +:short+ or +:long+. Default +:long+ + attr_writer :theme + + def theme + @theme ||= :long + end + + ## Adds text to the help display. + def text s; @order << [:text, s] end + + def spec_names + @specs.collect{|name, spec| spec[:long]} + end + + # should probably be somewhere else + def load_all_commands + GitStyleBinary.subcommand_names.each do |name| + cmd_file = GitStyleBinary.binary_filename_for(name) + GitStyleBinary.load_command_file(name, cmd_file) + end + end + + ## Print the help message to 'stream'. + def educate(stream=$stdout) + load_all_commands + width # just calculate it now; otherwise we have to be careful not to + # call this unless the cursor's at the beginning of a line. + GitStyleBinary::Helpers::Pager.run_pager + self.send("educate_#{theme}", stream) + end + + def educate_long(stream=$stdout) + left = {} + + @specs.each do |name, spec| + left[name] = + ((spec[:short] ? "-#{spec[:short]}, " : "") + + "--#{spec[:long]}" + + case spec[:type] + when :flag; "" + when :int; "=" + when :ints; "=" + when :string; "=" + when :strings; "=" + when :float; "=" + when :floats; "=" + end).colorize(:red) + end + + leftcol_width = left.values.map { |s| s.length }.max || 0 + rightcol_start = leftcol_width + 6 # spaces + leftcol_start = 6 + leftcol_spaces = " " * leftcol_start + + unless @order.size > 0 && @order.first.first == :text + + if @name_desc + stream.puts "NAME".colorize(:red) + stream.puts "#{leftcol_spaces}"+ colorize_known_words(eval(%Q["#{@name_desc}"])) + "\n" + stream.puts + end + + if @version + stream.puts "VERSION".colorize(:red) + stream.puts "#{leftcol_spaces}#@version\n" + end + + stream.puts + + banner = colorize_known_words_array(wrap(eval(%Q["#{@banner}"]) + "\n", :prefix => leftcol_start)) if @banner # lazy banner + stream.puts banner + + stream.puts + stream.puts "OPTIONS".colorize(:red) + else + stream.puts "#@banner\n" if @banner + end + + @order.each do |what, opt| + if what == :text + stream.puts wrap(opt) + next + end + + spec = @specs[opt] + stream.printf " %-#{leftcol_width}s\n", left[opt] + desc = spec[:desc] + + if spec[:default] + if spec[:desc] =~ /\.$/ + " (Default: #{spec[:default]})" + else + " (default: #{spec[:default]})" + end + else + "" + end + stream.puts wrap(" %s" % [desc], :prefix => leftcol_start, :width => width - rightcol_start - 1 ) + stream.puts + stream.puts + end + + end + + def educate_short(stream=$stdout) + left = {} + + @specs.each do |name, spec| + left[name] = "--#{spec[:long]}" + + (spec[:short] ? ", -#{spec[:short]}" : "") + + case spec[:type] + when :flag; "" + when :int; " " + when :ints; " " + when :string; " " + when :strings; " " + when :float; " " + when :floats; " " + end + end + + leftcol_width = left.values.map { |s| s.length }.max || 0 + rightcol_start = leftcol_width + 6 # spaces + leftcol_start = 0 + + unless @order.size > 0 && @order.first.first == :text + stream.puts "#@version\n" if @version + stream.puts colorize_known_words_array(wrap(eval(%Q["#{@banner}"]) + "\n", :prefix => leftcol_start)) if @banner # jit banner + stream.puts "Options:" + else + stream.puts "#@banner\n" if @banner + end + + @order.each do |what, opt| + if what == :text + stream.puts wrap(opt) + next + end + + spec = @specs[opt] + stream.printf " %#{leftcol_width}s: ", left[opt] + desc = spec[:desc] + + if spec[:default] + if spec[:desc] =~ /\.$/ + " (Default: #{spec[:default]})" + else + " (default: #{spec[:default]})" + end + else + "" + end + stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start) + end + + end + + + def colorize_known_words_array(txts) + txts.collect{|txt| colorize_known_words(txt)} + end + + def colorize_known_words(txt) + txt = txt.gsub(/^([A-Z]+\s*)$/, '\1'.colorize(:red)) # all caps words on their own line + txt = txt.gsub(/\b(#{bin_name})\b/, '\1'.colorize(:light_blue)) # the current command name + txt = txt.gsub(/\[([^\s]+)\]/, "[".colorize(:magenta) + '\1'.colorize(:green) + "]".colorize(:magenta)) # synopsis options + end + + def consume(&block) + cloaker(&block).bind(self).call + end + + def consume_all(blocks) + blocks.each {|b| consume(&b)} + end + + def bin_name + GitStyleBinary.full_current_command_name + end + + def all_options_string + # '#{spec_names.collect(&:to_s).collect{|name| "[".colorize(:magenta) + "--" + name + "]".colorize(:magenta)}.join(" ")} COMMAND [ARGS]' + '#{spec_names.collect(&:to_s).collect{|name| "[" + "--" + name + "]"}.join(" ")} COMMAND [ARGS]' + end + + def run(&block) + @runs << block + end + + def action(name = :action, &block) + block.call(self) if block + end + +end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/flickr b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/flickr new file mode 100755 index 0000000..8eca1b9 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/flickr @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +$:.unshift(File.dirname(__FILE__) + "/../../lib") +VERSION="0.0.2" # just to test it +require 'git-style-binary/command' diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/flickr-download b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/flickr-download new file mode 100755 index 0000000..aff4128 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/flickr-download @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby +$:.unshift(File.dirname(__FILE__) + "/../../lib") +require 'git-style-binary/command' + +GitStyleBinary.command do + short_desc "download a flickr image" + banner <<-EOS +SYNOPSIS + #{command.full_name} #{all_options_string} url + +Downloads an image from flickr + +EOS + run do |command| + puts "would download: #{command.argv.inspect}" + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress new file mode 100755 index 0000000..90a1cd6 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress @@ -0,0 +1,42 @@ +#!/usr/bin/env ruby +$:.unshift(File.dirname(__FILE__) + "/../../lib") + +require 'git-style-binary/command' +GitStyleBinary.primary do + version "0.0.1 (c) 2009 Nate Murray - local" + opt :test_primary, "test an option on the primary", :type => String + + action do + @categories = ["sports", "news"] + end + + before_run do |cmd| + puts "before_run command #{cmd}" + end + + after_run do |cmd| + puts "after_run command #{cmd}" + end + + run do |command| + puts "Primary Options: #{command.opts.inspect}" + end +end + +# OR + +# require 'git-style-binary/primary' +# command = GitStyleBinary::primary("wordpress") do +# version "#{$0} 0.0.1 (c) 2009 Nate Murray" +# banner <<-EOS +# usage: #{$0} #{all_options.collect(:&to_s).join(" ")} COMMAND [ARGS] +# +# The wordpress subcommands commands are: +# {subcommand_names.pretty_print} +# +# See 'wordpress help COMMAND' for more information on a specific command. +# EOS +# opt :verbose, "verbose", :default => false +# opt :dry, "dry run", :default => false +# opt :test_global, "a basic global string option", :type => String +# end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-categories b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-categories new file mode 100755 index 0000000..66c44a4 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-categories @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +$:.unshift(File.dirname(__FILE__) + "/../../lib") +require 'git-style-binary/command' + +GitStyleBinary.command do + short_desc "do something with categories" + banner <<-EOS +SYNOPSIS + #{command.full_name} #{all_options_string} + +Does something with categories + +EOS + run do |command| + puts "does something with categories" + puts @categories.join(" ") + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-list b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-list new file mode 100755 index 0000000..dbe82a7 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-list @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby +$:.unshift(File.dirname(__FILE__) + "/../../lib") +require 'git-style-binary/command' + +GitStyleBinary.command do + short_desc "list blog postings" + banner <<-EOS +SYNOPSIS + #{command.full_name} #{all_options_string} + +Lists the posts on the blog + +EOS + run do |command| + puts "listing blog posts" + end +end + diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-post b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-post new file mode 100755 index 0000000..61f08f4 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/fixtures/wordpress-post @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +$:.unshift(File.dirname(__FILE__) + "/../../lib") +require 'git-style-binary/command' + +GitStyleBinary.command do + short_desc "create a blog post" + banner <<-EOS +SYNOPSIS + #{command.full_name} #{all_options_string} {content|STDIN} + +EOS + opt :blog, "short name of the blog to use", :default => 'default' + opt :category, "tag/category. specify multiple times for multiple categories", :type => String, :multi => true + opt :title, "title for the post", :required => true, :type => String + opt :type, "type of the content [html|xhtml|text]", :default => 'html', :type => String + + run do |command| + command.die :type, "type must be one of [html|xhtml|text]" unless command.opts[:type] =~ /^(x?html|text)$/i + + puts "Subcommand name: #{command.name.inspect}" + puts "Options: #{command.opts.inspect}" + puts "Remaining arguments: #{command.argv.inspect}" + end +end + + diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/git-style-binary/command_test.rb b/bin/moda/lib/git-style-binaries-0.1.11/test/git-style-binary/command_test.rb new file mode 100644 index 0000000..0b35c98 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/git-style-binary/command_test.rb @@ -0,0 +1,17 @@ +require File.dirname(__FILE__) + "/../test_helper.rb" +require 'git-style-binary/command' + +class CommandTest < Test::Unit::TestCase + context "cmd" do + setup do + @c = GitStyleBinary::Command.new + end + + should "be able to easily work with constraints" do + assert_equal @c.constraints, [] + @c.constraints << "foo" + assert_equal @c.constraints, ["foo"] + end + + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/git_style_binary_test.rb b/bin/moda/lib/git-style-binaries-0.1.11/test/git_style_binary_test.rb new file mode 100644 index 0000000..aa715d8 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/git_style_binary_test.rb @@ -0,0 +1,21 @@ +require File.dirname(__FILE__) + "/test_helper.rb" + +class GitStyleBinariesTest < Test::Unit::TestCase + context "parsing basenames" do + should "accurately parse basenames" do + assert_equal "wordpress", GitStyleBinary.basename("bin/wordpress") + assert_equal "wordpress", GitStyleBinary.basename("bin/wordpress-post") + assert_equal "wordpress", GitStyleBinary.basename("wordpress-post") + end + + should "get the current command name" do + # doesn't really apply any more b/c it calls 'current' which is never the + # current when your running rake_test_loader.rb + # + # assert_equal "wordpress", GitStyleBinary.current_command_name("bin/wordpress", ["--help"]) + # assert_equal "post", GitStyleBinary.current_command_name("bin/wordpress-post", ["--help"]) + # assert_equal "post", GitStyleBinary.current_command_name("bin/wordpress post", ["--help"]) + #assert_equal "post", GitStyleBinary.current_command_name("bin/wordpress post", []) + end + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/running_binaries_test.rb b/bin/moda/lib/git-style-binaries-0.1.11/test/running_binaries_test.rb new file mode 100644 index 0000000..887b651 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/running_binaries_test.rb @@ -0,0 +1,224 @@ +require File.dirname(__FILE__) + "/test_helper.rb" + +THIS_YEAR=Time.now.year # todo + +class RunningBinariesTest < Test::Unit::TestCase + include RunsBinaryFixtures + + context "when running primary" do + ["wordpress -h", "wordpress help"].each do |format| + context "and getting help as a '#{format}'" do + setup { @stdout, @stderr = bin(format) } + + should "have the command name and short description" do + unless format == "wordpress -h" # doesn't apply to wordpress -h + output_matches /NAME\n\s*wordpress\-help \- get help for a specific command/m + end + end + + should "have a local (not default) version string" do + output_matches /0\.0\.1 \(c\) 2009 Nate Murray - local/ + end + + should "get a list of subcommands" do + output_matches /subcommands/mi + end + + should "have subcommand short descriptions" do + output_matches /post\s*create a blog post/ + output_matches /categories\s*do something with categories/ + output_matches /help\s*get help for a specific command/ + output_matches /list\s*list blog postings/ + end + + should "have a usage" do + output_matches /SYNOPSIS/i + output_matches /wordpress(\-help)? \[/ + end + + should "be able to ask for help about help" + end + end + + context "and getting help as subcommand" do + # ["wordpress -h", "wordpress help"].each do |format| + ["wordpress help"].each do |format| + context "'#{format}'" do + should "get help on subcommand post" + end + end + end + + context "with no options" do + setup { @stdout, @stderr = bin("wordpress") } + + should "output the options" do + output_matches /Primary Options:/ + end + + should "have the test_primary option" do + output_matches /test_primary=>nil/ + end + end + should "be able to require 'primary' and run just fine" + end + + context "when running with an action" do + # should be the same for both formats + ["wordpress-categories", "wordpress categories"].each do |bin_format| + context "#{bin_format}" do + + context "with action block" do + setup { @stdout, @stderr = bin("#{bin_format}") } + should "have the parsed action items in the help output" do + output_matches /sports news/m + end + end + end + end + end + + context "callbacks" do + context "on a binary" do + setup { @stdout, @stderr = bin("wordpress") } + + %w(before after).each do |time| + should "run the callback #{time}_run}" do + assert @stdout.match(/#{time}_run command/) + end + end + end + + context "on help" do + setup { @stdout, @stderr = bin("wordpress -h") } + + %w(before after).each do |time| + should "not run the callback #{time}_run" do + assert_nil @stdout.match(/#{time}_run command/) + end + end + end + + end + + + context "when running the subcommand" do + # should be the same for both formats + ["wordpress-post", "wordpress post"].each do |bin_format| + context "#{bin_format}" do + + context "with no options" do + setup { @stdout, @stderr = bin("#{bin_format}") } + should "fail because title is required" do + output_matches /Error: option 'title' must be specified.\s*Try --help for help/m + end + end + + context "with options" do + setup { @stdout, @stderr = bin("#{bin_format} --title='glendale'") } + should "be running the subcommand's run block" do + output_matches /Subcommand name/ + end + should "have some default options" do + output_matches /version=>false/ + output_matches /help=>false/ + end + should "have some primary options" do + output_matches /test_primary=>nil/ + end + should "have some local options" do + output_matches /title=>"glendale"/ + output_matches /type=>"html"/ + end + end + + context "testing die statements" do + setup { @stdout, @stderr = bin("#{bin_format} --title='glendale' --type=yaml") } + + should "die on invalid options" do + output_matches /argument \-\-type type must be one of \[html\|xhtml\|text\]/ + end + end + + end # end bin_format + end # end #each + end + + ["wordpress help post", "wordpress post -h"].each do |format| + context "when calling '#{format}'" do + + setup { @stdout, @stderr = bin(format) } + should "have a description" do + output_matches /create a blog post/ + end + + should "have the proper usage line" do + output_matches /SYNOPSIS\n\s*wordpress\-post/m + output_matches /\[--title\]/ + end + + should "have option flags" do + output_matches /\-\-title(.*)/ + end + + should "have primary option flags" do + output_matches /\-\-test-primary(.*)/ + end + + should "have default option flags" do + output_matches /\-\-verbose/ + end + + should "have trollop default option flags" do + output_matches /\-e, \-\-version/ + end + + should "have the correct binary name and short description" do + output_matches /NAME\n\s*wordpress\-post \- create a blog post/m + end + + should "have a the primaries version string" do + output_matches /0\.0\.1 \(c\) 2009 Nate Murray - local/ + end + + should "have options" do + output_matches /Options/i + + output_matches /\-b, \-\-blog=/ + output_matches /short name of the blog to use/ + + output_matches /-i, \-\-title=/ + output_matches /title for the post/ + end + + end + end + + context "when running a bare primary" do + ["flickr -h", "flickr help"].each do |format| + context format do + setup { @stdout, @stderr = bin(format) } + + should "have the name and short description" do + unless format == "flickr -h" # hmm + output_matches /NAME\n\s*flickr\-help \- get help for a specific command/m + end + end + + should "have a local (not default) version string" do + output_matches /0\.0\.2 \(c\) #{Time.now.year}/ + end + end + end + ["flickr-download -h", "flickr download -h"].each do |format| + context format do + setup { @stdout, @stderr = bin(format) } + + should "match on usage" do + output_matches /SYNOPSIS\n\s*flickr\-download/m + end + end + end + end + +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/shoulda_macros/matching_stdio.rb b/bin/moda/lib/git-style-binaries-0.1.11/test/shoulda_macros/matching_stdio.rb new file mode 100644 index 0000000..e8e90e5 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/shoulda_macros/matching_stdio.rb @@ -0,0 +1,13 @@ +class Test::Unit::TestCase + def output_should_match(regexp) + assert_match regexp, @stdout + @stderr + end + alias_method :output_matches, :output_should_match + + def stdout_should_match(regexp) + assert_match regexp, @stdout + end + def stderr_should_match(regexp) + assert_match regexp, @stderr + end +end diff --git a/bin/moda/lib/git-style-binaries-0.1.11/test/test_helper.rb b/bin/moda/lib/git-style-binaries-0.1.11/test/test_helper.rb new file mode 100644 index 0000000..7fcb576 --- /dev/null +++ b/bin/moda/lib/git-style-binaries-0.1.11/test/test_helper.rb @@ -0,0 +1,28 @@ +require 'rubygems' +require 'test/unit' +require 'shoulda' +begin require 'redgreen'; rescue LoadError; end +require 'open3' + +$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) +$LOAD_PATH.unshift(File.dirname(__FILE__)) +Dir[File.join(File.dirname(__FILE__), "shoulda_macros", "*.rb")].each {|f| require f} +ENV['NO_COLOR'] = "true" + +require 'git-style-binary' +GitStyleBinary.run = true + +class Test::Unit::TestCase + def fixtures_dir + File.join(File.dirname(__FILE__), "fixtures") + end +end + +module RunsBinaryFixtures + # run the specified cmd returning the string values of [stdout,stderr] + def bin(cmd) + stdin, stdout, stderr = Open3.popen3("#{fixtures_dir}/#{cmd}") + [stdout.read, stderr.read] + end +end + diff --git a/bin/moda/lib/trollop-1.16.2/FAQ.txt b/bin/moda/lib/trollop-1.16.2/FAQ.txt new file mode 100644 index 0000000..809b35d --- /dev/null +++ b/bin/moda/lib/trollop-1.16.2/FAQ.txt @@ -0,0 +1,84 @@ +Trollop FAQ +----------- + +Q: Why is it called "Trollop"? +A: No reason. + +Q: Why should I use Trollop? +A: Because it will take you FEWER LINES OF CODE to do reasonable option parsing + than any other option parser out there. + + Look at this: + + opts = Trollop::options do + opt :monkey, "Use monkey mode" + opt :goat, "Use goat mode", :default => true + opt :num_limbs, "Set number of limbs", :default => 4 + end + + That's it. And opts is a hash and you do whatever you want with it. + Trivial. You don't have to mix option processing code blocks with the + declarations. You don't have to make a class for every option (what is this, + Java?). You don't have to write more than 1 line of code per option. + + Plus, you get a beautiful help screen that detects your terminal width and + wraps appropriately. C'mon, that's hot. + +Q: What is the philosophy behind Trollop? +A: Must a commandline option processor have a philosophy? + +Q: Seriously now. What is it? +A: Ok, it's this: Trollop *just* does the parsing and gives you a hash table + of the result. So whatever fancy logic or constraints you need, you can + implement by operating on that hash table. Options that disable other + options, fancy constraints involving multiple sets of values across multiple + sets of options, etc. are all left for you to do manually. + + (Trollop does support limited constraint setting (see #conflicts and + #depends), but any non-trivial program will need to get fancier.) + + The result is that using Trollop is pretty simple, and whatever bizarre + logic you want, you can write yourself. And don't forget, you can call + Trollop::die to abort the program and give a fancy options-related error + message. + +Q: What happens to the other stuff on the commandline? +A: Anything Trollop doesn't recognize as an option or as an option parameter is + left in ARGV for you to process. + +Q: Does Trollop support multiple-value arguments? +A: Yes. If you set the :type of an option to something plural, like ":ints", + ":strings", ":doubles", ":floats", ":ios", it will accept multiple arguments + on the commandline and the value will be an array of these. + +Q: Does Trollop support arguments that can be given multiple times? +A: Yes. If you set :multi to true, then the argument can appear multiple times + on the commandline, and the value will be an array of the parameters. + +Q: Does Trollop support subcommands? +A: Yes. You get subcommand support by adding a call #stop_on within the options + block, and passing the names of the subcommands to it. (See the third + example on the webpage.) When Trollop encounters one of these subcommands on + the commandline, it stops processing and returns. + + ARGV at that point will contain the subcommand followed by any subcommand + options, since Trollop has contained the rest. So you can consume the + subcommand and call Trollop.options again with the particular options set + for that subcommand. + + If you don't know the subcommands ahead of time, you can call + #stop_on_unknown, which will cause Trollop to stop when it encounters any + unknown token. This might be more trouble than its worth if you're also + passing filenames on the commandline. + + It's probably easier to see the example on the webpage than to read all + that. + +Q: Why does Trollop disallow numeric short argument names, like '-1' and '-9'? +A: Because it's ambiguous whether these are arguments or negative integer or + floating-point parameters to arguments. E.g., what about "-f -3". Is that a + negative three parameter to -f, or two separate parameters? + + I could be very clever and detect when there are no arguments that require + floating-point parameters, and allow such short option names in those cases, + but opted for simplicity and consistency. diff --git a/bin/moda/lib/trollop-1.16.2/History.txt b/bin/moda/lib/trollop-1.16.2/History.txt new file mode 100644 index 0000000..bb2c8df --- /dev/null +++ b/bin/moda/lib/trollop-1.16.2/History.txt @@ -0,0 +1,116 @@ +== 1.16.2 / 2010-04-06 +* Bugfix in Trollop::options. Thanks to Brian C. Thomas for pointing it out. + +== 1.16.1 / 2010-04-05 +* Bugfix in Trollop::die method introduced in last release. + +== 1.16 / 2010-04-01 +* Add Trollop::with_standard_exception_handling method for easing the use of Parser directly. +* Handle scientific notation in float arguments, thanks to Will Fitzgerald. +* Drop hoe dependency. + +== 1.15 / 2009-09-30 +* Don't raise an exception when out of short arguments (thanks to Rafael + Sevilla for pointing out how dumb this behavior was). + +== 1.14 / 2009-06-19 +* Make :multi arguments default to [], not nil, when not set on the commandline. +* Minor commenting and error message improvements + +== 1.13 / 2009-03-16 +* Fix parsing of "--longarg=". + +== 1.12 / 2009-01-30 +* Fix some unit test failures in the last release. Should be more careful. +* Make default short options only be assigned *after* all user-specified + short options. Now there's a little less juggling to do when you just + want to specify a few short options. + +== 1.11 / 2009-01-29 +* Set _given keys in the results hash for options that were specified + on the commandline. + +== 1.10.2 / 2008-10-23 +* No longer try `stty size` for screen size detection. Just use curses, and + screen users will have to deal with the screen clearing. + +== 1.10.1 / 2008-10-22 +* Options hash now responds to method calls as well as standard hash lookup. +* Default values for multi-occurrence parameters now autoboxed. +* The relationship between multi-value, multi-occurrence, and default values + improved and explained. +* Documentation improvements. + +== 1.10 / 2008-10-21 +* Added :io type for parameters that point to IO streams (filenames, URIs, etc). +* For screen size detection, first try `stty size` before loading Curses. +* Improved documentation. + +== 1.9 / 2008-08-20 +* Added 'stop_on_unknown' command to stop parsing on any unknown argument. + This is useful for handling sub-commands when you don't know the entire + set of commands up front. (E.g. if the initial arguments can change it.) +* Added a :multi option for parameters, signifying that they can be specified + multiple times. +* Added :ints, :strings, :doubles, and :floats option types, which can take + multiple arguments. + +== 1.8.2 / 2008-06-25 +* Bugfix for #conflicts and #depends error messages + +== 1.8.1 / 2008-06-24 +* Bugfix for short option autocreation +* More aggressive documentation + +== 1.8 / 2008-06-16 +* Sub-command support via Parser#stop_on + +== 1.7.2 / 2008-01-16 +* Ruby 1.9-ify. Apparently this means replacing :'s with ;'s. + +== 1.7.1 / 2008-01-07 +* Documentation improvements + +== 1.7 / 2007-06-17 +* Fix incorrect error message for multiple missing required arguments + (thanks to Neill Zero) + +== 1.6 / 2007-04-01 +* Don't attempt curses screen-width magic unless running on a terminal. + +== 1.5 / 2007-03-31 +* --help and --version do the right thing even if the rest of the + command line is incorrect. +* Added #conflicts and #depends to model dependencies and exclusivity + between arguments. +* Minor bugfixes. + +== 1.4 / 2007-03-26 +* Disable short options with :short => :none. +* Minor bugfixes and error message improvements. + +== 1.3 / 2007-01-31 +* Wrap at (screen width - 1) instead of screen width. +* User can override --help and --version. +* Bugfix in handling of -v and -h. +* More tests to confirm the above. + +== 1.2 / 2007-01-31 +* Minor documentation tweaks. +* Removed hoe dependency. + +== 1.1 / 2007-01-30 +* Trollop::options now passes any arguments as block arguments. Since + instance variables are not properly captured by the block, this + makes it slightly less noisy to pass them in as local variables. + (A real-life use for _why's cloaker!) +* Help display now preserves original argument order. +* Trollop::die now also has a single string form in case death is not + due to a single argument. +* Parser#text now an alias for Parser#banner, and can be called + multiple times, with the output being placed in the right position + in the help text. +* Slightly more indicative formatting for parameterized arguments. + +== 1.0 / 2007-01-29 +* Initial release. diff --git a/bin/moda/lib/trollop-1.16.2/README.txt b/bin/moda/lib/trollop-1.16.2/README.txt new file mode 100644 index 0000000..7258008 --- /dev/null +++ b/bin/moda/lib/trollop-1.16.2/README.txt @@ -0,0 +1,52 @@ +== trollop + +by William Morgan (http://masanjin.net/) + +Main page: http://trollop.rubyforge.org + +Release announcements and comments: http://all-thing.net/label/trollop + +Documentation quickstart: See Trollop.options and then Trollop::Parser#opt. +Also see the examples at http://trollop.rubyforge.org/. + +== DESCRIPTION + +Trollop is a commandline option parser for Ruby that just gets out of your +way. One line of code per option is all you need to write. For that, you get a +nice automatically-generated help page, robust option parsing, command +subcompletion, and sensible defaults for everything you don't specify. + +== FEATURES/PROBLEMS + +- Dirt-simple usage. +- Sensible defaults. No tweaking necessary, much tweaking possible. +- Support for long options, short options, short option bundling, and + automatic type validation and conversion. +- Support for subcommands. +- Automatic help message generation, wrapped to current screen width. +- Lots of unit tests. + +== REQUIREMENTS + +* A burning desire to write less code. + +== INSTALL + +* gem install trollop + +== SYNOPSIS + + require 'trollop' + opts = Trollop::options do + opt :monkey, "Use monkey mode" # flag --monkey, default false + opt :goat, "Use goat mode", :default => true # flag --goat, default true + opt :num_limbs, "Number of limbs", :default => 4 # integer --num-limbs , default to 4 + opt :num_thumbs, "Number of thumbs", :type => :int # integer --num-thumbs , default nil + end + + p opts # a hash: { :monkey => false, :goat => true, :num_limbs => 4, :num_thumbs => nil } + +== LICENSE + +Copyright (c) 2008--2009 William Morgan. Trollop is distributed under the same +terms as Ruby. diff --git a/bin/moda/lib/trollop-1.16.2/lib/trollop.rb b/bin/moda/lib/trollop-1.16.2/lib/trollop.rb new file mode 100644 index 0000000..06ee2af --- /dev/null +++ b/bin/moda/lib/trollop-1.16.2/lib/trollop.rb @@ -0,0 +1,781 @@ +## lib/trollop.rb -- trollop command-line processing library +## Author:: William Morgan (mailto: wmorgan-trollop@masanjin.net) +## Copyright:: Copyright 2007 William Morgan +## License:: the same terms as ruby itself + +require 'date' + +module Trollop + +VERSION = "1.16.2" + +## Thrown by Parser in the event of a commandline error. Not needed if +## you're using the Trollop::options entry. +class CommandlineError < StandardError; end + +## Thrown by Parser if the user passes in '-h' or '--help'. Handled +## automatically by Trollop#options. +class HelpNeeded < StandardError; end + +## Thrown by Parser if the user passes in '-h' or '--version'. Handled +## automatically by Trollop#options. +class VersionNeeded < StandardError; end + +## Regex for floating point numbers +FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))([eE][-+]?[\d]+)?$/ + +## Regex for parameters +PARAM_RE = /^-(-|\.$|[^\d\.])/ + +## The commandline parser. In typical usage, the methods in this class +## will be handled internally by Trollop::options. In this case, only the +## #opt, #banner and #version, #depends, and #conflicts methods will +## typically be called. +## +## If you want to instantiate this class yourself (for more complicated +## argument-parsing logic), call #parse to actually produce the output hash, +## and consider calling it from within +## Trollop::with_standard_exception_handling. +class Parser + + ## The set of values that indicate a flag option when passed as the + ## +:type+ parameter of #opt. + FLAG_TYPES = [:flag, :bool, :boolean] + + ## The set of values that indicate a single-parameter (normal) option when + ## passed as the +:type+ parameter of #opt. + ## + ## A value of +io+ corresponds to a readable IO resource, including + ## a filename, URI, or the strings 'stdin' or '-'. + SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io, :date] + + ## The set of values that indicate a multiple-parameter option (i.e., that + ## takes multiple space-separated values on the commandline) when passed as + ## the +:type+ parameter of #opt. + MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios, :dates] + + ## The complete set of legal values for the +:type+ parameter of #opt. + TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES + + INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc: + + ## The values from the commandline that were not interpreted by #parse. + attr_reader :leftovers + + ## The complete configuration hashes for each option. (Mainly useful + ## for testing.) + attr_reader :specs + + ## Initializes the parser, and instance-evaluates any block given. + def initialize *a, &b + @version = nil + @leftovers = [] + @specs = {} + @long = {} + @short = {} + @order = [] + @constraints = [] + @stop_words = [] + @stop_on_unknown = false + + #instance_eval(&b) if b # can't take arguments + cloaker(&b).bind(self).call(*a) if b + end + + ## Define an option. +name+ is the option name, a unique identifier + ## for the option that you will use internally, which should be a + ## symbol or a string. +desc+ is a string description which will be + ## displayed in help messages. + ## + ## Takes the following optional arguments: + ## + ## [+:long+] Specify the long form of the argument, i.e. the form with two dashes. If unspecified, will be automatically derived based on the argument name by turning the +name+ option into a string, and replacing any _'s by -'s. + ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+. + ## [+:type+] Require that the argument take a parameter or parameters of type +type+. For a single parameter, the value can be a member of +SINGLE_ARG_TYPES+, or a corresponding Ruby class (e.g. +Integer+ for +:int+). For multiple-argument parameters, the value can be any member of +MULTI_ARG_TYPES+ constant. If unset, the default argument type is +:flag+, meaning that the argument does not take a parameter. The specification of +:type+ is not necessary if a +:default+ is given. + ## [+:default+] Set the default value for an argument. Without a default value, the hash returned by #parse (and thus Trollop::options) will have a +nil+ value for this key unless the argument is given on the commandline. The argument type is derived automatically from the class of the default value given, so specifying a +:type+ is not necessary if a +:default+ is given. (But see below for an important caveat when +:multi+: is specified too.) If the argument is a flag, and the default is set to +true+, then if it is specified on the the commandline the value will be +false+. + ## [+:required+] If set to +true+, the argument must be provided on the commandline. + ## [+:multi+] If set to +true+, allows multiple occurrences of the option on the commandline. Otherwise, only a single instance of the option is allowed. (Note that this is different from taking multiple parameters. See below.) + ## + ## Note that there are two types of argument multiplicity: an argument + ## can take multiple values, e.g. "--arg 1 2 3". An argument can also + ## be allowed to occur multiple times, e.g. "--arg 1 --arg 2". + ## + ## Arguments that take multiple values should have a +:type+ parameter + ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+ + ## value of an array of the correct type (e.g. [String]). The + ## value of this argument will be an array of the parameters on the + ## commandline. + ## + ## Arguments that can occur multiple times should be marked with + ## +:multi+ => +true+. The value of this argument will also be an array. + ## In contrast with regular non-multi options, if not specified on + ## the commandline, the default value will be [], not nil. + ## + ## These two attributes can be combined (e.g. +:type+ => +:strings+, + ## +:multi+ => +true+), in which case the value of the argument will be + ## an array of arrays. + ## + ## There's one ambiguous case to be aware of: when +:multi+: is true and a + ## +:default+ is set to an array (of something), it's ambiguous whether this + ## is a multi-value argument as well as a multi-occurrence argument. + ## In thise case, Trollop assumes that it's not a multi-value argument. + ## If you want a multi-value, multi-occurrence argument with a default + ## value, you must specify +:type+ as well. + + def opt name, desc="", opts={} + raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name + + ## fill in :type + opts[:type] = # normalize + case opts[:type] + when :boolean, :bool; :flag + when :integer; :int + when :integers; :ints + when :double; :float + when :doubles; :floats + when Class + case opts[:type].name + when 'TrueClass', 'FalseClass'; :flag + when 'String'; :string + when 'Integer'; :int + when 'Float'; :float + when 'IO'; :io + when 'Date'; :date + else + raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'" + end + when nil; nil + else + raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type]) + opts[:type] + end + + ## for options with :multi => true, an array default doesn't imply + ## a multi-valued argument. for that you have to specify a :type + ## as well. (this is how we disambiguate an ambiguous situation; + ## see the docs for Parser#opt for details.) + disambiguated_default = + if opts[:multi] && opts[:default].is_a?(Array) && !opts[:type] + opts[:default].first + else + opts[:default] + end + + type_from_default = + case disambiguated_default + when Integer; :int + when Numeric; :float + when TrueClass, FalseClass; :flag + when String; :string + when IO; :io + when Date; :date + when Array + if opts[:default].empty? + raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'" + end + case opts[:default][0] # the first element determines the types + when Integer; :ints + when Numeric; :floats + when String; :strings + when IO; :ios + when Date; :dates + else + raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'" + end + when nil; nil + else + raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'" + end + + raise ArgumentError, ":type specification and default type don't match (default type is #{type_from_default})" if opts[:type] && type_from_default && opts[:type] != type_from_default + + opts[:type] = opts[:type] || type_from_default || :flag + + ## fill in :long + opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-") + opts[:long] = + case opts[:long] + when /^--([^-].*)$/ + $1 + when /^[^-]/ + opts[:long] + else + raise ArgumentError, "invalid long option name #{opts[:long].inspect}" + end + raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]] + + ## fill in :short + opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none + opts[:short] = case opts[:short] + when /^-(.)$/; $1 + when nil, :none, /^.$/; opts[:short] + else raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'" + end + + if opts[:short] + raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]] + raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX + end + + ## fill in :default for flags + opts[:default] = false if opts[:type] == :flag && opts[:default].nil? + + ## autobox :default for :multi (multi-occurrence) arguments + opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array) + + ## fill in :multi + opts[:multi] ||= false + + opts[:desc] ||= desc + @long[opts[:long]] = name + @short[opts[:short]] = name if opts[:short] && opts[:short] != :none + @specs[name] = opts + @order << [:opt, name] + end + + ## Sets the version string. If set, the user can request the version + ## on the commandline. Should probably be of the form " + ## ". + def version s=nil; @version = s if s; @version end + + ## Adds text to the help display. Can be interspersed with calls to + ## #opt to build a multi-section help page. + def banner s; @order << [:text, s] end + alias :text :banner + + ## Marks two (or more!) options as requiring each other. Only handles + ## undirected (i.e., mutual) dependencies. Directed dependencies are + ## better modeled with Trollop::die. + def depends *syms + syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] } + @constraints << [:depends, syms] + end + + ## Marks two (or more!) options as conflicting. + def conflicts *syms + syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] } + @constraints << [:conflicts, syms] + end + + ## Defines a set of words which cause parsing to terminate when + ## encountered, such that any options to the left of the word are + ## parsed as usual, and options to the right of the word are left + ## intact. + ## + ## A typical use case would be for subcommand support, where these + ## would be set to the list of subcommands. A subsequent Trollop + ## invocation would then be used to parse subcommand options, after + ## shifting the subcommand off of ARGV. + def stop_on *words + @stop_words = [*words].flatten + end + + ## Similar to #stop_on, but stops on any unknown word when encountered + ## (unless it is a parameter for an argument). This is useful for + ## cases where you don't know the set of subcommands ahead of time, + ## i.e., without first parsing the global options. + def stop_on_unknown + @stop_on_unknown = true + end + + ## Parses the commandline. Typically called by Trollop::options, + ## but you can call it directly if you need more control. + ## + ## throws CommandlineError, HelpNeeded, and VersionNeeded exceptions. + def parse cmdline=ARGV + vals = {} + required = {} + + opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"] + opt :help, "Show this message" unless @specs[:help] || @long["help"] + + @specs.each do |sym, opts| + required[sym] = true if opts[:required] + vals[sym] = opts[:default] + vals[sym] = [] if opts[:multi] && !opts[:default] # multi arguments default to [], not nil + end + + resolve_default_short_options + + ## resolve symbols + given_args = {} + @leftovers = each_arg cmdline do |arg, params| + sym = case arg + when /^-([^-])$/ + @short[$1] + when /^--([^-]\S*)$/ + @long[$1] + else + raise CommandlineError, "invalid argument syntax: '#{arg}'" + end + raise CommandlineError, "unknown argument '#{arg}'" unless sym + + if given_args.include?(sym) && !@specs[sym][:multi] + raise CommandlineError, "option '#{arg}' specified multiple times" + end + + given_args[sym] ||= {} + + given_args[sym][:arg] = arg + given_args[sym][:params] ||= [] + + # The block returns the number of parameters taken. + num_params_taken = 0 + + unless params.nil? + if SINGLE_ARG_TYPES.include?(@specs[sym][:type]) + given_args[sym][:params] << params[0, 1] # take the first parameter + num_params_taken = 1 + elsif MULTI_ARG_TYPES.include?(@specs[sym][:type]) + given_args[sym][:params] << params # take all the parameters + num_params_taken = params.size + end + end + + num_params_taken + end + + ## check for version and help args + raise VersionNeeded if given_args.include? :version + raise HelpNeeded if given_args.include? :help + + ## check constraint satisfaction + @constraints.each do |type, syms| + constraint_sym = syms.find { |sym| given_args[sym] } + next unless constraint_sym + + case type + when :depends + syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym } + when :conflicts + syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) } + end + end + + required.each do |sym, val| + raise CommandlineError, "option --#{@specs[sym][:long]} must be specified" unless given_args.include? sym + end + + ## parse parameters + given_args.each do |sym, given_data| + arg = given_data[:arg] + params = given_data[:params] + + opts = @specs[sym] + raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag + + vals["#{sym}_given".intern] = true # mark argument as specified on the commandline + + case opts[:type] + when :flag + vals[sym] = !opts[:default] + when :int, :ints + vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } } + when :float, :floats + vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } } + when :string, :strings + vals[sym] = params.map { |pg| pg.map { |p| p.to_s } } + when :io, :ios + vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } } + when :date, :dates + vals[sym] = params.map { |pg| pg.map { |p| parse_date_parameter p, arg } } + end + + if SINGLE_ARG_TYPES.include?(opts[:type]) + unless opts[:multi] # single parameter + vals[sym] = vals[sym][0][0] + else # multiple options, each with a single parameter + vals[sym] = vals[sym].map { |p| p[0] } + end + elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi] + vals[sym] = vals[sym][0] # single option, with multiple parameters + end + # else: multiple options, with multiple parameters + end + + ## modify input in place with only those + ## arguments we didn't process + cmdline.clear + @leftovers.each { |l| cmdline << l } + + ## allow openstruct-style accessors + class << vals + def method_missing(m, *args) + self[m] || self[m.to_s] + end + end + vals + end + + def parse_date_parameter param, arg #:nodoc: + begin + begin + time = Chronic.parse(param) + rescue NameError + # chronic is not available + end + time ? Date.new(time.year, time.month, time.day) : Date.parse(param) + rescue ArgumentError => e + raise CommandlineError, "option '#{arg}' needs a date" + end + end + + ## Print the help message to +stream+. + def educate stream=$stdout + width # just calculate it now; otherwise we have to be careful not to + # call this unless the cursor's at the beginning of a line. + + left = {} + @specs.each do |name, spec| + left[name] = "--#{spec[:long]}" + + (spec[:short] && spec[:short] != :none ? ", -#{spec[:short]}" : "") + + case spec[:type] + when :flag; "" + when :int; " " + when :ints; " " + when :string; " " + when :strings; " " + when :float; " " + when :floats; " " + when :io; " " + when :ios; " " + when :date; " " + when :dates; " " + end + end + + leftcol_width = left.values.map { |s| s.length }.max || 0 + rightcol_start = leftcol_width + 6 # spaces + + unless @order.size > 0 && @order.first.first == :text + stream.puts "#@version\n" if @version + stream.puts "Options:" + end + + @order.each do |what, opt| + if what == :text + stream.puts wrap(opt) + next + end + + spec = @specs[opt] + stream.printf " %#{leftcol_width}s: ", left[opt] + desc = spec[:desc] + begin + default_s = case spec[:default] + when $stdout; "" + when $stdin; "" + when $stderr; "" + when Array + spec[:default].join(", ") + else + spec[:default].to_s + end + + if spec[:default] + if spec[:desc] =~ /\.$/ + " (Default: #{default_s})" + else + " (default: #{default_s})" + end + else + "" + end + end + stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start) + end + end + + def width #:nodoc: + @width ||= if $stdout.tty? + begin + require 'curses' + Curses::init_screen + x = Curses::cols + Curses::close_screen + x + rescue Exception + 80 + end + else + 80 + end + end + + def wrap str, opts={} # :nodoc: + if str == "" + [""] + else + str.split("\n").map { |s| wrap_line s, opts }.flatten + end + end + + ## The per-parser version of Trollop::die (see that for documentation). + def die arg, msg + if msg + $stderr.puts "Error: argument --#{@specs[arg][:long]} #{msg}." + else + $stderr.puts "Error: #{arg}." + end + $stderr.puts "Try --help for help." + exit(-1) + end + +private + + ## yield successive arg, parameter pairs + def each_arg args + remains = [] + i = 0 + + until i >= args.length + if @stop_words.member? args[i] + remains += args[i .. -1] + return remains + end + case args[i] + when /^--$/ # arg terminator + remains += args[(i + 1) .. -1] + return remains + when /^--(\S+?)=(.*)$/ # long argument with equals + yield "--#{$1}", [$2] + i += 1 + when /^--(\S+)$/ # long argument + params = collect_argument_parameters(args, i + 1) + unless params.empty? + num_params_taken = yield args[i], params + unless num_params_taken + if @stop_on_unknown + remains += args[i + 1 .. -1] + return remains + else + remains += params + end + end + i += 1 + num_params_taken + else # long argument no parameter + yield args[i], nil + i += 1 + end + when /^-(\S+)$/ # one or more short arguments + shortargs = $1.split(//) + shortargs.each_with_index do |a, j| + if j == (shortargs.length - 1) + params = collect_argument_parameters(args, i + 1) + unless params.empty? + num_params_taken = yield "-#{a}", params + unless num_params_taken + if @stop_on_unknown + remains += args[i + 1 .. -1] + return remains + else + remains += params + end + end + i += 1 + num_params_taken + else # argument no parameter + yield "-#{a}", nil + i += 1 + end + else + yield "-#{a}", nil + end + end + else + if @stop_on_unknown + remains += args[i .. -1] + return remains + else + remains << args[i] + i += 1 + end + end + end + + remains + end + + def parse_integer_parameter param, arg + raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/ + param.to_i + end + + def parse_float_parameter param, arg + raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE + param.to_f + end + + def parse_io_parameter param, arg + case param + when /^(stdin|-)$/i; $stdin + else + require 'open-uri' + begin + open param + rescue SystemCallError => e + raise CommandlineError, "file or url for option '#{arg}' cannot be opened: #{e.message}" + end + end + end + + def collect_argument_parameters args, start_at + params = [] + pos = start_at + while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do + params << args[pos] + pos += 1 + end + params + end + + def resolve_default_short_options + @order.each do |type, name| + next unless type == :opt + opts = @specs[name] + next if opts[:short] + + c = opts[:long].split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) } + if c # found a character to use + opts[:short] = c + @short[c] = name + end + end + end + + def wrap_line str, opts={} + prefix = opts[:prefix] || 0 + width = opts[:width] || (self.width - 1) + start = 0 + ret = [] + until start > str.length + nextt = + if start + width >= str.length + str.length + else + x = str.rindex(/\s/, start + width) + x = str.index(/\s/, start) if x && x < start + x || str.length + end + ret << (ret.empty? ? "" : " " * prefix) + str[start ... nextt] + start = nextt + 1 + end + ret + end + + ## instance_eval but with ability to handle block arguments + ## thanks to why: http://redhanded.hobix.com/inspect/aBlockCostume.html + def cloaker &b + (class << self; self; end).class_eval do + define_method :cloaker_, &b + meth = instance_method :cloaker_ + remove_method :cloaker_ + meth + end + end +end + +## The easy, syntactic-sugary entry method into Trollop. Creates a Parser, +## passes the block to it, then parses +args+ with it, handling any errors or +## requests for help or version information appropriately (and then exiting). +## Modifies +args+ in place. Returns a hash of option values. +## +## The block passed in should contain zero or more calls to +opt+ +## (Parser#opt), zero or more calls to +text+ (Parser#text), and +## probably a call to +version+ (Parser#version). +## +## The returned block contains a value for every option specified with +## +opt+. The value will be the value given on the commandline, or the +## default value if the option was not specified on the commandline. For +## every option specified on the commandline, a key "