dryml 1.1.0 → 1.3.0.RC

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.
@@ -1,7 +1,7 @@
1
1
  module Dryml
2
2
 
3
3
  class TemplateEnvironment
4
-
4
+
5
5
  class << self
6
6
  def inherited(subclass)
7
7
  subclass.compiled_local_names = []
@@ -26,10 +26,9 @@ module Dryml
26
26
  include ActionView::Helpers
27
27
  include Helper ## FIXME remove
28
28
 
29
- def initialize(view_name=nil, view=nil)
30
- unless view_name.nil? && view.nil?
29
+ def initialize(view=nil)
30
+ unless view.nil?
31
31
  @view = view
32
- @_view_name = view_name
33
32
  @_erb_binding = binding
34
33
  @_part_contexts = {}
35
34
  @_scoped_variables = ScopedVariables.new
@@ -49,14 +48,14 @@ module Dryml
49
48
  end
50
49
  end
51
50
 
52
- for attr in [:erb_binding, :part_contexts, :view_name,
51
+ for attr in [:erb_binding, :part_contexts,
53
52
  :this, :this_parent, :this_field, :this_key,
54
53
  :form_this, :form_field_path, :form_field_names]
55
54
  class_eval "def #{attr}; @_#{attr}; end"
56
55
  end
57
-
56
+
58
57
  def path_for_form_field
59
- @_form_field_path.nil? and raise Dryml::DrymlException,
58
+ @_form_field_path.nil? and raise Dryml::DrymlException,
60
59
  "DRYML cannot provide the correct form-field name here (this_field = #{this_field.inspect}, this = #{this.inspect})"
61
60
  @_form_field_path
62
61
  end
@@ -142,10 +141,10 @@ module Dryml
142
141
  object = this
143
142
  end
144
143
  end
145
-
144
+
146
145
  id = if (typed_id = object.try.typed_id)
147
146
  typed_id
148
- elsif object == @this
147
+ elsif object == this
149
148
  "this"
150
149
  end
151
150
  attribute ? "#{id}:#{attribute}" : id
@@ -160,26 +159,26 @@ module Dryml
160
159
  end
161
160
  res
162
161
  end
163
-
164
-
162
+
163
+
165
164
  def refresh_part(encoded_context, session, dom_id)
166
- context = Dryml::PartContext.for_refresh(encoded_context, @this, session)
167
-
165
+ context = Dryml::PartContext.for_refresh(encoded_context, this, session)
166
+
168
167
  with_part_context(context) do
169
168
  send("#{context.part_name}_part", *context.locals)
170
169
  end
171
170
  end
172
171
 
173
-
172
+
174
173
  def with_part_context(context, &block)
175
174
  this, this_field = context.this, context.this_field
176
-
175
+
177
176
  b = if context.form_field_path
178
177
  proc { with_form_context(:unknown, context.form_field_path, &block) }
179
178
  else
180
179
  block
181
180
  end
182
-
181
+
183
182
  if this && this_field
184
183
  new_object_context(this) { new_field_context(this_field, &b) }
185
184
  elsif this
@@ -206,11 +205,13 @@ module Dryml
206
205
 
207
206
  def find_polymorphic_tag(name, call_type=nil)
208
207
  call_type ||= (this.respond_to?(:member_class) && this.member_class) || this_type
209
-
210
208
  begin
211
209
  found = nil
212
210
  while true
213
- if respond_to?(poly_name = "#{name}__for_#{call_type.name.to_s.underscore.gsub('/', '__')}")
211
+ # ActiveSupport::TimeWithZone.name would return 'Time'
212
+ # so we add an exception to pick the right datetime type
213
+ type_name = ( call_type == ActiveSupport::TimeWithZone ? 'datetime' : call_type.name.to_s).underscore.gsub('/', '__')
214
+ if respond_to?(poly_name = "#{name}__for_#{type_name}")
214
215
  found = poly_name
215
216
  break
216
217
  else
@@ -236,7 +237,7 @@ module Dryml
236
237
  else
237
238
  res = context_map(string_or_array) { yield }
238
239
  end
239
- res.join
240
+ res.safe_join
240
241
  end
241
242
 
242
243
 
@@ -283,17 +284,17 @@ module Dryml
283
284
  parent, field, obj = Dryml.get_field_path(this, path)
284
285
  @_this, @_this_parent, @_this_field = obj, parent, field
285
286
  end
286
-
287
+
287
288
  if @_form_field_path
288
- @_form_field_path += path
289
+ @_form_field_path += path
289
290
  @_form_field_paths_by_object[@_this] = @_form_field_path
290
291
  end
291
-
292
+
292
293
  yield
293
294
  end
294
295
  end
295
-
296
-
296
+
297
+
297
298
  def find_form_field_path(object)
298
299
  back = []
299
300
  while object
@@ -310,8 +311,8 @@ module Dryml
310
311
  end
311
312
  end
312
313
  end
313
-
314
-
314
+
315
+
315
316
 
316
317
 
317
318
  def _tag_context(attributes)
@@ -331,13 +332,14 @@ module Dryml
331
332
 
332
333
 
333
334
  def with_form_context(form_this=this, form_field_path=[form_this.class.name.underscore])
335
+ ctx = [@_form_this, @_form_field_path, @_form_field_paths_by_object]
334
336
  @_form_this = form_this
335
337
  @_form_field_path = form_field_path
336
338
  @_form_field_paths_by_object = { form_this => form_field_path }
337
339
  res = scope.new_scope :in_form => true, :form_field_names => [] do
338
340
  yield
339
341
  end
340
- @_form_this = @_form_field_path = @_form_field_paths_by_object = nil
342
+ @_form_this, @_form_field_path, @_form_field_paths_by_object = ctx
341
343
  res
342
344
  end
343
345
 
@@ -348,7 +350,7 @@ module Dryml
348
350
 
349
351
 
350
352
  def _tag_locals(attributes, locals)
351
- attributes.symbolize_keys!
353
+ attributes = attributes.symbolize_keys
352
354
  #ensure with and field are not in attributes
353
355
  attributes.delete(:with)
354
356
  attributes.delete(:field)
@@ -386,13 +388,13 @@ module Dryml
386
388
  def call_tag_parameter(the_tag, attributes, parameters, caller_parameters, param_name)
387
389
  overriding_proc = caller_parameters[param_name]
388
390
  replacing_proc = caller_parameters[:"#{param_name}_replacement"]
389
-
391
+
390
392
  unless param_name == the_tag || param_name == :default
391
393
  classes = attributes[:class]
392
394
  param_class = param_name.to_s.gsub('_', '-')
393
395
  attributes[:class] = if classes
394
396
  classes =~ /\b#{param_class}\b/ ? classes : "#{classes} #{param_class}"
395
- else
397
+ else
396
398
  param_class
397
399
  end
398
400
  end
@@ -456,7 +458,7 @@ module Dryml
456
458
  else
457
459
  proc { |default| default_content.call(default) if default_content }
458
460
  end
459
- parameters = parameters.merge(:default => d)
461
+ parameters = parameters.merge(:default => d)
460
462
  end
461
463
 
462
464
  if the_tag.is_one_of?(String, Symbol)
@@ -511,25 +513,17 @@ module Dryml
511
513
  end
512
514
  end
513
515
  end
514
-
515
-
516
+
517
+
516
518
  def merge_parameter_hashes(given_parameters, overriding_parameters)
517
519
  to_merge = given_parameters.keys & overriding_parameters.keys
518
520
  no_merge = overriding_parameters.keys - to_merge
519
521
  result = given_parameters.dup
520
-
522
+
521
523
  no_merge.each { |k| result[k] = overriding_parameters[k] }
522
524
  to_merge.each { |k| result[k] = merge_tag_parameter(given_parameters[k], overriding_parameters[k])}
523
-
524
- result
525
- end
526
-
527
-
528
525
 
529
-
530
- def part_contexts_javascripts
531
- storage = part_contexts_storage
532
- storage.blank? ? "" : "<script type=\"text/javascript\">\n#{storage}</script>\n"
526
+ result
533
527
  end
534
528
 
535
529
 
@@ -541,14 +535,7 @@ module Dryml
541
535
  def render_tag(tag_name, attributes)
542
536
  method_name = tag_name.to_s.gsub('-', '_')
543
537
  if respond_to?(method_name)
544
- res = send(method_name, attributes).strip
545
-
546
- # TODO: Temporary hack to get the dryml metadata comments in the right place
547
- if false && RAILS_ENV == "development"
548
- res.gsub(/^(.*?)(<!DOCTYPE.*?>).*?(<html.*?>)/m, "\\2\\3\\1")
549
- else
550
- res
551
- end
538
+ send(method_name, attributes).strip
552
539
  else
553
540
  false
554
541
  end
@@ -580,14 +567,13 @@ module Dryml
580
567
  end
581
568
  attr_string = " #{attrs.sort * ' '}" unless attrs.empty?
582
569
  end
583
-
584
- content = new_context { yield } if block_given?
570
+ content = capture { new_context &block } if block_given?
585
571
  res = if empty
586
- "<#{name}#{attr_string}#{scope.xmldoctype ? ' /' : ''}>"
572
+ "<#{name}#{attr_string}#{scope.xmldoctype ? ' /' : ''}>".html_safe
587
573
  else
588
- "<#{name}#{attr_string}>#{content}</#{name}>"
574
+ "<#{name}#{attr_string}>".html_safe + content + "</#{name}>".html_safe
589
575
  end
590
- if block_called_from_erb? block
576
+ if content.is_a? ActionView::NonConcattingString
591
577
  concat res
592
578
  else
593
579
  res
data/lib/dryml.rb CHANGED
@@ -4,294 +4,232 @@
4
4
  # Copyright:: Copyright (c) 2008
5
5
  # License:: Distributes under the same terms as Ruby
6
6
 
7
-
8
-
9
- # gem dependencies
10
- require 'hobosupport'
7
+ require 'hobo_support'
11
8
  require 'action_pack'
12
- require 'active_record' if ActionPack::VERSION::MAJOR==2 && ActionPack::VERSION::MINOR==2
13
-
14
- if ActiveSupport.const_defined? :Dependencies
15
- if ActiveSupport::Dependencies.respond_to?(:autoload_paths)
16
- ActiveSupport::Dependencies.autoload_paths |= [ File.dirname(__FILE__)]
17
- else
18
- ActiveSupport::Dependencies.load_paths |= [ File.dirname(__FILE__)]
19
- end
20
- end
21
9
 
22
- # Hobo can be installed in /vendor/hobo, /vendor/plugins/hobo, vendor/plugins/hobo/hobo, etc.
23
- ::DRYML_ROOT = File.expand_path(File.dirname(__FILE__) + "/..")
10
+ ActiveSupport::Dependencies.autoload_paths |= [File.dirname(__FILE__)]
24
11
 
25
12
  # The Don't Repeat Yourself Markup Language
26
13
  module Dryml
27
14
 
28
- VERSION = "1.1.0"
29
-
30
- class DrymlSyntaxError < RuntimeError; end
31
-
32
- class DrymlException < Exception
33
- def initialize(message, path=nil, line_num=nil)
34
- if path && line_num
35
- super(message + " -- at #{path}:#{line_num}")
36
- else
37
- super(message)
38
- end
39
- end
40
- end
41
-
42
- TagDef = Struct.new "TagDef", :name, :attrs, :proc
15
+ VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
16
+ @@root = Pathname.new File.expand_path('../..', __FILE__)
17
+ def self.root; @@root; end
43
18
 
44
- RESERVED_WORDS = %w{if for while do class else elsif unless case when module in}
19
+ class DrymlSyntaxError < RuntimeError; end
45
20
 
46
- EMPTY_PAGE = "[tag-page]"
47
-
48
- APPLICATION_TAGLIB = { :src => "taglibs/application" }
49
- CORE_TAGLIB = { :src => "core", :plugin => "dryml" }
50
-
51
- DEFAULT_IMPORTS = defined?(ApplicationHelper) ? [ApplicationHelper] : []
52
-
53
- @renderer_classes = {}
54
- @tag_page_renderer_classes = {}
55
-
56
- extend self
57
-
58
- attr_accessor :last_if
59
-
60
- def enable(generator_directories=[], output_directory=".")
61
- ActionView::Template.register_template_handler("dryml", Dryml::TemplateHandler)
62
- if ActionView::Template.respond_to? :exempt_from_layout
63
- ActionView::Template.exempt_from_layout('dryml')
64
- elsif
65
- ActionView::Base.exempt_from_layout('dryml')
66
- end
67
- DrymlGenerator.enable(generator_directories, output_directory)
68
- end
69
-
70
-
71
- def precompile_taglibs
72
- Dir.chdir(RAILS_ROOT) do
73
- taglibs = Dir["vendor/plugins/**/taglibs/**/*.dryml"] + Dir["app/views/taglibs/**/*.dryml"]
74
- taglibs.each do |f|
75
- Dryml::Taglib.get(:template_dir => File.dirname(f), :src => File.basename(f).remove(".dryml"))
76
- end
21
+ class DrymlException < Exception
22
+ def initialize(message, path=nil, line_num=nil)
23
+ if path && line_num
24
+ super(message + " -- at #{path}:#{line_num}")
25
+ else
26
+ super(message)
77
27
  end
78
28
  end
79
-
80
-
81
- def clear_cache
82
- @renderer_classes = {}
83
- @tag_page_renderer_classes = {}
84
- end
85
-
86
- def render_tag(view, tag, options={})
87
- renderer = empty_page_renderer(view)
88
- renderer.render_tag(tag, options)
89
- end
90
-
91
-
92
- def empty_page_renderer(view)
93
- controller_name = view.controller.class.name.underscore.sub(/_controller$/, "")
94
- page_renderer(view, [], "#{controller_name}/#{EMPTY_PAGE}")
95
- end
96
-
97
-
98
- def page_renderer_for_template(view, local_names, template)
99
- page_renderer(view, local_names, template.path_without_extension, template.filename)
100
- end
101
-
102
-
103
- def page_renderer(view, local_names=[], page=nil, filename=nil)
104
- if RAILS_ENV == "development"
105
- clear_cache
106
- Taglib.clear_cache
107
- end
108
-
109
- prepare_view!(view)
110
- included_taglibs = ([APPLICATION_TAGLIB, subsite_taglib(page)] + controller_taglibs(view.controller.class)).compact
111
-
112
- if page.ends_with?(EMPTY_PAGE)
113
- # DELETE ME: controller_class = controller_class_for(page)
114
- controller_class = view.controller.class
115
- @tag_page_renderer_classes[controller_class.name] ||=
116
- make_renderer_class("", page, local_names, DEFAULT_IMPORTS, included_taglibs)
117
- @tag_page_renderer_classes[controller_class.name].new(page, view)
118
- else
119
- filename ||= if view.view_paths.respond_to? :find_template
120
- # Rails 2.3
121
- view.view_paths.find_template(page + ".dryml").filename
122
- else
123
- # Rails 2.2
124
- view._pick_template(page + ".dryml").filename
125
- end
126
- mtime = File.mtime(filename)
127
- renderer_class = @renderer_classes[page]
29
+ end
128
30
 
129
- # do we need to recompile?
130
- if (!renderer_class || # nothing cached?
131
- (local_names - renderer_class.compiled_local_names).any? || # any new local names?
132
- renderer_class.load_time < mtime) # cache out of date?
133
- renderer_class = make_renderer_class(File.read(filename), filename, local_names,
134
- DEFAULT_IMPORTS, included_taglibs)
135
- renderer_class.load_time = mtime
136
- @renderer_classes[page] = renderer_class
137
- end
138
- renderer_class.new(page, view)
31
+ TagDef = Struct.new "TagDef", :name, :attrs, :proc
32
+ RESERVED_WORDS = %w{if for while do class else elsif unless case when module in}
33
+ ID_SEPARATOR = '; dryml-tag: '
34
+ APPLICATION_TAGLIB = { :src => "taglibs/application" }
35
+ CORE_TAGLIB = { :src => "core", :plugin => "dryml" }
36
+ DEFAULT_IMPORTS = defined?(ApplicationHelper) ? [ApplicationHelper] : []
37
+ @cache = {}
38
+ extend self
39
+ attr_accessor :last_if
40
+
41
+ def precompile_taglibs
42
+ Dir.chdir(Rails.root) do
43
+ Dir["app/views/taglibs/**/*.dryml"].each do |f|
44
+ Taglib.get(:template_dir => File.dirname(f), :src => File.basename(f).remove(".dryml"))
139
45
  end
140
46
  end
47
+ end
141
48
 
49
+ def clear_cache
50
+ @cache = {}
51
+ end
142
52
 
143
- # TODO: Delete this - not needed (use view.controller.class)
144
- def controller_class_for(page)
145
- controller, view = Controller.controller_and_view_for(page)
146
- "#{controller.camelize}Controller".constantize
147
- end
148
-
53
+ def render_tag(view, tag, options={})
54
+ renderer = empty_page_renderer(view)
55
+ renderer.render_tag(tag, options)
56
+ end
149
57
 
150
- def controller_taglibs(controller_class)
151
- controller_class.try.included_taglibs || []
152
- end
58
+ def empty_page_renderer(view)
59
+ page_renderer(view, page_tag_identifier(view.controller.controller_path))
60
+ end
153
61
 
62
+ def page_tag_identifier(controller_path, tag_name='')
63
+ "controller: #{controller_path}#{ID_SEPARATOR}#{tag_name}"
64
+ end
154
65
 
155
- def subsite_taglib(page)
156
- parts = page.split("/")
157
- subsite = parts.length >= 3 ? parts[0..-3].join('_') : "front"
158
- src = "taglibs/#{subsite}_site"
159
- { :src => src } if Object.const_defined?(:RAILS_ROOT) && File.exists?("#{RAILS_ROOT}/app/views/#{src}.dryml")
66
+ def call_render(view, local_assigns, identifier)
67
+ renderer = page_renderer(view, identifier, local_assigns.keys)
68
+ this = view.controller.send(:dryml_context) || local_assigns[:this]
69
+ view.instance_variable_set("@this", this)
70
+ if identifier =~ /#{ID_SEPARATOR}/
71
+ tag_name = identifier.split(ID_SEPARATOR).last
72
+ renderer.render_tag(tag_name, {:with => this} )
73
+ else
74
+ renderer.render_page(this, local_assigns).strip
160
75
  end
76
+ end
161
77
 
162
- def get_field(object, field)
163
- return nil if object.nil?
164
- field_str = field.to_s
165
- begin
166
- return object.send(field_str)
167
- rescue NoMethodError => ex
168
- if field_str =~ /^\d+$/
169
- return object[field.to_i]
170
- else
171
- return object[field]
172
- end
78
+ def page_renderer(view, identifier, local_names=[], controller_path=nil)
79
+ controller_path ||= view.controller.controller_path
80
+ if identifier =~ /#{ID_SEPARATOR}/
81
+ identifier = identifier.split(ID_SEPARATOR).first
82
+ @cache[identifier] ||= make_renderer_class("", "", local_names, taglibs_for(controller_path))
83
+ @cache[identifier].new(view)
84
+ else
85
+ mtime = File.mtime(identifier)
86
+ renderer_class = @cache[identifier]
87
+ # do we need to recompile?
88
+ if (!renderer_class || # nothing cached?
89
+ (local_names - renderer_class.compiled_local_names).any? || # any new local names?
90
+ renderer_class.load_time < mtime) # cache out of date?
91
+ renderer_class = make_renderer_class(File.read(identifier), identifier,
92
+ local_names, taglibs_for(controller_path))
93
+ renderer_class.load_time = mtime
94
+ @cache[identifier] = renderer_class
173
95
  end
96
+ renderer_class.new(view)
174
97
  end
98
+ end
175
99
 
176
-
177
- def get_field_path(object, path)
178
- path = if path.is_a? String
179
- path.split('.')
180
- else
181
- Array(path)
182
- end
183
-
184
- parent = nil
185
- path.each do |field|
186
- return nil if object.nil?
187
- parent = object
188
- object = get_field(parent, field)
189
- end
190
- [parent, path.last, object]
191
- end
192
-
193
-
194
- def prepare_view!(view)
195
- # Not sure why this isn't done for me...
196
- # There's probably a button to press round here somewhere
197
- for var in %w(@flash @cookies @action_name @_session @_request @request_origin
198
- @template @request @ignore_missing_templates @_headers @variables_added
199
- @_flash @response @template_class
200
- @_cookies @before_filter_chain_aborted @url
201
- @_response @template_root @headers @_params @params @session)
202
- unless @view.instance_variables.include?(var)
203
- view.instance_variable_set(var, view.controller.instance_variable_get(var))
204
- end
205
- end
100
+ def get_field(object, field)
101
+ return nil if object.nil?
102
+ field_str = field.to_s
103
+ case
104
+ when object.respond_to?(field_str)
105
+ object.send(field_str)
106
+ when field_str =~ /^\d+$/
107
+ object[field.to_i]
108
+ else
109
+ object[field]
206
110
  end
111
+ end
207
112
 
208
- # create and compile a renderer class (AKA Dryml::Template::Environment)
209
- #
210
- # template_src:: the DRYML source
211
- # template_path:: the filename of the source. This is used for
212
- # caching
213
- # locals:: local variables.
214
- # imports:: A list of helper modules to import. For example, Hobo
215
- # uses [Hobo::HoboHelper, Hobo::Translations,
216
- # ApplicationHelper]
217
- # included_taglibs:: A list of Taglibs to include. { :src =>
218
- # "core", :plugin => "dryml" } is automatically
219
- # added to this list.
220
- #
221
- def make_renderer_class(template_src, template_path, locals=[], imports=[], included_taglibs=[])
222
- renderer_class = Class.new(TemplateEnvironment)
223
- compile_renderer_class(renderer_class, template_src, template_path, locals, imports, included_taglibs)
224
- renderer_class
113
+ def get_field_path(object, path)
114
+ return nil if object.nil?
115
+ path = path.is_a?(String) ? path.split('.') : Array(path)
116
+ parent = nil
117
+ path.each do |field|
118
+ parent = object
119
+ object = get_field(parent, field)
225
120
  end
121
+ [parent, path.last, object]
122
+ end
226
123
 
124
+ def unreserve(word)
125
+ word = word.to_s
126
+ word += '_' if RESERVED_WORDS.include?(word)
127
+ word
128
+ end
227
129
 
228
- def compile_renderer_class(renderer_class, template_src, template_path, locals, imports, included_taglibs=[])
229
- template = Dryml::Template.new(template_src, renderer_class, template_path)
230
- imports.each {|m| template.import_module(m)}
130
+ def static_tags
131
+ @static_tags ||= begin
132
+ path = if Object.const_defined?(:Rails) && FileTest.exists?("#{Rails.root}/config/dryml_static_tags.txt")
133
+ "#{Rails.root}/config/dryml_static_tags.txt"
134
+ else
135
+ File.join(File.dirname(__FILE__), "dryml/static_tags")
136
+ end
137
+ File.readlines(path).*.chop
138
+ end
139
+ end
231
140
 
232
- taglibs = [CORE_TAGLIB] + included_taglibs
141
+ attr_writer :static_tags
142
+
143
+ # FIXME: This helper seems to be useless, since it does need Rails,
144
+ # and with Rails it is useless since Dryml does not need Hobo
145
+ #
146
+ # Helper function for use outside Hobo/Rails
147
+ #
148
+ # Pass the template context in locals[:this]
149
+ #
150
+ # This function caches. If the mtime of template_path is older
151
+ # than the last compilation time, the cached version will be
152
+ # used. If no template_path is given, template_src is used as the
153
+ # key to the cache.
154
+ #
155
+ # If a local variable is not present when the template is
156
+ # compiled, it will be ignored when the template is used. In
157
+ # other words, the variable values may change, but the names may
158
+ # not.
159
+ #
160
+ # included_taglibs is only used during template compilation.
161
+ #
162
+ # @param [String] template_src the DRYML source
163
+ # @param [Hash] locals local variables.
164
+ # @param [String, nil] template_path the filename of the source.
165
+ # @param [Array] included_taglibs A list of Taglibs to include. { :src =>
166
+ # "core", :plugin => "dryml" } is automatically
167
+ # added to this list.
168
+ # @param [ActionView::Base] view an ActionView instance
169
+ def render(template_src, locals={}, template_path=nil, included_taglibs=[], view=nil)
170
+ template_path ||= template_src
171
+ view ||= ActionView::Base.new(ActionController::Base.view_paths, {})
172
+ this = locals.delete(:this) || nil
173
+
174
+ renderer_class = Dryml::Template.build_cache[template_path]._?.environment ||
175
+ make_renderer_class(template_src, template_path, locals.keys)
176
+ renderer_class.new(view).render_page(this, locals)
177
+ end
233
178
 
234
- # the sum of all the names we've seen so far - eventually we'll be ready for all of 'em
235
- all_local_names = renderer_class.compiled_local_names | locals
179
+ private
236
180
 
237
- template.compile(all_local_names, taglibs)
238
- end
181
+ def taglibs_for(controller_path)
182
+ ( taglibs_in_dir('application').unshift(APPLICATION_TAGLIB) +
183
+ subsite_taglibs(controller_path) +
184
+ (controller_path.camelize+"Controller").constantize.try.included_taglibs||[]
185
+ ).compact
186
+ end
239
187
 
188
+ def subsite_taglibs(controller_path)
189
+ parts = controller_path.split("/")
190
+ subsite = parts.length >= 2 ? parts[0..-2].join('_') : "front"
191
+ src = "taglibs/#{subsite}_site"
192
+ Object.const_defined?(:Rails) && File.exists?("#{Rails.root}/app/views/#{src}.dryml") ?
193
+ taglibs_in_dir("#{subsite}_site").unshift({ :src => src }) : []
194
+ end
240
195
 
241
- def unreserve(word)
242
- word = word.to_s
243
- if RESERVED_WORDS.include?(word)
244
- word + "_"
245
- else
246
- word
196
+ def taglibs_in_dir(dir_name)
197
+ Dir.chdir(Rails.root) do
198
+ Dir["app/views/taglibs/#{dir_name}/**/*.dryml"].map{|f| File.basename f, '.dryml'}.map do |n|
199
+ { :src => "taglibs/#{dir_name}/#{n}" }
247
200
  end
248
201
  end
202
+ end
249
203
 
204
+ # create and compile a renderer class (AKA Dryml::Template::Environment)
205
+ #
206
+ # template_src:: the DRYML source
207
+ # template_path:: the filename of the source. This is used for
208
+ # caching
209
+ # locals:: local variables.
210
+ # imports:: A list of helper modules to import. For example, Hobo
211
+ # uses [Hobo::Helper, Hobo::Helper::Translations,
212
+ # ApplicationHelper]
213
+ # included_taglibs:: A list of Taglibs to include. { :src =>
214
+ # "core", :plugin => "dryml" } is automatically
215
+ # added to this list.
216
+ #
217
+ def make_renderer_class(template_src, template_path, locals=[], taglibs=[])
218
+ renderer_class = Class.new(TemplateEnvironment)
219
+ compile_renderer_class(renderer_class, template_src, template_path, locals, taglibs)
220
+ renderer_class
221
+ end
250
222
 
251
- def static_tags
252
- @static_tags ||= begin
253
- path = if Object.const_defined?(:RAILS_ROOT) && FileTest.exists?("#{RAILS_ROOT}/config/dryml_static_tags.txt")
254
- "#{RAILS_ROOT}/config/dryml_static_tags.txt"
255
- else
256
- File.join(File.dirname(__FILE__), "dryml/static_tags")
257
- end
258
- File.readlines(path).*.chop
259
- end
260
- end
223
+ def compile_renderer_class(renderer_class, template_src, template_path, locals, taglibs=[])
224
+ template = Dryml::Template.new(template_src, renderer_class, template_path)
225
+ DEFAULT_IMPORTS.each {|m| template.import_module(m)}
261
226
 
262
- attr_writer :static_tags
227
+ # the sum of all the names we've seen so far - eventually we'll be ready for all of 'em
228
+ all_local_names = renderer_class.compiled_local_names | locals
263
229
 
264
- # Helper function for use outside Hobo/Rails
265
- #
266
- # Pass the template context in locals[:this]
267
- #
268
- # This function caches. If the mtime of template_path is older
269
- # than the last compilation time, the cached version will be
270
- # used. If no template_path is given, template_src is used as the
271
- # key to the cache.
272
- #
273
- # If a local variable is not present when the template is
274
- # compiled, it will be ignored when the template is used. In
275
- # other words, the variable values may change, but the names may
276
- # not.
277
- #
278
- # included_taglibs is only used during template compilation.
279
- #
280
- # @param [String] template_src the DRYML source
281
- # @param [Hash] locals local variables.
282
- # @param [String, nil] template_path the filename of the source.
283
- # @param [Array] included_taglibs A list of Taglibs to include. { :src =>
284
- # "core", :plugin => "dryml" } is automatically
285
- # added to this list.
286
- # @param [ActionView::Base] view an ActionView instance
287
- def render(template_src, locals={}, template_path=nil, included_taglibs=[], view=nil)
288
- template_path ||= template_src
289
- view ||= ActionView::Base.new(ActionController::Base.view_paths, {})
290
- this = locals.delete(:this) || nil
230
+ template.compile(all_local_names, [CORE_TAGLIB]+taglibs)
231
+ end
291
232
 
292
- renderer_class = Dryml::Template.build_cache[template_path]._?.environment ||
293
- Dryml.make_renderer_class(template_src, template_path, locals.keys, [], included_taglibs)
294
- renderer_class.new(template_path, view).render_page(this, locals)
295
- end
296
-
297
233
  end
234
+
235
+ require 'dryml/railtie' if Object.const_defined?(:Rails)