html_mockup 0.8.4 → 0.9.0
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.
- data/.gitignore +2 -2
- data/.travis.yml +12 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -0
- data/README.md +95 -0
- data/Rakefile +9 -4
- data/bin/mockup +1 -1
- data/doc/cli.md +46 -0
- data/doc/mockupfile.md +3 -0
- data/doc/templating.md +88 -0
- data/html_mockup.gemspec +8 -4
- data/lib/html_mockup/cli.rb +57 -65
- data/lib/html_mockup/cli/command.rb +23 -0
- data/lib/html_mockup/cli/generate.rb +5 -0
- data/lib/html_mockup/cli/release.rb +10 -0
- data/lib/html_mockup/cli/serve.rb +29 -0
- data/lib/html_mockup/generators.rb +18 -1
- data/lib/html_mockup/generators/generator.rb +23 -0
- data/lib/html_mockup/generators/new.rb +4 -3
- data/lib/html_mockup/generators/templates/generator.tt +13 -0
- data/lib/html_mockup/project.rb +11 -11
- data/lib/html_mockup/release.rb +3 -3
- data/lib/html_mockup/resolver.rb +51 -28
- data/lib/html_mockup/template.rb +95 -11
- data/roger.gemspec +29 -0
- data/test/project/Gemfile +2 -1
- data/test/project/Gemfile.lock +17 -12
- data/test/project/Mockupfile +3 -0
- data/test/project/html/formats/index.html +1 -0
- data/test/project/html/formats/json.json.erb +0 -0
- data/test/project/html/layouts/content-for.html.erb +17 -0
- data/test/project/html/mockup/encoding.html +3 -0
- data/test/project/html/partials/load_path.html.erb +3 -0
- data/test/project/layouts/test.html.erb +8 -1
- data/test/project/layouts/yield.html.erb +1 -0
- data/test/project/lib/generators/test.rb +9 -0
- data/test/project/partials/formats/erb.html.erb +1 -0
- data/test/project/partials/partials-test.html.erb +1 -0
- data/test/project/partials/test/front_matter.html.erb +1 -0
- data/test/project/partials/test/json.json.erb +1 -0
- data/test/project/partials/test/simple.html.erb +1 -0
- data/test/project/partials2/partials2-test.html.erb +1 -0
- data/test/unit/cli_test.rb +12 -0
- data/test/unit/generators_test.rb +75 -0
- data/test/unit/release/cleaner_test.rb +13 -8
- data/test/unit/resolver_test.rb +92 -0
- data/test/unit/template_test.rb +127 -0
- metadata +100 -8
- data/README.rdoc +0 -89
- data/test/generator-subcommand.rb +0 -54
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module HtmlMockup
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              class Cli::Command < Thor::Group
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class_option :verbose,
         | 
| 6 | 
            +
                  :desc =>  "Set's verbose output",
         | 
| 7 | 
            +
                  :aliases => ["-v"],
         | 
| 8 | 
            +
                  :default => false,
         | 
| 9 | 
            +
                  :type => :boolean
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize_project
         | 
| 12 | 
            +
                  @project = Cli::Base.project
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                protected
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def project_banner(project)
         | 
| 18 | 
            +
                  puts "  Html: \"#{project.html_path}\""
         | 
| 19 | 
            +
                  puts "  Partials: \"#{project.partial_path}\""
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module HtmlMockup
         | 
| 2 | 
            +
              class Cli::Serve < Cli::Command
         | 
| 3 | 
            +
             | 
| 4 | 
            +
             | 
| 5 | 
            +
                desc "Serve the current project"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class_options :port => :string, # Defaults to 9000
         | 
| 8 | 
            +
                               :handler => :string, # The handler to use (defaults to mongrel)
         | 
| 9 | 
            +
                               :validate => :boolean # Run validation?
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def serve
         | 
| 12 | 
            +
                  
         | 
| 13 | 
            +
                  server_options = {} 
         | 
| 14 | 
            +
                  options.each{|k,v| server_options[k.to_sym] = v }
         | 
