masterview 0.3.2 → 0.3.3
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/CHANGELOG +15 -0
- data/RELEASE_NOTES +26 -2
- data/Rakefile +35 -10
- data/ReleaseAnnouncement +124 -0
- data/TODO +6 -0
- data/doc/configuration.html +39 -0
- data/doc/guide.html +14 -13
- data/doc/index.html +1 -1
- data/doc/installation.html +1 -1
- data/doc/media_list.html +19 -3
- data/examples/rails_app_config/masterview/settings.rb +5 -0
- data/lib/masterview/analyzer.rb +13 -1
- data/lib/masterview/directives/form.rb +4 -1
- data/lib/masterview/directives/stylesheet_link.rb +1 -1
- data/lib/masterview/extras/auto_copy.rb +80 -0
- data/lib/masterview/initializer.rb +87 -4
- data/lib/masterview/io.rb +11 -0
- data/lib/masterview/masterview_version.rb +1 -1
- data/lib/masterview/mtime_tracking_hash.rb +12 -3
- data/lib/masterview/parser.rb +2 -2
- data/lib/masterview/rails_ext/action_controller_reparse_checking.rb +10 -9
- data/lib/masterview/rails_ext/action_view_erb_direct.rb +53 -34
- data/lib/masterview/rails_ext/short_path_calc.rb +127 -0
- data/lib/masterview/template_spec.rb +27 -9
- data/lib/masterview.rb +1 -1
- data/test/tmp/dst/public/images/FOO.GIF +1 -0
- data/test/tmp/dst/public/images/bar/baz.png +1 -0
- data/test/tmp/dst/public/images/blank.gif +1 -0
- data/test/tmp/dst/public/images/cat/dog/mouse.JPG +1 -0
- data/test/tmp/dst/public/images/star.jpg +1 -0
- data/test/tmp/dst/public/images/test.png +1 -0
- data/test/tmp/dst/public/javascript/custom/script.js +1 -0
- data/test/tmp/dst/public/javascript/nested/custom/foo.js +1 -0
- data/test/tmp/dst/public/javascript/prototype.js +1 -0
- data/test/tmp/dst/public/javascript/scriptaculous.js +1 -0
- data/test/tmp/dst/public/stylesheets/client/standard/great1.css +1 -0
- data/test/tmp/dst/public/stylesheets/custom/blue.css +1 -0
- data/test/tmp/dst/public/stylesheets/style.css +1 -0
- data/test/tmp/src/css/client/standard/great1.css +1 -0
- data/test/tmp/src/css/custom/blue.css +1 -0
- data/test/tmp/src/css/style.css +1 -0
- data/test/tmp/src/images/FOO.GIF +1 -0
- data/test/tmp/src/images/bar/baz.png +1 -0
- data/test/tmp/src/images/blank.gif +1 -0
- data/test/tmp/src/images/cat/dog/mouse.JPG +1 -0
- data/test/tmp/src/images/star.jpg +1 -0
- data/test/tmp/src/images/test.png +1 -0
- data/test/tmp/src/mixed/FOO.GIF +1 -0
- data/test/tmp/src/mixed/bar/baz.png +1 -0
- data/test/tmp/src/mixed/blank.gif +1 -0
- data/test/tmp/src/mixed/cat/dog/mouse.JPG +1 -0
- data/test/tmp/src/mixed/client/standard/great1.css +1 -0
- data/test/tmp/src/mixed/custom/blue.css +1 -0
- data/test/tmp/src/mixed/custom/script.js +1 -0
- data/test/tmp/src/mixed/nested/custom/foo.js +1 -0
- data/test/tmp/src/mixed/prototype.js +1 -0
- data/test/tmp/src/mixed/scriptaculous.js +1 -0
- data/test/tmp/src/mixed/star.jpg +1 -0
- data/test/tmp/src/mixed/style.css +1 -0
- data/test/tmp/src/mixed/test.png +1 -0
- data/test/tmp/src/scripts/custom/script.js +1 -0
- data/test/tmp/src/scripts/nested/custom/foo.js +1 -0
- data/test/tmp/src/scripts/prototype.js +1 -0
- data/test/tmp/src/scripts/scriptaculous.js +1 -0
- data/test/unit/auto_copy_test.rb +181 -0
- data/test/unit/directive_form_test.rb +63 -0
- data/test/unit/directive_stylesheet_link_test.rb +3 -3
- data/test/unit/file_mio_test.rb +24 -8
- data/test/unit/mtime_string_hash_mio_tree_test.rb +19 -6
- data/test/unit/short_path_calc_test.rb +135 -0
- data/test/unit/string_hash_mio_test.rb +18 -5
- data/test/unit/template_test.rb +37 -0
- metadata +85 -2
@@ -290,6 +290,31 @@ module MasterView
|
|
290
290
|
#
|
291
291
|
attr_accessor :template_asset_base_ref_pattern
|
292
292
|
|
293
|
+
# Configuration for locations of files that MasterView will autocopy to a runtime location.
|
294
|
+
# This autocopy feature makes it easy to have prototypes that display properly for
|
295
|
+
# WYSIWYG editing and design, using files (images, stylesheets, and javascript) which are not
|
296
|
+
# in the standard Rails locations but are automatically copied to proper place for runtime.
|
297
|
+
# This is commonly used in conjunction with template_src_dir_path (which changes the
|
298
|
+
# location of the source MasterView templates). Developers can have their templates in a non-standard
|
299
|
+
# location along with images, stylesheets, and javascript, and then still have everything copied to
|
300
|
+
# the proper runtime locations when Rails is fired up. In debug mode, timestamps are checked on every request,
|
301
|
+
# in production mode, copy is done only on startup.
|
302
|
+
#
|
303
|
+
# Each entry is a hash that needs to contain
|
304
|
+
# :source => 'path to source folder' # absolute or relative to RAILS_ROOT
|
305
|
+
# :destination => 'path to place to copy to' # absolute or relative to RAILS_ROOT
|
306
|
+
#
|
307
|
+
# and can optionally have a file extension filter
|
308
|
+
# :extensions => [:gif, :GIF, :jpg, :JPG] # limit files copied to this array of extensions, case sensitive
|
309
|
+
#
|
310
|
+
# Default: [] (empty array) - nothing is auto copied
|
311
|
+
# Example usage showing three paths added to be auto copied:
|
312
|
+
# config.auto_copy_file_entries << { :source => 'path_to_my_images', :destination => 'public/images' }
|
313
|
+
# config.auto_copy_file_entries << { :source => 'path_to_my_scripts', :destination => 'public/javascripts', :extensions => [:js, :JS] } # only copy js files
|
314
|
+
# config.auto_copy_file_entries << { :source => 'path_to_my_css', :destination => 'public/stylesheets' }
|
315
|
+
attr_accessor :auto_copy_file_entries
|
316
|
+
|
317
|
+
|
293
318
|
# === Template Generation Options
|
294
319
|
|
295
320
|
# Path to the directory where Masterview template output (rhtml)
|
@@ -401,6 +426,15 @@ module MasterView
|
|
401
426
|
# Needs to match +inline_erb_start+ and +inline_erb_end+.
|
402
427
|
attr_accessor :inline_erb_substitution_regex
|
403
428
|
|
429
|
+
# boolean to specify whether to use the original (unpatched) rexml sax2parser.
|
430
|
+
# If this is not true and the REXML version is 3.1.4 -3.1.6 MasterView will use
|
431
|
+
# a patched version of rexml sax2parser which properly handles doctypes.
|
432
|
+
# If this is true or the REXML version is outside this range the original
|
433
|
+
# sax2 parser will be used
|
434
|
+
#
|
435
|
+
# Default: <tt>false</tt>
|
436
|
+
attr_accessor :use_original_rexml_sax2parser
|
437
|
+
|
404
438
|
# === Rails Application Options
|
405
439
|
|
406
440
|
# Boolean which specifies whether masterview templates are parsed
|
@@ -537,9 +571,10 @@ module MasterView
|
|
537
571
|
@mv_code_base_dir = File.expand_path( File.dirname(__FILE__) )
|
538
572
|
builtin_directives_path = File.join( mv_code_base_dir, 'directives')
|
539
573
|
@mv_installation_dir = File.expand_path( "#{File.dirname(__FILE__)}/../.." )
|
574
|
+
@auto_copy_file_entries = []
|
540
575
|
|
541
576
|
#ISSUE: should probably also detect std console or breakpointer launch scripts [DJL 10-Jun-2006]
|
542
|
-
@rails_runner_scripts_pattern = /server|dispatch|mongrel_rails|cgi/ #cgi picks up scgi and fcgi
|
577
|
+
@rails_runner_scripts_pattern = /server|dispatch|mongrel_rails|cgi|-e/ #cgi picks up scgi and fcgi, -e for RadRails
|
543
578
|
|
544
579
|
@has_rails_context = (defined?(::RAILS_ROOT) != nil)
|
545
580
|
decide_if_running_rails
|
@@ -676,6 +711,7 @@ module MasterView
|
|
676
711
|
@running_rails = has_rails_context && ($PROGRAM_NAME =~ rails_runner_scripts_pattern) != nil
|
677
712
|
|
678
713
|
# TODO could try checking if things are defined instead but what would we check for?? Something related to Dispatcher?
|
714
|
+
# Dispatcher doesn't seemed to be defined when we come through here
|
679
715
|
# @running_rails = has_rails_context && (defined?(::Dispatcher.dispatch)) != nil
|
680
716
|
end
|
681
717
|
|
@@ -713,12 +749,12 @@ module MasterView
|
|
713
749
|
|
714
750
|
# Add masterview directive implementations from plugins
|
715
751
|
# to the masterview directive load path
|
716
|
-
#
|
752
|
+
#
|
717
753
|
# EXPERIMENTAL PROTOTYPE - NOT YET PUBLICIZED [DJL 13-Feb-2007]
|
718
754
|
def add_plugin_directives(*base_paths) #:nodo:
|
719
755
|
# append plugin directives in alphabetical order, per Rails plugin loading
|
720
756
|
plugin_directives = find_plugin_directives(base_paths)
|
721
|
-
plugin_directives.each { | plugin_dir_path |
|
757
|
+
plugin_directives.each { | plugin_dir_path |
|
722
758
|
add_directive_path plugin_dir_path
|
723
759
|
}
|
724
760
|
plugin_directives
|
@@ -728,7 +764,7 @@ module MasterView
|
|
728
764
|
# Return list of directives paths from plugins
|
729
765
|
def find_plugin_directives(*base_paths)
|
730
766
|
directive_paths = []
|
731
|
-
find_plugins(base_paths).each do | plugin_dir_path |
|
767
|
+
find_plugins(base_paths).each do | plugin_dir_path |
|
732
768
|
next if File.basename(plugin_dir_path) == 'masterview' #skip masterview's own built-in directives
|
733
769
|
directive_dir_path = File.join(plugin_dir_path, 'directives')
|
734
770
|
if File.directory?(directive_dir_path)
|
@@ -974,6 +1010,7 @@ module MasterView
|
|
974
1010
|
MasterView.const_set('InlineErbStart', config.inline_erb_start)
|
975
1011
|
MasterView.const_set('InlineErbEnd', config.inline_erb_end)
|
976
1012
|
MasterView.const_set('InlineErbSubstitutionRegex', config.inline_erb_substitution_regex)
|
1013
|
+
MasterView.const_set('UseOriginalRexmlSax2Parser', config.use_original_rexml_sax2parser)
|
977
1014
|
|
978
1015
|
# Rails application options
|
979
1016
|
MasterView.const_set('ParseMasterViewTemplatesAtStartup', config.parse_masterview_templates_at_startup)
|
@@ -996,6 +1033,8 @@ module MasterView
|
|
996
1033
|
configuration.namespace_prefix_extensions )
|
997
1034
|
initialize_logger
|
998
1035
|
initialize_mio
|
1036
|
+
set_rexml_parser_class
|
1037
|
+
initialize_auto_copy_files
|
999
1038
|
#Back out experiment: causes load order problems
|
1000
1039
|
##load_directives # held off on this until logger is installed
|
1001
1040
|
install_in_rails
|
@@ -1039,6 +1078,45 @@ module MasterView
|
|
1039
1078
|
MasterView::LoadedFeatures[:tidy_template_read] = config.default_parser_options[:tidy]
|
1040
1079
|
end
|
1041
1080
|
|
1081
|
+
# Initialize the auto_copy_files MasterView I/O and AutoCopy setup
|
1082
|
+
def initialize_auto_copy_files
|
1083
|
+
require 'masterview/extras/auto_copy'
|
1084
|
+
auto_copy_file_entries = configuration.auto_copy_file_entries
|
1085
|
+
if auto_copy_file_entries
|
1086
|
+
auto_copy_file_entries.each do |entry|
|
1087
|
+
if entry[:source] && entry[:destination]
|
1088
|
+
sourceMIO = MasterView::MIO::FileMIOTree.new(entry[:source])
|
1089
|
+
destMIO = MasterView::MIO::FileMIOTree.new(entry[:destination])
|
1090
|
+
extensions = entry[:extensions] || []
|
1091
|
+
filename_patterns = extensions.collect{ |ext| "*.#{ext.to_s}" }
|
1092
|
+
filename_patterns = ['*'] if filename_patterns.empty?
|
1093
|
+
filename_pattern_for_log = (filename_patterns.empty?) ? '*' : filename_patterns.join(',')
|
1094
|
+
MasterView::AutoCopy.register(sourceMIO, destMIO, filename_patterns)
|
1095
|
+
MasterView::Log.info{ "Auto copying files from #{entry[:source]} to #{entry[:destination]} with filter #{filename_patterns.join(',')}" }
|
1096
|
+
else
|
1097
|
+
MasterView::Log.error{ 'config.auto_copy_file_entries entry is missing required :source or :destination values, will be ignored. entry='+entry.inspect }
|
1098
|
+
end
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
# set the REXML SAX2ParserClass, use patched parser or standard SAX2Parser
|
1104
|
+
# checks version of REXML and value of :use_patched_rexml_sax2parser
|
1105
|
+
def set_rexml_parser_class
|
1106
|
+
if REXML::Version < '3.1.4' # below minimum version
|
1107
|
+
MasterView::Log.error { 'Fatal error: MasterView requires REXML version 3.1.4 or greater' }
|
1108
|
+
raise 'Fatal error: MasterView requires REXML version 3.1.4 or greater'
|
1109
|
+
elsif MasterView::UseOriginalRexmlSax2Parser || !['3.1.4', '3.1.5', '3.1.6'].include?(REXML::Version)
|
1110
|
+
MasterView::Log.info { 'MasterView using REXML Sax2Parser version = '+REXML::Version }
|
1111
|
+
require 'rexml/parsers/sax2parser'
|
1112
|
+
MasterView.const_set('REXMLSax2ParserClass', REXML::Parsers::SAX2Parser)
|
1113
|
+
else
|
1114
|
+
MasterView::Log.info { 'MasterView using REXML '+REXML::VERSION+' Sax2ParserWithDoctypeFix' }
|
1115
|
+
require 'rexml/parsers/sax2parser_with_doctype_fix'
|
1116
|
+
MasterView.const_set('REXMLSax2ParserClass', REXML::Parsers::SAX2ParserWithDoctypeFix)
|
1117
|
+
end
|
1118
|
+
end
|
1119
|
+
|
1042
1120
|
#NOTE: not currently used - caused problems during startup, so reverted to original
|
1043
1121
|
# scheme where loading is triggered on demand by template parsing
|
1044
1122
|
# [SJL 20-Sep-2006]
|
@@ -1052,6 +1130,7 @@ module MasterView
|
|
1052
1130
|
return if ! configuration.on_rails?
|
1053
1131
|
enable_mv_admin_pages
|
1054
1132
|
parse_templates_at_startup
|
1133
|
+
auto_copy_at_startup
|
1055
1134
|
enable_reparse_changed_templates
|
1056
1135
|
enable_rails_erb_direct
|
1057
1136
|
MasterView::Log.info{ 'MasterView plugin initialized - Version '+MasterView::VERSION::STRING }
|
@@ -1074,6 +1153,10 @@ module MasterView
|
|
1074
1153
|
end
|
1075
1154
|
end
|
1076
1155
|
|
1156
|
+
def auto_copy_at_startup #:nodoc:
|
1157
|
+
MasterView::AutoCopy.copy_all_updated_files
|
1158
|
+
end
|
1159
|
+
|
1077
1160
|
#--
|
1078
1161
|
# DBC-style notation per DbC - rubydbc-0.1 (Andy Hunt's Design by Contract)
|
1079
1162
|
#pre( MasterView::ParseMasterViewTemplatesAtStartup )
|
data/lib/masterview/io.rb
CHANGED
@@ -259,6 +259,11 @@ module MIO
|
|
259
259
|
end
|
260
260
|
written
|
261
261
|
end
|
262
|
+
|
263
|
+
# remove - delete file
|
264
|
+
def remove
|
265
|
+
full_pathname.delete
|
266
|
+
end
|
262
267
|
end
|
263
268
|
|
264
269
|
class StringMIO < MIOBase
|
@@ -295,6 +300,11 @@ module MIO
|
|
295
300
|
def exist?
|
296
301
|
@string_hash.has_key?(self.pathname.to_s)
|
297
302
|
end
|
303
|
+
|
304
|
+
# remove - delete hash entry
|
305
|
+
def remove
|
306
|
+
@string_hash.delete(self.pathname.to_s)
|
307
|
+
end
|
298
308
|
end
|
299
309
|
|
300
310
|
# used by MTimeStringHashMIOTree to create MIO objects that check
|
@@ -314,6 +324,7 @@ module MIO
|
|
314
324
|
include MasterViewIOIdenticalMixin
|
315
325
|
def exist?; end
|
316
326
|
def mtime; end
|
327
|
+
def remove; end
|
317
328
|
end
|
318
329
|
|
319
330
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module MasterView
|
2
2
|
|
3
3
|
# this hash is designed to track modified times of its values
|
4
|
-
# this behaviour is only supported through using []= and store
|
4
|
+
# this behaviour is only supported through using []= and store
|
5
5
|
# mechanisms and thus default semantics have been excluded
|
6
|
-
# other update methods such as merge! have been excluded from
|
6
|
+
# other update methods such as merge! have been excluded from
|
7
7
|
# this implementation and will raise errors
|
8
8
|
class MTimeTrackingHash < Hash
|
9
9
|
|
@@ -13,7 +13,7 @@ module MasterView
|
|
13
13
|
super
|
14
14
|
@mtimes = {}
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def []=(key, value)
|
18
18
|
update_mtime(key)
|
19
19
|
super
|
@@ -24,6 +24,11 @@ module MasterView
|
|
24
24
|
super
|
25
25
|
end
|
26
26
|
|
27
|
+
def delete(key)
|
28
|
+
delete_mtime(key)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
27
32
|
# returns the Time object for this key
|
28
33
|
def mtime(key)
|
29
34
|
@mtimes[key]
|
@@ -35,6 +40,10 @@ module MasterView
|
|
35
40
|
@mtimes[key] = Time.now
|
36
41
|
end
|
37
42
|
|
43
|
+
def delete_mtime(key)
|
44
|
+
@mtimes.delete(key)
|
45
|
+
end
|
46
|
+
|
38
47
|
def default=(obj); raise "Not implemented"; end
|
39
48
|
def merge!(obj,&block); raise "Not implemented"; end
|
40
49
|
def reject!(obj,&block); raise "Not implemented"; end
|
data/lib/masterview/parser.rb
CHANGED
@@ -596,7 +596,7 @@ module MasterView
|
|
596
596
|
end
|
597
597
|
|
598
598
|
def generate_replace(value)
|
599
|
-
@renderer.append_raw
|
599
|
+
@renderer.append_raw ERB_CONTENT_START+value+ERB_CONTENT_END
|
600
600
|
end
|
601
601
|
|
602
602
|
# handle a mv:gen_partial attribute, which calls generate and outputs a token
|
@@ -690,7 +690,7 @@ module MasterView
|
|
690
690
|
ensure_standard_options_configured(options)
|
691
691
|
|
692
692
|
begin
|
693
|
-
sax_parser =
|
693
|
+
sax_parser = MasterView::REXMLSax2ParserClass.new( template )
|
694
694
|
options[:listeners].each do |listener|
|
695
695
|
if listener.is_a? Class
|
696
696
|
sax_parser.listen( listener.new(options) )
|
@@ -1,16 +1,16 @@
|
|
1
1
|
#
|
2
2
|
# Installs hooks to insert MasterView changed-template reparsing
|
3
3
|
# into the Rails request dispatching handler in ActionController::Base.
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# Ensures that MasterView output files are always current while running a
|
6
6
|
# Rails application. The <code>:rails_reparse_checking</code> option in the
|
7
|
-
# MasterView configuration should generally be enabled/disabled in conjunction
|
8
|
-
# with Rails class load caching, which is normally off in a development environment
|
9
|
-
# configuration.
|
10
|
-
#
|
11
|
-
# Requires that MasterView templates be parsed at application startup to properly
|
7
|
+
# MasterView configuration should generally be enabled/disabled in conjunction
|
8
|
+
# with Rails class load caching, which is normally off in a development environment
|
9
|
+
# configuration.
|
10
|
+
#
|
11
|
+
# Requires that MasterView templates be parsed at application startup to properly
|
12
12
|
# initialize the mechanism for detecting template changes after application startup.
|
13
|
-
#
|
13
|
+
#
|
14
14
|
|
15
15
|
module ActionController #:nodoc:
|
16
16
|
class Base #:nodoc
|
@@ -18,10 +18,11 @@ module ActionController #:nodoc:
|
|
18
18
|
# changed templates during Rails request dispatching.
|
19
19
|
alias :process_pre_mv :process #:nodoc:
|
20
20
|
def process(request, response, method = :perform_action, *arguments) #:nodoc:
|
21
|
-
MasterView::TemplateWatcher.check_updated(MasterView::IOMgr.template, MasterView::TemplateFilenamePattern ) do |mio|
|
21
|
+
MasterView::TemplateWatcher.check_updated(MasterView::IOMgr.template, MasterView::TemplateFilenamePattern ) do |mio|
|
22
22
|
MasterView::Parser.parse_mio( mio, MasterView::IOMgr.erb )
|
23
23
|
end
|
24
|
+
MasterView::AutoCopy.copy_all_updated_files
|
24
25
|
process_pre_mv(request, response, method, *arguments)
|
25
26
|
end
|
26
27
|
end
|
27
|
-
end
|
28
|
+
end
|
@@ -12,6 +12,8 @@
|
|
12
12
|
# to rewrite this code to use the provided hooks.
|
13
13
|
#
|
14
14
|
|
15
|
+
require File.join( File.dirname(__FILE__), 'short_path_calc' )
|
16
|
+
|
15
17
|
module ActionView #:nodoc:
|
16
18
|
|
17
19
|
class Base #:nodoc:
|
@@ -20,20 +22,31 @@ module ActionView #:nodoc:
|
|
20
22
|
# check MasterView paths because might not exist on file system
|
21
23
|
alias :template_exists_pre_mv? :template_exists? #:nodoc:
|
22
24
|
def template_exists?(template_path, extension) #:nodoc:
|
23
|
-
|
24
|
-
|
25
|
+
found = template_exists_pre_mv?(template_path, extension)
|
26
|
+
#MasterView::Log.debug{ "template_exists? tpath=#{template_path} base=#{self.base_path}"}
|
27
|
+
|
28
|
+
# template is relative to view_base
|
29
|
+
unless found
|
30
|
+
short_path_no_ext = MasterView::RailsExt::ShortPathCalculator.calc_short_path(self.base_path, template_path)
|
31
|
+
if short_path_no_ext
|
32
|
+
short_path = short_path_no_ext+'.'+extension.to_s
|
33
|
+
found = MasterView::IOMgr.erb.path(short_path).exist?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
found
|
25
37
|
end
|
26
38
|
|
27
39
|
# checks for the existence of the template in MasterView first before using the
|
28
40
|
# rails file system based read_template_file
|
29
41
|
alias :read_template_file_pre_mv :read_template_file #:nodoc:
|
30
|
-
def read_template_file(
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
42
|
+
def read_template_file(template_path_with_ext, extension) #:nodoc:
|
43
|
+
#MasterView::Log.debug{ "read_template_file tpath=#{template_path_with_ext} base=#{self.base_path}"}
|
44
|
+
|
45
|
+
# template is relative to Rails root
|
46
|
+
# if short_path found and exists in mio, then read and return otherwise use original read method
|
47
|
+
MasterView::RailsExt::ShortPathCalculator.calc_short_path_and_retrieve(MasterView::ConfigSettings.rails_root_path, template_path_with_ext,
|
48
|
+
MasterView::IOMgr.erb) ||
|
49
|
+
read_template_file_pre_mv(template_path_with_ext, extension)
|
37
50
|
end
|
38
51
|
|
39
52
|
# I submitted a patch to rails to make this easier it was picked up in changeset 5587
|
@@ -47,16 +60,18 @@ module ActionView #:nodoc:
|
|
47
60
|
# not stored on the file system can hook and extend appropriately
|
48
61
|
alias :template_changed_since_pre_mv? :template_changed_since?
|
49
62
|
def template_changed_since?(file_name, compile_time)
|
50
|
-
|
51
|
-
|
52
|
-
|
63
|
+
#MasterView::Log.debug { "template_changed_since? tpath=#{file_name} base=#{self.base_path}"}
|
64
|
+
|
65
|
+
# template is relative to rails root
|
66
|
+
mio_mtime = MasterView::RailsExt::ShortPathCalculator.calc_short_path_and_get_mtime(MasterView::ConfigSettings.rails_root_path, file_name,
|
67
|
+
MasterView::IOMgr.erb)
|
68
|
+
if mio_mtime
|
69
|
+
compile_time < mio_mtime
|
53
70
|
else # delegate to rails original file based version
|
54
71
|
template_changed_since_pre_mv?(file_name, compile_time)
|
55
72
|
end
|
56
73
|
end
|
57
74
|
|
58
|
-
public
|
59
|
-
|
60
75
|
else # older rails needs to use old method
|
61
76
|
|
62
77
|
# Check whether compilation is necessary.
|
@@ -66,15 +81,19 @@ module ActionView #:nodoc:
|
|
66
81
|
# original code.
|
67
82
|
alias :compile_template_pre_mv? :compile_template? #:nodoc:
|
68
83
|
def compile_template?(template, file_name, local_assigns) #:nodoc:
|
69
|
-
|
70
|
-
|
84
|
+
#MasterView::Log.debug { "compile_template? tpath=#{file_name} base=#{self.base_path}"}
|
85
|
+
|
86
|
+
# templat is relative to Rails root
|
87
|
+
mio_mtime = MasterView::RailsExt::ShortPathCalculator.calc_short_path_and_get_mtime(MasterView::ConfigSettings.rails_root_path, file_name,
|
88
|
+
MasterView::IOMgr.erb)
|
89
|
+
if mio_mtime
|
71
90
|
method_key = file_name || template
|
72
91
|
render_symbol = @@method_names[method_key]
|
73
92
|
|
74
93
|
if @@compile_time[render_symbol] && supports_local_assigns?(render_symbol, local_assigns)
|
75
94
|
if file_name && !@@cache_template_loading
|
76
|
-
need_to_compile = (@@compile_time[render_symbol] <
|
77
|
-
MasterView::Log.debug{ 'compile_template?
|
95
|
+
need_to_compile = (@@compile_time[render_symbol] < mio_mtime) # use mio.mtime instead of File.mtime
|
96
|
+
MasterView::Log.debug{ 'compile_template? file_name = '+file_name+' compile?='+need_to_compile.to_s }
|
78
97
|
need_to_compile
|
79
98
|
end
|
80
99
|
else
|
@@ -87,14 +106,6 @@ module ActionView #:nodoc:
|
|
87
106
|
|
88
107
|
end
|
89
108
|
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
# returns the short path relative to view_base since MasterView uses relative paths exclusively
|
94
|
-
def short_relative_path_mv(template_path) #:nodoc:
|
95
|
-
(template_path.starts_with?(self.base_path)) ? template_path[self.base_path.length+1..-1] : template_path
|
96
|
-
end
|
97
|
-
|
98
109
|
end
|
99
110
|
|
100
111
|
# The TemplateError exception is raised when the compilation of the template fails. This exception then gathers a
|
@@ -108,10 +119,14 @@ module ActionView #:nodoc:
|
|
108
119
|
return unless num = line_number
|
109
120
|
num = num.to_i
|
110
121
|
|
111
|
-
#
|
112
|
-
|
113
|
-
|
114
|
-
|
122
|
+
#MasterView::Log.debug { "source_extract12 tpath=#{@file_path} base=#{@base_path}"}
|
123
|
+
|
124
|
+
# template is relative to Rails root
|
125
|
+
|
126
|
+
#added/modified the following two lines to support reading from MasterView with fallback to file system
|
127
|
+
filedata = MasterView::RailsExt::ShortPathCalculator.calc_short_path_and_retrieve(MasterView::ConfigSettings.rails_root_path, @file_path,
|
128
|
+
MasterView::IOMgr.erb)
|
129
|
+
source_code = (filedata) ? StringIO.new(filedata).readlines : IO.readlines(@file_path) # mio.exists? use it, else original file read
|
115
130
|
# source_code = IO.readlines(@file_path) # original rails 1.2 source
|
116
131
|
|
117
132
|
start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
|
@@ -133,10 +148,14 @@ module ActionView #:nodoc:
|
|
133
148
|
class TemplateError < ActionViewError #:nodoc:
|
134
149
|
def source_extract(indention = 0) #:nodoc:
|
135
150
|
|
136
|
-
#
|
137
|
-
|
138
|
-
|
139
|
-
|
151
|
+
#MasterView::Log.debug { "source_extract116 tpath=#{@file_name} base=#{@base_path}"}
|
152
|
+
|
153
|
+
# template is relative to Rails root
|
154
|
+
|
155
|
+
#added/modified the following two lines to support reading from MasterView with fallback to file system
|
156
|
+
filedata = MasterView::RailsExt::ShortPathCalculator.calc_short_path_and_retrieve(MasterView::ConfigSettings.rails_root_path, @file_name,
|
157
|
+
MasterView::IOMgr.erb)
|
158
|
+
source_code = (filedata) ? StringIO.new(filedata).readlines : IO.readlines(@file_name) # mio.exists? use it, else original file read
|
140
159
|
|
141
160
|
start_on_line = [ line_number - SOURCE_CODE_RADIUS - 1, 0 ].max
|
142
161
|
end_on_line = [ line_number + SOURCE_CODE_RADIUS - 1, source_code.length].min
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module MasterView
|
2
|
+
module RailsExt
|
3
|
+
|
4
|
+
# short path calculator, computes the short relative path for given the mv_view_path, a base_path,
|
5
|
+
# and a template_path which may be relative or absolute. This calculator checks to see if it is
|
6
|
+
# absolute or relative and cleans up the ./../ returning the short_path relative to mv_view_path
|
7
|
+
# if it can be calculated, otherwise simply returns full_path.
|
8
|
+
#
|
9
|
+
# Example usage:
|
10
|
+
# short_path = MasterView::RailsExt::ShortPathCalculator.calc_short_path(view_base_path, template_path)
|
11
|
+
#
|
12
|
+
# Requires Pathname extensions
|
13
|
+
# Requires String#starts_with?
|
14
|
+
# Requires MasterView::ConfigSettings.rails_views_dir_path be set before this class is required
|
15
|
+
#
|
16
|
+
# Example data:
|
17
|
+
#
|
18
|
+
# MV_RAILS_ROOT_VIEW_DIR = /home/foo/app/views
|
19
|
+
# RAILS_ROOT = /home/foo/config/..
|
20
|
+
# RAILS_ROOT_VIEW_DIR = /home/foo/config/../app/views
|
21
|
+
# BASE_DIR = /home/foo/config/../app/views
|
22
|
+
# BASE_DIR = /home/foo/vendor/plugins/goldberg/lib/../app/views
|
23
|
+
# template_path = store/list # already relative, return existing
|
24
|
+
# template_path = /home/foo/config/../app/views/store/list # starts with RAILS_ROOT_VIEW_DIR return short
|
25
|
+
# template_path = /home/foo/vendor/plugins/goldberg/lib/../app/views/../../../../../app/views/store/list # cleaned starts with RAILS_ROOT_VIEW_DIR return short
|
26
|
+
# template_path = ../../../../../app/views/store/list # when combined with base_path and cleaned starts with RAILS_ROOT_VIEW_DIR, return short
|
27
|
+
# template_path = /home/foo/vendor/plugins/goldberg/lib/../app/views/not/railsroot, return nil
|
28
|
+
# template_path = store/list # but base_path is not RAILS_ROOT_VIEW_DIR, return nil
|
29
|
+
#
|
30
|
+
class ShortPathCalculator
|
31
|
+
|
32
|
+
PATH_NOT_FOUND = -1
|
33
|
+
|
34
|
+
class << self # class methods
|
35
|
+
# cleans and expands the path storing in a class instance var
|
36
|
+
def mv_path=(view_path)
|
37
|
+
@clean_mv_view_path = Pathname.for_path(view_path).expand_path.cleanpath.to_s unless view_path.nil?
|
38
|
+
#MasterView::Log.debug { "ShortPathCalculator.mv_path=#{@clean_mv_view_path}"}
|
39
|
+
end
|
40
|
+
|
41
|
+
def mv_path
|
42
|
+
@clean_mv_view_path
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# hash of base_path to hash of template_paths containing short_path, stored as class instance variable
|
47
|
+
@short_path_cache = {} # one and only cache, double hash
|
48
|
+
|
49
|
+
# set mv_view_path
|
50
|
+
self.mv_path = MasterView::ConfigSettings.rails_views_dir_path
|
51
|
+
|
52
|
+
|
53
|
+
class << self # class methods
|
54
|
+
# class method that computes the short relative path to mv_view_path for a template_path which
|
55
|
+
# may be absolute or relative. If short_path cannot be calculated (not under mv_view_path)
|
56
|
+
# then return nil. This calculation cleans up messy paths including ./.. and
|
57
|
+
# resultant calculations are hashed.
|
58
|
+
def calc_short_path(view_base_path, template_path)
|
59
|
+
base_path_cache = short_path_cache(view_base_path)
|
60
|
+
short_path = base_path_cache.fetch(template_path, PATH_NOT_FOUND) # defaults to PATH_NOT_FOUND
|
61
|
+
#MasterView::Log.debug { "calc_short_path - short_path=#{short_path} using cache view_base=#{view_base_path} template_path=#{template_path}"} unless short_path == PATH_NOT_FOUND #todo comment out
|
62
|
+
return short_path unless short_path == PATH_NOT_FOUND # if already cached (even if nil was saved), then return it
|
63
|
+
|
64
|
+
|
65
|
+
clean_view_base_pathname = Pathname.for_path(view_base_path).expand_path.cleanpath # expanded and cleaned
|
66
|
+
clean_view_base_str = clean_view_base_pathname.to_s
|
67
|
+
clean_template_pathname = Pathname.for_path(template_path).expand_path(clean_view_base_pathname).cleanpath # expanded from view_base and cleaned
|
68
|
+
clean_template_str = clean_template_pathname.to_s
|
69
|
+
|
70
|
+
|
71
|
+
raise "MasterView::ConfigSettings.rails_views_dir_path is nil, need to set config.rails_views_dir_path" if mv_path.nil?
|
72
|
+
|
73
|
+
short_path = nil
|
74
|
+
if clean_template_str.starts_with?(mv_path) # if clean_template_path starts with MV_VIEW_DIR (both are absolute)
|
75
|
+
short_path = clean_template_str[mv_path.length+1..-1] # strip off MV_VIEW_DIR and return short path
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
#MasterView::Log.debug { "calc_short_path - short_path=#{short_path} view_base=#{view_base_path} template_path=#{template_path} RAILS_VIEW=#{@clean_mv_view_path}"} # todo comment out
|
81
|
+
#MasterView::Log.debug { "cspdetails- #{clean_view_base_str}+#{clean_template_str} <=> #{mv_path}"}
|
82
|
+
base_path_cache[template_path] = short_path # store in cache and return
|
83
|
+
end
|
84
|
+
|
85
|
+
# calculate the short path and if exists then retrieve the data from the mioTree, otherwise return nil
|
86
|
+
def calc_short_path_and_retrieve(view_base_path, template_path, mioTree)
|
87
|
+
calc_short_path_and_call_block(view_base_path, template_path, mioTree) do |mio|
|
88
|
+
mio.read
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# calculate the short_path and if exists return the mtime, otherwise nil
|
93
|
+
def calc_short_path_and_get_mtime(view_base_path, template_path, mioTree)
|
94
|
+
calc_short_path_and_call_block(view_base_path, template_path, mioTree) do |mio|
|
95
|
+
mio.mtime
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# get/create hash for view_base_path, class method
|
102
|
+
def short_path_cache(view_base_path) #:nodoc:
|
103
|
+
@short_path_cache[view_base_path] ||= {}
|
104
|
+
end
|
105
|
+
|
106
|
+
# calculate short path and if exists execute block
|
107
|
+
def calc_short_path_and_call_block(view_base_path, template_path, mioTree, &block)
|
108
|
+
short_path = calc_short_path(view_base_path, template_path)
|
109
|
+
if short_path
|
110
|
+
short_path_mio = mioTree.path(short_path)
|
111
|
+
if short_path_mio && short_path_mio.exist?
|
112
|
+
yield short_path_mio
|
113
|
+
else
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
else
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|