Created
December 2, 2008 01:21
-
-
Save jm/30934 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require File.dirname(__FILE__) + '/scm/scm' | |
require File.dirname(__FILE__) + '/scm/git' | |
require File.dirname(__FILE__) + '/scm/svn' | |
require 'open-uri' | |
require 'fileutils' | |
module Rails | |
class TemplateRunner | |
attr_reader :behavior, :description, :root | |
def initialize(root, template) # :nodoc: | |
@root = Dir.pwd + "/" + root | |
puts "applying template: #{template}" | |
load_template(template) | |
puts "#{template} applied." | |
end | |
def load_template(template) | |
begin | |
code = open(template).read | |
in_root { self.instance_eval(code) } | |
rescue LoadError | |
raise "The template [#{template}] could not be loaded." | |
end | |
end | |
# Create a new file in the Rails project folder. Specify the | |
# relative path from RAILS_ROOT. Data is the return value of a block | |
# or a data string. | |
# | |
# ==== Examples | |
# | |
# file("lib/fun_party.rb") do | |
# hostname = ask("What is the virtual hostname I should use?") | |
# "vhost.name = #{hostname}" | |
# end | |
# | |
# file("config/apach.conf", "your apache config") | |
# | |
def file(filename, data = nil, &block) | |
puts "creating file #{filename}" | |
dir, file = [File.dirname(filename), File.basename(filename)] | |
inside(dir) do | |
File.open(file, "w") do |f| | |
if block_given? | |
f.write(block.call) | |
else | |
f.write(data) | |
end | |
end | |
end | |
end | |
# Install a plugin. You must provide either a Subversion url or Git url. | |
# | |
# ==== Examples | |
# | |
# plugin 'restful-authentication', :git => 'git://github.com/technoweenie/restful-authentication.git' | |
# plugin 'restful-authentication', :svn => 'svn://svnhub.com/technoweenie/restful-authentication/trunk' | |
# | |
def plugin(name, options) | |
puts "installing plugin #{name}" | |
if options[:git] || options[:svn] | |
in_root do | |
`script/plugin install #{options[:svn] || options[:git]}` | |
end | |
else | |
puts "! no git or svn provided for #{name}. skipping..." | |
end | |
end | |
# Install a gem into vendor/gems. You can install a gem in one of three ways: | |
# | |
# 1. Provide a git repository URL... | |
# | |
# gem 'will-paginate', :git => 'git://github.com/mislav/will_paginate.git' | |
# | |
# 2. Provide a subversion repository URL... | |
# | |
# gem 'will-paginate', :svn => 'svn://svnhub.com/mislav/will_paginate/trunk' | |
# | |
# 3. Provide a gem name and use your system sources to install and unpack it. | |
# | |
# gem 'ruby-openid' | |
# | |
def gem(name, options = {}) | |
puts "vendoring gem #{name}" | |
if options[:git] | |
inside("vendor/gems") { Git.clone(options[:git], options[:branch]) } | |
elsif options[:svn] | |
inside("vendor/gems") { Svn.checkout(options[:svn], options[:branch]) } | |
else | |
# TODO: Gem dependencies. Split output on \n, iterate lines looking for Downloaded... | |
inside("vendor/gems") do | |
# Filename may be different than gem name | |
filename = (`gem fetch #{name}`).chomp.gsub(/Downloaded /, '') | |
`gem unpack #{filename}.gem` | |
File.delete("#{filename}.gem") | |
end | |
end | |
end | |
# Run a command in git. | |
# | |
# ==== Examples | |
# | |
# git :init | |
# git :add => "this.file that.rb" | |
# git :add => "onefile.rb", :rm => "badfile.cxx" | |
# | |
def git(command = {}) | |
puts "running git #{command}" | |
in_root do | |
if command.is_a?(Symbol) | |
Git.run(command.to_s) | |
else | |
command.each do |command, options| | |
Git.run("#{command} #{options}") | |
end | |
end | |
end | |
end | |
# Create a new file in the vendor/ directory. Code can be specified | |
# in a block or a data string can be given. | |
# | |
# ==== Examples | |
# | |
# vendor("sekrit.rb") do | |
# sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--" | |
# "salt = '#{sekrit_salt}'" | |
# end | |
# | |
# vendor("foreign.rb", "# Foreign code is fun") | |
# | |
def vendor(filename, data = nil, &block) | |
puts "vendoring file #{filename}" | |
inside("vendor") do |folder| | |
File.open("#{folder}/#{filename}", "w") do |f| | |
if block_given? | |
f.write(block.call) | |
else | |
f.write(data) | |
end | |
end | |
end | |
end | |
# Create a new file in the lib/ directory. Code can be specified | |
# in a block or a data string can be given. | |
# | |
# ==== Examples | |
# | |
# lib("crypto.rb") do | |
# "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'" | |
# end | |
# | |
# lib("foreign.rb", "# Foreign code is fun") | |
# | |
def lib(filename, data = nil) | |
puts "add lib file #{filename}" | |
inside("lib") do |folder| | |
File.open("#{folder}/#{filename}", "w") do |f| | |
if block_given? | |
f.write(block.call) | |
else | |
f.write(data) | |
end | |
end | |
end | |
end | |
# Create a new Rake task in the lib/tasks/application.rake file. | |
# Code can be specified in a block or a data string can be given. | |
# | |
# ==== Examples | |
# | |
# task(:whatever) do | |
# name = ask("What should the task be named?") | |
# | |
# " | |
# task :#{name} do | |
# puts 'hi from rake' | |
# end | |
# " | |
# end | |
# | |
# task(:go_away, "puts 'be gone!'") | |
# | |
def task(name, description = nil, &block) | |
puts "adding task :#{name}" | |
inside("lib/tasks") do |folder| | |
File.open("#{folder}/application.rake", "a+") do |f| | |
if block_given? | |
f.write(block.call) | |
else | |
f.write(data) | |
end | |
end | |
end | |
end | |
# Create a new Rakefile with the provided code (either in a block or a string). | |
# | |
# ==== Examples | |
# | |
# rakefile("bootstrap.rake") do | |
# project = ask("What is the UNIX name of your project?") | |
# | |
# "namespace :#{project} do | |
# task :bootstrap do | |
# puts "i like boots!" | |
# end | |
# end" | |
# end | |
# | |
# rakefile("seed.rake", "puts 'im plantin ur seedz'") | |
# | |
def rakefile(filename, data = nil, &block) | |
puts "adding rakefile #{filename}" | |
inside("lib/tasks") do |folder| | |
File.open("#{folder}/#{filename}", "w") do |f| | |
if block_given? | |
f.write(block.call) | |
else | |
f.write(data) | |
end | |
end | |
end | |
end | |
# Create a new initializer with the provided code (either in a block or a string). | |
# | |
# ==== Examples | |
# | |
# initializer("globals.rb") do | |
# data = "" | |
# | |
# ['MY_WORK', 'ADMINS', 'BEST_COMPANY_EVAR'].each do | |
# data << "#{const} = :entp" | |
# end | |
# | |
# data | |
# end | |
# | |
# initializer("api.rb", "API_KEY = '123456'") | |
# | |
def initializer(filename, data = nil, &block) | |
puts "adding initializer #{filename}" | |
inside("config/initializers") do |folder| | |
File.open("#{folder}/#{filename}", "w") do |f| | |
if block_given? | |
f.write(block.call) | |
else | |
f.write(data) | |
end | |
end | |
end | |
end | |
# Generate something using a generator from Rails or a plugin. | |
# The second parameter is the argument string that is passed to | |
# the generator or an Array that is joined. | |
# | |
# ==== Example | |
# | |
# generate(:authenticated, "user session") | |
# | |
def generate(what, args = nil) | |
puts "generating #{what}" | |
args = args.join(" ") if args.class == Array | |
in_root { `#{root}/script/generate #{what} #{args}` } | |
end | |
# Executes a command | |
# | |
# ==== Example | |
# inside('vendor') do | |
# run('ln -s ~/edge rails) | |
# end | |
def run(command) | |
puts "executing #{command} from #{Dir.pwd}" | |
`#{command}` | |
end | |
# Just run the capify command in root | |
# | |
# ==== Example | |
# | |
# capify! | |
# | |
def capify! | |
in_root { `capify .` } | |
end | |
# Add Rails to /vendor/rails | |
# | |
# ==== Example | |
# | |
# freeze! | |
# | |
def freeze!(args = {}) | |
puts "vendoring rails edge" | |
in_root { `rake rails:freeze:edge` } | |
end | |
# Get a user's input | |
# | |
# ==== Example | |
# | |
# answer = ask("Should I freeze the latest Rails?") | |
# freeze! if ask("Should I freeze the latest Rails?") == "yes" | |
# | |
def ask(string) | |
puts string | |
gets.strip | |
end | |
# Make an entry in Rails routing file conifg/routes.rb | |
# | |
# === Example | |
# | |
# route "map.root :controller => :welcome" | |
# | |
def route(routing_code) | |
sentinel = 'ActionController::Routing::Routes.draw do |map|' | |
in_root do | |
gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match| | |
"#{match}\n #{routing_code}\n" | |
end | |
end | |
end | |
protected | |
# Do something in the root of the Rails application or | |
# a provided subfolder; the full path is yielded to the block you provide. | |
# The path is set back to the previous path when the method exits. | |
def inside(dir = '', &block) | |
folder = File.join(root, dir) | |
FileUtils.mkdir_p(folder) unless File.exist?(folder) | |
FileUtils.cd(folder) { block.arity == 1 ? yield(folder) : yield } | |
end | |
def in_root | |
FileUtils.cd(root) { yield } | |
end | |
# Helper to test if the user says yes(y)? | |
# | |
# ==== Example | |
# | |
# freeze! if yes?("Should I freeze the latest Rails?") | |
# | |
def yes?(question) | |
answer = ask(question).downcase | |
answer == "y" || answer == "yes" | |
end | |
# Helper to test if the user does NOT say yes(y)? | |
# | |
# ==== Example | |
# | |
# capify! if no?("Will you be using vlad to deploy your application?") | |
# | |
def no?(question) | |
!yes?(question) | |
end | |
def gsub_file(relative_destination, regexp, *args, &block) | |
path = destination_path(relative_destination) | |
content = File.read(path).gsub(regexp, *args, &block) | |
File.open(path, 'wb') { |file| file.write(content) } | |
end | |
def destination_path(relative_destination) | |
File.join(root, relative_destination) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment