masterview 0.2.2 → 0.2.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.
Files changed (41) hide show
  1. data/CHANGELOG +14 -0
  2. data/RELEASE_NOTES +12 -0
  3. data/TODO +16 -1
  4. data/doc/configuration.html +19 -8
  5. data/doc/directives.html +173 -4
  6. data/doc/guide.html +2 -2
  7. data/doc/index.html +2 -2
  8. data/doc/stylesheets/masterview.css +13 -0
  9. data/examples/rails_app_config/masterview/environment/development.rb +2 -2
  10. data/lib/masterview/attr_string_parser.rb +105 -0
  11. data/lib/masterview/directive_base.rb +146 -14
  12. data/lib/masterview/directive_helpers.rb +22 -8
  13. data/lib/masterview/directive_registry.rb +169 -0
  14. data/lib/masterview/directives/check_box.rb +31 -0
  15. data/lib/masterview/directives/collection_select.rb +44 -0
  16. data/lib/masterview/directives/hidden_field.rb +2 -2
  17. data/lib/masterview/directives/image_tag.rb +4 -1
  18. data/lib/masterview/directives/insert_generated_comment.rb +7 -6
  19. data/lib/masterview/directives/javascript_include.rb +4 -1
  20. data/lib/masterview/directives/password_field.rb +2 -2
  21. data/lib/masterview/directives/radio_button.rb +35 -0
  22. data/lib/masterview/directives/select.rb +38 -0
  23. data/lib/masterview/directives/stylesheet_link.rb +4 -1
  24. data/lib/masterview/directives/text_area.rb +2 -2
  25. data/lib/masterview/directives/text_field.rb +2 -2
  26. data/lib/masterview/extras/app/controllers/masterview_controller.rb +46 -59
  27. data/lib/masterview/extras/app/views/layouts/masterview_admin.rhtml +73 -0
  28. data/lib/masterview/extras/app/views/masterview/admin/configuration.rhtml +1 -0
  29. data/lib/masterview/extras/app/views/masterview/admin/list.rhtml +1 -1
  30. data/lib/masterview/initializer.rb +73 -20
  31. data/lib/masterview/masterview_info.rb +117 -0
  32. data/lib/masterview/masterview_version.rb +1 -1
  33. data/lib/masterview/parser.rb +22 -35
  34. data/lib/masterview/plugin_load_tracking.rb +17 -8
  35. data/lib/masterview.rb +3 -0
  36. data/test/fixtures/configs/fake_rails_app_with_config/config/masterview/environments/production.rb +5 -1
  37. data/test/unit/config_settings_test.rb +16 -4
  38. data/test/unit/directive_base_test.rb +29 -0
  39. data/test/unit/directive_helpers_parse_test.rb +324 -0
  40. data/test/unit/template_test.rb +242 -0
  41. metadata +14 -2
@@ -3,7 +3,9 @@ module MasterView
3
3
 
4
4
  #creates a link_to
5
5
  class Stylesheet_link < MasterView::DirectiveBase
6
- STYLESHEET_SRC_EXTRACT_REGEX = /public\/stylesheets\/(.*)/
6
+
7
+ # /public\/stylesheets\/(.*)/
8
+ STYLESHEET_SRC_EXTRACT_REGEX = MasterView::ConfigSettings.template_asset_base_ref_pattern[:stylesheets]
7
9
 
8
10
  def stag(dcs)
9
11
  end
@@ -19,5 +21,6 @@ module MasterView
19
21
  erb_content('stylesheet_link_tag ' + quote(ss_loc))
20
22
  end
21
23
  end
24
+
22
25
  end
23
26
  end
@@ -11,8 +11,8 @@ module MasterView
11
11
  obj = args[0]
12
12
  method = args[1]
13
13
 
14
- obj = quote(obj) unless obj =~ /^:|'|"/
15
- method = quote(method) unless method =~ /^:|'|"/
14
+ obj = quote_if(obj)
15
+ method = quote_if(method)
16
16
 
17
17
  options = {}
18
18
  options[:rows] = attrs_lck['rows'].to_i if attrs_lck['rows']
@@ -11,8 +11,8 @@ module MasterView
11
11
  obj = args[0]
12
12
  method = args[1]
13
13
 
14
- obj = quote(obj) unless obj =~ /^:|'|"/
15
- method = quote(method) unless method =~ /^:|'|"/
14
+ obj = quote_if(obj)
15
+ method = quote_if(method)
16
16
 
