Object
# File lib/action_view/template.rb, line 112 112: def initialize(source, identifier, handler, details) 113: @source = source 114: @identifier = identifier 115: @handler = handler 116: @original_encoding = nil 117: @method_names = {} 118: 119: format = details[:format] || :html 120: @formats = Array.wrap(format).map(&:to_sym) 121: @virtual_path = details[:virtual_path].try(:sub, ".#{format}", "") 122: end
# File lib/action_view/template.rb, line 154 154: def counter_name 155: @counter_name ||= "#{variable_name}_counter".to_sym 156: end
# File lib/action_view/template.rb, line 158 158: def inspect 159: @inspect ||= 160: if defined?(Rails.root) 161: identifier.sub("#{Rails.root}/", '') 162: else 163: identifier 164: end 165: end
# File lib/action_view/template.rb, line 146 146: def mime_type 147: @mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first 148: end
# File lib/action_view/template.rb, line 124 124: def render(view, locals, &block) 125: # Notice that we use a bang in this instrumentation because you don't want to 126: # consume this in production. This is only slow if it's being listened to. 127: ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do 128: if view.is_a?(ActionView::CompiledTemplates) 129: mod = ActionView::CompiledTemplates 130: else 131: mod = view.singleton_class 132: end 133: 134: method_name = compile(locals, view, mod) 135: view.send(method_name, locals, &block) 136: end 137: rescue Exception => e 138: if e.is_a?(Template::Error) 139: e.sub_template_of(self) 140: raise e 141: else 142: raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e) 143: end 144: end
# File lib/action_view/template.rb, line 270 270: def build_method_name(locals) 271: @method_names[locals.keys.hash] ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") 272: end
Among other things, this method is responsible for properly setting the encoding of the source. Until this point, we assume that the source is BINARY data. If no additional information is supplied, we assume the encoding is the same as Encoding.default_external.
The user can also specify the encoding via a comment on the first line of the template (# encoding: NAME-OF-ENCODING). This will work with any template engine, as we process out the encoding comment before passing the source on to the template engine, leaving a blank line in its stead.
If the template engine handles encodings, we send the encoded String to the engine without further processing. This allows the template engine to support additional mechanisms for specifying the encoding. For instance, ERB supports <%# encoding: %>
Otherwise, after we figure out the correct encoding, we then encode the source into Encoding.default_internal. In general, this means that templates will be UTF-8 inside of Rails, regardless of the original source encoding.
# File lib/action_view/template.rb, line 188 188: def compile(locals, view, mod) 189: method_name = build_method_name(locals) 190: return method_name if view.respond_to?(method_name) 191: 192: locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join 193: 194: if source.encoding_aware? 195: # Look for # encoding: *. If we find one, we'll encode the 196: # String in that encoding, otherwise, we'll use the 197: # default external encoding. 198: if source.sub!(/\A#{ENCODING_FLAG}/, '') 199: encoding = magic_encoding = $1 200: else 201: encoding = Encoding.default_external 202: end 203: 204: # Tag the source with the default external encoding 205: # or the encoding specified in the file 206: source.force_encoding(encoding) 207: 208: # If the user didn't specify an encoding, and the handler 209: # handles encodings, we simply pass the String as is to 210: # the handler (with the default_external tag) 211: if !magic_encoding && @handler.respond_to?(:handles_encoding?) && @handler.handles_encoding? 212: source 213: # Otherwise, if the String is valid in the encoding, 214: # encode immediately to default_internal. This means 215: # that if a handler doesn't handle encodings, it will 216: # always get Strings in the default_internal 217: elsif source.valid_encoding? 218: source.encode! 219: # Otherwise, since the String is invalid in the encoding 220: # specified, raise an exception 221: else 222: raise WrongEncodingError.new(source, encoding) 223: end 224: end 225: 226: code = @handler.call(self) 227: 228: # Make sure that the resulting String to be evalled is in the 229: # encoding of the code 230: source = def #{method_name}(local_assigns) _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code} ensure @_virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer end 231: 232: if source.encoding_aware? 233: # Make sure the source is in the encoding of the returned code 234: source.force_encoding(code.encoding) 235: 236: # In case we get back a String from a handler that is not in 237: # BINARY or the default_internal, encode it to the default_internal 238: source.encode! 239: 240: # Now, validate that the source we got back from the template 241: # handler is valid in the default_internal. This is for handlers 242: # that handle encoding but screw up 243: unless source.valid_encoding? 244: raise WrongEncodingError.new(@source, Encoding.default_internal) 245: end 246: end 247: 248: begin 249: mod.module_eval(source, identifier, 0) 250: ObjectSpace.define_finalizer(self, Finalizer[method_name, mod]) 251: 252: method_name 253: rescue Exception => e # errors from template code 254: if logger = (view && view.logger) 255: logger.debug "ERROR: compiling #{method_name} RAISED #{e}" 256: logger.debug "Function body: #{source}" 257: logger.debug "Backtrace: #{e.backtrace.join("\n")}" 258: end 259: 260: raise ActionView::Template::Error.new(self, {}, e) 261: end 262: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.