Archive for May, 2008

RailsConf ‘08

Tuesday, May 27th, 2008

Well folks, RailsConf ‘08, is just about upon us. I’m heading out to Portland, are you? If so, let’s make contact. It’ll be great to meet everyone who’s been following Mack and supporting what we’re doing here.

I’m going to be leading a Birds of a Feather session Thursday night, “Rails Alternatives and You” from 7.30pm – 8.30pm in room D133. There are going to representatives of Merb and DataMapper there as well, so it should be a good time. Again, it’d be great to meet some of you.

On Friday during lunch at 12.35pm, I’ll be signing copies of the ‘Advanced Rails Recipes’ book at the Powell’s Book booth, along with some of the other authors. I think I’m more excited about this than anything else happening at the rest of the conference!

For those of you who have been to a RailsConf in the past, know it’s a great time. For those who haven’t, it’s a great time. :) Last year I got to meet a lot of great people, and this year I’m looking forward to meeting more. I hope you’ll be one of them.

See ya in Portland.

OT: Some Music

Monday, May 26th, 2008

So I know this is off topic, but hey, it’s my blog, I’ll do what I want. My new band, The Blue Wires, has finally released it’s first demos. We’re pretty excited about them. If you have a moment, why not hop on over there and check them out, I think you’ll enjoy!

http://www.thebluewires.com/music/

Release 0.5.5

Wednesday, May 21st, 2008

Finally, Mack 0.5.5 is released! In addition to some great bug fixes, there is now a new rendering engine, support for automatic mime-types, the ability to register new mime-types, Markaby and Haml support, and much much more! It’s a great release.

To find out more about the new rendering engine check out these two posts:

http://www.mackframework.com/2008/05/20/the-new-rendering-engine/

http://www.mackframework.com/2008/05/20/055-adding-pdfwriter-plugin-support-tutorial/