17
17
  options = {}
18
18
  options[:size] = attrs_lck['size'].to_i if attrs_lck['size']
@@ -44,13 +44,24 @@
44
44
  # [DJL 17-Jun-2006]
45
45
  #++
46
46
  #
47
+
48
+
47
49
  class MasterviewController < ApplicationController
48
50
 
49
51
  before_filter :check_authorization, :except => [ :access_not_allowed ]
50
52
 
53
+ ENABLE_ADMIN_LAYOUT = false #:nodoc: #UNDER CONSTRUCTION - fine idea, but doesn't work yet [DJL 03-Jun-2006]
54
+
51
55
  # Describe the MasterView configuration option settings
52
56
  def configuration
53
- render :text => configuration_html, :layout => true
57
+ if ENABLE_ADMIN_LAYOUT
58
+ smart_render_with_layout('masterview/admin/configuration', 'masterview_admin')
59
+ else
60
+ #ugly, but keep this version
61
+ aint_got_no_layout_backstop = '<div style="padding-top: 6px;">(back to <a href=".">Admin home</a>)</div>'
62
+ config_html = MasterView::Info.to_html( :postscript => aint_got_no_layout_backstop )
63
+ render :text => config_html
64
+ end
54
65
  end
55
66
 
56
67
  def index
@@ -155,61 +166,6 @@ class MasterviewController < ApplicationController
155
166
  end
156
167
  end
157
168
 
158
- # Answer an HTML rendering of the current MasterView configuration
159
- def configuration_html
160
- # This is a quick-and-dirty impl until a more elegant solution is provided
161
- #e.g. do something more like Rails::Info
162
-
163
- config = MasterView::ConfigSettings
164
-
165
- section_general_options = 'General Options'
166
- section_specs = [
167
- # [ <section-name>, [prop-name [, prop-name]... ] ]
168
- [ 'MasterView Roots',
169
- [ :mv_installation_dir, :rails_app?, :on_rails? ] ],
170
- [ section_general_options,
171
- [ :root_path, :config_dir_path, :environment ] ], #:directive_paths
172
- [ 'Template Source Options',
173
- [ :template_src_dir_path, :template_filename_pattern ] ],
174
- [ 'Template Generation Options',
175
- [ :template_dst_dir_path, :output_filename_extension, :generated_file_default_extension, :include_generated_file_comment ] ],
176
- [ 'Template Parsing Options',
177
- [ :default_parser_options, :namespace_prefix ] ],
178
- [ 'Rails Application Options',
179
- [ :parse_masterview_templates_at_startup, :reparse_changed_masterview_templates, :generate_rhtml_files ] ]
180
- ]
181
-
182
- #"<h1>MasterView Configuration</h1>\n<table>\n<tbody>\n#{html}</tbody>\n</table>\n<div style=\"padding-top: 6px;\">(back to <a href=\".\">Admin home</a>)</div>"
183
- html_config_settings = "<h1>MasterView Configuration</h1>\n<table>\n<tbody>\n%s</tbody>\n</table>\n<div style=\"padding-top: 6px;\">(back to <a href=\".\">Admin home</a>)</div>" % '%s'
184
-
185
- #"<tr style=\"background-color: #dcdcdc; font-weight: bold; margin-top: 6px;\"><td colspan=\"2\">#{section_name}</td></tr>"
186
- html_subsection_entry = '<tr style="background-color: #dcdcdc; font-weight: bold; margin-top: 6px;"><td colspan="2">%s</td></tr>' #parm: section_name
187
-
188
- # "<tr><td><b>#{option_name}</b></td><td>#{option_value}</td></tr>"
189
- html_option_entry = '<tr><td style="padding-left: 6px; padding-right: 6px; font-weight: bold;">%s</td><td>%s</td></tr>' #parms: option_name, option_value
190
-
191
- html = []
192
- section_specs.each { | section_name, options |
193
- html << html_subsection_entry % section_name
194
- options.each { | option |
195
- option_name = CGI.escapeHTML(option.to_s)
196
- option_value = config.send(option)
197
- #tbd: option_value.kind_of?(Hash) then make it pretty?
198
- option_value = option_value.nil? ? '(nil)' : CGI.escapeHTML(option_value.inspect)
199
- html << html_option_entry % [ option_name, option_value ]
200
- }
201
- if section_name == section_general_options
202
- option_name = 'logger'
203
- option_value = MasterView::Log.class.name
204
- html << html_option_entry % [ option_name, option_value ]
205
- option_name = 'log_level'
206
- option_value = MasterView.log_level
207
- html << html_option_entry % [ option_name, option_value ]
208
- end
209
- }
210
- html_config_settings % html.join("\n")
211
- end
212
-
213
169
  private