| 15 | 
            +
                  server_options[:server] = {}
         | 
| 16 | 
            +
                  [:port, :handler, :validate].each do |k|
         | 
| 17 | 
            +
                    server_options[:server][k] = server_options.delete(k) if server_options.has_key?(k)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                  
         | 
| 20 | 
            +
                  server = @project.server
         | 
| 21 | 
            +
                  server.set_options(server_options[:server])
         | 
| 22 | 
            +
                  
         | 
| 23 | 
            +
                  puts "Running HtmlMockup with #{server.handler.inspect} on port #{server.port}"
         | 
| 24 | 
            +
                  puts project_banner(@project) 
         | 
| 25 | 
            +
                  
         | 
| 26 | 
            +
                  server.run!
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -1,6 +1,23 @@ | |
| 1 | 
            +
            require 'thor'
         | 
| 2 | 
            +
            require 'thor/group'
         | 
| 3 | 
            +
             | 
| 1 4 | 
             
            module HtmlMockup
         | 
| 2 5 | 
             
              module Generators
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                class Base < Cli::Command
         | 
| 8 | 
            +
                  def self.register(sub)
         | 
| 9 | 
            +
                    name = sub.to_s.sub(/Generator$/, "").sub(/^.*Generators::/,"").downcase
         | 
| 10 | 
            +
                    usage = "#{name} #{sub.arguments.map{ |arg| arg.banner }.join(" ")}"
         | 
| 11 | 
            +
                    long_desc =  sub.desc || "Run #{name} generator"
         | 
| 12 | 
            +
                    
         | 
| 13 | 
            +
                    Cli::Generate.register sub, name, usage, long_desc
         | 
| 14 | 
            +
                    Cli::Generate.tasks[name].options = sub.class_options if sub.class_options
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 3 18 | 
             
              end
         | 
| 4 19 | 
             
            end
         | 
| 5 20 |  | 
| 6 | 
            -
             | 
| 21 | 
            +
            # Default generators
         | 
| 22 | 
            +
            require File.dirname(__FILE__) + "/generators/new"
         | 
| 23 | 
            +
            require File.dirname(__FILE__) + "/generators/generator"
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            class HtmlMockup::Generators::GeneratorGenerator < HtmlMockup::Generators::Base
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              include Thor::Actions
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              desc "Create your own generator for html_mockup"
         | 
| 6 | 
            +
              argument :name, :type => :string, :required => true, :desc => "Name of the new generator"
         | 
| 7 | 
            +
              argument :path, :type => :string, :required => true, :desc => "Path to generate the new generator"
         | 
| 8 | 
            +
              # class_option :template, :type => :string, :aliases => ["-t"], :desc => "Template to use, can be a path or a git repository remote, uses built in minimal as default"
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              def self.source_root
         | 
| 11 | 
            +
                File.dirname(__FILE__)
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def create_lib_file
         | 
| 15 | 
            +
                destination = "#{path}/#{name}_generator.rb"
         | 
| 16 | 
            +
                template('templates/generator.tt', destination)
         | 
| 17 | 
            +
                say "Add `require #{destination}` to your mockup file and run mockup generate #{name}."
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            HtmlMockup::Generators::Base.register HtmlMockup::Generators::GeneratorGenerator
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            require 'shellwords'
         | 
| 2 2 |  | 
| 3 | 
            -
            class HtmlMockup::Generators:: | 
| 3 | 
            +
            class HtmlMockup::Generators::NewGenerator < Thor::Group
         | 
| 4 4 |  | 
| 5 5 | 
             
              include Thor::Actions
         | 
| 6 6 |  | 
| @@ -62,5 +62,6 @@ class HtmlMockup::Generators::New < Thor::Group | |
| 62 62 | 
             
                directory(".", ".")
         | 
| 63 63 | 
             
              end
         | 
