regenerate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,32 @@
1
+ begin
2
+ require "bundler"
3
+ Bundler.setup
4
+ rescue LoadError
5
+ $stderr.puts "You need to have Bundler installed to be able build this gem."
6
+ end
7
+
8
+ gemspec = eval(File.read("regenerate.gemspec"))
9
+
10
+ desc "Validate the gemspec"
11
+ task :gemspec do
12
+ gemspec.validate
13
+ end
14
+
15
+ desc "Build gem locally"
16
+ task :build => :gemspec do
17
+ system "gem build #{gemspec.name}.gemspec"
18
+ FileUtils.mkdir_p "pkg"
19
+ FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg"
20
+ end
21
+
22
+ desc "Install gem locally"
23
+ task :install => :build do
24
+ system "gem install pkg/#{gemspec.name}-#{gemspec.version}"
25
+ end
26
+
27
+ desc "Clean automatically generated files"
28
+ task :clean do
29
+ FileUtils.rm_rf "pkg"
30
+ end
31
+
32
+ task :default => :build
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'regenerate'
4
+
5
+ if ARGV.length == 1
6
+ Regenerate.regenerate(ARGV[0])
7
+ else
8
+ raise Exception, "regenerate expects exactly one argument: #{ARGV.inspect}"
9
+ end
@@ -0,0 +1,13 @@
1
+ # A framework for static website generation which regenerates files in place.
2
+
3
+ require 'regenerate/web-page.rb'
4
+ require 'regenerate/site-regenerator.rb'
5
+
6
+ STDOUT.sync = true
7
+ STDERR.sync = true
8
+
9
+ #puts "ARGV = #{ARGV.inspect}"
10
+
11
+ if ARGV.length >= 1
12
+ Regenerate.regeneratePath(ARGV[0])
13
+ end
@@ -0,0 +1,31 @@
1
+ module Regenerate
2
+
3
+ module Utils
4
+
5
+ def makeBackupFile(outFile)
6
+ backupFileName = outFile+"~"
7
+ if File.exists? backupFileName
8
+ puts "Deleting existing backup file #{backupFileName} ..."
9
+ File.delete (backupFileName)
10
+ end
11
+ if File.exists? outFile
12
+ puts "Renaming file #{outFile} to #{backupFileName} ..."
13
+ File.rename(outFile, backupFileName)
14
+ end
15
+ end
16
+
17
+ def ensureDirectoryExists(directoryName)
18
+ if File.exist? directoryName
19
+ if not File.directory? directoryName
20
+ raise "Cannot create directory #{directoryName}, already exists as a non-directory file"
21
+ end
22
+ else
23
+ puts "Creating missing directory #{directoryName} ..."
24
+ FileUtils.makedirs(directoryName)
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
@@ -0,0 +1,156 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'regenerate/regenerate-utils.rb'
4
+
5
+ module Regenerate
6
+
7
+ class PathAndParents
8
+ def initialize(path)
9
+ @path = path
10
+ end
11
+
12
+ def each
13
+ currentPath = @path
14
+ topLevel = false
15
+ while !topLevel do
16
+ yield currentPath
17
+ parentPath = File.dirname(currentPath)
18
+ topLevel = parentPath == currentPath
19
+ currentPath = parentPath
20
+ end
21
+ end
22
+ end
23
+
24
+ class SiteRegenerator
25
+
26
+ include Regenerate::Utils
27
+
28
+ def initialize(baseDir, sourceSubDir, outputSubDir)
29
+ @baseDir = File.expand_path(baseDir)
30
+ @sourceSubDir = sourceSubDir
31
+ @outputSubDir = outputSubDir
32
+ @sourceTypeSubDirs = {:source => @sourceSubDir, :output => @outputSubDir}
33
+ @sourceTypeDirs = {:source => File.join(@baseDir, @sourceSubDir),
34
+ :output => File.join(@baseDir, @outputSubDir)}
35
+ @oppositeSourceType = {:source => :output, :output => :source}
36
+ puts "SiteRegenerator, @baseDir = #{@baseDir.inspect}"
37
+ end
38
+
39
+ def checkNotSourceOnly(pathComponents)
40
+ for component in pathComponents do
41
+ if component.start_with?("_")
42
+ raise "Cannot regenerate source-only component #{pathComponents.join("/")}"
43
+ end
44
+ end
45
+ end
46
+
47
+ REGENERATE_EXTENSIONS = [".htm", ".html", ".xml"]
48
+
49
+ def copySrcToOutputFile(srcFile, outFile)
50
+ makeBackupFile(outFile)
51
+ FileUtils.cp(srcFile, outFile, :verbose => true)
52
+ end
53
+
54
+ def regenerateFileFromSource(srcFile, pathComponents)
55
+ puts "regenerateFileFromSource, srcFile = #{srcFile}, pathComponents = #{pathComponents.inspect}"
56
+ subPath = pathComponents.join("/")
57
+ outFile = File.join(@sourceTypeDirs[:output], subPath)
58
+ puts " outFile = #{outFile}"
59
+ ensureDirectoryExists(File.dirname(outFile))
60
+ extension = File.extname(srcFile).downcase
61
+ puts " extension = #{extension}"
62
+ if REGENERATE_EXTENSIONS.include? extension
63
+ WebPage.new(srcFile).regenerateToOutputFile(outFile)
64
+ else
65
+ copySrcToOutputFile(srcFile, outFile)
66
+ end
67
+ end
68
+
69
+ def regenerateSourceFromOutput(outFile, pathComponents)
70
+ puts "regenerateSourceFromOutput, outFile = #{outFile}, pathComponents = #{pathComponents.inspect}"
71
+ subPath = pathComponents.join("/")
72
+ srcFile = File.join(@sourceTypeDirs[:source], subPath)
73
+ puts " srcFile = #{srcFile}"
74
+ ensureDirectoryExists(File.dirname(srcFile))
75
+ extension = File.extname(outFile).downcase
76
+ puts " extension = #{extension}"
77
+ if REGENERATE_EXTENSIONS.include? extension
78
+ raise "Regeneration from output not yet implemented."
79
+ else
80
+ copySrcToOutputFile(outFile, srcFile)
81
+ end
82
+ end
83
+
84
+ def regenerateFile(srcFile, pathComponents, sourceType)
85
+ puts "regenerateFile, srcFile = #{srcFile}, sourceType = #{sourceType.inspect}"
86
+ outFile = File.join(@sourceTypeDirs[@oppositeSourceType[sourceType]], File.join(pathComponents))
87
+ puts " outFile = #{outFile}"
88
+ outFileDir = File.dirname(outFile)
89
+ if !File.exists?(outFileDir)
90
+ if sourceType == :output
91
+ raise "Cannot create missing source directory #{outFileDir} - please do so manually if required"
92
+ end
93
+ ensureDirectoryExists(outFileDir)
94
+ end
95
+ if sourceType == :output
96
+ regenerateSourceFromOutput(srcFile, pathComponents)
97
+ elsif sourceType == :source
98
+ regenerateFileFromSource(srcFile, pathComponents)
99
+ end
100
+ end
101
+
102
+ def regenerateSubPath(pathComponents, sourceType)
103
+ puts "regenerateSubPath, pathComponents = #{pathComponents.inspect}, sourceType = #{sourceType.inspect}"
104
+ srcPath = File.join(@sourceTypeDirs[sourceType], File.join(pathComponents))
105
+ puts " srcPath = #{srcPath}"
106
+ if File.directory? (srcPath)
107
+ for entry in Dir.entries(srcPath) do
108
+ if ![".", ".."].include? entry
109
+ if !entry.start_with?("_")
110
+ regenerateSubPath(pathComponents + [entry], sourceType)
111
+ end
112
+ end
113
+ end
114
+ elsif File.file? (srcPath)
115
+ regenerateFile(srcPath, pathComponents, sourceType)
116
+ end
117
+ end
118
+
119
+ def regeneratePath(path)
120
+ path = File.expand_path(path)
121
+ puts "SiteRegenerator.regeneratePath, path = #{path}"
122
+ relativePath = Pathname.new(path).relative_path_from(Pathname.new(@baseDir))
123
+ puts " relativePath = #{relativePath}"
124
+ relativePathComponents = relativePath.to_s.split("/")
125
+ puts " relativePathComponents = #{relativePathComponents.inspect}"
126
+ subDir = relativePathComponents[0]
127
+ relativeSubDirPathComponents = relativePathComponents[1..-1]
128
+ checkNotSourceOnly(relativeSubDirPathComponents)
129
+ if subDir == @sourceSubDir
130
+ regenerateSubPath(relativeSubDirPathComponents, :source)
131
+ elsif subDir == @outputSubDir
132
+ regenerateSubPath(relativeSubDirPathComponents, :output)
133
+ else
134
+ raise "Path #{path} to regenerate is not contained in #{@sourceSubDir} (source) or #{@outputSubDir} (output) sub-directory of base dir #{@baseDir}"
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+ def self.findRegenerateScript(path, fileName)
141
+ for dir in PathAndParents.new(path) do
142
+ scriptFileName = File.join(dir, fileName)
143
+ puts " looking for #{scriptFileName} ..."
144
+ if File.exists?(scriptFileName)
145
+ return scriptFileName
146
+ end
147
+ end
148
+ raise "File #{fileName} not found in #{path} or any or its parent directories"
149
+ end
150
+
151
+ def self.regeneratePath(path)
152
+ regenerateScriptFileName = findRegenerateScript(path, ".regenerate.rb")
153
+ regenerateScript = File.read(regenerateScriptFileName)
154
+ eval(regenerateScript, binding, regenerateScriptFileName, 1)
155
+ end
156
+ end
@@ -0,0 +1,468 @@
1
+ require 'set'
2
+ require 'erb'
3
+ require 'json'
4
+ require 'regenerate/regenerate-utils.rb'
5
+
6
+ module Regenerate
7
+
8
+ # A component, which includes a sequence of lines which make up the text of that component
9
+ class PageComponent
10
+ attr_reader :text
11
+ attr_accessor :parentPage
12
+
13
+ def initialize
14
+ @lines = []
15
+ @text = nil # if text is nil, component is not yet finished
16
+ @parentPage = nil
17
+ end
18
+
19
+ def processStartComment(parsedCommentLine)
20
+ @startName = parsedCommentLine.name
21
+ initializeFromStartComment(parsedCommentLine)
22
+ if parsedCommentLine.sectionEnd # section end in start comment line, so already finished
23
+ finishText
24
+ end
25
+ end
26
+
27
+ def processEndComment(parsedCommentLine)
28
+ finishText
29
+ if parsedCommentLine.name != @startName
30
+ raise ParseException.new("Name #{parsedCommentLine.name.inspect} in end comment doesn't match name #{@startName.inspect} in start comment.")
31
+ end
32
+ end
33
+
34
+ def initializeFromStartComment(parsedCommentLine)
35
+ # default do nothing
36
+ end
37
+
38
+ def finished
39
+ @text != nil
40
+ end
41
+
42
+ def addLine(line)
43
+ @lines << line
44
+ end
45
+
46
+ def addToParentPage
47
+ # default do nothing
48
+ end
49
+
50
+ def finishText
51
+ @text = @lines.join("\n")
52
+ addToParentPage
53
+ end
54
+ end
55
+
56
+ # A component of static text which is not assigned to any variable, and which does not change
57
+ class StaticHtml < PageComponent
58
+ def output(showSource = true)
59
+ text + "\n"
60
+ end
61
+
62
+ def varName
63
+ nil
64
+ end
65
+ end
66
+
67
+ class RubyCode<PageComponent
68
+
69
+ attr_reader :lineNumber
70
+
71
+ def initialize(lineNumber)
72
+ super()
73
+ @lineNumber = lineNumber
74
+ end
75
+
76
+ def output(showSource = true)
77
+ if showSource
78
+ "<!-- [ruby\n#{text}\nruby] -->\n"
79
+ else
80
+ ""
81
+ end
82
+ end
83
+
84
+ def addToParentPage
85
+ @parentPage.addRubyComponent(self)
86
+ end
87
+ end
88
+
89
+ class SetPageObjectClass<PageComponent
90
+ attr_reader :className
91
+ def initialize(className)
92
+ super()
93
+ @className = className
94
+ end
95
+
96
+ def output(showSource = true)
97
+ if showSource
98
+ "<!-- [class #{@className}] -->\n"
99
+ else
100
+ ""
101
+ end
102
+ end
103
+
104
+ def addToParentPage
105
+ @parentPage.setPageObject(@className)
106
+ end
107
+ end
108
+
109
+ # Base class for the text variable types
110
+ class TextVariable<PageComponent
111
+ attr_reader :varName
112
+
113
+ def initializeFromStartComment(parsedCommentLine)
114
+ @varName = parsedCommentLine.instanceVarName
115
+ end
116
+
117
+ def addToParentPage
118
+ #puts "TextVariable.addToParentPage #{@varName} = #{@text.inspect}"
119
+ @parentPage.setPageObjectInstanceVar(@varName, @text)
120
+ end
121
+
122
+ def textVariableValue
123
+ @parentPage.getPageObjectInstanceVar(@varName)
124
+ end
125
+ end
126
+
127
+ # HtmlVariable Can be both source and result
128
+ class HtmlVariable < TextVariable
129
+
130
+ def processEndComment(parsedCommentLine)
131
+ super(parsedCommentLine)
132
+ if !parsedCommentLine.hasCommentStart
133
+ raise ParseException.new("End comment for HTML variable does not have a comment start")
134
+ end
135
+ end
136
+
137
+ def output(showSource = true)
138
+ if showSource
139
+ textValue = textVariableValue
140
+ if textValue == nil || textValue == ""
141
+ "<!-- [#{@varName}] -->\n"
142
+ else
143
+ "<!-- [#{@varName} -->\n#{textValue}\n<!-- #{@varName}] -->\n"
144
+ end
145
+ else
146
+ text
147
+ end
148
+ end
149
+ end
150
+
151
+ # CommentVariable Is an input only
152
+ class CommentVariable < TextVariable
153
+ def processEndComment(parsedCommentLine)
154
+ super(parsedCommentLine)
155
+ if parsedCommentLine.hasCommentStart
156
+ raise ParseException.new("End comment for comment variable has an unexpected comment start")
157
+ end
158
+ end
159
+
160
+ def output(showSource = true)
161
+ if showSource
162
+ "<!-- [#{@varName}\n#{textVariableValue}\n#{@varName}] -->\n"
163
+ else
164
+ ""
165
+ end
166
+ end
167
+ end
168
+
169
+ COMMENT_LINE_REGEX = /^\s*(<!--\s*|)(\[|)((@|)[_a-zA-Z][_a-zA-Z0-9]*)(|\s+([_a-zA-Z0-9]*))(\]|)(\s*-->|)?\s*$/
170
+
171
+ class ParseException<Exception
172
+ end
173
+
174
+ class ParsedRejennerCommentLine
175
+
176
+ attr_reader :isInstanceVar, :hasCommentStart, :hasCommentEnd, :sectionStart, :sectionEnd
177
+ attr_reader :isEmptySection, :line, :name, :value
178
+
179
+ def initialize(line, match)
180
+ @hasCommentStart = match[1] != ""
181
+ @sectionStart = match[2] != ""
182
+ @isInstanceVar = match[4] != ""
183
+ @name = match[3]
184
+ @value = match[6]
185
+ @sectionEnd = match[7] != ""
186
+ @hasCommentEnd = match[8] != ""
187
+ @line = line
188
+ @isEmptySection = @sectionStart && @sectionEnd
189
+ end
190
+
191
+ def to_s
192
+ "#{@hasCommentStart ? "<!-- ":""}#{@sectionStart ? "[ ":""}#{@isInstanceVar ? "@ ":""}#{@name.inspect}#{@value ? " "+@value:""}#{@sectionEnd ? " ]":""}#{@hasCommentEnd ? " -->":""}"
193
+ end
194
+
195
+ def isRejennerCommentLine
196
+ return (@hasCommentStart || @hasCommentEnd) && (@sectionStart || @sectionEnd)
197
+ end
198
+
199
+ def isRuby
200
+ !@isInstanceVar && @name == "ruby"
201
+ end
202
+
203
+ def instanceVarName
204
+ return @name
205
+ end
206
+
207
+ def raiseParseException(message)
208
+ raise ParseException.new("Error parsing line #{@line.inspect}: #{message}")
209
+ end
210
+
211
+ # only call this method if isRejennerCommentLine returns true
212
+ def checkIsValid
213
+ if !@isInstanceVar and !["ruby", "class"].include?(@name)
214
+ raiseParseException("Unknown section name #{@name.inspect}")
215
+ end
216
+ if @isEmptySection and (!@hasCommentStart && !@hasCommentEnd)
217
+ raiseParseException("Empty section, but is not a closed comment")
218
+ end
219
+ if !@sectionStart && !@hasCommentEnd
220
+ raiseParseException("End of section in comment start")
221
+ end
222
+ if !@sectionEnd && !@hasCommentStart
223
+ raiseParseException("Start of section in comment end")
224
+ end
225
+ if (@sectionStart && @sectionEnd) && isRuby
226
+ raiseParseException("Empty ruby section")
227
+ end
228
+ end
229
+
230
+ end
231
+
232
+ class WebPage
233
+
234
+ include Regenerate::Utils
235
+
236
+ attr_reader :fileName
237
+
238
+ def initialize(fileName)
239
+ @fileName = fileName
240
+ @components = []
241
+ @currentComponent = nil
242
+ @componentInstanceVariables = {}
243
+ initializePageObject(PageObject.new) # default, can be overridden by SetPageObjectClass
244
+ @rubyComponents = []
245
+ readFileLines
246
+ end
247
+
248
+ def initializePageObject(pageObject)
249
+ @pageObject = pageObject
250
+ setPageObjectInstanceVar("@fileName", @fileName)
251
+ setPageObjectInstanceVar("@baseDir", File.dirname(@fileName))
252
+ setPageObjectInstanceVar("@baseFileName", File.basename(@fileName))
253
+ @initialInstanceVariables = Set.new(@pageObject.instance_variables)
254
+ end
255
+
256
+ def getPageObjectInstanceVar(varName)
257
+ @pageObject.instance_variable_get(varName)
258
+ end
259
+
260
+ def setPageObjectInstanceVar(varName, value)
261
+ puts " setPageObjectInstanceVar, #{varName} = #{value.inspect}"
262
+ @pageObject.instance_variable_set(varName, value)
263
+ end
264
+
265
+ def addRubyComponent(rubyComponent)
266
+ @rubyComponents << rubyComponent
267
+ end
268
+
269
+ def setInstanceVarValue(varName, value)
270
+ if @initialInstanceVariables.member? varName
271
+ raise Exception, "Instance variable #{varName} is a pre-existing instance variable"
272
+ end
273
+ if @componentInstanceVariables.member? varName
274
+ raise Exception, "Instance variable #{varName} is a already defined for a component"
275
+ end
276
+ instance_variable_set(varName, value)
277
+ componentInstanceVariables << varName
278
+ end
279
+
280
+ def startNewComponent(component, startComment = nil)
281
+
282
+ component.parentPage = self
283
+ @currentComponent = component
284
+ #puts "startNewComponent, @currentComponent = #{@currentComponent.inspect}"
285
+ @components << component
286
+ if startComment
287
+ component.processStartComment(startComment)
288
+ end
289
+ end
290
+
291
+ def processTextLine(line, lineNumber)
292
+ #puts "text: #{line}"
293
+ if @currentComponent == nil
294
+ startNewComponent(StaticHtml.new)
295
+ end
296
+ @currentComponent.addLine(line)
297
+ end
298
+
299
+ def classFromString(str)
300
+ str.split('::').inject(Object) do |mod, class_name|
301
+ mod.const_get(class_name)
302
+ end
303
+ end
304
+
305
+ def setPageObject(className)
306
+ pageObjectClass = classFromString(className)
307
+ initializePageObject(pageObjectClass.new)
308
+ end
309
+
310
+ def processCommandLine(parsedCommandLine, lineNumber)
311
+ #puts "command: #{parsedCommandLine}"
312
+ if @currentComponent && (@currentComponent.is_a? StaticHtml)
313
+ @currentComponent.finishText
314
+ @currentComponent = nil
315
+ end
316
+ if @currentComponent
317
+ if parsedCommandLine.sectionStart
318
+ raise ParseException.new("Unexpected section start #{parsedCommandLine} inside component")
319
+ end
320
+ @currentComponent.processEndComment(parsedCommandLine)
321
+ @currentComponent = nil
322
+ else
323
+ if !parsedCommandLine.sectionStart
324
+ raise ParseException.new("Unexpected section end #{parsedCommandLine}, outside of component")
325
+ end
326
+ if parsedCommandLine.isInstanceVar
327
+ if parsedCommandLine.hasCommentEnd
328
+ startNewComponent(HtmlVariable.new, parsedCommandLine)
329
+ else
330
+ startNewComponent(CommentVariable.new, parsedCommandLine)
331
+ end
332
+ else
333
+ if parsedCommandLine.name == "ruby"
334
+ startNewComponent(RubyCode.new(lineNumber+1), parsedCommandLine)
335
+ elsif parsedCommandLine.name == "class"
336
+ startNewComponent(SetPageObjectClass.new(parsedCommandLine.value), parsedCommandLine)
337
+ else
338
+ raise ParseException.new("Unknown section type #{parsedCommandLine.name.inspect}")
339
+ end
340
+ end
341
+ if @currentComponent.finished
342
+ @currentComponent = nil
343
+ end
344
+ end
345
+
346
+ end
347
+
348
+ def finish
349
+ if @currentComponent
350
+ if @currentComponent.is_a? StaticHtml
351
+ @currentComponent.finishText
352
+ @currentComponent = nil
353
+ else
354
+ raise ParseException.new("Unfinished last component at end of file")
355
+ end
356
+ end
357
+ end
358
+
359
+ def writeRegeneratedFile(outFile)
360
+ makeBackupFile(outFile)
361
+ puts "Outputting regenerated page to #{outFile} ..."
362
+ File.open(outFile, "w") do |f|
363
+ for component in @components do
364
+ f.write(component.output)
365
+ end
366
+ end
367
+ puts "Finished writing #{outFile}"
368
+ end
369
+
370
+ def readFileLines
371
+ puts "Opening #{@fileName} ..."
372
+ lineNumber = 0
373
+ File.open(@fileName).each_line do |line|
374
+ line.chomp!
375
+ lineNumber += 1
376
+ #puts "line #{lineNumber}: #{line}"
377
+ commentLineMatch = COMMENT_LINE_REGEX.match(line)
378
+ if commentLineMatch
379
+ parsedCommandLine = ParsedRejennerCommentLine.new(line, commentLineMatch)
380
+ #puts "parsedCommandLine = #{parsedCommandLine}"
381
+ if parsedCommandLine.isRejennerCommentLine
382
+ parsedCommandLine.checkIsValid
383
+ processCommandLine(parsedCommandLine, lineNumber)
384
+ else
385
+ processTextLine(line, lineNumber)
386
+ end
387
+ else
388
+ processTextLine(line, lineNumber)
389
+ end
390
+ end
391
+ finish
392
+ #puts "Finished reading #{@fileName}."
393
+ end
394
+
395
+ def regenerate
396
+ executeRubyComponents
397
+ writeRegeneratedFile(@fileName)
398
+ #display
399
+ end
400
+
401
+ def regenerateToOutputFile(outFile)
402
+ executeRubyComponents
403
+ writeRegeneratedFile(outFile)
404
+ end
405
+
406
+ def executeRubyComponents
407
+ fileDir = File.dirname(@fileName)
408
+ puts "Executing ruby components in directory #{fileDir} ..."
409
+ Dir.chdir(fileDir) do
410
+ for rubyComponent in @rubyComponents
411
+ rubyCode = rubyComponent.text
412
+ puts ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
413
+ puts "Executing ruby (line #{rubyComponent.lineNumber}) #{rubyCode.inspect} ..."
414
+ @pageObject.instance_eval(rubyCode, @fileName, rubyComponent.lineNumber)
415
+ #puts "Finished executing ruby at line #{rubyComponent.lineNumber}"
416
+ end
417
+ end
418
+ #puts "Finished executing ruby components."
419
+ end
420
+
421
+ def display
422
+ puts "=========================================================================="
423
+ puts "Output of #{@fileName}"
424
+ for component in @components do
425
+ puts "--------------------------------------"
426
+ puts(component.output)
427
+ end
428
+ end
429
+ end
430
+
431
+ class PageObject
432
+ include Regenerate::Utils
433
+
434
+ def erb(templateFileName)
435
+ @binding = binding
436
+ File.open(relative_path(templateFileName), "r") do |input|
437
+ templateText = input.read
438
+ template = ERB.new(templateText, nil, nil)
439
+ template.filename = templateFileName
440
+ result = template.result(@binding)
441
+ end
442
+ end
443
+
444
+ def relative_path(path)
445
+ File.expand_path(File.join(@baseDir, path.to_str))
446
+ end
447
+
448
+ def require_relative(path)
449
+ require relative_path(path)
450
+ end
451
+
452
+ def saveProperties
453
+ properties = {}
454
+ for property in propertiesToSave
455
+ value = instance_variable_get("@" + property.to_s)
456
+ properties[property] = value
457
+ end
458
+ propertiesFileName = relative_path(self.class.propertiesFileName(@baseFileName))
459
+ puts "Saving properties #{properties.inspect} to #{propertiesFileName}"
460
+ ensureDirectoryExists(File.dirname(propertiesFileName))
461
+ File.open(propertiesFileName,"w") do |f|
462
+ f.write(JSON.pretty_generate(properties))
463
+ end
464
+ end
465
+
466
+ end
467
+
468
+ end