docjs 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CONCEPT.md +80 -0
- data/DOCUMENTATION.md +41 -0
- data/LICENSE.md +19 -0
- data/README.md +19 -0
- data/RENDERING.md +8 -0
- data/bin/docjs +190 -0
- data/docjs.gemspec +32 -0
- data/lib/boot.rb +34 -0
- data/lib/code_object/base.rb +48 -0
- data/lib/code_object/converter.rb +48 -0
- data/lib/code_object/exceptions.rb +5 -0
- data/lib/code_object/function.rb +84 -0
- data/lib/code_object/object.rb +18 -0
- data/lib/code_object/type.rb +43 -0
- data/lib/configs.rb +53 -0
- data/lib/document/document.rb +25 -0
- data/lib/dom/dom.rb +188 -0
- data/lib/dom/exceptions.rb +12 -0
- data/lib/dom/no_doc.rb +26 -0
- data/lib/dom/node.rb +415 -0
- data/lib/helper/helper.rb +120 -0
- data/lib/helper/linker.rb +130 -0
- data/lib/logger.rb +49 -0
- data/lib/parser/comment.rb +69 -0
- data/lib/parser/comment_parser.rb +90 -0
- data/lib/parser/exceptions.rb +6 -0
- data/lib/parser/meta_container.rb +20 -0
- data/lib/parser/parser.rb +269 -0
- data/lib/processor.rb +123 -0
- data/lib/renderer.rb +108 -0
- data/lib/tasks/render_task.rb +112 -0
- data/lib/thor.rb +27 -0
- data/lib/token/container.rb +84 -0
- data/lib/token/exceptions.rb +6 -0
- data/lib/token/handler.rb +242 -0
- data/lib/token/token.rb +46 -0
- data/templates/application.rb +14 -0
- data/templates/helpers/template.rb +66 -0
- data/templates/resources/css/.sass-cache/98c121fba905284c2c8ca6220fe3c590e5c9ec19/application.scssc +0 -0
- data/templates/resources/css/application.css +836 -0
- data/templates/resources/img/arrow_down.png +0 -0
- data/templates/resources/img/arrow_right.png +0 -0
- data/templates/resources/img/arrow_up.png +0 -0
- data/templates/resources/img/bullet_toggle_minus.png +0 -0
- data/templates/resources/img/bullet_toggle_plus.png +0 -0
- data/templates/resources/img/constructor.png +0 -0
- data/templates/resources/img/function.png +0 -0
- data/templates/resources/img/object.png +0 -0
- data/templates/resources/img/page.png +0 -0
- data/templates/resources/img/prototype.png +0 -0
- data/templates/resources/img/tag.png +0 -0
- data/templates/resources/js/application.js +318 -0
- data/templates/resources/js/jcore.js +129 -0
- data/templates/resources/js/jquery.cookie.js +92 -0
- data/templates/resources/js/jquery.js +16 -0
- data/templates/resources/js/jquery.tooltip.js +77 -0
- data/templates/resources/js/jquery.treeview.js +238 -0
- data/templates/resources/scss/_footer.scss +10 -0
- data/templates/resources/scss/_header.scss +184 -0
- data/templates/resources/scss/_helpers.scss +91 -0
- data/templates/resources/scss/_print.scss +20 -0
- data/templates/resources/scss/_resets.scss +132 -0
- data/templates/resources/scss/_tooltip.scss +26 -0
- data/templates/resources/scss/application.scss +442 -0
- data/templates/tasks/api_index_task.rb +26 -0
- data/templates/tasks/docs_task.rb +33 -0
- data/templates/tasks/json_data_task.rb +55 -0
- data/templates/tasks/typed_task.rb +54 -0
- data/templates/tokens/tokens.rb +22 -0
- data/templates/types/prototype.rb +20 -0
- data/templates/views/api_index.html.erb +21 -0
- data/templates/views/doc_page.html.erb +11 -0
- data/templates/views/function/_detail.html.erb +8 -0
- data/templates/views/function/index.html.erb +53 -0
- data/templates/views/index.html.erb +0 -0
- data/templates/views/layout/application.html.erb +73 -0
- data/templates/views/layout/json.html.erb +3 -0
- data/templates/views/object/index.html.erb +63 -0
- data/templates/views/tokens/_default.html.erb +11 -0
- data/templates/views/tokens/_default_token.html.erb +19 -0
- data/templates/views/tokens/_example.html.erb +2 -0
- data/templates/views/tokens/_examples.html.erb +1 -0
- data/test/code_object/converter.rb +78 -0
- data/test/code_object/prototype.rb +70 -0
- data/test/configs.rb +65 -0
- data/test/docs/README.CONCEPT.md +83 -0
- data/test/docs/README.md +14 -0
- data/test/dom/dom.absolute_nodes.rb +40 -0
- data/test/dom/dom.rb +72 -0
- data/test/dom/node.rb +53 -0
- data/test/integration/converter.rb +72 -0
- data/test/integration/parser_factory.rb +28 -0
- data/test/interactive.rb +7 -0
- data/test/js-files/absolute.js +11 -0
- data/test/js-files/comments_in_strings.js +31 -0
- data/test/js-files/core-doc-relative.js +77 -0
- data/test/js-files/core-doc.js +145 -0
- data/test/js-files/nested.js +34 -0
- data/test/js-files/nested_with_strings.js +35 -0
- data/test/js-files/prototype.js +33 -0
- data/test/js-files/simple.js +17 -0
- data/test/js-files/tokens.js +32 -0
- data/test/parser/comments_in_strings.rb +51 -0
- data/test/parser/intelligent_skip_until.rb +110 -0
- data/test/parser/parser.rb +273 -0
- data/test/rspec_helper.rb +23 -0
- data/test/token/handler.rb +136 -0
- data/test/token/tokens.rb +52 -0
- metadata +184 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
# ../data.img#1772248:1
|
2
|
+
module Parser
|
3
|
+
|
4
|
+
# is included by {CodeObject::Base} and {Parser::Comment}
|
5
|
+
module MetaContainer
|
6
|
+
|
7
|
+
attr_reader :filepath, :source, :line_start
|
8
|
+
|
9
|
+
def add_meta_data(filepath, source, line_start)
|
10
|
+
@filepath, @source, @line_start = filepath, source, line_start+1 # counting from 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def clone_meta(other)
|
14
|
+
@filepath, @source, @line_start = other.filepath, other.source, other.line_start
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,269 @@
|
|
1
|
+
# ../data.img#1869414:2
|
2
|
+
require 'strscan'
|
3
|
+
require_relative 'comment_parser'
|
4
|
+
|
5
|
+
#
|
6
|
+
# 
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Parser
|
10
|
+
|
11
|
+
NO_BR = /((?!\n)\s)/
|
12
|
+
ALL = /./m
|
13
|
+
|
14
|
+
# Multiline Comments
|
15
|
+
M_START = /\/\*+/
|
16
|
+
|
17
|
+
# End of multiline comment with all leading whitespaces (no breaks)
|
18
|
+
M_END = /#{NO_BR}*\*+\//
|
19
|
+
|
20
|
+
# Singleline Comments
|
21
|
+
S_START = /\/\//
|
22
|
+
S_END = /\n/
|
23
|
+
|
24
|
+
|
25
|
+
LINE_START = /(#{NO_BR})*\*+#{NO_BR}?/
|
26
|
+
LINE_END = /\n/
|
27
|
+
EMPTY_LINE = /^\s*$/
|
28
|
+
|
29
|
+
# CAUTION: \s can contain breaks "\n"
|
30
|
+
TOKENLINE_START = /\s*@/
|
31
|
+
TOKENLINE = /
|
32
|
+
#{TOKENLINE_START}
|
33
|
+
(?<name>\w+)
|
34
|
+
(?:#{NO_BR}?(?<content>#{ALL}+)|$)
|
35
|
+
/x
|
36
|
+
|
37
|
+
# String delimiter
|
38
|
+
S_STRING = /'/
|
39
|
+
D_STRING = /"/
|
40
|
+
|
41
|
+
REGEXP_START = /\/[^\/]/
|
42
|
+
REGEXP_END = /\//
|
43
|
+
|
44
|
+
NON_COMMENT_PATTERNS = {
|
45
|
+
S_STRING => S_STRING,
|
46
|
+
D_STRING => D_STRING,
|
47
|
+
REGEXP_START => REGEXP_END
|
48
|
+
}
|
49
|
+
|
50
|
+
NON_CODE_PATTERNS = {
|
51
|
+
M_START => M_END,
|
52
|
+
S_START => S_END,
|
53
|
+
S_STRING => S_STRING,
|
54
|
+
D_STRING => D_STRING,
|
55
|
+
REGEXP_START => REGEXP_END
|
56
|
+
}
|
57
|
+
|
58
|
+
class Parser
|
59
|
+
|
60
|
+
attr_reader :filepath, :offset
|
61
|
+
|
62
|
+
# A new StringScanner instance will be used to {#parse parse} the given
|
63
|
+
# `input`.
|
64
|
+
#
|
65
|
+
# @param [String] input
|
66
|
+
def initialize(input, args = {})
|
67
|
+
|
68
|
+
raise Exception, "Expected input to be a String, got #{input.class}" unless input.is_a? String
|
69
|
+
|
70
|
+
# Default Values
|
71
|
+
@filepath = args[:filepath] || "No File specified"
|
72
|
+
@offset = args[:offset] || -1 # we are adding 1 later
|
73
|
+
|
74
|
+
|
75
|
+
# clean input and convert windows linebreaks to normal ones
|
76
|
+
@to_parse = input.gsub(/\r\n/, "\n")
|
77
|
+
@scanner = StringScanner.new @to_parse
|
78
|
+
@comments = []
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Recursivly parses the {#initialize given input} and thereby ignores
|
83
|
+
# strings.
|
84
|
+
# @todo Rewrite to use skip_intelligent_until
|
85
|
+
# @return [Array<Parser::Comment>] the parsed comment-stream
|
86
|
+
def parse()
|
87
|
+
@scanner.skip /\s/
|
88
|
+
@scanner.skip_until /#{M_START}|#{S_START}|#{NON_COMMENT_PATTERNS.keys.join('|')}|$/
|
89
|
+
|
90
|
+
found = @scanner.matched
|
91
|
+
|
92
|
+
if found.match M_START
|
93
|
+
parse_comment_until(M_END)
|
94
|
+
|
95
|
+
elsif found.match S_START
|
96
|
+
parse_comment_until(S_END)
|
97
|
+
|
98
|
+
else
|
99
|
+
matched_pattern = NON_COMMENT_PATTERNS.detect do |start_pattern, end_pattern|
|
100
|
+
found.match start_pattern
|
101
|
+
end
|
102
|
+
@scanner.skip_escaping_until matched_pattern.last unless matched_pattern.nil?
|
103
|
+
end
|
104
|
+
|
105
|
+
if @scanner.eos?
|
106
|
+
return @comments
|
107
|
+
else
|
108
|
+
parse
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.parse_file(path)
|
113
|
+
stream = File.read path
|
114
|
+
Parser.new(stream, :filepath => path).parse
|
115
|
+
end
|
116
|
+
|
117
|
+
protected
|
118
|
+
|
119
|
+
def parse_comment_until(ending)
|
120
|
+
content = @scanner.scan_until_ahead ending
|
121
|
+
comment = CommentParser.new(content).parse unless content.nil?
|
122
|
+
|
123
|
+
# only proceed, if it is a tokenized comment
|
124
|
+
return parse unless comment.has_tokens?
|
125
|
+
|
126
|
+
# search scope for that comment
|
127
|
+
@scanner.skip /\n/
|
128
|
+
scope = @scanner.save_scanned { find_scope }
|
129
|
+
|
130
|
+
code_line = @to_parse.line_of(scope.min) + @offset + 1
|
131
|
+
source = @to_parse[scope]
|
132
|
+
|
133
|
+
# Add Metadata
|
134
|
+
comment.add_meta_data @filepath, source, code_line
|
135
|
+
|
136
|
+
# Save Comment
|
137
|
+
@comments << comment
|
138
|
+
|
139
|
+
comment.add_children Parser.new(source, :filepath => @filepath, :offset => code_line-1).parse
|
140
|
+
end
|
141
|
+
|
142
|
+
def find_scope(scope_stack = [], ignore_line_end = false)
|
143
|
+
|
144
|
+
if ignore_line_end
|
145
|
+
return if scope_stack.empty?
|
146
|
+
@scanner.skip /\s/
|
147
|
+
end
|
148
|
+
|
149
|
+
# adding |$ only if we don't ignore line_ends (which is most of the time)
|
150
|
+
@scanner.intelligent_skip_until /\{|\(|\}|\)#{'|$' unless ignore_line_end}/
|
151
|
+
|
152
|
+
match = @scanner.matched
|
153
|
+
|
154
|
+
case match
|
155
|
+
when '{'
|
156
|
+
find_scope(scope_stack << '}', ignore_line_end)
|
157
|
+
|
158
|
+
when '('
|
159
|
+
find_scope(scope_stack << ')', ignore_line_end)
|
160
|
+
|
161
|
+
when '}', ')'
|
162
|
+
if(scope_stack.last == match)
|
163
|
+
scope_stack.pop
|
164
|
+
find_scope(scope_stack, ignore_line_end)
|
165
|
+
else
|
166
|
+
# currently just ignore non matching closing pairs
|
167
|
+
puts "I'm ignoring #{match} at #{@scanner.pos} of #{@filepath}"
|
168
|
+
end
|
169
|
+
else
|
170
|
+
|
171
|
+
if ignore_line_end
|
172
|
+
if not @scanner.eos?
|
173
|
+
find_scope(scope_stack, ignore_line_end)
|
174
|
+
|
175
|
+
elsif not scope_stack.empty?
|
176
|
+
raise "Unmatched Scope-Stack: #{scope_stack}"
|
177
|
+
end
|
178
|
+
|
179
|
+
else
|
180
|
+
find_scope(scope_stack, true) unless scope_stack.empty?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
# We have to extend StringScanner a little bit to fit our needs.
|
190
|
+
#
|
191
|
+
# @see Parser::Parser
|
192
|
+
# @see Parser::CommentParser
|
193
|
+
class StringScanner
|
194
|
+
|
195
|
+
# returns the string until `pattern` matches, then consums `pattern`
|
196
|
+
#
|
197
|
+
# @example
|
198
|
+
# scanner = StringScanner.new("hello world")
|
199
|
+
# scanner.scan_until_ahead(/\s+/) #=> "hello"
|
200
|
+
# scanner.pos #=> 5
|
201
|
+
#
|
202
|
+
# @param [Regexp] pattern the pattern to scan until
|
203
|
+
# @return [String] the String before `pattern`
|
204
|
+
def scan_until_ahead(pattern)
|
205
|
+
content = self.scan_until /(?=(#{pattern}))/
|
206
|
+
self.skip pattern
|
207
|
+
return content
|
208
|
+
end
|
209
|
+
|
210
|
+
# will stop to scan at the specified pattern or at eos and returns the
|
211
|
+
# consumed string.
|
212
|
+
#
|
213
|
+
# @param [Regexp] pattern the pattern to scan for
|
214
|
+
# @return [String] the String before `pattern`
|
215
|
+
def scan_until_or_end(pattern)
|
216
|
+
self.scan_until(pattern) or self.scan_until(/$/)
|
217
|
+
end
|
218
|
+
|
219
|
+
# skips content within comments, strings and regularexpressions
|
220
|
+
def intelligent_skip_until(pattern)
|
221
|
+
|
222
|
+
self.skip_escaping_until(/#{pattern}|#{Parser::NON_CODE_PATTERNS.keys.join('|')}/)
|
223
|
+
|
224
|
+
found = self.matched
|
225
|
+
|
226
|
+
raise end_of_string_error(pattern) if self.matched.nil?
|
227
|
+
|
228
|
+
return if found.match pattern
|
229
|
+
|
230
|
+
Parser::NON_CODE_PATTERNS.each do |start_pattern, end_pattern|
|
231
|
+
if found.match start_pattern
|
232
|
+
self.skip_escaping_until end_pattern
|
233
|
+
return self.intelligent_skip_until pattern
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def save_scanned
|
239
|
+
pos_start = self.pos #- 1 # fixes missing first char
|
240
|
+
yield
|
241
|
+
pos_end = self.pos
|
242
|
+
Range.new(pos_start, pos_end)
|
243
|
+
end
|
244
|
+
|
245
|
+
def skip_escaping_until(pattern)
|
246
|
+
|
247
|
+
self.skip_until(/\\|#{pattern}/)
|
248
|
+
|
249
|
+
raise end_of_string_error(pattern) if self.matched.nil?
|
250
|
+
|
251
|
+
if self.matched.match /\\/
|
252
|
+
self.getch
|
253
|
+
skip_escaping_until(pattern)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
protected
|
258
|
+
|
259
|
+
def end_of_string_error(pattern)
|
260
|
+
Error.new "Unexpected end of String, expected: #{pattern.inspect} in \"#{self.string}\" at pos:#{self.pos}"
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
class String
|
266
|
+
def line_of(pos)
|
267
|
+
self[0..pos].count "\n"
|
268
|
+
end
|
269
|
+
end
|
data/lib/processor.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'rdiscount'
|
2
|
+
require_relative 'dom/dom'
|
3
|
+
require_relative 'tasks/render_task'
|
4
|
+
require_relative 'document/document'
|
5
|
+
|
6
|
+
module Processor
|
7
|
+
|
8
|
+
RenderTask = Struct.new :name, :description, :block
|
9
|
+
@@render_tasks = {}
|
10
|
+
|
11
|
+
# Accessor Method for RenderTasks
|
12
|
+
def self.render_tasks
|
13
|
+
@@render_tasks
|
14
|
+
end
|
15
|
+
|
16
|
+
# @group Combined Stages
|
17
|
+
|
18
|
+
def self.process_and_render
|
19
|
+
process_files_to_dom
|
20
|
+
perform_all_tasks
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.process_files_to_dom(files = nil)
|
24
|
+
process_comments parse_files(files)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @group Stage #1 - FileProcessor
|
28
|
+
|
29
|
+
# Parsing Files and creating comment stream
|
30
|
+
def self.parse_files(files = nil)
|
31
|
+
files ||= Configs.files
|
32
|
+
|
33
|
+
return if files.nil?
|
34
|
+
|
35
|
+
files = [files] unless files.is_a? Array
|
36
|
+
comments = []
|
37
|
+
|
38
|
+
files.each do |file|
|
39
|
+
Logger.info "Processing file #{file}"
|
40
|
+
comments += Parser::Parser.parse_file(file)
|
41
|
+
end
|
42
|
+
|
43
|
+
return comments
|
44
|
+
end
|
45
|
+
|
46
|
+
# @group Stage #2 - CommentProcessor
|
47
|
+
|
48
|
+
# Processing comment-stream and convert to {CodeObject CodeObjects}
|
49
|
+
# This stage also adds the CodeObjects to Dom.
|
50
|
+
def self.process_comments(comments)
|
51
|
+
|
52
|
+
comments = [comments] unless comments.is_a? Array
|
53
|
+
|
54
|
+
comments.each do |comment|
|
55
|
+
code_object = comment.to_code_object # convert to code_object
|
56
|
+
Logger.debug "Adding to Dom: #{code_object}"
|
57
|
+
Dom.add_node(code_object.path, code_object) # add to dom
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# @group Stage #3 - TemplateProcessor
|
63
|
+
|
64
|
+
# just some notes
|
65
|
+
|
66
|
+
# command line:
|
67
|
+
# $~ jsdoc render_tasks
|
68
|
+
# Registered Rendertasks:
|
69
|
+
# - typed: renders objects type-dependant
|
70
|
+
# - overview: renders an overview
|
71
|
+
# - files: converts specified markdown files and renders them
|
72
|
+
#
|
73
|
+
def self.perform_all_tasks
|
74
|
+
perform_tasks @@render_tasks.keys
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.perform_tasks(tasks)
|
78
|
+
|
79
|
+
tasks = [tasks] unless tasks.is_a? Array
|
80
|
+
|
81
|
+
tasks.each do |task|
|
82
|
+
task = task.to_sym
|
83
|
+
raise Exception, "No render-task registered with name '#{task}'" unless @@render_tasks.has_key? task
|
84
|
+
|
85
|
+
Logger.debug "Rendering task '#{task}'"
|
86
|
+
@@render_tasks[task].new.perform
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# @group Stage #4 - Document Processor
|
91
|
+
|
92
|
+
def self.prepare_documents
|
93
|
+
# underscores will be replaced with whitespaces as title
|
94
|
+
Configs.docs.each do |doc|
|
95
|
+
|
96
|
+
doc_path = File.expand_path(doc, Configs.wdir)
|
97
|
+
Logger.debug "Working with Document #{doc_path}"
|
98
|
+
|
99
|
+
contents = File.read(doc_path)
|
100
|
+
|
101
|
+
# Those documents get registered in a special {Dom::Node} Dom.docs
|
102
|
+
document = Document::Document.new(doc_path, contents)
|
103
|
+
Dom.docs.add_node(document.path, document)
|
104
|
+
|
105
|
+
# The docs can be accessed via Dom later on
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
# @group RenderTask-Setup
|
112
|
+
|
113
|
+
def self.register_render_task(name, klass)
|
114
|
+
@@render_tasks[name.to_sym] = klass
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.unregister_render_task(name)
|
118
|
+
@@render_tasks.delete(name.to_sym)
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
end
|
data/lib/renderer.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# ../data.img#1783836:1
|
2
|
+
require 'erb'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class Renderer
|
6
|
+
|
7
|
+
def initialize(default_path, layout)
|
8
|
+
@_path = default_path
|
9
|
+
@_layout = layout
|
10
|
+
end
|
11
|
+
|
12
|
+
# Teilweise aus rails...
|
13
|
+
# @todo better error-handling with partial and layout context information!!!
|
14
|
+
def render(opt = nil, extra_options = {})
|
15
|
+
|
16
|
+
if opt.nil?
|
17
|
+
opt = { :layout => @_layout }
|
18
|
+
|
19
|
+
elsif opt.is_a?(String) || opt.is_a?(Symbol)
|
20
|
+
extra_options[:template] = opt
|
21
|
+
extra_options[:layout] ||= @_layout
|
22
|
+
opt = extra_options
|
23
|
+
|
24
|
+
elsif !opt.is_a?(Hash)
|
25
|
+
extra_options[:partial] = opt
|
26
|
+
opt = extra_options
|
27
|
+
end
|
28
|
+
|
29
|
+
if opt[:partial]
|
30
|
+
|
31
|
+
# add underscore to last element of foo/bar/baz
|
32
|
+
parts = opt[:partial].split('/')
|
33
|
+
parts[-1] = "_"+parts.last
|
34
|
+
|
35
|
+
begin
|
36
|
+
template_file = File.read path_to_template(parts.join('/'))
|
37
|
+
rescue Exception
|
38
|
+
raise "Could not find Partial '#{opt[:partial]}'"
|
39
|
+
end
|
40
|
+
if opt[:collection]
|
41
|
+
|
42
|
+
partial_name = opt[:partial].split('/').last
|
43
|
+
|
44
|
+
opt[:collection].map { |item|
|
45
|
+
define_singleton_method(partial_name) { item }
|
46
|
+
ERB.new(template_file).result(binding)
|
47
|
+
}.join "\n"
|
48
|
+
else
|
49
|
+
|
50
|
+
# If there are locals we have to save our instance binding, otherwise we will store our
|
51
|
+
# newly created local-variables in the blockcontext of each_pair
|
52
|
+
# values has to be defined explicitly to be overridden by the block and still available inside of eval
|
53
|
+
if opt[:locals]
|
54
|
+
value = nil
|
55
|
+
instance_context = binding
|
56
|
+
opt[:locals].each_pair do |local, value|
|
57
|
+
Logger.warn("Please change your partial-name or local binding, because #{local} is already set in this context.") if respond_to? local
|
58
|
+
define_singleton_method(local) { value }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
ERB.new(template_file).result(binding)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
# bind @current_path correctly to use in helpers and views
|
66
|
+
if opt[:to_file]
|
67
|
+
# Make absolute
|
68
|
+
opt[:to_file] = File.expand_path(opt[:to_file], Configs.output)
|
69
|
+
@current_path = File.dirname opt[:to_file]
|
70
|
+
else
|
71
|
+
@current_path ||= Configs.output
|
72
|
+
end
|
73
|
+
|
74
|
+
# render 'view_name', :option1 => 1, :option2 => 2
|
75
|
+
view = ERB.new(File.read path_to_template opt[:template]).result(binding)
|
76
|
+
|
77
|
+
# then render with layout
|
78
|
+
if opt[:layout]
|
79
|
+
layout = File.read path_to_template opt[:layout]
|
80
|
+
view = render_in_layout(layout) { view }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Render to file, if desired
|
84
|
+
if opt[:to_file]
|
85
|
+
# create directories recursive
|
86
|
+
FileUtils.mkpath File.dirname opt[:to_file]
|
87
|
+
|
88
|
+
File.open(opt[:to_file], "w+") do |f|
|
89
|
+
f.write view
|
90
|
+
end
|
91
|
+
else
|
92
|
+
return view
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def render_in_layout(layout, &view)
|
101
|
+
ERB.new(layout).result(binding)
|
102
|
+
end
|
103
|
+
|
104
|
+
def path_to_template(file)
|
105
|
+
File.expand_path "#{file}.html.erb", @_path
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|