214
170
 
215
171
  # checks app path first for views and files, then falls back to files in MV
@@ -225,9 +181,40 @@ class MasterviewController < ApplicationController
225
181
  if File.exist?(local_path)
226
182
  render :template => short_path
227
183
  else
228
- mv_path = File.join(File.dirname(__FILE__), '../../app/views', short_path)+'.rhtml'
229
- MasterView::Log.debug { 'mv_path='+mv_path }
230
- render :file => mv_path
184
+ mv_path = File.join(File.dirname(__FILE__), '../../app/views', short_path)+'.rhtml'
185
+ MasterView::Log.debug { 'mv_path='+mv_path }
186
+ render :file => mv_path
187
+ end
188
+ end
189
+
190
+ # render local template file if exists otherwise render file from mv
191
+ def smart_render_with_layout(short_path, layout) #:nodoc: #UNDER CONSTRUCTION
192
+ #DOESN'T WORK YET - we get the right path, but need a way into template rendering
193
+ # (usual path through rails bolts in assumption of app/views rel path)
194
+ # [DJL 03-Jul-2006]
195
+ local_path = File.join(RAILS_ROOT, 'app/views', short_path)+'.rhtml'
196
+ if File.exist?(local_path)
197
+ render :template => short_path, :layout => smart_layout_path(layout)
198
+ else
199
+ mv_path = File.join(File.dirname(__FILE__), '../../app/views', short_path)+'.rhtml'
200
+ MasterView::Log.debug { 'mv_path='+mv_path }
201
+ render :file => mv_path, :layout => smart_layout_path(layout)
202
+ end
203
+ end
204
+
205
+ def smart_layout_path(short_path) #:nodoc: #UNDER CONSTRUCTION
206
+ local_path = File.join(RAILS_ROOT, 'app/views/layouts', short_path)+'.rhtml'
207
+ if File.exist?(local_path)
208
+ short_path
209
+ else
210
+ mv_layouts_dir_path = File.expand_path( File.join(File.dirname(__FILE__), '../../app/views/layouts') )
211
+ mv_path = File.join(mv_layouts_dir_path, short_path)+'.rhtml'
212
+ if File.exist?(mv_path)
213
+ MasterView::Log.debug { 'admin layout mv_path='+mv_path }
214
+ else
215
+ MasterView::Log.error { '***BAD ADMIN PAGE LAYOUT REF: mv_path='+mv_path }
216
+ end
217
+ mv_path
231
218
  end
232
219
  end
233
220
 
@@ -0,0 +1,73 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml"
5
+ xml:lang="en" lang="en">
6
+
7
+ <head>
8
+ <title>MasterView Admin</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+
11
+ <%= stylesheet_link_tag 'masterview/style' %>
12
+ <%= stylesheet_link_tag 'masterview/sidebox' %>
13
+ <%= stylesheet_link_tag 'masterview/color-scheme' %>
14
+ <%= javascript_include_tag :defaults %>
15
+ </head>
16
+
17
+ <body>
18
+
19
+ <!-- ###### Header ###### -->
20
+
21
+ <div id="header">
22
+ <span class="headerTitle">Admin</span>
23
+ <div class="menuBar">
24
+ <%= link_to 'Home', :action => :index %>
25
+ <!-- | <a href="">Another link</a> -->
26
+ </div>
27
+ </div>
28
+
29
+
30
+ <div class="main">
31
+
32
+ <div class="mv_admin_list sidebar LHS">
33
+ <h2>Tasks:</h2>
34
+ <ul>
35
+ <li><%= link_to 'View Configuration', :action => 'configuration' %></li>
36
+ <li><%= link_to 'View Loaded Features', :action => 'features' %></li>
37
+ <li style="margin-top: 6px; padding-top: 4px; border-top: 1px dashed;"><%= link_to 'Rebuild all outdated templates', :action => 'rebuild_all' %></li>
38
+ </ul>
39
+ </div>
40
+
41
+ <div class="mv_admin_list content">
42
+ <h1>MasterView Admin</h1>
43
+
44
+ <% if @flash[:notice] %>
45
+ <div class="messages" id="admin_messages">
46
+ <%= h @flash[:notice] %>
47
+ </div>
48
+ <% end %>
49
+
50
+ <%= @content_for_layout %>
51
+
52
+ </div>
53
+
54
+ </div>
55
+
56
+ <!-- ###### Footer ###### -->
57
+
58
+ <div id="footer">
59
+ <div class="footerLHS">
60
+ <a href="http://validator.w3.org/check/referer">Valid XHTML 1.0 Strict</a>
61
+ </div>
62
+
63
+ <div class="footerLHS">
64
+ <a href="http://jigsaw.w3.org/css-validator/check/referer">Valid CSS 2</a>
65
+ </div>
66
+
67
+ <div>
68
+ <a href="http://masterview.org">Powered by MasterView</a>
69
+ </div>
70
+ </div>
71
+
72
+ </body>
73
+ </html>
@@ -0,0 +1 @@
1
+ <%= MasterView::Info.to_html() %>
@@ -28,7 +28,7 @@
28
28
  <ul>
