require 'fileutils' module Temp # A Copier object provides various methods for creating a project from a # template. It can also be given a path to the directory where templates can # be found. class Copier attr_reader :options def initialize(options = {}) @options = options @template_dir = File.expand_path(options[:template_dir] || '~/.temp') end # Creates a new project from a template. If a path is supplied, the # project's name will be the last item in the path. Otherwise, it will have # the same name as the template and be created in the current working # directory. def create_project(project = nil, template) project = File.expand_path(project || template) template_path = File.expand_path(File.join(@template_dir, template)) raise 'project already exists' if File.exist? project raise 'template does not exist' unless File.exist? template_path ignore = read_tempignore(template) files = find_files(template, ignore) if File.file? template_path FileUtils.cp(template_path, project) else FileUtils.mkdir(project) files.each do |file| p = File.join(project, file) t = File.join(template_path, file) if File.directory? t FileUtils.mkdir(p) else FileUtils.cp(t, p) end end end end # Returns an array of all files in a template, optionally ignoring all files # in ignore. def find_files(template, ignore = []) template = File.expand_path(File.join(@template_dir, template)) Dir.glob(File.join(template, '**/*')).map do |file| file.sub(template + '/', '') end - ignore end # Returns an array of files in a template to ignore. def read_tempignore(template) template = File.expand_path(File.join(@template_dir, template)) tempignore = File.join(template, '.tempignore') files = ['.tempignore'] if File.exist? tempignore files |= File.read(tempignore).split(?\n).map do |line| Dir.glob(File.join(template, line)).map do |file| file.sub(template + '/', '') end end.flatten end files end end end