Ruby on Rails
TabbedNavbarGenerator

USAGE

Description:
    The tabbed navbar generator creates the CSS and sample HTML for a 3-state
    tab bar (unselected, mouseover, and selected).  The images that are
    used MUST be a single image containing the three states of the tab in
    this order from top to bottom: unselected, mouseover, selected.  It is
    compatible with Win/IE 5.0+, Safari, FireFox and Opera browsers.

    The generator takes the relative paths of each image in the tab bar as
    parameters.  The public/images folder is assumed to be where the images
    reside.  The width and height of each image can be placed before the
    file name to override any defaults:

      50x90:tab_home.gif

    If the dimensions are not specified, the tabbed navbar generator will
    attempt to get the dimensions using the "file" shell command.  "File" 
    only gets GIF image dimensions.

    The generator creates a CSS stylesheet in in public/stylesheets, and
    a sample HTML tab bar in app/views.

Example:

    ./script/generate tabbed_navbar tab_home.gif tab_cart.gif tab_logout.gif
    ./script/generate tabbed_navbar 50x90:tab_home.jpg 60x90:tab_cart.jpg 55x90:tab_logout.jpg

tabbed_navbar_generator.rb

class TabbedNavbarGenerator < Rails::Generator::Base
  attr_accessor :height_in_pixels, :width_in_pixels, :images

  def initialize(*runtime_args)
    super(*runtime_args)
    @images = args.collect { |i| Image.new(i) }

    # Height of the Tabbed navbar is the height of any image in that bar / 3
    @height_in_pixels = @images[0].height / 3
    # Sum of each tab's width
    @width_in_pixels = @images.inject(0) { |sum, img| sum + img.width }
  end

  def manifest
    record do |m|
      # Stylesheet and public directories.
      m.directory File.join('public', 'stylesheets')
      m.directory File.join('app', 'views')

      # Model class, unit test, and fixtures.
      m.template 'tabbed_navbar.css', File.join('public', 'stylesheets', "tabbed_navbar.css")
      m.template '_tabbed_navbar.rhtml', File.join('app', 'views', "_tabbed_navbar.rhtml")
    end
  end

  protected
    # Override with your own usage banner.
    def banner
      "Usage: #{$0} #{spec.name} [WIDTHxHEIGHT:image1 [WIDTHxHEIGHT:image2 [ ... ]]]" 
    end
end

class Image
  attr_accessor :basename, :filename, :extension
  attr_accessor :css_tag, :width, :height, :uri
  DEFAULT_WIDTH = 50
  DEFAULT_HEIGHT = 60 # 20 * 3

  def initialize(arg)
    if arg =~ /(\d+)x(\d+)\:(.+)$/
      @width, @height, @filename = $1.to_i, $2.to_i, $3
    elsif arg =~ /(.+)/
      @filename = $1
    end
    @basename = @filename.split("/").last || "" 
    @css_tag = @basename.split(".")[0].gsub("/", "_")
    @extension = @basename.split(".")[1]
    @uri = "/images/#{@filename}" 

    set_dimensions unless @width and @height

    show_dimensions
  end

protected
  def set_dimensions
    puts "Setting dimensions automatically for #{@filename}" 
    case @extension
      when "gif":
      dimensions = `file public/images/#{filename}`
      if dimensions.match /GIF.+ (\d+) x (\d+)/
        @width = $1.to_i; @height = $2.to_i
      end
    end
    unless @width and @height
      puts "Setting dimensions of #{@filename} to default " +
        "#{DEFAULT_WIDTH} x #{DEFAULT_HEIGHT}." 
      @width, @height = DEFAULT_WIDTH, DEFAULT_HEIGHT
    end
  end

  def show_dimensions
    if @width and @height
      puts "Dimensions of #{@filename}: #{@width} x #{@height}" 
      if @height % 3 != 0
        puts "WARNING: Height of #{@filename} is not evenly divisible by 3." 
      end
    else
      puts "Dimensions of #{@filename} unknown." 
    end
  end
end

templates/tabbed_navbar.css

#nav_container {
  position: relative;
  padding-left: 0;
  clear: none;
  /* margin: 3px 0 20px 0; */
  /* background: #7FA0B1;    */
  width: <%= width_in_pixels %>px;
  height: <%= height_in_pixels %>px;
}

#nav {
  position: absolute;
  top: 0px;
  left: 40px;
  margin: 0;
  padding: 0;
  list-style: none;
  display: inline;
  overflow: hidden;
  width: <%= width_in_pixels %>px;
  height: <%= height_in_pixels %>px;
}

#nav li {
  margin: 0; 
  padding: 0;
  list-style-type: none;
  display: inline;
}

#nav a {
  float: left;
  padding: <%= height_in_pixels %>px 0 0 0;
  overflow: hidden;
  height: 0px !important; 
  height /**/:<%= height_in_pixels %>px; /* for IE5/Win only */
}

#nav a:hover {
  background-position: 0 -<%= height_in_pixels %>px;
}

#nav a:active, #nav a.selected {
  background-position: 0 -<%= height_in_pixels * 2 %>px;
}

/* Custom link tabs for each nav element in this application */
<% for image in images %>
/* <%= image.filename %> */
#<%= image.css_tag %> a  {
  width: <%= image.width %>px;
  background: url(<%= image.uri %>) top left no-repeat;
}
<% end %>

templates/_tabbed_navbar.rhtml

<div id="nav_container">
  <ul id="nav">
    <% for image in images -%>
    <li id="<%= image.css_tag %>"><%= "<" + "%=" %> link_to <%= image.css_tag.humanize %> <%= "%" + ">" %> %></li>
    <% end -%>
  </ul>
</div>

Note: The complicated-looking eRb switching in the tabbed_navbar.rhtml file is due to the fact that in this generator, we actually want to generate eRb code. Normal escaping using <%= and > may or may not work. In any case, I chose to split it up as in the example above so that eRb didn’t falsely detect the end of the escaped eRb tag.

category: Generator, Example

From:MaurizioMarek

You can avoid the escaping using doubles. So you can write this:

<%<%=link_to <%= image.css_tag.humanize %>%>

instead of this:

<%= "<" + "%=" %> link_to <%= image.css_tag.humanize %> <%= "%" + ">" %> %>