From 0fc9a0e3c81a3781b2afe35ad9ed763049dc8acf Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Sun, 4 Oct 2009 00:33:36 -0700 Subject: [PATCH] Subcommand UI for project creation and initialization. --- COMMAND_LINE.markdown | 68 ++++++++++++++++++++++ lib/compass/commands/base.rb | 6 +- lib/compass/commands/create_project.rb | 68 +++++++++++++++++++++- lib/compass/commands/installer_command.rb | 4 +- lib/compass/exec.rb | 10 ++-- lib/compass/exec/command_option_parser.rb | 16 +++++ lib/compass/exec/global_options_parser.rb | 37 ++++++++++++ lib/compass/exec/project_options_parser.rb | 42 +++++++++++++ lib/compass/exec/sub_command_ui.rb | 42 +++++++++++++ lib/compass/exec/switch_ui.rb | 67 +++------------------ 10 files changed, 286 insertions(+), 74 deletions(-) create mode 100644 COMMAND_LINE.markdown create mode 100644 lib/compass/exec/command_option_parser.rb create mode 100644 lib/compass/exec/global_options_parser.rb create mode 100644 lib/compass/exec/project_options_parser.rb diff --git a/COMMAND_LINE.markdown b/COMMAND_LINE.markdown new file mode 100644 index 00000000..591a093f --- /dev/null +++ b/COMMAND_LINE.markdown @@ -0,0 +1,68 @@ +Compass Command Line Documentation +================================== + +Extensions Commands +------------------- + + # install a global extension. probably requires sudo. + compass extension install extension_name + + # install an extension into a project + compass extension unpack extension_name [path/to/project] + + # uninstall a local or global extension. global extensions will require sudo. + compass extension uninstall extension_name [path/to/project] + + # list the extensions in the project + compass extensions list + + # list the extensions available for install + compass extensions available + +Project Commands +---------------- + + # Create a new compass project + compass create path/to/project [--using blueprint] [--sass-dir=sass ...] [--project-type=rails] + + # Initialize an existing project to work with compass + compass init rails path/to/project [--using blueprint] + + # Install a pattern from an extension into a project + compass install blueprint/buttons [path/to/project] + + # Compile the project's sass files into css + compass compile [path/to/project] + + # Watch the project for changes and compile whenever it does + compass watch [path/to/project] + + # Emit a configuration file at the location specified. + compass config [path/to/config] [--sass-dir=sass --css-dir=css ...] + + # Validate the generated CSS. + compass validate [path/to/project] + +misc commands +------------- + + # Generate a background image that can be used to verify grid alignment + compass grid-background W+GxH [path/to/image.png] + + # Emit the version of compass + compass version + + # Get help on compass + compass help + + # Get help on an extension + compass help extension_name + + # Get help about an extension pattern + compass help extension_name/pattern_name + + # Get help about a particular sub command + compass help command_name + + + diff --git a/lib/compass/commands/base.rb b/lib/compass/commands/base.rb index 072ce7f5..91a0850f 100644 --- a/lib/compass/commands/base.rb +++ b/lib/compass/commands/base.rb @@ -1,10 +1,8 @@ module Compass module Commands class Base - def self.inherited(command_class) - if command_class.respond_to? :name - Compass::Commands[command_class.name] = command_class - end + def self.register(command_name) + Compass::Commands[command_name] = self end include Actions diff --git a/lib/compass/commands/create_project.rb b/lib/compass/commands/create_project.rb index 45cf2706..bf764f52 100644 --- a/lib/compass/commands/create_project.rb +++ b/lib/compass/commands/create_project.rb @@ -3,10 +3,72 @@ require 'compass/commands/stamp_pattern' module Compass module Commands + module CreateProjectOptionsParser + def set_options(opts) + + opts.banner = %q{ + Usage: compass create path/to/project [options] + + Description: + Create a new compass project at the path specified. + }.split("\n").map{|l| l.gsub(/^ */,'')}.join("\n") + + opts.on("--using FRAMEWORK", "Framework to use when creating the project.") do |framework| + framework = framework.split('/', 2) + self.options[:framework] = framework[0] + self.options[:pattern] = framework[1] + end + + super + end + end + class CreateProject < StampPattern - def initialize(working_path, options) - super(working_path, options.merge(:pattern => "project", :pattern_name => nil)) + register :create + register :init + + class << self + def parse!(arguments) + parser = parse_options!(arguments) + parse_arguments!(parser, arguments) + set_default_arguments(parser) + parser.options + end + + def parse_init!(arguments) + parser = parse_options!(arguments) + if arguments.size > 0 + parser.options[:project_type] = arguments.shift.to_sym + end + parse_arguments!(parser, arguments) + set_default_arguments(parser) + parser.options + end + + def parse_options!(arguments) + parser = Compass::Exec::CommandOptionParser.new(arguments) + parser.extend(Compass::Exec::GlobalOptionsParser) + parser.extend(Compass::Exec::ProjectOptionsParser) + parser.extend(CreateProjectOptionsParser) + parser.parse! + parser + end + + def parse_arguments!(parser, arguments) + if arguments.size == 1 + parser.options[:project_name] = arguments.shift + elsif arguments.size == 0 + raise Compass::Error, "Please specify a path to the project." + else + raise Compass::Error, "Too many arguments were specified." + end + end + + def set_default_arguments(parser) + parser.options[:framework] ||= :compass + parser.options[:pattern] ||= "project" + end end def is_project_creation? @@ -15,4 +77,4 @@ module Compass end end -end \ No newline at end of file +end diff --git a/lib/compass/commands/installer_command.rb b/lib/compass/commands/installer_command.rb index 35bc0af3..6069f593 100644 --- a/lib/compass/commands/installer_command.rb +++ b/lib/compass/commands/installer_command.rb @@ -27,8 +27,8 @@ module Compass end def installer_args - [template_directory(options[:pattern]), project_directory, options] + [template_directory(options[:pattern] || "project"), project_directory, options] end end end -end \ No newline at end of file +end diff --git a/lib/compass/exec.rb b/lib/compass/exec.rb index 105175ed..ee489695 100644 --- a/lib/compass/exec.rb +++ b/lib/compass/exec.rb @@ -8,8 +8,8 @@ require 'compass/commands' module Compass::Exec end -require 'compass/exec/helpers' -require 'compass/exec/switch_ui' -require 'compass/exec/sub_command_ui' - - +%w(helpers switch_ui sub_command_ui + global_options_parser project_options_parser + command_option_parser).each do |lib| + require "compass/exec/#{lib}" +end diff --git a/lib/compass/exec/command_option_parser.rb b/lib/compass/exec/command_option_parser.rb new file mode 100644 index 00000000..2bd599cc --- /dev/null +++ b/lib/compass/exec/command_option_parser.rb @@ -0,0 +1,16 @@ +module Compass::Exec + class CommandOptionParser + attr_accessor :options, :arguments + def initialize(arguments) + self.arguments = arguments + self.options = {} + end + def parse! + opts = OptionParser.new(&method(:set_options)) + opts.parse!(arguments) + end + def set_options(opts) + + end + end +end diff --git a/lib/compass/exec/global_options_parser.rb b/lib/compass/exec/global_options_parser.rb new file mode 100644 index 00000000..955ee8e0 --- /dev/null +++ b/lib/compass/exec/global_options_parser.rb @@ -0,0 +1,37 @@ +module Compass::Exec::GlobalOptionsParser + def set_options(opts) + super + set_global_options(opts) + end + def set_global_options(opts) + opts.on('-r LIBRARY', '--require LIBRARY', + "Require the given ruby LIBRARY before running commands.", + " This is used to access compass plugins without having a", + " project configuration file.") do |library| + ::Compass.configuration.require library + end + + opts.on('-q', '--quiet', :NONE, 'Quiet mode.') do + self.options[:quiet] = true + end + + opts.on('--trace', :NONE, 'Show a full stacktrace on error') do + self.options[:trace] = true + end + + opts.on('--force', :NONE, 'Allows some failing commands to succeed instead.') do + self.options[:force] = true + end + + opts.on('--dry-run', :NONE, 'Dry Run. Tells you what it plans to do.') do + self.options[:dry_run] = true + end + + opts.on_tail("-?", "-h", "--help", "Show this message") do + puts opts + exit + end + + end + +end diff --git a/lib/compass/exec/project_options_parser.rb b/lib/compass/exec/project_options_parser.rb new file mode 100644 index 00000000..a7c201b6 --- /dev/null +++ b/lib/compass/exec/project_options_parser.rb @@ -0,0 +1,42 @@ +module Compass::Exec::ProjectOptionsParser + def set_options(opts) + super + set_project_options(opts) + end + def set_project_options(opts) + opts.on('-c', '--config CONFIG_FILE', 'Specify the location of the configuration file explicitly.') do |configuration_file| + self.options[:configuration_file] = configuration_file + end + + opts.on('--sass-dir SRC_DIR', "The source directory where you keep your sass stylesheets.") do |sass_dir| + self.options[:sass_dir] = sass_dir + end + + opts.on('--css-dir CSS_DIR', "The target directory where you keep your css stylesheets.") do |css_dir| + self.options[:css_dir] = css_dir + end + + opts.on('--images-dir IMAGES_DIR', "The directory where you keep your images.") do |images_dir| + self.options[:images_dir] = images_dir + end + + opts.on('--javascripts-dir JS_DIR', "The directory where you keep your javascripts.") do |javascripts_dir| + self.options[:javascripts_dir] = javascripts_dir + end + + opts.on('-e ENV', '--environment ENV', [:development, :production], 'Use sensible defaults for your current environment.', + ' One of: development, production (default)') do |env| + self.options[:environment] = env + end + + opts.on('-s STYLE', '--output-style STYLE', [:nested, :expanded, :compact, :compressed], 'Select a CSS output mode.', + ' One of: nested, expanded, compact, compressed') do |style| + self.options[:output_style] = style + end + + opts.on('--relative-assets', :NONE, 'Make compass asset helpers generate relative urls to assets.') do + self.options[:relative_assets] = true + end + end + +end diff --git a/lib/compass/exec/sub_command_ui.rb b/lib/compass/exec/sub_command_ui.rb index e69de29b..867514ab 100644 --- a/lib/compass/exec/sub_command_ui.rb +++ b/lib/compass/exec/sub_command_ui.rb @@ -0,0 +1,42 @@ +require 'compass/exec/global_options_parser' +require 'compass/exec/project_options_parser' + +module Compass::Exec + class SubCommandUI + + attr_accessor :args + + def initialize(args) + self.args = args + end + + def run! + begin + perform! + rescue Exception => e + raise e if e.is_a? SystemExit + if e.is_a?(::Compass::Error) || e.is_a?(OptionParser::ParseError) + $stderr.puts e.message + else + ::Compass::Exec::Helpers.report_error(e, @options) + end + return 1 + end + return 0 + end + + protected + + def perform! + command = args.shift + command_class = Compass::Commands[command] + options = if command_class.respond_to?("parse_#{command}!") + command_class.send("parse_#{command}!", args) + else + command_class.parse!(args) + end + command_class.new(Dir.getwd, options).execute + end + + end +end diff --git a/lib/compass/exec/switch_ui.rb b/lib/compass/exec/switch_ui.rb index fe2f2b5e..384092cd 100644 --- a/lib/compass/exec/switch_ui.rb +++ b/lib/compass/exec/switch_ui.rb @@ -1,6 +1,10 @@ +require 'compass/exec/global_options_parser' +require 'compass/exec/project_options_parser' + module Compass::Exec class SwitchUI - + include GlobalOptionsParser + include ProjectOptionsParser attr_accessor :args, :options, :opts def initialize(args) @@ -127,64 +131,12 @@ END opts.separator '' opts.separator 'Configuration Options:' - opts.on('-c', '--config CONFIG_FILE', 'Specify the location of the configuration file explicitly.') do |configuration_file| - self.options[:configuration_file] = configuration_file - end - - opts.on('--sass-dir SRC_DIR', "The source directory where you keep your sass stylesheets.") do |sass_dir| - self.options[:sass_dir] = sass_dir - end - - opts.on('--css-dir CSS_DIR', "The target directory where you keep your css stylesheets.") do |css_dir| - self.options[:css_dir] = css_dir - end - - opts.on('--images-dir IMAGES_DIR', "The directory where you keep your images.") do |images_dir| - self.options[:images_dir] = images_dir - end - - opts.on('--javascripts-dir JS_DIR', "The directory where you keep your javascripts.") do |javascripts_dir| - self.options[:javascripts_dir] = javascripts_dir - end - - opts.on('-e ENV', '--environment ENV', [:development, :production], 'Use sensible defaults for your current environment.', - ' One of: development, production (default)') do |env| - self.options[:environment] = env - end - - opts.on('-s STYLE', '--output-style STYLE', [:nested, :expanded, :compact, :compressed], 'Select a CSS output mode.', - ' One of: nested, expanded, compact, compressed') do |style| - self.options[:output_style] = style - end - - opts.on('--relative-assets', :NONE, 'Make compass asset helpers generate relative urls to assets.') do - self.options[:relative_assets] = true - end + set_project_options(opts) opts.separator '' opts.separator 'General Options:' - opts.on('-r LIBRARY', '--require LIBRARY', "Require the given ruby LIBRARY before running commands.", - " This is used to access compass plugins without having a", - " project configuration file.") do |library| - ::Compass.configuration.require library - end - - opts.on('-q', '--quiet', :NONE, 'Quiet mode.') do - self.options[:quiet] = true - end - - opts.on('--dry-run', :NONE, 'Dry Run. Tells you what it plans to do.') do - self.options[:dry_run] = true - end - - opts.on('--trace', :NONE, 'Show a full stacktrace on error') do - self.options[:trace] = true - end - - opts.on('--force', :NONE, 'Force. Allows some failing commands to succeed instead.') do - self.options[:force] = true - end + set_global_options(opts) opts.on('--imports', :NONE, 'Emit an imports suitable for passing to the sass command-line.', ' Example: sass `compass --imports`', @@ -198,11 +150,6 @@ END exit end - opts.on_tail("-?", "-h", "--help", "Show this message") do - puts opts - exit - end - opts.on_tail("-v", "--version", "Print version") do self.options[:command] = :print_version end