29
29
  <li><%= link_to 'View Configuration', :action => 'configuration' %></li>
30
30
  <li><%= link_to 'View Loaded Features', :action => 'features' %></li>
31
- <li><%= link_to 'Rebuild all outdated templates', :action => 'rebuild_all' %></li>
31
+ <li style="margin-top: 6px; padding-top: 4px; border-top: 1px dashed;"><%= link_to 'Rebuild all outdated templates', :action => 'rebuild_all' %></li>
32
32
  </ul>
33
33
  </div>
34
34
 
@@ -227,6 +227,27 @@ module MasterView
227
227
  # Default: <tt>'*.html'</tt>
228
228
  attr_accessor :template_filename_pattern
229
229
 
230
+ # Regex pattern specifications for identifying the base directory
231
+ # on asset references in a template document to convert
232
+ # design-time assert references for images, stylesheets,
233
+ # and javascript files into relative references for use
234
+ # with the standard Rails asset helper functions.
235
+ #
236
+ # The patterns are a hash indexed by asset type.
237
+ # Asset types are :images, :stylesheets, :javascripts
238
+ #
239
+ # The standard patterns match path prefixes up through
240
+ # <code>public/<i>asset-type</i></code>. For example,
241
+ # an <code>mv:stylesheet_link</code> directive of the form:
242
+ #
243
+ # <link rel="stylesheet" type="text/css" href="../../../public/stylesheets/mystyles.css" mv:stylesheet_link="" />
244
+ #
245
+ # would match the standard base-dir prefix and result in:
246
+ #
247
+ # <%= stylesheet_link_tag "mystyles" %>
248
+ #
249
+ attr_accessor :template_asset_base_ref_pattern
250
+
230
251
  # === Template Generation Options
231
252
 
232
253
  # Path to the directory where Masterview template output (rhtml)
@@ -415,6 +436,8 @@ module MasterView
415
436
  rails_app_root_path = params[:rails_app_root_path]
416
437
  env = params[:environment]
417
438
 
439
+ is_development = env == 'development'
440
+
418
441
  program_root_path = File.expand_path( '.' )
419
442
  #assert program_root_path == Dir.pwd
420
443
 
@@ -487,6 +510,7 @@ module MasterView
487
510
  self.config_dir_path = rails_app? ? "config/masterview" : nil
488
511
  self.environment = on_rails? ? ::RAILS_ENV : env
489
512
  self.directive_paths = [ builtin_directives_path ]
513
+ discover_standard_directive_path_additions()
490
514
 
491
515
  #TODO: if rails_app? && File.exist?( "#{rails_root_path}/app/masterview/directives" ) THEN append it as well
492
516
  self.rebuild_backups_tmp_dir_path = rails_app? ? File.join( rails_root_path, 'tmp/masterview/rebuild/backups') : nil
@@ -507,6 +531,11 @@ module MasterView
507
531
  # template source options
508
532
  self.template_src_dir_path = rails_app? ? 'app/views' : 'masterview/templates' # bolts down abs ref
509
533
  self.template_filename_pattern = '*.html'
534
+ self.template_asset_base_ref_pattern = {
535
+ :images => /public\/images\/(.*)/,
536
+ :stylesheets => /public\/stylesheets\/(.*)/,
537
+ :javascripts => /public\/javascripts\/(.*)/,
538
+ }
510
539
 
511
540
  STDOUT.puts "...template_src_dir_path=#{template_src_dir_path || 'nil'}" if debug_TRACE_HACK
512
541
 
@@ -538,8 +567,8 @@ module MasterView
538
567
  # Rails application options
