templater 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +199 -0
- data/Rakefile +69 -0
- data/TODO +5 -0
- data/lib/templater.rb +44 -0
- data/lib/templater/capture_helpers.rb +62 -0
- data/lib/templater/cli/generator.rb +162 -0
- data/lib/templater/cli/manifold.rb +57 -0
- data/lib/templater/cli/parser.rb +88 -0
- data/lib/templater/core_ext/string.rb +8 -0
- data/lib/templater/file.rb +58 -0
- data/lib/templater/generator.rb +560 -0
- data/lib/templater/manifold.rb +72 -0
- data/lib/templater/proxy.rb +66 -0
- data/lib/templater/template.rb +67 -0
- data/spec/core_ext/string_spec.rb +39 -0
- data/spec/file_spec.rb +74 -0
- data/spec/generator_spec.rb +1011 -0
- data/spec/manifold_spec.rb +77 -0
- data/spec/results/erb.rbs +1 -0
- data/spec/results/file.rbs +1 -0
- data/spec/results/random.rbs +1 -0
- data/spec/results/simple_erb.rbs +1 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/template_spec.rb +124 -0
- data/spec/templater_spec.rb +7 -0
- data/spec/templates/erb.rbt +1 -0
- data/spec/templates/glob/README +1 -0
- data/spec/templates/glob/arg.js +3 -0
- data/spec/templates/glob/subfolder/jessica_alba.jpg +1 -0
- data/spec/templates/glob/subfolder/monkey.rb +1 -0
- data/spec/templates/glob/test.rb +1 -0
- data/spec/templates/literals_erb.rbt +1 -0
- data/spec/templates/simple.rbt +1 -0
- data/spec/templates/simple_erb.rbt +1 -0
- metadata +123 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Jonas Nicklas
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
= Templater
|
2
|
+
|
3
|
+
Templater is a system for generating files. Templater has the ability to both copy files from A to B and also to render templates using ERB. Templater consists of four parts:
|
4
|
+
|
5
|
+
- Actions (Files and Templates)
|
6
|
+
- Generators
|
7
|
+
- Manifolds
|
8
|
+
- The command line interface
|
9
|
+
|
10
|
+
Each manifold has many generator, and each generator has many actions.
|
11
|
+
|
12
|
+
== Example
|
13
|
+
|
14
|
+
This is how to create a very simple system for generating things:
|
15
|
+
|
16
|
+
module MyGenerators
|
17
|
+
|
18
|
+
extend Templater::Manifold
|
19
|
+
|
20
|
+
class BlogGenerator < Templater::Generator
|
21
|
+
|
22
|
+
def self.source_root
|
23
|
+
File.join(File.dirname(__FILE__), 'templates')
|
24
|
+
end
|
25
|
+
|
26
|
+
template :blog, 'blog.rb'
|
27
|
+
file :me, 'me.jpg'
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
class WikiGenerator < Templater::Generator
|
32
|
+
|
33
|
+
def self.source_root
|
34
|
+
File.join(File.dirname(__FILE__), 'templates')
|
35
|
+
end
|
36
|
+
|
37
|
+
template :wiki, 'wiki.rb'
|
38
|
+
file :img, 'wiki.jpg'
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
add :blog, BlogGenerator
|
43
|
+
add :wiki, WikiGenerator
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
MyGenerators.run_cli Dir.pwd, 'my_generators', '0.1', ARGV
|
48
|
+
|
49
|
+
The generator classes override the source_root method to specify where templates will be located. All subclasses of Templater::Generator that have any actions must do this. The +template+ and +file+ methods add actions to the generator. In the first case, a template that is rendered with ERB and then put in its destination location, in the other case a file that is copied.
|
50
|
+
|
51
|
+
The generators are added to the manifold, and assigned the names 'wiki' and 'blog'.
|
52
|
+
|
53
|
+
Neither manifolds or generators actually do anything by themselves, they are just abstract represenations. The last line invokes the command-line-interface, which fetches the desired generator, tells it to render its templates and checks with the user if there are any problems. The generators can easily be used without the command-line-interface, so it is easy to construct an alternative interface.
|
54
|
+
|
55
|
+
== Invoking other generators
|
56
|
+
|
57
|
+
Generators can invoke other generators, a WikiBlog generator that creates both a Wiki and a Blog could look like this:
|
58
|
+
|
59
|
+
module MyGenerators
|
60
|
+
|
61
|
+
extend Templater::Manifold
|
62
|
+
|
63
|
+
class WikiBlogGenerator < Templater::Generator
|
64
|
+
|
65
|
+
invoke :wiki
|
66
|
+
invoke :blog
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
add :wiki_blog, WikiBlogGenerator
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
It needs to source_root, since it has no actions. Not here that the generators are invoked by their name in the manifold, *not* by their class name. This gives the system a great deal of flexibility.
|
75
|
+
|
76
|
+
== Automatically adding actions
|
77
|
+
|
78
|
+
It can get tedious to declare each action, instead you can search in a given directory and automatically add all files to your generator, this is done with the glob! function.
|
79
|
+
|
80
|
+
class MyGenerator < Templater::Generator
|
81
|
+
|
82
|
+
def self.source_root
|
83
|
+
File.join(File.dirname(__FILE__), 'templates')
|
84
|
+
end
|
85
|
+
|
86
|
+
glob!
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
This will search the source root and add all files as actions.
|
91
|
+
|
92
|
+
== Templates
|
93
|
+
|
94
|
+
There are a lot of ways of adding templates:
|
95
|
+
|
96
|
+
template :one_argument, 'source_and_destination.rb'
|
97
|
+
|
98
|
+
template :two_arguments, 'source.rb', 'destination.rb'
|
99
|
+
|
100
|
+
template :block do
|
101
|
+
source('source.rb')
|
102
|
+
destination(some_instance_method)
|
103
|
+
end
|
104
|
+
|
105
|
+
template :expression, 'source.rb' '%some_instance_method%.rb'
|
106
|
+
|
107
|
+
In the last example, the characters enclosed in percentage signs will be replaced with the results of the instance method +some_instance_method+
|
108
|
+
|
109
|
+
Inside the templates normal ERB can be used. The templates are rendered in the same context as the generator instance, so generator instance methods can be called from inside the template.
|
110
|
+
|
111
|
+
<% if name %>
|
112
|
+
puts "My name is <%= name %>"
|
113
|
+
<% else %>
|
114
|
+
puts "I have no name"
|
115
|
+
<% end %>
|
116
|
+
|
117
|
+
IF you need to render templates where the result should contain actual erb, simply use a double percentage sign, this will prevent the statement from being executed.
|
118
|
+
|
119
|
+
<%= 2 + 2 %>
|
120
|
+
<%%= 2 + 2 %>
|
121
|
+
|
122
|
+
will result in
|
123
|
+
|
124
|
+
4
|
125
|
+
<%= 2 + 2 %>
|
126
|
+
|
127
|
+
== An advanced example
|
128
|
+
|
129
|
+
A generator for creating a model class, such as it used by Merb or Rails, could look like this:
|
130
|
+
|
131
|
+
module Merb::Generators
|
132
|
+
|
133
|
+
class ModelGenerator < ComponentGenerator
|
134
|
+
|
135
|
+
def self.source_root
|
136
|
+
File.join(super, 'model')
|
137
|
+
end
|
138
|
+
|
139
|
+
desc <<-DESC
|
140
|
+
This is a model generator
|
141
|
+
DESC
|
142
|
+
|
143
|
+
option :testing_framework, :desc => 'Specify which testing framework to use (spec, test_unit)'
|
144
|
+
option :orm, :desc => 'Specify which Object-Relation Mapper to use (none, activerecord, datamapper, sequel)'
|
145
|
+
|
146
|
+
first_argument :name, :required => true
|
147
|
+
second_argument :attributes, :as => :hash, :default => {}
|
148
|
+
|
149
|
+
invoke :migration do |generator|
|
150
|
+
generator.new(destination_root, options.merge(:model => true), name, attributes)
|
151
|
+
end
|
152
|
+
|
153
|
+
template :model, :orm => :none do
|
154
|
+
source('model.rbt')
|
155
|
+
destination('app/models/' + file_name + '.rb')
|
156
|
+
end
|
157
|
+
|
158
|
+
template :model_activerecord, :orm => :activerecord do
|
159
|
+
source('model_activerecord.rbt')
|
160
|
+
destination('app/models/' + file_name + '.rb')
|
161
|
+
end
|
162
|
+
|
163
|
+
template :model_datamapper, :orm => :datamapper do
|
164
|
+
source('model_datamapper.rbt')
|
165
|
+
destination('app/models/' + file_name + '.rb')
|
166
|
+
end
|
167
|
+
|
168
|
+
template :model_sequel, :orm => :sequel do
|
169
|
+
source('model_sequel.rbt')
|
170
|
+
destination('app/models/' + file_name + '.rb')
|
171
|
+
end
|
172
|
+
|
173
|
+
template :spec, :testing_framework => :rspec do
|
174
|
+
source('spec.rbt')
|
175
|
+
destination('spec/models/' + file_name + '_spec.rb')
|
176
|
+
end
|
177
|
+
|
178
|
+
template :test_unit, :testing_framework => :test_unit do
|
179
|
+
source('test_unit.rbt')
|
180
|
+
destination('test/models/' + file_name + '_test.rb')
|
181
|
+
end
|
182
|
+
|
183
|
+
def class_name
|
184
|
+
self.name.camel_case
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_class_name
|
188
|
+
self.class_name + "Test"
|
189
|
+
end
|
190
|
+
|
191
|
+
def file_name
|
192
|
+
self.name.snake_case
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
add :model, ModelGenerator
|
198
|
+
|
199
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rubygems/specification'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
PLUGIN = "templater"
|
8
|
+
NAME = "templater"
|
9
|
+
GEM_VERSION = "0.1"
|
10
|
+
AUTHOR = "Jonas Nicklas"
|
11
|
+
EMAIL = "jonas.nicklas@gmail.com"
|
12
|
+
HOMEPAGE = "http://templater.rubyforge.org/"
|
13
|
+
SUMMARY = "File generation system"
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = NAME
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
21
|
+
s.summary = SUMMARY
|
22
|
+
s.description = s.summary
|
23
|
+
s.author = AUTHOR
|
24
|
+
s.email = EMAIL
|
25
|
+
s.homepage = HOMEPAGE
|
26
|
+
s.require_path = 'lib'
|
27
|
+
s.autorequire = PLUGIN
|
28
|
+
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
|
29
|
+
|
30
|
+
s.add_dependency "highline", ">= 1.4.0"
|
31
|
+
s.add_dependency "diff-lcs", ">= 1.1.2"
|
32
|
+
# Templater uses facets only for a single instance_exec. This dependency might be a bit stupid.
|
33
|
+
s.add_dependency "facets"
|
34
|
+
end
|
35
|
+
|
36
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
37
|
+
pkg.gem_spec = spec
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "install the plugin locally"
|
41
|
+
task :install => [:package] do
|
42
|
+
sh %{sudo gem install pkg/#{NAME}-#{VERSION} --no-update-sources}
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "create a gemspec file"
|
46
|
+
task :make_spec do
|
47
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
48
|
+
file.puts spec.to_ruby
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
namespace :jruby do
|
53
|
+
|
54
|
+
desc "Run :package and install the resulting .gem with jruby"
|
55
|
+
task :install => :package do
|
56
|
+
sh %{#{SUDO} jruby -S gem install pkg/#{NAME}-#{Merb::VERSION}.gem --no-rdoc --no-ri}
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Generate documentation for Templater.'
|
62
|
+
Rake::RDocTask.new(:doc) do |rdoc|
|
63
|
+
rdoc.rdoc_dir = 'doc'
|
64
|
+
rdoc.title = 'Templater'
|
65
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
66
|
+
rdoc.rdoc_files.include('README')
|
67
|
+
rdoc.rdoc_files.include('LICENSE')
|
68
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
69
|
+
end
|
data/TODO
ADDED
data/lib/templater.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
path = File.dirname(__FILE__) + '/templater/'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'highline'
|
5
|
+
require "highline/import"
|
6
|
+
require 'diff/lcs'
|
7
|
+
require 'facets'
|
8
|
+
|
9
|
+
|
10
|
+
require path + 'capture_helpers'
|
11
|
+
require path + 'template'
|
12
|
+
require path + 'file'
|
13
|
+
require path + 'generator'
|
14
|
+
require path + 'proxy'
|
15
|
+
require path + 'manifold'
|
16
|
+
require path + 'cli/parser'
|
17
|
+
require path + 'cli/manifold'
|
18
|
+
require path + 'cli/generator'
|
19
|
+
require path + 'core_ext/string'
|
20
|
+
|
21
|
+
require 'erb'
|
22
|
+
|
23
|
+
module Templater
|
24
|
+
|
25
|
+
class TemplaterError < StandardError #:nodoc:
|
26
|
+
end
|
27
|
+
class GeneratorError < TemplaterError #:nodoc:
|
28
|
+
end
|
29
|
+
class SourceNotSpecifiedError < TemplaterError #:nodoc:
|
30
|
+
end
|
31
|
+
class ArgumentError < GeneratorError #:nodoc:
|
32
|
+
end
|
33
|
+
class TooManyArgumentsError < ArgumentError #:nodoc:
|
34
|
+
end
|
35
|
+
class TooFewArgumentsError < ArgumentError #:nodoc:
|
36
|
+
end
|
37
|
+
class JustTheRightAmountOfArgumentsError < ArgumentError #:nodoc:
|
38
|
+
end
|
39
|
+
class MalformattedArgumentError < ArgumentError #:nodoc:
|
40
|
+
end
|
41
|
+
|
42
|
+
VERSION = '0.1'
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Templater
|
2
|
+
|
3
|
+
# Stolen from merb-core. Merb-core is licensed under the MIT license as follows:
|
4
|
+
|
5
|
+
# Copyright (c) 2008 Ezra Zygmuntowicz
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
# a copy of this software and associated documentation files (the
|
9
|
+
# "Software"), to deal in the Software without restriction, including
|
10
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
# the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
|
26
|
+
# TODO: this should be specced in some way.
|
27
|
+
module CaptureHelpers #:nodoc:
|
28
|
+
|
29
|
+
def _erb_buffer( the_binding )
|
30
|
+
@_buffer = eval( "_erbout", the_binding, __FILE__, __LINE__)
|
31
|
+
end
|
32
|
+
|
33
|
+
def capture(*args, &block)
|
34
|
+
# get the buffer from the block's binding
|
35
|
+
buffer = _erb_buffer( block.binding ) rescue nil
|
36
|
+
|
37
|
+
# If there is no buffer, just call the block and get the contents
|
38
|
+
if buffer.nil?
|
39
|
+
block.call(*args)
|
40
|
+
# If there is a buffer, execute the block, then extract its contents
|
41
|
+
else
|
42
|
+
pos = buffer.length
|
43
|
+
block.call(*args)
|
44
|
+
|
45
|
+
# extract the block
|
46
|
+
data = buffer[pos..-1]
|
47
|
+
|
48
|
+
# replace it in the original with empty string
|
49
|
+
buffer[pos..-1] = ''
|
50
|
+
|
51
|
+
data
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# DOC
|
56
|
+
def concat(string, binding)
|
57
|
+
_erb_buffer(binding) << string
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
module Templater
|
2
|
+
|
3
|
+
module CLI
|
4
|
+
|
5
|
+
class Generator
|
6
|
+
|
7
|
+
def initialize(generator_name, destination_root, manifold, name, version)
|
8
|
+
@destination_root, @manifold, @name, @version = destination_root, manifold, name, version
|
9
|
+
@generator_name = generator_name
|
10
|
+
@generator_class = @manifold.generator(@generator_name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def version
|
14
|
+
puts @version
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
# outputs a helpful message and quits
|
19
|
+
def help
|
20
|
+
puts "Usage: #{@name} #{@generator_name} [options] [args]"
|
21
|
+
puts ''
|
22
|
+
puts @generator_class.desc
|
23
|
+
puts ''
|
24
|
+
puts @options[:opts]
|
25
|
+
puts ''
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
def run(arguments)
|
30
|
+
generator_class = @generator_class # FIXME: closure wizardry, there has got to be a better way than this?
|
31
|
+
@options = Templater::CLI::Parser.parse(arguments) do |opts, options|
|
32
|
+
opts.separator "Options specific for this generator:"
|
33
|
+
# the reason this is reversed is so that the 'main' generator will always have the last word
|
34
|
+
# on the description of the option
|
35
|
+
generator_class.generators.reverse.each do |generator|
|
36
|
+
# Loop through this generator's options and add them as valid command line options
|
37
|
+
# so that they show up in help messages and such
|
38
|
+
generator.options.each do |option|
|
39
|
+
name = option[:name].to_s.gsub('_', '-')
|
40
|
+
if option[:options][:as] == :boolean
|
41
|
+
opts.on("--#{name}", option[:options][:desc]) do |s|
|
42
|
+
options[option[:name]] = s
|
43
|
+
end
|
44
|
+
else
|
45
|
+
opts.on("--#{name} OPTION", option[:options][:desc]) do |s|
|
46
|
+
options[option[:name]] = s.to_sym
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
self.help if @options[:help]
|
54
|
+
self.help if arguments.first == 'help'
|
55
|
+
self.version if @options[:version]
|
56
|
+
|
57
|
+
# Try to instantiate a generator, if the arguments to it were incorrect: show a help message
|
58
|
+
begin
|
59
|
+
@generator = @generator_class.new(@destination_root, @options, *arguments)
|
60
|
+
rescue Templater::ArgumentError
|
61
|
+
self.help
|
62
|
+
end
|
63
|
+
|
64
|
+
if @options[:pretend]
|
65
|
+
puts "Generating with #{@generator_name} generator (just pretending):"
|
66
|
+
else
|
67
|
+
puts "Generating with #{@generator_name} generator:"
|
68
|
+
end
|
69
|
+
step_through_templates
|
70
|
+
end
|
71
|
+
|
72
|
+
def step_through_templates
|
73
|
+
@generator.actions.each do |action|
|
74
|
+
if action.identical?
|
75
|
+
say_status('identical', action, :blue)
|
76
|
+
elsif action.exists?
|
77
|
+
if @options[:force]
|
78
|
+
say_status('forced', action, :yellow)
|
79
|
+
action.invoke! unless @options[:pretend]
|
80
|
+
elsif @options[:skip]
|
81
|
+
say_status('skipped', action, :yellow)
|
82
|
+
else
|
83
|
+
say_status('conflict', action, :red)
|
84
|
+
conflict_menu(action)
|
85
|
+
end
|
86
|
+
else
|
87
|
+
say_status('added', action, :green)
|
88
|
+
action.invoke! unless @options[:pretend]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def conflict_menu(template)
|
96
|
+
choose do |menu|
|
97
|
+
menu.prompt = "How do you wish to proceed with this file?"
|
98
|
+
|
99
|
+
menu.choice(:skip) do
|
100
|
+
say("Skipped file")
|
101
|
+
end
|
102
|
+
menu.choice(:overwrite) do
|
103
|
+
say("Overwritten")
|
104
|
+
template.invoke! unless @options[:pretend]
|
105
|
+
end
|
106
|
+
menu.choice(:render) do
|
107
|
+
puts "Rendering " + template.relative_destination
|
108
|
+
puts ""
|
109
|
+
# outputs each line of the file with the row number prepended
|
110
|
+
template.render.to_a.each_with_index do |line, i|
|
111
|
+
puts((i+1).to_s.rjust(4) + ': ' + line)
|
112
|
+
end
|
113
|
+
puts ""
|
114
|
+
puts ""
|
115
|
+
conflict_menu(template)
|
116
|
+
end
|
117
|
+
menu.choice(:diff) do
|
118
|
+
puts "Showing differences for " + template.relative_destination
|
119
|
+
puts ""
|
120
|
+
|
121
|
+
diffs = Diff::LCS.diff(File.read(template.destination).to_s.to_a, template.render.to_a).first
|
122
|
+
|
123
|
+
diffs.each do |diff|
|
124
|
+
output_diff_line(diff)
|
125
|
+
end
|
126
|
+
|
127
|
+
puts ""
|
128
|
+
puts ""
|
129
|
+
conflict_menu(template)
|
130
|
+
end
|
131
|
+
menu.choice(:abort) do
|
132
|
+
say("Aborted!")
|
133
|
+
exit
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def say_status(status, template, color = nil)
|
139
|
+
status_flag = "[#{status.to_s.upcase}]".rjust(12)
|
140
|
+
if color and not @options[:no_color]
|
141
|
+
say "<%= color('#{status_flag}', :#{color}) %> " + template.relative_destination
|
142
|
+
else
|
143
|
+
say "#{status_flag} " + template.relative_destination
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def output_diff_line(diff)
|
148
|
+
case diff.action
|
149
|
+
when '-'
|
150
|
+
say "<%= color('- #{diff.element.chomp}', :red) %>"
|
151
|
+
when '+'
|
152
|
+
say "<%= color('+ #{diff.element.chomp}', :green) %>"
|
153
|
+
else
|
154
|
+
say "#{diff.action} #{diff.element.chomp}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|