require ‘sprout/generator/base’ require ‘sprout/generator/command’ require ‘sprout/generator/manifest’ require ‘sprout/generator/file_manifest’ require ‘sprout/generator/template_manifest’ require ‘sprout/generator/directory_manifest’
module Sprout
## # # = Introduction # # Sprout Generators are command line applications that are # installed by RubyGems and should universally provide the # following features: # # * Terminal tab completion to discover generators # * Call with no arguments to see help output # * Call with an +--input+ (or trailing) argument to create # * Call with a collection of arguments given on a previous run # plus +--delete+ to undo a previous +create+ # # = Usage # # == Discovery # # Sprout generators should be installed by RubyGems as command line # applications on your system. After installing the flashsdk gem, you # should have access to a variety of generators. You can find out what # generators are available by typing: sprout- followed by pressing the # <TAB> key. # # Your terminal should list out all available applications that match # this name. # # Some generators are expected to create new projects, others expect to # run within existing projects. You should be able to infer the kind of # generator you're looking at by the name, but if you can't just run the # generator with no arguments to see it's usage guidelines. # # Generators that expect to be run from within a project will usually # expect a file named +Gemfile+ to exist in the project root. If you're # trying to run Sprout generators in a project that wasn't created using # Sprouts, create this file and add the Rubygems that include the # generators that you want to use. # # == Execution # # Generators are created by human beings and sometimes they have # different assumptions than you do. If you're running a generator # within a project (especially for the first time - or since updating a # gem), be sure to get your project checked into version control before # running anything. # # Non-application generators should always be executed at the project # root (where you store your Rakefile, Gemfile or build.xml). # # == Deletion # # Any generator that inherits from the provided Sprout::Generators::Base # includes support for deletion. If you run a generator and realize that # you don't want the files that it created, you can always run the same # generator again with the same arguments, but add the --delete (or -d) # argument. # # == Templates # # Each time a generator is asked to locate a template, it begins a lookup # process. This process is designed to make it easy for you to modify any # template at the scope you desire. # # The lookup process will end at the first location where the expected # file is found. # # The search will begin with the location specified by the +-templates+ # option (if provided) and will continue by adding '/templates' to the # end of each location specified by the listing for # Sprout::Generator#search_paths . # # = Creation # # The core Sprout gem comes with a Sprout::GeneratorGenerator. This command line # application is intended to be executed within a project and given the name # of a generator that you'd like to create. # # Try experimenting with this, and please # suggest[http://groups.google.com/group/projectsprouts/] any improvements to # the Google Group. # # --- # # Back to Home: {file:README.textile} # # Next Topic: {Sprout::Library} # # --- # # @see Sprout::GeneratorGenerator # @see Sprout::Library # @see Sprout::Executable # @see Sprout::Specification # @see Sprout::RubyFeature # @see Sprout::System # module Generator include RubyFeature class << self ## # Register a generator class and template path for future use. # Generator class names must end with "Generator", and everything # to the left will be used for future lookups. # # The following example will register a TestGenerator that can be # retrieved as +:test+. # # Sprout::Generator.register TestGenerator # # @param generator_class [Class] A reference to the concrete Generator class. # Usually these classes extend Sprout::Generator::Base. # @param templates_path [Directory] The path to the default templates that should # be used for this generator. By default, a folder named +templates+ relative to # the class definition will be used. Templates will also be searched for in a variety # of locations depending on the user system. This path is simply the final searching # point. # @return [Hash] the entity that was stored to represent the provided Generator. # The entity will generally have the keys, :class and :templates. def register generator_class, templates_path=nil generator_paths << { :class => generator_class, :templates => templates_path } unless templates_path.nil? super(generator_class) end ## # Create an instance of a concrete Generator using a +type+ argument. # # The idea is that libraries may register a generator class named, # +TestGenerator+, and other generators can instantiate it without # including it's Class by reference with: # # Sprout::Generator.create_instance :test # # @param type [Symbol] A snake-cased name of the class without the Generator suffix. # for example, to instantiate a generator named, +TestSuiteGenerator+, this argument # would be +:test_suite+ # @param options [Hash] deprecated - please remove this argument wherever it's found. def create_instance type, =nil class_name = "#{type.to_s.camel_case}Generator" registered_entities.each do |entity| if(entity.to_s.match(/::#{class_name}$/) || entity.to_s.match(/^#{class_name}$/)) return entity.new end end raise Sprout::Errors::MissingGeneratorError.new "Could not find any generator named: (#{class_name}). Perhaps you need to add a RubyGem to your Gemfile?" end ## # Retrieve the root template folder for the provided Class. # # This method will look for a templates folder next to # each superclass in the inheritance chain. # def template_folder_for clazz # Search the potential matches in reverse order # because subclasses have registered AFTER their # superclasses and superclasses match the === # check... generator_paths.reverse.each do || if [:class] === clazz return [:templates] end end nil end ## # Returns a new collection of paths to search within for generator # declarations and more importantly, folders named, 'templates'. # # The collection of search_paths will be a subset of the following # that will include only those directories that exist: # # ./config/generators # ./vendor/generators # ~/Library/Sprouts/1.0/generators # OS X only # ~/.sprouts/1.0/generators # Unix only # [USER_HOME]/Application Data/Sprouts/cache/1.0/generators # Windows only # ENV['SPROUT_GENERATORS'] # Only if defined # [Generator Declaration __FILE__] # [Generator SUPER-class declaration __FILE__] # [Repeat step above until there is no super-class] # # When the generators attempt to resolve templates, each of the preceding # folders will be scanned for a child directory named 'templates'. Within # that directory, the requested template name will be scanned and the first # found template file will be used. This process will be repeated for each # template file that is requested. # # The results of this search are not cached, so you can override a single # template and leave the rest wherever the generator has defined them. # # @return [Array] of paths # def search_paths # NOTE: Do not cache this list, specific generators # will modify it with their own lookups create_search_paths.select { |path| File.directory?(path) } end private def create_search_paths paths = [ File.join('config', 'generators'), File.join('vendor', 'generators'), Sprout.generator_cache ] paths << ENV['SPROUT_GENERATORS'] unless ENV['SPROUT_GENERATORS'].nil? paths end ## # I know this seems weird - but we can't instantiate the classes # during registration because they register before they've been fully # interpreted... def update_registered_entities registered_entities.collect! do |gen| (gen.is_a?(Class)) ? gen.new : gen end end def configure_instance generator generator end def generator_paths @generator_paths ||= [] end end end
end