539
568
  self.parse_masterview_templates_at_startup = true
540
569
  self.reparse_changed_masterview_templates = on_rails? ? (not ActionController::Base.perform_caching) : false
541
- self.enable_admin_pages = false
542
- self.enable_view_rhtml = false
570
+ self.enable_admin_pages = is_development
571
+ self.enable_view_rhtml = is_development
543
572
  self.generate_rhtml_files = false
544
573
 
545
574
  STDOUT.puts "...mv config initialized with default settings\n" if debug_TRACE_HACK
@@ -559,6 +588,16 @@ module MasterView
559
588
  true
560
589
  end
561
590
 
591
+ # automatically append directives in std app dir to mv builtins, if available
592
+ def discover_standard_directive_path_additions() #:nodoc:
593
+ return if ! rails_app? #?or can we take a point of view of std loc? e.g., 'masterview/directives'
594
+ app_directives_path = rails_app? ? "app/masterview/directives" : nil #??"masterview/directives"?
595
+ app_directives_path = File.join( root_path, app_directives_path )
596
+ if File.directory?(app_directives_path) #?and not empty?
597
+ directive_paths << app_directives_path #root_path already expanded
598
+ end
599
+ end
600
+
562
601
  # The path to the application's config settings file.
563
602
  # By default the file is at <tt>config/masterview/settings.rb</tt>.
564
603
  def app_settings_path
@@ -641,6 +680,7 @@ module MasterView
641
680
  # instance.
642
681
  def initialize(configuration) #:nodoc:
643
682
  @configuration = configuration
683
+ @log_msg_q = [] # collect log messages that arrive prior to the logger
644
684
  end
645
685
 
646
686
  # Load the MasterView configuration settings
@@ -659,7 +699,6 @@ module MasterView
659
699
  #?? return if MasterView.const_defined?(:ConfigSettings) ??
660
700
  load_config_settings
661
701
  ensure_valid_settings
662
- discover_standard_directive_path_additions
663
702
  install_config_settings
664
703
  # make a final check for running_rails? (in case config settings changed scripts spec)
665
704
  configuration.decide_if_running_rails
@@ -695,21 +734,6 @@ module MasterView
695
734
  eval(IO.read(config_file_path), binding)
696
735
  end
697
736
 
698
- def discover_standard_directive_path_additions #:nodoc:
699
- #TODO: check for config/masterview/directives and automatically
700
- # append to the configuration.directive_paths if found.
701
- # We have to wait until all the config settings are loaded so that
702
- # all references to root locations and client's own prefs for
703
- # locating directives.
704
- # [DJL 01-Jun-2006]
705
- #... something like:
706
- #return if not config_dir_path
707
- #config_directives_path = File.join(configuration.config_dir_path, 'directives')
708
- #if File.directory?(config_directives_path)
709
- # configuration.directivePaths << File.expand_path(config_directives_path unless it's already there
710
- #end
711
- end
712
-
713
737
  # ensure that the requested configuration settings are consistent and valid
714
738
  # before we actually install anything. Normalize representations as needed.
715
739
  def ensure_valid_settings #:nodoc:
@@ -718,8 +742,22 @@ module MasterView
718
742
 
719
743
  #??config.root_path = File.expand_path(config.root_path) if config.root_path #?? ensure bolted down firmly?
720
744
 
721
-
722
- ####if config.directive_paths.length > 1 then expand_path on user-appended entries??
745
+ # ensure that the directive load path entries are clean and available
746
+ if not config.directive_paths.empty?
747
+ clean_paths = []
748
+ config.directive_paths.each { | dir |
749
+ if dir.nil? || ! File.directory?(dir)
750
+ err_msg = "Invalid directive load path directory: '#{dir}'"
751
+ #overzealous: raise InvalidPathError.new()
752
+ #but doesn't exist yet: Log.error err_mage
753
+ @log_msg_q << [ :error, err_msg ]
754
+ else
755
+ dir_path = File.expand_path( dir )
756
+ clean_paths << dir_path if ! clean_paths.include?(dir_path) # no dups
757
+ end
758
+ }
759
+ config.directive_paths = clean_paths
760
+ end
723
761
 
724
762
  # template source and generation options
725
763
  if config.on_rails?
@@ -801,6 +839,8 @@ module MasterView
801
839
  #?? return if MasterView.const_defined?(:Initialized) ??
802
840
  initialize_mio
803
841
  initialize_logger
