require 'optparse' module Apimaster::Generators module Options def self.included(base) base.extend(ClassMethods) class << base if respond_to?(:inherited) alias_method :inherited_without_options, :inherited end alias_method :inherited, :inherited_with_options end end module ClassMethods EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze def inherited_with_options(sub) inherited_without_options(sub) if respond_to?(:inherited_without_options) sub.extend(Apimaster::Generators::Options::ClassMethods) end def mandatory_options(options = nil) if options write_inheritable_attribute(:mandatory_options, options) else read_inheritable_attribute(:mandatory_options) or write_inheritable_attribute(:mandatory_options, {}) end end def default_options(options = nil) if options write_inheritable_attribute(:default_options, options) else read_inheritable_attribute(:default_options) or write_inheritable_attribute(:default_options, {}) end end def read_inheritable_attribute(key) inheritable_attributes[key] end def write_inheritable_attribute(key, value) if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES) @inheritable_attributes = {} end inheritable_attributes[key] = value end def inheritable_attributes @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES end # Merge together our class options. In increasing precedence: # default_options (class default options) # runtime_options (provided as argument) # mandatory_options (class mandatory options) def full_options(runtime_options = {}) default_options.merge(runtime_options).merge(mandatory_options) end end # Each instance has an options hash that's populated by #parse. def options @options ||= {} end attr_writer :options protected # Convenient access to class mandatory options. def mandatory_options self.class.mandatory_options end # Convenient access to class default options. def default_options self.class.default_options end # Merge together our instance options. In increasing precedence: # default_options (class default options) # options (instance options) # runtime_options (provided as argument) # mandatory_options (class mandatory options) def full_options(runtime_options = {}) self.class.full_options(options.merge(runtime_options)) end # Parse arguments into the options hash. Classes may customize # parsing behavior by overriding these methods: # #banner Usage: ./script/generate [options] # #add_options! Options: # some options.. # #add_general_options! General Options: # general options.. def parse!(args, runtime_options = {}) self.options = {} @option_parser = OptionParser.new do |opt| opt.banner = banner add_options!(opt) add_general_options!(opt) opt.parse!(args) end return args ensure self.options = full_options(runtime_options) end # Raise a usage error. Override usage_message to provide a blurb # after the option parser summary. def usage(message = usage_message) #raise UsageError, "#{@option_parser}\n#{message}" puts "#{@option_parser}\n#{message}" end def usage_message '' end # Override with your own usage banner. def banner "Usage: #{$0} [options]" end # Override to add your options to the parser: # def add_options!(opt) # opt.on('-v', '--verbose') { |value| options[:verbose] = value } # end def add_options!(opt) end # Adds general options like -h and --quiet. Usually don't override. def add_general_options!(opt) opt.separator 'General Options:' opt.on('-h', '--help', 'Show this help message and quit.') { |v| options[:help] = v } opt.on('-p', '--pretend', 'Run but do not make any changes.') { |v| options[:pretend] = v } opt.on('-f', '--force', 'Overwrite files that already exist.') { options[:collision] = :force } opt.on('-s', '--skip', 'Skip files that already exist.') { options[:collision] = :skip } opt.on('-q', '--quiet', 'Suppress normal output.') { |v| options[:quiet] = v } opt.on('-t', '--backtrace', 'Debugging: show backtrace on errors.') { |v| options[:backtrace] = v } opt.on('-c', '--svn', 'Modify files with subversion. (Note: svn must be in path)') do options[:svn] = `svn status`.inject({}) do |opt, e| opt[e.chomp[7..-1]] = true opt end end opt.on('-g', '--git', 'Modify files with git. (Note: git must be in path)') do options[:git] = `git status`.inject({:new => {}, :modified => {}}) do |opt, e| opt[:new][e.chomp[14..-1]] = true if e =~ /new file:/ opt[:modified][e.chomp[14..-1]] = true if e =~ /modified:/ opt end end end end end