| 64 64 |  | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 65 | 
            +
            end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            HtmlMockup::Generators::Base.register HtmlMockup::Generators::NewGenerator
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            class <%= name.capitalize %>Generator < HtmlMockup::Generators::Base
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              include Thor::Actions
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              desc "<%= name.capitalize %> generator helps you doing ... and ..."
         | 
| 6 | 
            +
              argument :path, :type => :string, :required => true, :desc => "Path to generate the new generator"
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              def create_stuff
         | 
| 9 | 
            +
                # your stuff
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            HtmlMockup::Generators::Base.register <%= name.capitalize %>Generator
         | 
    
        data/lib/html_mockup/project.rb
    CHANGED
    
    | @@ -33,8 +33,6 @@ module HtmlMockup | |
| 33 33 | 
             
                  self.layouts_path = @options[:layouts_path]
         | 
| 34 34 | 
             
                  self.shell = @options[:shell]
         | 
| 35 35 |  | 
| 36 | 
            -
                  
         | 
| 37 | 
            -
                  load_dependencies!
         | 
| 38 36 | 
             
                  load_mockup!
         | 
| 39 37 | 
             
                end
         | 
| 40 38 |  | 
| @@ -57,27 +55,29 @@ module HtmlMockup | |
| 57 55 | 
             
                end
         | 
| 58 56 |  | 
| 59 57 | 
             
                def partial_path=(p)
         | 
| 60 | 
            -
                  @partial_path = self. | 
| 58 | 
            +
                  @partial_path = self.single_or_multiple_paths(p)
         | 
| 61 59 | 
             
                end
         | 
| 62 60 | 
             
                alias :partials_path :partial_path
         | 
| 63 61 | 
             
                alias :partials_path= :partial_path=
         | 
| 64 62 |  | 
| 65 63 | 
             
                def layouts_path=(p)
         | 
| 66 | 
            -
                  @layouts_path = self. | 
| 64 | 
            +
                  @layouts_path = self.single_or_multiple_paths(p)
         | 
| 67 65 | 
             
                end
         | 
| 68 66 |  | 
| 69 67 | 
             
                protected
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                def load_dependencies!
         | 
| 72 | 
            -
                  if Object.const_defined?(:Bundler)
         | 
| 73 | 
            -
                    Bundler.require(:default)
         | 
| 74 | 
            -
                  end
         | 
| 75 | 
            -
                end
         | 
| 76 | 
            -
                
         | 
| 68 | 
            +
             | 
| 77 69 | 
             
                def load_mockup!
         | 
| 78 70 | 
             
                  @mockupfile = Mockupfile.new(self)
         | 
| 79 71 | 
             
                  @mockupfile.load      
         | 
| 80 72 | 
             
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def single_or_multiple_paths(p)
         | 
| 75 | 
            +
                  if p.kind_of?(Array)
         | 
| 76 | 
            +
                    p.map{|tp| self.realpath_or_path(tp) }
         | 
| 77 | 
            +
                  else
         | 
| 78 | 
            +
                    self.realpath_or_path(p)
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 81 |  | 
| 82 82 | 
             
                def realpath_or_path(path)
         | 
| 83 83 | 
             
                  path = Pathname.new(path)
         | 
    
        data/lib/html_mockup/release.rb
    CHANGED
    
    | @@ -339,8 +339,8 @@ module HtmlMockup | |