842
+ #Back out experiment: causes load order problems
843
+ ##load_directives # held off on this until logger is installed
804
844
  install_in_rails
805
845
  # mark the module as fully loaded and configured
806
846
  MasterView.const_set('Initialized', true)
@@ -834,6 +874,19 @@ module MasterView
834
874
  def initialize_logger #:nodoc:
835
875
  #?return if defined?(Log)
836
876
  require 'masterview/extras/init_logger'
877
+ # Kick out any queued-up log messages yearning to be free
878
+ @log_msg_q.each { | msg_level, msg |
879
+ Log.send err_level, msg
880
+ }
881
+ @log_msg_q.clear
882
+ end
883
+
884
+ def load_directives #:nodoc:
885
+ # get the directives loaded prior to firing up any template parsing
886
+ return if ! configuration.on_rails? #ISSUE: causes problem for test cases; is this ever a good idea??
887
+ MasterView::DirectivesRegistry.process_directives_load_path(
888
+ configuration.directive_paths,
889
+ configuration.namespace_prefix )
837
890
  end
838
891
 
839
892
  def install_in_rails #:nodoc:
@@ -0,0 +1,117 @@
1
+ #--
2
+ # Copyright (c) 2006 Jeff Barczewski and Deborah Lewis
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+ #--
24
+ # This gadget is (roughly) modelled after the Rails builtin/rails_info facility.
25
+ # We don't provide masterview_info_controller in quite the same way,
26
+ # since at the moment we just want to use this in our Admin controller,
27
+ # but the Info module approach for exposing config properties is kinda nice.
28
+ # [DJL 03-Jul-2006]
29
+ #++
30
+
31
+ module MasterView
32
+ module Info #:nodoc:
33
+
34
+ PROP_CATEGORY_ROOTS = 'MasterView Roots'
35
+ PROP_CATEGORY_GENERAL_OPTIONS = 'General Options'
36
+ PROP_CATEGORY_TEMPLATE_SRC_OPTIONS = 'Template Source Options'
37
+ PROP_CATEGORY_TEMPLATE_GEN_OPTIONS = 'Template Generation Options'
38
+ PROP_CATEGORY_TEMPLATE_PARSE_OPTIONS = 'Template Parsing Options'
39
+ PROP_CATEGORY_RAILS_APP_OPTIONS = 'Rails Application Options'
40
+
41
+ CATEGORIZED_PROPERTY_SPECS = [
42
+ # [ <section-name>, [prop-name [, prop-name]... ] ]
43
+ [ PROP_CATEGORY_ROOTS,
44
+ [ :mv_installation_dir, :rails_app?, :on_rails? ] ],
45
+ [ PROP_CATEGORY_GENERAL_OPTIONS,
46
+ [ :root_path, :config_dir_path, :environment ] ], #:directive_paths
47
+ [ PROP_CATEGORY_TEMPLATE_SRC_OPTIONS,
48
+ [ :template_src_dir_path, :template_filename_pattern ] ],
49
+ [ PROP_CATEGORY_TEMPLATE_GEN_OPTIONS,
50
+ [ :template_dst_dir_path, :output_filename_extension, :generated_file_default_extension, :include_generated_file_comment ] ],
51
+ [ PROP_CATEGORY_TEMPLATE_PARSE_OPTIONS,
52
+ [ :default_parser_options, :namespace_prefix ] ],
53
+ [ PROP_CATEGORY_RAILS_APP_OPTIONS,
54
+ [ :parse_masterview_templates_at_startup, :reparse_changed_masterview_templates, :generate_rhtml_files ] ]
55
+ ]
56
+
57
+ PROPERTY_CATEGORIES = CATEGORIZED_PROPERTY_SPECS.collect { | catEntry | catEntry[0] }
58
+
59
+
60
+ # Answer an html rendering
61
+ def self.to_html( params={} )
62
+
63
+ # unpack the supported keyword args
64
+ # Provide HTML fragment templates; optionally include class/style attributes to control rendering
65
+ title_html_template = params.fetch( :title, '<h1>%s</h1>' ) #parms: MV Config title
66
+ preamble_html_template = params.fetch( :preamble, '<p><b>MasterView Version:</b> %s</p>' ) #parms: MasterView version
67
+ config_settings_html_template = params.fetch( :table, "<table>\n<tbody>%s</tbody>\n</table>" % ['%s'] ) #parms: section/property table rows
68
+ section_entry_attrs = params.fetch( :section_attrs, 'style="background-color: #dcdcdc; font-weight: bold; margin-top: 6px;"' )
69
+ section_entry_html_template = params.fetch( :section_entry, '<tr%s><td colspan="2">%s</td></tr>' ) #parms: :section_attrs, section_name
70
+ option_entry_name_attrs = params.fetch( :option_name_attrs, 'style="padding-left: 6px; padding-right: 6px; font-weight: bold;"' )
71
+ option_entry_value_attrs = params.fetch( :option_value_attrs, '' )
72
+ option_entry_html_template = params.fetch( :option_entry, '<tr><td%s>%s</td><td%s>%s</td></tr>' ) #parms: :option_name_attrs, option_name, :option_value_attrs, option_value
73
+ postscript_html = params.fetch( :postscript, '' ) #'<div style="padding-top: 6px;">(back to <a href=".">Admin home</a>)</div>'
74
+
75
+ # prepare our templates for convenient use during the generation loop below
76
+ config_settings_html_start, config_settings_html_end = config_settings_html_template.split('%s')
77
+ # ensure separator space for ' style="xxx"' on the section entry style/class attr(s)
78
+ section_entry_attrs.insert(0, ' ') if (section_entry_attrs && section_entry_attrs != '' && section_entry_attrs[0...1] != ' ')
79
+ section_entry_html_template = section_entry_html_template % [ section_entry_attrs, '%s' ] # install the optional style setting once, just plug in section_name hereafter
80
+ # ensure separator space for ' style="xxx"' on the option name/value style/class attr(s)
81
+ option_entry_name_attrs.insert(0, ' ') if (option_entry_name_attrs && option_entry_name_attrs != '' && option_entry_name_attrs[0...1] != ' ')
82
+ option_entry_value_attrs.insert(0, ' ') if (option_entry_value_attrs && option_entry_value_attrs != '' && option_entry_value_attrs[0...1] != ' ')
83
+ option_entry_html_template = option_entry_html_template % [ option_entry_name_attrs, '%s', option_entry_value_attrs, '%s' ] # install the optional style settings once, just plug in option name/value hereafter
84
+
85
+ # and off we go at last
86
+ config = MasterView::ConfigSettings
87
+ html = []
88
+ html << title_html_template % [ 'MasterView Configuration' ] if title_html_template # allow client to suppress
89
+ html << preamble_html_template % [ MasterView::VERSION::STRING ] if preamble_html_template
90
+ html << config_settings_html_start
91
+ CATEGORIZED_PROPERTY_SPECS.each { | section_name, options |
92
+ html << section_entry_html_template % section_name
93
+ options.each { | option |
94
+ option_name = CGI.escapeHTML(option.to_s)
95
+ option_value = config.send(option)
96
+ #tbd: option_value.kind_of?(Hash) then make it pretty?
97
+ option_value = option_value.nil? ? '(nil)' : CGI.escapeHTML(option_value.inspect)
98
+ html << option_entry_html_template % [ option_name, option_value ]
99
+ }
100
+ # hack in options which aren't direct properties of the MasterView::Configuration
101
+ if section_name == PROP_CATEGORY_GENERAL_OPTIONS
102
+ option_name = 'logger'
103
+ option_value = MasterView::Log.class.name
104
+ html << option_entry_html_template % [ option_name, option_value ]
105
+ option_name = 'log_level'
106
+ option_value = MasterView.log_level
107
+ html << option_entry_html_template % [ option_name, option_value ]
108
+ end
109
+ }
110
+ html << config_settings_html_end
111
+ html << postscript_html if postscript_html
112
+ html.join("\n")
113
+
114
+ end
115
+
116
+ end
117
+ end
@@ -2,7 +2,7 @@ module MasterView
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 2
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -232,7 +232,8 @@ module MasterView
232
232
  XHTMLEmptyElementNameSet = %w{ base meta link hr br param img area input col }.to_set
