Is it possible to copy a directory of *.tt files without executing template engine. I'd like to improve my rails templates and add custom scaffold templates (views, controllers and specs), but every time I use directory
method
directory "lib/templates", force: true
I see an exception when thor tries to start template engine for those files. How to just copy my directory?
I think the simplest and safest option is to glob and copy_file
as described ^ by @engineersmnky.
But, there is a way to use directory
and not execute templates. The only thing that stands in the way is this constant:
TEMPLATE_EXTNAME = ".tt"
Normally, you shouldn't change constants, but it was asking for it by not being frozen. What's the worst that can happentm:
# test.thor
class Test < Thor
include Thor::Actions
def self.source_root = __dir__
desc "example", "task"
def example
ignore_tt do
directory "templates", "copy" # <= ok
end
# directory_with_tt "templates", "copy" # <= ok
# directory "templates", "copy" # <= fail
end
private
def ignore_tt
# NOTE: change template extension so it would skip
# `when /#{TEMPLATE_EXTNAME}$/` condition and
# fallback to default `copy_file`
Thor::TEMPLATE_EXTNAME.concat "_no_match" # => .tt_no_match
yield
ensure
# NOTE: make sure to undo our dirty work after the block
Thor::TEMPLATE_EXTNAME.chomp! "_no_match" # => .tt
end
def directory_with_tt(...)
ignore_tt do
directory(...)
end
end
end
and a little test:
$ cat templates/*.tt
class <%= name.capitalize %>
end
$ thor test:example
create copy
create copy/file.tt
$ cat copy/*.tt
class <%= name.capitalize %>
end
If the above method is too hacky, here is another one, wasn't as simple as I thought, just had to get source_root
and destination_root
right.
class Test < Thor
include Thor::Actions
def self.source_root = "#{__dir__}/templates"
argument :name
desc "example", "task"
def example
# copy directory, skip .tt
directory ".", "copy", exclude_pattern: /\.tt$/
# copy .tt
Pathname.new(self.class.source_root).glob("**/*.tt").each do |tt|
copy_file tt, File.join("copy", tt.relative_path_from(self.class.source_root))
end
# # this works too
# self.destination_root = "copy"
# Pathname.new(self.class.source_root).glob("**/*.tt").each do |tt|
# copy_file tt.relative_path_from(self.class.source_root)
# end
end
end
# %name% and .empty_directory are handled by `directory`
# file.tt is copied with `copy_file`
templates
├── %name%.rb
├── empty
│ └── .empty_directory
└── tt
└── file.tt
$ thor test:example app_name
create copy
create copy/app_name.rb
create copy/empty
create copy/tt/file.tt