-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinline-partials.rake
103 lines (89 loc) · 3.69 KB
/
inline-partials.rake
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
##########################################################################
# Copyright 2016 ThoughtWorks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##########################################################################
RAILS_INTERPOLATED_VIEWS = (ENV['INPUT_DIR'] or raise 'INPUT_DIR not defined')
def inline_partials(dir = RAILS_INTERPOLATED_VIEWS)
Dir[File.join(dir, '*')].each do |path|
File.directory?(path) ? inline_partials(path) : inline_partial(path)
end
end
def erb_ruby(call)
call.scan(/\A<%=\s*(.+?)\s*-?%>\Z/m).flatten[0]
end
def args_of_fn(fn_name, call)
ruby_code = erb_ruby(call)
call_matcher_with_paren = /\A\s*#{fn_name}\s*\(/m
arg_match = (ruby_code =~ call_matcher_with_paren) ? ruby_code.scan(/#{call_matcher_with_paren}(.*?);?\s*\);?\s*\Z/m) : ruby_code.scan(/\A\s*#{fn_name}\s*(.*?)\s*;?\s*\Z/m)
arg_match.flatten[0]
end
def render_args(call)
args_of_fn('render', call)
end
def locals_hash(file, call)
render_arguments = render_args(call)
scope_map = render_arguments.scan(/:locals\s*=>\s*\{\s*:scope\s*=>\s*(.*?)\s*\}[\s)]*\Z/m)
locals_hash_value = scope_map.flatten[0]
parser_says_there_are_no_locals = locals_hash_value.nil?
probably_has_locals = render_arguments =~ /locals.*scope/
scope_is_not_empty = render_arguments !~ /:locals\s*=>\s*:scope\s*=>\s*\{\s*\}/
if parser_says_there_are_no_locals && probably_has_locals && scope_is_not_empty
raise "ERROR: Inlining partials of #{file}. Parser says there are no locals here: #{call}"
end
locals_hash_value
end
def inline_partial_render_calls(file, depth)
inline_render_calls(File.read(file), file, /<%=\s*render[\s(]*:partial.*?%>/m, depth)
end
def inline_render_calls(buffer, file, scanned_by, depth)
render_partial_calls = buffer.scan(scanned_by)
render_partial_calls.each do |call|
ruby_code = erb_ruby(call)
local_hash = locals_hash(file, call)
partial_path = ruby_code.scan(/:partial\s*=>\s*("|')(.+?)\1/m).flatten[1] #make me locals style
partial_path = (partial_path =~ /\//m ? File.join(RAILS_INTERPOLATED_VIEWS, File.dirname(partial_path), '_' + File.basename(partial_path)) : File.join(File.dirname(file), '_' + File.basename(partial_path)))
actual_partial_path = actual_partial_path(partial_path)
content = inline_partial(actual_partial_path, depth + 1)
if local_hash
prefix = '_'*depth
content = "<% #{prefix}scope = #{local_hash}; -%>" + fix_scope_calls(content, prefix)
end
buffer.sub!(call, block_given? ? yield(content) : content)
end
buffer
end
def actual_partial_path(partial_path)
glob = Dir.glob(partial_path)
if glob.empty?
glob = Dir.glob(partial_path + '.*')
raise "cannot find partial: #{partial_path}" if glob.empty?
end
glob[0]
end
def inline_partial(file, depth = 0)
return unless File.extname(file) == '.erb'
buffer = inline_partial_render_calls(file, depth)
unless File.basename(file) =~ /^_/
File.open(file, 'w') do |fd|
fd.write(buffer)
end
end
buffer
end
def fix_scope_calls(content, prefix)
content.gsub(/([^_])scope\[:/, "\\1#{prefix}scope[:")
end
task 'default' do
inline_partials
end