233
233
 
234
234
  attr_reader :directive_load_paths, :mv_ns, :keyword_expander, :default_extension
235
- attr_accessor :render_levels, :directive_classes, :default_render_handler, :serializer, :template_pathname, :template_full_pathname
235
+ attr_accessor :render_levels, :default_render_handler, :serializer, :template_pathname, :template_full_pathname
236
+ attr_reader :directives_registry #:nodoc:
236
237
 
237
238
  def self.last_renderer; @@last_renderer; end
238
239
 
@@ -251,6 +252,9 @@ module MasterView
251
252
  @default_extension = (options[:output_mio_tree]) ? options[:output_mio_tree].default_extension : IOMgr.erb.default_extension
252
253
  @keyword_expander = KeywordExpander.new
253
254
  @keyword_expander.set_template_pathname(self.template_pathname, @default_extension)
255
+ #ISSUE: if :additional_directive_paths then do cleaning and validity checks here and now
256
+ # (then we don't need to keep re-checking in DirectiveRegistry or other processing)
257
+ # [DJL 04-Jul-2006]
254
258
  self.directive_load_paths = ( DefaultDirectiveLoadPaths << options[:additional_directive_paths] ).flatten
255
259
  end
256
260
 
@@ -262,35 +266,24 @@ module MasterView
262
266
  # Sets directive_load_paths, re-requiring all the new load paths, however any directives that were
