Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add inline template support

  • Loading branch information...
commit 3c8ad823eb9c892123412c19892bbc625be34f3d 1 parent 3eb95b8
authored
22  LICENSE
@@ -19,3 +19,25 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 19
 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 20
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 21
 
  22
+Copyright (c) 2007, 2008, 2009 Blake Mizerany
  23
+
  24
+Permission is hereby granted, free of charge, to any person
  25
+obtaining a copy of this software and associated documentation
  26
+files (the "Software"), to deal in the Software without
  27
+restriction, including without limitation the rights to use,
  28
+copy, modify, merge, publish, distribute, sublicense, and/or sell
  29
+copies of the Software, and to permit persons to whom the
  30
+Software is furnished to do so, subject to the following
  31
+conditions:
  32
+
  33
+The above copyright notice and this permission notice shall be
  34
+included in all copies or substantial portions of the Software.
  35
+
  36
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  37
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  38
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  39
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  40
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  41
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  42
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  43
+OTHER DEALINGS IN THE SOFTWARE.
86  lib/astaire.rb
@@ -3,6 +3,80 @@
3 3
 require 'astaire/railtie' if defined?(Rails)
4 4
 
5 5
 module Astaire
  6
+  # Thanks Sinatra
  7
+  CALLERS_TO_IGNORE = [
  8
+    /\/astaire(\/(railtie))?\.rb$/, # all astaire code
  9
+    /lib\/tilt.*\.rb$/,    # all tilt code
  10
+    /\(.*\)/,              # generated code
  11
+    /custom_require\.rb$/, # rubygems require hacks
  12
+    /active_support/,      # active_support require hacks
  13
+  ]
  14
+
  15
+  # add rubinius (and hopefully other VM impls) ignore patterns ...
  16
+  CALLERS_TO_IGNORE.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
  17
+
  18
+  class InlineTemplates < ActionView::PathResolver
  19
+    def initialize
  20
+      super
  21
+      @templates = {}
  22
+    end
  23
+
  24
+    def add_controller(controller)
  25
+      file = caller_files.first
  26
+
  27
+      begin
  28
+        app, data =
  29
+          ::IO.read(file).gsub("\r\n", "\n").split(/^__END__$/, 2)
  30
+      rescue Errno::ENOENT
  31
+        app, data = nil
  32
+      end
  33
+
  34
+      if data
  35
+        lines = app.count("\n") + 1
  36
+        template = nil
  37
+        data.each_line do |line|
  38
+          lines += 1
  39
+          if line =~ /^@@\s*(.*)/
  40
+            template = ''
  41
+            @templates["#{controller.controller_path}/#{$1}"] =
  42
+              [template, file, lines]
  43
+          elsif template
  44
+            template << line
  45
+          end
  46
+        end
  47
+      end
  48
+    end
  49
+
  50
+    def query(path, exts, formats)
  51
+      query = Regexp.escape(path)
  52
+      exts.each do |ext|
  53
+        query << '(' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)'
  54
+      end
  55
+
  56
+      templates = []
  57
+      @templates.select { |k,v| k =~ /^#{query}$/ }.each do |path, (source, file, lines)|
  58
+        handler, format = extract_handler_and_format(path, formats)
  59
+        templates << ActionView::Template.new(source, path, handler,
  60
+          :virtual_path => path, :format => format)
  61
+      end
  62
+
  63
+      templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
  64
+    end
  65
+
  66
+    # Like Kernel#caller but excluding certain magic entries and without
  67
+    # line / method information; the resulting array contains filenames only.
  68
+    def caller_files
  69
+      caller_locations.
  70
+        map { |file,line| file }
  71
+    end
  72
+
  73
+    def caller_locations
  74
+      caller(1).
  75
+        map    { |line| line.split(/:(?=\d|in )/)[0,2] }.
  76
+        reject { |file,line| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
  77
+    end
  78
+  end
  79
+
6 80
   module DSL
7 81
     extend ActiveSupport::Concern
8 82
 
@@ -15,8 +89,15 @@ module DSL
15 89
       class_attribute :_astaire_helpers
16 90
       self._astaire_helpers = url_helper_module
17 91
 
  92
+      class_attribute :_inline_resolver
  93
+      self._inline_resolver = InlineTemplates.new
  94
+
  95
+      _inline_resolver.add_controller(self)
  96
+
18 97
       include _astaire_helpers
19 98
       helper _astaire_helpers
  99
+
  100
+      append_view_path _inline_resolver
20 101
     end
21 102
 
22 103
     module ClassMethods
@@ -36,6 +117,11 @@ def #{method}(path, opts = {}, &blk)
36 117
         R
37 118
       end
38 119
 
  120
+      def inherited(klass)
  121
+        super
  122
+        _inline_resolver.add_controller(klass)
  123
+      end
  124
+
39 125
     private
40 126
 
41 127
       def map_astaire_action(method, path, opts, blk)
51  spec/templates_spec.rb
... ...
@@ -0,0 +1,51 @@
  1
+require 'helper'
  2
+
  3
+describe "Inline templates" do
  4
+  class MyController < ActionController::Base
  5
+    include Astaire::DSL
  6
+
  7
+    get "/hello" do
  8
+      render :index
  9
+    end
  10
+  end
  11
+
  12
+  class MyOtherController < ActionController::Base
  13
+    include Astaire::DSL
  14
+
  15
+    get "/word" do
  16
+      render :foo
  17
+    end
  18
+  end
  19
+
  20
+  class SubclassController < MyOtherController
  21
+    get "/what" do
  22
+      render :index
  23
+    end
  24
+  end
  25
+
  26
+  it "is able to find inline templates" do
  27
+    @app = Rack::Lint.new(MyController)
  28
+    get "/hello"
  29
+    last_response.body.should == "Hello World\n\n"
  30
+  end
  31
+
  32
+  it "is able to have multiple controllers per file" do
  33
+    @app = Rack::Lint.new(MyOtherController)
  34
+    get "/word"
  35
+    last_response.body.should == "OMG HI!"
  36
+  end
  37
+
  38
+  it "works with subclasses of Astaire controllers" do
  39
+    @app = Rack::Lint.new(SubclassController)
  40
+    get "/what"
  41
+    last_response.body.should == "Hello World\n\n"
  42
+  end
  43
+end
  44
+
  45
+__END__
  46
+
  47
+@@ index.html.erb
  48
+Hello <%= 'World' %>
  49
+
  50
+@@ foo.html.erb
  51
+OMG HI!

0 notes on commit 3c8ad82

Please sign in to comment.
Something went wrong with that request. Please try again.