Changelog:

  • INCOMPATIBILITY NOTICE: Ripped apart the ENTIRE rendering engine and rewrote it from the ground up. This means that wherever you are using ‘render’ calls in your views and controllers need to be changed. The new format is render(type, value, options). Examples: render(:action, :show), render(:url, “http://www.mackframework.com”), etc…
  • INCOMPATIBILITY NOTICE: Files named *.xml.erb need to be changed to *.xml.builder to use the Builder::XmlMarkup library. If you leave the .erb extension on there the file will be run through Erubis.
  • INCOMPATIBILITY NOTICE: <%= @content_for_layout %> is now <%= yield_to :view %>
  • Added Markaby support.
  • Added Haml support.
  • Added content_for and yield_to methods in views.
  • Erubis compiled templates are now cached for increased performance.
  • Added render(:inline) and render(:template) support.
  • Refactored, and reorganized some files to clean up the gem.
  • Fixed bug with cookies not merging with configured app_config parameters.
  • Added mime-types. The ‘Content-Type’ header is now being set based on the format that is requested. Default is text/html.
  • Fixed r.defaults in routes so they are always the last routes to be checked, no matter where they are placed in the routes definitions.
  • render(:url) now recognizes ‘local’ urls and tries to run them through the app, mimicking most headers from the original request.
  • Added ‘options’ banners to the mack and mack_ring_server binaries.
  • gem: genosaurus 1.1.8
  • gem: mack_ruby_core_extensions 0.1.28
  • gem: markaby 0.5.0
  • gem: mack-data_mapper 0.5.5

Preview (0.5.5): Adding PDF::Writer Plugin Support Tutorial

Tuesday, May 20th, 2008

Ok, let’s take the new rendering system out for a spin, shall we? Let’s add the PDF::Writer library to our Obligatory Blog Demo application. If you haven’t followed this demo you should do that now.

Let’s start by requiring the gem in our system. Open up your gems.rb file found in config/initializers and let’s add the gem:

require_gems do |gem|
  gem.add "pdf-writer", :version => "1.1.8", :libs => "pdf/writer"
end

Great! We’ve told Mack we want to use the ‘pdf-writer’ gem, version ‘1.1.8′, and we want to automatically require the file ‘pdf/writer’. Now, let’s install the gem:

$ sudo rake gems:install

See how easy this is? We’ve installed the gem, required the libraries, now we’re ready to write our plugin.

$ rake generate:plugin name=render_pdf

That should generate a few files/folders in our vendor/plugins directory. Let’s open up vendor/plugins/render_pdf/lib/render_pdf.rb and let’s start coding.

What we want to do is create a new Mack::Rendering::Engine::Base class so that when we call render(:action) it will have a new engine to render the view file as a PDF.

We’ll examine each section in a minute, but for now, let’s type this into our render_pdf.rb file:

module Mack
  module Rendering
    module Engine
      class Pdf < Mack::Rendering::Engine::Base

        def render(io, binding)
          @_pdf = ::PDF::Writer.new
          self.view_template.instance_variable_set("@_pdf", @_pdf)
          eval(io, binding)
          @_pdf.render
        end

        def extension
          :pdfw
        end

        module ViewHelpers
          def pdf
            @_pdf
          end
        end

      end
    end
  end
end
Mack::Rendering::ViewTemplate.send(:include, Mack::Rendering::Engine::Pdf::ViewHelpers)
Mack::Rendering::Engine::Registry.register(:action, :pdf)

Ok, so on line #4 we extended Mack::Rendering::Engine::Base. This will give us access to a view methods, and will allow us to write to a very simple API. The only method you are absolutely required to implement is the render method. As we can see on line #6, we did just that.

First thing we do in the render method is instantiate a new PDF::Writer class and assign it to an instance variable. We then set that instance variable into the Mack::Rendering::ViewTemplate object we have. We do that because the way the PDF::Writer object works you need to constantly reference the instance of the writer to do your work. Example:

@_pdf.text "Hello World", :font_size => 24, :justification => :center

On line #9 we eval the io and the binding we’ve been given. The io will be contents of the view file we have disk, as a String, and the binding will be that of the Mack::Rendering::ViewTemplate object we’ve been given.

In the extension method we tell the system that are files are going to be found with the extension, pdfw. Another example of this would be the Erubis engine which declares its extension as erb.

The Mack::Rendering::Engine::Pdf::ViewHelpers module we’ve declared on line #17 is there to hide the @_pdf instance variable with a nicer pdf method. On line #27 we include this module into Mack::Rendering::ViewTemplate so it has access to it.

Finally, and most importantly, we need to register the new engine we’ve built with the system. We do that on line #28 with this bit of code:

Mack::Rendering::Engine::Registry.register(:action, :pdf)

That’s saying whenever someone calls render(:action), consider me as an engine to render that. The way the selection of which engine to use is done, is very simple. First come first serve. The engines are in an array, and the first one to have a file with its extension on disk wins. Plain and simple.

Now, let’s see all this in action. Let’s add PDF support for our ’show’ page.

Open up views/posts/show.html.erb and add the following line:

<%= link_to("pdf", posts_show_url(:id => @post, :format => :pdf)) %>

That will give us a link that looks like ‘/posts/:id.pdf’. This will, of course, go to our PostsController and the show action. This method does not need to be altered. That’s right, you heard me. It does not need to change. Mack will handle the appropriate content-type headers for you. Just another great feature in 0.5.5.

Create a file called views/posts/show.pdf.pdfw. I know this might look a little weird, what with ‘pdf.pdfw’, but here’s the reason why. That’s break the file name down into its three parts. ’show’ is the name of the action. ‘pdf’ is the format of the request, think also html, xml, etc… ‘pdfw’ is the engine we want to use. If we hated ourselves we could do this all in erb with a file called show.pdf.erb, but why would we want to do that?

Anyway, let’s dump this nice block of code into our show.pdf.pdfw file:

pdf.select_font "Times-Roman"
pdf.fill_color(Color::RGB::Red)
pdf.text @post.title, :font_size => 24, :justification => :center
pdf.fill_color(Color::RGB::Black)
pdf.text "by #{@post.email}", :font_size => 12, :justification => :center
pdf.with_options(:font_size => 10, :justification => :left) do |p|
  p.text "\n\n"
  p.text @post.body
  p.text "\n\n"
  p.text "Created at: #{@post.created_at}"
  p.text "Updated at: #{@post.updated_at}"
end

Since this is not a tutorial on this particular gem, I’m not going to go into what all that does. Instead, let’s just have a look at it in action.

Fire up your server:

$ rake server

And go to: http://localhost:3000. If you don’t already have a post created, create one. Now click on the show link. You should have a link on your page that says ‘pdf’ click on that link. Voila! You should be seeing a wonderfully formatted PDF right now!

Congrats! You’ve built a plugin and a new rendering engine for Mack. Now, go crazy!

The source for all this can be found at: http://github.com/markbates/mack_blog_demo/tree/master

Preview (0.5.5): The New Rendering Engine

Tuesday, May 20th, 2008

In the latest version of Mack the rendering engine has been completely re-written from the ground up. With this comes some new features, some incompatibility, and most importantly, extensibility. Let’s jump on in and see what we can expect with this release.

Incompatibility

  • Gone is <%= @content_for_layout %> in layouts. In is <%= yield_to :view %>.
  • Gone is render(options_hash) in controllers/views. In is render(type, value, options_hash)
    Examples:
    render(:action => :new) is now render(:action, :new)
    render(:url => “http://www.mackframework.com”, :parameters => {:message => “hi”}) is now render(:url, “http://www.mackframework.com”, :parameters => {:message => “hi”})
  • Gone is *.xml.erb. In is *.xml.builder
Let’s quickly talk about how these incompatibilities have come about. First there were several bugs that needed to be addressed with the rendering engine. For example, if you set an instance variable in a view, it wasn’t available in the layout. That’s a pain if you want to do things like programatically set the page title. There were also ‘hacks’ used to do things like render xml using the Builder::XmlMarkup library. It wasn’t clean, but it worked. Finally, the rendering engine itself wasn’t that extensible. All of that has now changed.

Render Me Softly

In the new rendering engine there are two parts to the system, Mack::Rendering::Type::* objects and Mack::Rendering::Engine::* objects. Let me explain the difference.

Mack::Rendering::Type::*

A type is something like :action, :text, :inline, :url, etc… That is the type of thing you want to do. I want to render an action. I want to render a url, etc… There are classes for each of these types, and you can easily add your own. These types do all sorts of work before they pass it off to an engine, if need be. For example, in the case of Mack::Rendering::Type::Partial the render method does the work of inserting an ‘_’ in the appropriate place, so the file can found.

<%= render(:partial, "users/form") %> # => "users/_form"

Once that happens it tries to find an engine to process the partial.

Mack::Rendering::Engine::*

An engine does the actual work of rendering the io, with the binding of the Mack::Rendering::ViewTemplate object, it’s been given by the results of the render method in the Mack::Rendering::Type::* object. Engine examples would be, Erubis (ERB), Markaby, Haml, and Builder::XmlMarkup, all of which are included with Mack in this release. New engines can easily be plugged in and registered with the system.

Coming soon a tutorial on adding PDF::Writer support using the new system.