263
267
  # already required (and loaded) will still be in memory because these are not reset.
264
268
  def directive_load_paths=( directive_paths )
265
- @directive_classes = {}
266
- @auto_directives = []
267
- directive_paths.each do |directive_path|
268
- next if directive_path.nil?
269
- raise InvalidPathError.new('directive_path does not exist, path='+directive_path) unless File.exist? directive_path
270
- Dir.open( directive_path ).each { |fn| require "#{directive_path}/#{fn}" if fn =~ /[.]rb$/ }
271
269
 
270
+ @directives_registry = MasterView::DirectivesRegistry
271
+ #ISSUE: can we optimize this if there aren't :additional_directive_paths?
272
+ # Do we even need/want the notion of per-invocation :additional_directive_paths
273
+ # given that the directives load path is configurable for the client app?
274
+ # [DJL 04-Jul-2006]
275
+ directives_registry.load_directives( directive_paths ) #?? if directive_load_paths != DefaultDirectiveLoadPaths ??
276
+
277
+ # is this a good idea? no clear that we need/want to modify mv_ns after app initialization
278
+ # If so, this could be simplifed. Discuss with jeffb.
279
+ # [DJL 04-Jul-2006]
280
+ if @mv_ns != NamespacePrefix
281
+ @directives_registry = directives_registry.clone
272
282
  end
273
-
274
- Log.debug { 'directive plugins loaded:' +
275
- (DirectiveBase.loaded_classes.collect do |c|
276
- c.name.split(':').last #strip off Module prefixes for brevity
277
- end).inspect
278
- }
279
- DirectiveBase.loaded_classes.each do |lc|
280
- lc.on_load if lc.respond_to?(:on_load)
281
- full_attr_name = (lc.respond_to? :full_attr_name) ? lc.full_attr_name(@mv_ns) : build_full_attribute_name(@mv_ns, lc)
282
- @directive_classes[full_attr_name] = lc
283
- lcinstance = lc.new(nil)
284
- @auto_directives << lc if lcinstance.respond_to?(:global_directive?) && lcinstance.global_directive?
285
- end
286
- Log.debug { 'auto_directives='+@auto_directives.inspect }
287
- end
288
283
 
289
- # this method is invoked to build the full attribute name (the attribute which will be watched for in
290
- # html attibutes. It concatenates the namespace prefix to the class name after first removing any module
291
- # prefixes and then downcasing the first letter
292
- def build_full_attribute_name(mv_ns, directive_class)
293
- mv_ns+directive_class.name.split(':').last.downcase_first_letter
284
+ # only need to do the following if :additional_directive_paths or nonstd @mv_ns???
285
+ directives_registry.build_directive_maps( @mv_ns )
286
+
294
287
  end
295
288
 
296
289
  def modes
@@ -392,14 +385,8 @@ module MasterView
392
385
 
393
386
  def select_active_directives(tag_name, attributes, mode)
394
387
  selected = DirectiveSet.new
395
- directives_needed = []
396
- @auto_directives.each do |directive_class|
397
- directives_needed << directive_class.new(nil)
398
- end
399
- @directive_classes.each do |key,directive_class|
400
- directives_needed << directive_class.new(attributes.delete(key)) if attributes[key]
401
- end
402
- sorted_directives = directives_needed.sort do |x,y|
388
+ directive_processors = directives_registry.construct_directive_processors( attributes )
389
+ sorted_directives = directive_processors.sort do |x,y|
403
390
  xval = (x.respond_to?(:priority)) ? x.priority : DirectivePriorities::Medium
404
391
  yval = (y.respond_to?(:priority)) ? y.priority : DirectivePriorities::Medium
405
392
  xval <=> yval