I'm building a cli to bootstrap my gem projects, setting up minitest, guard, travis, git etc...
I was planning on using Rake because I like how it handles dependencies, shell commands, and cleanup.
First I'm creating the directory structure of a "type" of project (gem, gli, methadone in this case), then rendering all the erb
files in the template
directory for project.
As shown methadone => gem
and gli => gem
but methadone !=> gli
. Which means methadone
needs all the files from gem
but may add new files/dirs and also may modify existing files/dirs.
I like how easy it is for me to express these dependencies with Rake tasks.
But I find it weird that I have to write the same code in 3 different places as shown below:
code:
require 'rake'
require 'rake/clean'
desc "Bootstrap gem"
task :gem, [:project_name] do |t, args|
Project.new(t.name, args.project_name).bootstrap
end
desc "Bootstrap methadone"
task :methadone, [:project_name] => :gem do |t, args|
Project.new(t.name, args.project_name).bootstrap
end
desc "Bootstrap gli"
task :gli, [:project_name] => :gem do |t, args|
Project.new(t.name, args.project_name).bootstrap
end
class Project
attr_reader :project_name, :template_name
def initialize template_name, project_name
@project_name = project_name
@template_name = template_name
end
def bootstrap
create_project_dirs
render
end
def create_project_dirs
puts "Copying dirs from #{template_dir} to #{project_dir}"
end
def render
puts "Rendering #{project_name} templates..."
end
def template_dir
File.expand_path(File.join(__dir__, "templates", template_name))
end
def project_dir
File.expand_path(File.join(__dir__, project_name))
end
end
CLEAN.include('templates')
template_files = %w( templates/gem/foo.erb templates/gem/bar.erb templates/methadone/foo.erb templates/gli/foo.erb )
template_files.each do |f|
file f do |t|
path = t.name
mkdir_p File.dirname path
touch path
end
end
desc "Setup tmp project"
task :setup => template_files
file structure:
$ tree .
.
├── Rakefile
├── some.rake
└── templates
├── gem
│ ├── bar.erb
│ └── foo.erb
├── gli
│ └── foo.erb
└── methadone
└── foo.erb
4 directories, 6 files
Is it possible to make a Rake task that can run in the context of the task that called it and take args?
Then I think I could have a task like:
desc "Bootstrap gem"
task :gem, [:project_name] => :bootstrap ??
desc "Bootstrap methadone"
task :methadone, [:project_name] => [:gem, :bootstrap]
desc "Bootstrap gli"
task :gli, [:project_name] =>[:gem, :bootstrap]
task :bootstrap ??
Project.new(t.name, args.project_name).bootstrap
end
output:
$ rake methadone['some_gem']
Copying dirs from /Users/max/Dropbox/work/tmp/devify_dependency/templates/gem to /Users/max/Dropbox/work/tmp/devify_dependency/some_gem
Rendering some_gem templates...
Copying dirs from /Users/max/Dropbox/work/tmp/devify_dependency/templates/methadone to /Users/max/Dropbox/work/tmp/devify_dependency/some_gem
Rendering some_gem templates...
But as it stands I don't know how to tell :bootstrap
about the tasks that called it or how to pass it the args from the task that called it.
If I properly understood what you want to achieve, there is a very simple refactoring:
BOOTSTRAP = lambda do |t, args|
Project.new(t.name, args.project_name).bootstrap
end
desc "Bootstrap gem"
task :gem, [:project_name], &BOOTSTRAP
desc "Bootstrap methadone"
task :methadone, [:project_name], &BOOTSTRAP
desc "Bootstrap gli"
task :gli, [:project_name] => :gem, &BOOTSTRAP