Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do "inline templates" work internally? #7

Open
ericgj opened this issue Jun 5, 2012 · 3 comments
Open

How do "inline templates" work internally? #7

ericgj opened this issue Jun 5, 2012 · 3 comments

Comments

@ericgj
Copy link
Member

ericgj commented Jun 5, 2012

@codereading/readers

@ericgj
Copy link
Member Author

ericgj commented Jun 5, 2012

The Sinatra docs say:

NOTE: Inline templates defined in the source file that requires sinatra are automatically loaded. Call enable :inline_templates explicitly if you have inline templates in other source files.

This is a puzzler: where do the inline templates defined in the source file that requires sinatra get loaded?

Here's the code that runs when you enable :inline_templates . Curious to see that you could also do something like set :inline_templates, 'another_file.rb' .

https://github.com/codereading/sinatra/blob/ver1.3.2/lib/sinatra/base.rb#L1049

      # Load embeded templates from the file; uses the caller's __FILE__
      # when no file is specified.
      def inline_templates=(file=nil)
        file = (file.nil? || file == true) ? (caller_files.first || File.expand_path($0)) : file

        begin
          io = ::IO.respond_to?(:binread) ? ::IO.binread(file) : ::IO.read(file)
          app, data = io.gsub("\r\n", "\n").split(/^__END__$/, 2)
        rescue Errno::ENOENT
          app, data = nil
        end

        if data
          if app and app =~ /([^\n]*\n)?#[^\n]*coding: *(\S+)/m
            encoding = $2
          else
            encoding = settings.default_encoding
          end
          lines = app.count("\n") + 1
          template = nil
          force_encoding data, encoding
          data.each_line do |line|
            lines += 1
            if line =~ /^@@\s*(.*\S)\s*$/
              template = force_encoding('', encoding)
              templates[$1.to_sym] = [template, file, lines]
            elsif template
              template << line
            end
          end
        end
      end

@kgrz
Copy link

kgrz commented Jun 6, 2012

Inline templates essentially are written after the entire app is written. For example:

require 'sinatra'
  get '/' do
    erb :index
  end
__END__
@@ index
<html>
 <!-- Some stuff here -->
</html>

A complete example can be found in the chat application under sinatra/examples folder

This is what I understood:

  • The part after __END__ is not executed by Ruby.
  • IO.binread(file) reads the file in binary mode, and splits it into two parts -> app and data. This happens at this step: io.gsub("\r\n", "\n").split(/^__END__$/, 2). The gsub method is called to normalize the line ending differences between different OSes (read CRLF, LF, CR issues) and the split method splits the file at the __END__ keyword into app and data. The data object, essentially contains the inline template info.
  • At line =~ /^@@\s*(.*\S)\s*$/, the inline template "index" specified in the example by @@ index gets matched so that any line after the regex match is considered as a template.

@lyonsinbeta
Copy link

I've never seen inline erb before, online inline HAML. This is good to know for when you're writing really small apps, and don't want to use HAML.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants