Skip to content

Instantly share code, notes, and snippets.

@edwardloveall
Forked from ttscoff/planter.rb
Last active December 17, 2015 05:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edwardloveall/5561850 to your computer and use it in GitHub Desktop.
Save edwardloveall/5561850 to your computer and use it in GitHub Desktop.
ruby script to create a directory structure from indented data
#!/usr/bin/ruby
=begin
Planter v1.3
Brett Terpstra 2013
ruby script to create a directory structure from indented data.
Three ways to use it:
- Pipe indented (tabs or 2 spaces) text to the script
- e.g. `cat "mytemplate" | planter.rb
- Create template.tpl files in ~/.planter and call them by their base name
- e.g. Create a text file in ~/.planter/site.tpl
- `planter.rb site`
- Call planter.rb without input and it will open your $EDITOR to create the tree on the fly
You can put %%X%% variables into templates, where X is a number that corresponds to the index
of the argument passed when planter is called. e.g. `planter.rb client "Mr. Butterfinger"`
would replace %%1%% in client.tpl with "Mr. Butterfinger". Use %%X|default%% to make a variable
optional with default replacement.
If a line in the template matches a file or folder that exists in ~/.planter, that file/folder
will be copied to the destination folder.
=end
require 'yaml'
require 'tmpdir'
require 'fileutils'
def get_hierarchy(input,parent=".",dirs_to_create=[])
input.each do |dirs|
if dirs.kind_of? Hash
dirs.each do |k,v|
dirs_to_create.push(File.expand_path("#{parent}/#{k.strip}"))
dirs_to_create = get_hierarchy(v,"#{parent}/#{k.strip}",dirs_to_create)
end
elsif dirs.kind_of? Array
dirs_to_create = get_hierarchy(dirs,parent,dirs_to_create)
elsif dirs.kind_of? String
dirs_to_create.push(File.expand_path("#{parent}/#{dirs.strip}"))
end
end
return dirs_to_create
end
def text_to_yaml(input, replacements = [])
variables_count = input.scan(/%%\d+%%/).length
input.gsub!(/%%(\d+)(?:\|(.*?))?%%/) do |match|
if replacements[$1.to_i - 1]
replacements[$1.to_i - 1]
elsif !$2.nil?
$2
else
print "Invalid variable"
Process.exit 1
end
end
lines = input.split(/[\n\r]/)
output = []
prev_indent = 0
lines.each_with_index do |line, i|
indent = line.gsub(/ /,"\t").match(/(\t*).*$/)[1]
if indent.length > prev_indent
lines[i-1] = lines[i-1].chomp + ":"
end
prev_indent = indent.length
lines[i] = indent.gsub(/\t/,' ') + "- " + lines[i].strip # unless indent.length == 0
end
lines.delete_if {|line|
line == ''
}
return "---\n" + lines.join("\n")
end
if STDIN.stat.size > 0
data = STDIN.read
elsif ARGV.length > 0
template = File.expand_path("~/.planter/#{ARGV[0].gsub(/\.tpl$/,'')}.tpl")
ARGV.shift
if File.exists? template
File.open(template, 'r') do |infile|
data = infile.read
end
else
puts "Specified template not found in ~/.planter/*.tpl"
end
else
tmpfile = File.expand_path(Dir.tmpdir + "/planter.tmp")
File.new(tmpfile, 'a+')
# at_exit {FileUtils.rm(tmpfile) if File.exists?(tmpfile)}
%x{$EDITOR "#{tmpfile}"}
data = ""
File.open(tmpfile, 'r') do |infile|
data = infile.read
end
end
data.strip!
yaml = YAML.load(text_to_yaml(data,ARGV))
dirs_to_create = get_hierarchy(yaml)
dirs_to_create.each do |dir|
curr_dir = ENV['PWD']
unless File.exists? dir
$stderr.puts "Creating #{dir.sub(/^#{curr_dir}\//,'')}"
if File.exists?(File.join(File.expand_path("~/.planter"),File.basename(dir)))
FileUtils.cp_r(File.join(File.expand_path("~/.planter"),File.basename(dir)), dir)
else
Dir.mkdir(dir)
end
else
$stderr.puts "Skipping #{dir.sub(/^#{curr_dir}\//,'')} (file exists)"
end
end
@edwardloveall
Copy link
Author

The fork here removes the check for the number of arguments to be equal to the number of placeholder variables, similar to Textmate's snippet syntax. This makes it possible to use a variable twice. For example:

%%1%%
    %%1%%.txt

By just running planter template name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment