RECIPES_DIR = File.expand_path('../recipes', __FILE__) USER_RECIPES_DIR = File.expand_path('~/.kick') module Kernel # If only given a name, the specified recipe will be loaded. For # instance, the following, in a .kick file, will load the Rails # recipe: # # recipe :rails # # However, this same method is used to define a callback that is called _if_ # the recipe is loaded. For instance, the following, in a recipe file, will # be called if the recipe is actually used: # # recipe :rails do # # Load anything needed for the recipe. # process do # # ... # end # end def recipe(name, &block) Kicker::Recipes.recipe(name, &block) end end class Kicker module Recipes #:nodoc: class << self def reset! @recipes = nil end def recipes @recipes ||= {} end def recipe_filename(name) [ USER_RECIPES_DIR, RECIPES_DIR ].each do |directory| filename = File.join(directory, "#{name}.rb") return filename if File.exist?(filename) end end def recipe_names recipe_files.map { |filename| File.basename(filename, '.rb').to_sym } end def recipe_files Dir.glob(File.join(RECIPES_DIR, '*.rb')) + Dir.glob(File.join(USER_RECIPES_DIR, '*.rb')) end def define_recipe(name, &block) recipes[name] = block end def load_recipe(name) if recipe_names.include?(name) load recipe_filename(name) else raise LoadError, "Can't load recipe `#{name}', it doesn't exist on disk. Loadable recipes are: #{recipe_names[0..-2].join(', ')}, and #{recipe_names[-1]}" end end def activate_recipe(name) unless recipes.has_key?(name) load_recipe(name) end if recipe = recipes[name] recipe.call else raise ArgumentError, "Can't activate the recipe `#{name}' because it hasn't been defined yet." end end # See Kernel#recipe for more information about the usage. def recipe(name, &block) name = name.to_sym if block_given? define_recipe(name, &block) else activate_recipe(name) end end end # Always load all the base recipes load_recipe :execute_cli_command load_recipe :could_not_handle_file load_recipe :dot_kick end end