| 339 339 |  | 
| 340 340 | 
             
                  commenters = {
         | 
| 341 341 | 
             
                    :html => Proc.new{|s| "<!-- #{s} -->" },
         | 
| 342 | 
            -
                    :css => Proc.new{|s| " | 
| 343 | 
            -
                    :js => Proc.new{|s| " | 
| 342 | 
            +
                    :css => Proc.new{|s| "/*! #{s} */" },
         | 
| 343 | 
            +
                    :js => Proc.new{|s| "/*! #{s} */" }                
         | 
| 344 344 | 
             
                  }
         | 
| 345 345 |  | 
| 346 346 | 
             
                  commenter = commenters[options[:style]] || commenters[:js]
         | 
| @@ -360,4 +360,4 @@ require File.dirname(__FILE__) + "/release/scm" | |
| 360 360 | 
             
            require File.dirname(__FILE__) + "/release/injector"
         | 
| 361 361 | 
             
            require File.dirname(__FILE__) + "/release/cleaner"
         | 
| 362 362 | 
             
            require File.dirname(__FILE__) + "/release/finalizers"
         | 
| 363 | 
            -
            require File.dirname(__FILE__) + "/release/processors"
         | 
| 363 | 
            +
            require File.dirname(__FILE__) + "/release/processors"
         | 
    
        data/lib/html_mockup/resolver.rb
    CHANGED
    
    | @@ -1,36 +1,55 @@ | |
| 1 1 | 
             
            module HtmlMockup
         | 
| 2 2 | 
             
              class Resolver
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                attr_reader :load_paths
         | 
| 3 5 |  | 
| 4 | 
            -
                def initialize( | 
| 5 | 
            -
                  raise ArgumentError, "Resolver base path can't be nil" if  | 
| 6 | 
            -
             | 
| 6 | 
            +
                def initialize(paths)
         | 
| 7 | 
            +
                  raise ArgumentError, "Resolver base path can't be nil" if paths.nil?
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  # Convert to paths
         | 
| 10 | 
            +
                  @load_paths = [paths].flatten.map{|p| Pathname.new(p) }
         | 
| 7 11 | 
             
                end
         | 
| 8 12 |  | 
| 9 13 | 
             
                # @param [String] url The url to resolve to a path
         | 
| 10 | 
            -
                # @param [ | 
| 11 | 
            -
                 | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 14 | 
            +
                # @param [Hash] options Options
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # @option options [true,false] :exact_match Wether or not to match exact paths, this is mainly used in the path_to_url method to match .js, .css, etc files.
         | 
| 17 | 
            +
                # @option options [String] :preferred_extension The part to chop off and re-add to search for more complex double-extensions. (Makes it possible to have context aware partials)
         | 
| 18 | 
            +
                def find_template(url, options = {})
         | 
| 19 | 
            +
                  orig_path, qs, anch = strip_query_string_and_anchor(url.to_s)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  options = {
         | 
| 22 | 
            +
                    :exact_match => false,
         | 
| 23 | 
            +
                    :preferred_extension => "html"  
         | 
| 24 | 
            +
                  }.update(options)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  paths = self.load_paths.map{|base| File.join(base, orig_path) }
         | 
| 15 27 |  | 
| 16 | 
            -
                   | 
| 17 | 
            -
                     | 
| 18 | 
            -
             | 
| 19 | 
            -
                  
         | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
                     | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                    path | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 28 | 
            +
                  paths.find do |path|
         | 
| 29 | 
            +
                    if options[:exact_match] && File.exist?(path)
         | 
| 30 | 
            +
                      return Pathname.new(path)
         | 
| 31 | 
            +
                    end      
         | 
| 32 | 
            +
                    
         | 
| 33 | 
            +
                    # It's a directory, add "/index"
         | 
| 34 | 
            +
                    if File.directory?(path)
         | 
| 35 | 
            +
                      path = File.join(path, "index")
         | 
| 36 | 
            +
                    end
         | 
| 37 | 
            +
                    
         | 
| 38 | 
            +
                    # 2. If it's preferred_extension, we strip of the extension
         | 
| 39 | 
            +
                    if path =~ /\.#{options[:preferred_extension]}\Z/
         | 
| 40 | 
            +
                      path.sub!(/\.#{options[:preferred_extension]}\Z/, "")
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    
         | 
| 43 | 
            +
                    extensions = Tilt.default_mapping.template_map.keys + Tilt.default_mapping.lazy_map.keys
         | 
| 31 44 |  | 
| 32 | 
            -
             | 
| 33 | 
            -
                     | 
| 45 | 
            +
                    # We have to re-add preferred_extension again as we have stripped it in in step 2!
         | 
| 46 | 
            +
                    extensions += extensions.map{|ext| "#{options[:preferred_extension]}.#{ext}"}
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    if found_extension = extensions.find { |ext| File.exist?(path + "." + ext) }
         | 
| 49 | 
            +
                      return Pathname.new(path + "." + found_extension)
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    false #Next iteration
         | 
| 34 53 | 
             
                  end
         | 
| 35 54 | 
             
                end
         | 
| 36 55 | 
             
                alias :url_to_path :find_template
         | 
| @@ -39,11 +58,15 @@ module HtmlMockup | |
| 39 58 | 
             
                # Convert a disk path on file to an url
         | 
| 40 59 | 
             
                def path_to_url(path, relative_to = nil)
         | 
| 41 60 |  | 
| 42 | 
            -
                  path  | 
| 61 | 
            +
                  # Find the parent path we're in
         | 
| 62 | 
            +
                  path = Pathname.new(path).realpath
         | 
| 63 | 
            +
                  base = self.load_paths.find{|lp| path.to_s =~ /\A#{Regexp.escape(lp.realpath.to_s)}/ }
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  path = path.relative_path_from(base).cleanpath
         | 
| 43 66 |  | 
| 44 67 | 
             
                  if relative_to
         | 
| 45 68 | 
             
                    if relative_to.to_s =~ /\A\//
         | 
| 46 | 
            -
                      relative_to = Pathname.new(File.dirname(relative_to.to_s)).relative_path_from( | 
| 69 | 
            +
                      relative_to = Pathname.new(File.dirname(relative_to.to_s)).relative_path_from(base).cleanpath
         | 
| 47 70 | 
             
                    else
         | 
| 48 71 | 
             
                      relative_to = Pathname.new(File.dirname(relative_to.to_s))
         | 
| 49 72 | 
             
                    end
         | 
| @@ -62,7 +85,7 @@ module HtmlMockup | |
| 62 85 | 
             
                  path, qs, anch = strip_query_string_and_anchor(url)
         | 
| 63 86 |  | 
| 64 87 | 
             
                  # Get disk path
         | 
| 65 | 
            -
                  if true_path =  self.url_to_path(path, true)
         | 
| 88 | 
            +
                  if true_path =  self.url_to_path(path, :exact_match => true)
         | 
| 66 89 | 
             
                    path = self.path_to_url(true_path, relative_to_path)
         | 
| 67 90 | 
             
                    path += qs if qs
         | 
| 68 91 | 
             
                    path += anch if anch
         | 
    
        data/lib/html_mockup/template.rb
    CHANGED
    
    | @@ -1,9 +1,13 @@ | |
| 1 1 | 
             
            require 'tilt'
         | 
| 2 | 
            +
            require 'mime/types'
         | 
| 2 3 | 
             
            require 'yaml'
         | 
| 3 4 | 
             
            require 'ostruct'
         | 
| 4 5 |  | 
| 5 6 | 
             
            require File.dirname(__FILE__) + "/mockup_template"
         | 
| 6 7 |  | 
| 8 | 
            +
            # We're enforcing Encoding to UTF-8
         | 
| 9 | 
            +
            Encoding.default_external = "UTF-8"
         | 
| 10 | 
            +
             | 
| 7 11 | 
             
            module HtmlMockup
         | 
| 8 12 |  | 
| 9 13 | 
             
              class Template
         | 
| @@ -44,28 +48,79 @@ module HtmlMockup | |
| 44 48 |  | 
| 45 49 | 
             
                def render(env = {})
         | 
| 46 50 | 
             
                  context = TemplateContext.new(self, env)
         | 
| 47 | 
            -
                  locals = {:document => OpenStruct.new(self.data)}
         | 
| 48 51 |  | 
| 49 52 | 
             
                  if @layout_template
         | 
| 50 | 
            -
                     | 
| 51 | 
            -
             | 
| 53 | 
            +
                    content_for_layout = self.template.render(context, {}) # yields
         | 
| 54 | 
            +
                    
         | 
| 55 | 
            +
                    @layout_template.render(context, {}) do |content_for|
         | 
| 56 | 
            +
                      if content_for
         | 
| 57 | 
            +
                        context._content_for_blocks[content_for]
         | 
| 58 | 
            +
                      else
         | 
| 59 | 
            +
                        content_for_layout
         | 
| 60 | 
            +
                      end
         | 
| 52 61 | 
             
                    end
         | 
| 53 62 | 
             
                  else
         | 
| 54 | 
            -
                    self.template.render(context,  | 
| 63 | 
            +
                    self.template.render(context, {})
         | 
| 55 64 | 
             
                  end
         | 
| 56 65 | 
             
                end
         | 
| 57 66 |  | 
| 58 67 | 
             
                def find_template(name, path_type)
         | 
| 59 68 | 
             
                  raise(ArgumentError, "path_type must be one of :partials_path or :layouts_path") unless [:partials_path, :layouts_path].include?(path_type)
         | 
| 60 69 |  | 
| 70 | 
            +
                  return nil unless @options[path_type]
         | 
| 71 | 
            +
             | 
| 61 72 | 
             
                  @resolvers ||= {}        
         | 
| 62 73 | 
             
                  @resolvers[path_type] ||= Resolver.new(@options[path_type])
         | 
| 63 74 |  | 
| 64 | 
            -
                  @resolvers[path_type]. | 
| 65 | 
            -
                end | 
| 75 | 
            +
                  @resolvers[path_type].find_template(name, :preferred_extension => self.target_extension)
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                # Try to infer the final extension of the output file.
         | 
| 79 | 
            +
                def target_extension
         | 
| 80 | 
            +
                  return @target_extension if @target_extension
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  if type = MIME::Types[self.target_mime_type].first
         | 
| 83 | 
            +
                    # Dirty little hack to enforce the use of .html instead of .htm
         | 
| 84 | 
            +
                    if type.sub_type == "html"
         | 
| 85 | 
            +
                      @target_extension = "html"
         | 
| 86 | 
            +
                    else
         | 
| 87 | 
            +
                      @target_extension = type.extensions.first
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
                  else
         | 
| 90 | 
            +
                    @target_extension = File.extname(self.source_path.to_s).sub(/^\./, "")
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def source_extension
         | 
| 95 | 
            +
                  parts = File.basename(File.basename(self.source_path.to_s)).split(".")
         | 
| 96 | 
            +
                  if parts.size > 2
         | 
| 97 | 
            +
                    parts[-2..-1].join(".")
         | 
| 98 | 
            +
                  else
         | 
| 99 | 
            +
                    File.extname(self.source_path.to_s).sub(/^\./, "")
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                # Try to figure out the mime type based on the Tilt class and if that doesn't
         | 
| 104 | 
            +
                # work we try to infer the type by looking at extensions (needed for .erb)
         | 
| 105 | 
            +
                def target_mime_type
         | 
| 106 | 
            +
                  mime = self.template.class.default_mime_type
         | 
| 107 | 
            +
                  return mime if mime
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  path = File.basename(self.source_path.to_s)
         | 
| 110 | 
            +
                  mime = MIME::Types.type_for(path).first
         | 
| 111 | 
            +
                  return mime.to_s if mime
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  parts = File.basename(path).split(".")
         | 
| 114 | 
            +
                  if parts.size > 2
         | 
| 115 | 
            +
                    mime = MIME::Types.type_for(parts[0..-2].join(".")).first
         | 
| 116 | 
            +
                    return mime.to_s if mime
         | 
| 117 | 
            +
                  else
         | 
| 118 | 
            +
                    nil
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
                end
         | 
| 66 121 |  | 
| 67 122 | 
             
                protected
         | 
| 68 | 
            -
             | 
| 123 | 
            +
             | 
| 69 124 | 
             
                # Get the front matter portion of the file and extract it.
         | 
| 70 125 | 
             
                def extract_front_matter(source)
         | 
| 71 126 | 
             
                  fm_regex = /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
         | 
| @@ -91,26 +146,55 @@ module HtmlMockup | |
| 91 146 | 
             
              end
         | 
| 92 147 |  | 
| 93 148 | 
             
              class TemplateContext
         | 
| 94 | 
            -
                
         | 
| 149 | 
            +
                attr_accessor :_content_for_blocks
         | 
| 150 | 
            +
             | 
| 95 151 | 
             
                def initialize(template, env={})
         | 
| 96 | 
            -
                  @_template, @_env = template, env
         | 
| 152 | 
            +
                  @_template, @_env = template, @_content_for_blocks = {}, env
         | 
| 97 153 | 
             
                end
         | 
| 98 154 |  | 
| 155 | 
            +
                # The current HtmlMockup::Template in use
         | 
| 99 156 | 
             
                def template
         | 
| 100 157 | 
             
                  @_template
         | 
| 101 158 | 
             
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                # Access to the front-matter of the document (if any)
         | 
| 161 | 
            +
                def document
         | 
| 162 | 
            +
                  @_data ||= OpenStruct.new(self.template.data)
         | 
| 163 | 
            +
                end
         | 
| 102 164 |  | 
| 165 | 
            +
                # The current environment variables.
         | 
| 103 166 | 
             
                def env
         | 
| 104 167 | 
             
                  @_env
         | 
| 105 168 | 
             
                end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                # Capture content in blocks in the template for later use in the layout.
         | 
| 171 | 
            +
                # Currently only works in ERB templates. Use like this in the template:
         | 
| 172 | 
            +
                #
         | 
| 173 | 
            +
                # ```
         | 
| 174 | 
            +
                #   <% content_for :name %> bla bla <% end %>
         | 
| 175 | 
            +
                # ```
         | 
| 176 | 
            +
                #
         | 
| 177 | 
            +
                # Place it like this in the layout:
         | 
| 178 | 
            +
                #
         | 
| 179 | 
            +
                # ```
         | 
| 180 | 
            +
                #   <%= yield :name %>
         | 
| 181 | 
            +
                # ```
         | 
| 182 | 
            +
                def content_for(block_name, &capture)
         | 
| 183 | 
            +
                  raise ArgumentError, "content_for works only with ERB Templates" if !self.template.template.kind_of?(Tilt::ERBTemplate)
         | 
| 184 | 
            +
                  eval "@_erbout_tmp = _erbout", capture.binding
         | 
| 185 | 
            +
                  eval "_erbout = \"\"", capture.binding
         | 
| 186 | 
            +
                  t = Tilt::ERBTemplate.new(){ "<%= yield %>" }
         | 
| 187 | 
            +
                  @_content_for_blocks[block_name] = t.render(&capture)
         | 
| 188 | 
            +
                  return nil
         | 
| 189 | 
            +
                ensure
         | 
| 190 | 
            +
                  eval "_erbout = @_erbout_tmp", capture.binding
         | 
| 191 | 
            +
                end
         | 
| 106 192 |  | 
| 107 193 | 
             
                def partial(name, options = {})
         | 
| 108 194 | 
             
                  if template_path = self.template.find_template(name, :partials_path)
         | 
| 109 | 
            -
                    # puts "Rendering partial #{name}, with template #{template_path}"
         | 
| 110 195 | 
             
                    partial_template = Tilt.new(template_path.to_s)
         | 
| 111 196 | 
             
                    partial_template.render(self, options[:locals] || {})
         | 
| 112 197 | 
             
                  elsif template_path = self.template.find_template(name + ".part", :partials_path)
         | 
| 113 | 
            -
                    # puts "Rendering old-style partial #{name}, with template #{template_path}"
         | 
| 114 198 | 
             
                    template = Tilt::ERBTemplate.new(template_path.to_s)
         | 
| 115 199 | 
             
                    context = MockupTemplate::TemplateContext.new(options[:locals] || {})
         | 
| 116 200 | 
             
                    template.render(context, :env => self.env)        
         |