-
Notifications
You must be signed in to change notification settings - Fork 1
/
templates.rb
121 lines (107 loc) · 3.79 KB
/
templates.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
require "guard"
require "guard/guard"
require 'guard/compilers'
module Guard
class Templates < Guard
DEFAULTS = {
:namespace => 'this'
}
# Initialize a Guard.
# @param [Array<Guard::Watcher>] watchers the Guard file watchers
# @param [Hash] options the custom Guard options
def initialize(watchers = [], options = {})
@watchers = watchers
@options = DEFAULTS.clone.merge(options)
@single_file_mode = @options[:output].match(/\.js$/)
super(watchers, @options)
end
# Call once when Guard starts. Please override initialize method to init stuff.
# @raise [:task_has_failed] when start has failed
def start
run_all
end
# Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard quits).
# @raise [:task_has_failed] when stop has failed
def stop
end
# Called when `reload|r|z + enter` is pressed.
# This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
# @raise [:task_has_failed] when reload has failed
def reload
end
# Called when just `enter` is pressed
# This method should be principally used for long action like running all specs/tests/...
# @raise [:task_has_failed] when run_all has failed
def run_all
run_on_change(Watcher.match_files(self, Dir.glob('**/*')))
end
# Called on file(s) modifications that the Guard watches.
# @param [Array<String>] paths the changes files or paths
# @raise [:task_has_failed] when run_on_change has failed
def run_on_change(paths)
templates = {}
paths.each do |path|
@watchers.each do |watcher|
if target = get_target(path, watcher)
contents = File.read(path)
if @single_file_mode
templates[target] = contents
else
dir = Pathname.new(target[:path]).dirname.to_s
FileUtils.mkdir_p(dir) if !File.exist?(dir)
File.open(target[:path], 'w') do |f|
f.write("#{@options[:namespace]}['#{target[:name]}'] = #{compile(contents, target)}")
end
end
end
end
end
if @single_file_mode
File.open(@options[:output], 'w') do |f|
js = templates.map{|target,content| "#{target[:name].dump}: #{compile(content, target)}" }.join(",\n")
f.write "#{@options[:namespace]}.templates = {#{js}}"
end
end
end
# Called on file(s) deletions that the Guard watches.
# @param [Array<String>] paths the deleted files or paths
# @raise [:task_has_failed] when run_on_change has failed
def run_on_deletion(paths)
matched = false
paths.each do |path|
@watchers.each do |watcher|
if target = get_target(path, watcher)
matched = true
FileUtils.rm target[:path] unless @single_file_mode
end
end
end
# this is slow, but works. would be better to do a eval + series of deletes,
# but how to re-serialize the js object?
run_all if @single_file_mode && matched
end
private
def get_target(path, watcher)
if match = path.match(watcher.pattern)
subpath = match[1]
jspath = File.join(@options[:output], "#{subpath}.js")
{:name => subpath,
:type => File.extname(path).gsub(/^\./,''),
:path => jspath}
end
end
def compile(str, target)
type = target[:type]
if Compilers.methods.include?("compile_#{type}")
Compilers.send("compile_#{type}", str)
else
begin
require "guard/templates/#{type}/compiler"
return Templates.const_get(type.capitalize)::Compiler.compile(str, target)
rescue LoadError
return str.dump
end
end
end
end
end