Fork me on GitHub

Archive for the ‘Tutorials’ Category

Using Sprockets without Rails

Wednesday, August 31st, 2011

I’ve started working this week on an example application for the next book I’m about to write and I wanted a simple way for my readers to easily run the app (it’s going to be a single HTML file with a ton of cool JavaScript going on in it). My first choice for running this app was to use the popular Ruby library, Rack. If you are unfamiliar with Rack, please check it out. It provides a simple interface for writing web applications. By writing a simple Ruby file readers can use their favorite Rack compatible web server to launch the application. Sounds simple, eh? That’s because it is.

With a simple Rack application written in a few lines of code I was able to start developing my example application. That’s when I realized I needed a good way to serve up all my CoffeeScript and Sass files. I was going to write a watchr script that did this, but I thought that was a bit heavy handed, and not very flexible, so I turned to Sprockets.

Sprockets recently gained a lot of attention because it is bundled in with Rails 3.1 to serve up an application’s assets. It’s a clever little library that will process your files using CoffeeScript, Sass, etc… and let you bundle them up in to a single asset by using a manifest. That was exactly what I wanted. After I spent the better part of an afternoon doing a bit of research and debugging here is the Rack configuration file I came up with:

require 'sprockets'
project_root = File.expand_path(File.dirname(__FILE__))
assets = Sprockets::Environment.new(project_root) do |env|
  env.logger = Logger.new(STDOUT)
end

assets.append_path(File.join(project_root, 'app', 'assets'))
assets.append_path(File.join(project_root, 'app', 'assets', 'javascripts'))
assets.append_path(File.join(project_root, 'app', 'assets', 'stylesheets'))

map "/assets" do
  run assets
end

map "/" do
  run lambda { |env|
    [
      200,
      {
        'Content-Type' => 'text/html',
        'Cache-Control' => 'public, max-age=86400'
      },
      File.open('public/index.html', File::RDONLY)
    ]
  }
end
view raw config.ru This Gist brought to you by GitHub.

That will serve

/assets/application.css

via Sprockets. The file itself will live in

<pwd>/app/assets/stylesheets/application.scss

The same goes for JavaScript files.

Hopefully this will save someone else a little of time when they’re trying to do the same thing. Enjoy!

Building Interfaces and Abstract Classes in Ruby

Monday, February 7th, 2011

So back in the dark ages of my career, pre-2006, I spent a long time coding Java. Yeah, I know, please don’t judge. Anyway, In Java, for those of you who are unaware were two constructs that I occasionally wish I had in Ruby, those are Interfaces and Abstract Classes. The difference between these two constructs is subtle, but important.

In Java an Interface is a basically a blueprint of methods that the class who implements the Interface needs to implement. For example:

interface Bicycle {

  void changeGear(int newValue);

  void speedUp(int increment);

  void applyBrakes(int decrement);
}

public class ACMEBicycle implements Bicycle {
   
   public void changeGear(int newValue) {
     // do some work here
   }
   
   public void speedUp(int increment) {
     // do some work here
   }
   
   public void applyBrakes(int decrement) {
     // do some work here
   }

}

Here we have a Bicycle Interface that says there are three methods that need to be implemented. It is then the responsibility of the ACMEBicycle class to implement those methods. Now, an Abstract Class in Java is similar to an Interface in that it too is a blueprint of methods that the extending class may or may not need to implement. There in lies one of the differences between the two. Let’s take a look at the same example, but this time we want to implement the same behavior of all of our extending classes for the applyBrakes method:

abstract class Bicycle {
  
  abstract public void changeGear(int newValue);

  abstract public void speedUp(int increment);

  public void applyBrakes(int decrement) {
    // do some work here
  }
  
}

public class ACMEBicycle extends Bicycle {
   
   public void applyBrakes(int decrement) {
     // do some work here
   }

}

An Abstract Class is a great way to provide a mix of fully implemented methods as well as providing subclasses with a mixture of methods that need to be implemented by the extending class.

The really powerful part of all of this is two fold. First, the Java compiler will happily yell at you and fail if it finds that you haven’t implemented some of the methods that you were told you had to. Second, you can easily see the methods that you need to document right there, you can even copy/paste their definitions right into your class so you can start to fill them out.

So, how does this bring us over to Ruby? Great question. I’d like to take a few moments and explore a few ways we can get some of this power in Ruby.

Unfortunately, or fortunately depending on how you look at it (I see it as a mixed blessing), there is no compiler in Ruby, so we don’t really have a good way of having the system yell at us if we don’t implement the methods we were supposed to. But, there is still plenty we can do to help those who are implementing our classes both know what they need to implement and to find out what they haven’t implemented when their program is executing.

Here is one implementation on we can gain a bit of that functionality back in Ruby:

module AbstractInterface
  
  class InterfaceNotImplementedError < NoMethodError
  end
  
  def self.included(klass)
    klass.send(:include, AbstractInterface::Methods)
    klass.send(:extend, AbstractInterface::Methods)
  end
  
  module Methods
    
    def api_not_implemented(klass)
      caller.first.match(/in \`(.+)\'/)
      method_name = $1
      raise AbstractInterface::InterfaceNotImplementedError.new("#{klass.class.name} needs to implement '#{method_name}' for interface #{self.name}!")
    end
    
  end
  
end

class Bicycle
  include AbstractInterface
  
  # Some documentation on the change_gear method
  def change_gear(new_value)
    Bicycle.api_not_implemented(self)
  end
  
  # Some documentation on the speed_up method
  def speed_up(increment)
    Bicycle.api_not_implemented(self)
  end
  
  # Some documentation on the apply_brakes method
  def apply_brakes(decrement)
    # do some work here
  end
  
end

class AcmeBicycle < Bicycle
end

bike = AcmeBicycle.new
bike.change_gear(1) # AbstractInterface::InterfaceNotImplementedError: AcmeBicycle needs to implement 'change_gear' for interface Bicycle!
view raw gistfile1.rb This Gist brought to you by GitHub.

What we’ve done here is to inject a Module into our Bicycle class to give it a nice error it can raise and a little bit of help building a nice error message for the user. Then in our Bicycle class we define all the methods we want and in the ones we need the end user to define we can call the api_not_implemented method and it will raise the AbstractInterface::InterfaceNotImplementedError error for us.

We could simplify this a bit by having a nice little helper macro that we can use to build these methods, like this:

module AbstractInterface
  
  class InterfaceNotImplementedError < NoMethodError
  end
  
  def self.included(klass)
    klass.send(:include, AbstractInterface::Methods)
    klass.send(:extend, AbstractInterface::Methods)
    klass.send(:extend, AbstractInterface::ClassMethods)
  end
  
  module Methods
    
    def api_not_implemented(klass, method_name = nil)
      if method_name.nil?
        caller.first.match(/in \`(.+)\'/)
        method_name = $1
      end
      raise AbstractInterface::InterfaceNotImplementedError.new("#{klass.class.name} needs to implement '#{method_name}' for interface #{self.name}!")
    end
    
  end
  
  module ClassMethods
    
    def needs_implementation(name, *args)
      self.class_eval do
        define_method(name) do |*args|
          Bicycle.api_not_implemented(self, name)
        end
      end
    end
    
  end
  
end

class Bicycle
  include AbstractInterface
  
  needs_implementation :change_gear, :new_value
  needs_implementation :speed_up, :increment
  
  # Some documentation on the apply_brakes method
  def apply_brakes(decrement)
    # do some work here
  end
  
end

class AcmeBicycle < Bicycle
end

bike = AcmeBicycle.new
bike.change_gear(1) # AbstractInterface::InterfaceNotImplementedError: AcmeBicycle needs to implement 'change_gear' for interface Bicycle!
view raw gistfile1.rb This Gist brought to you by GitHub.

That approach certainly makes our code look a bit cleaner, I’m not denying that, however it has one really big flaw, at least for me anyway, it doesn’t give us a good to place to hang our documentation hat. In the previous approach we had actual methods that we could then document and that documentation would then show up in RDoc when it’s outputted. With the latter approach, however, we can document the hell out of the needs_implementation calls we have in the Bicycle class, but they won’t ever show up in the documentation. That means that users of our library have to crack open the actual code itself to see what it they are expected to implement.

Another approach we could’ve taken, which I bother to demonstrate here as I don’t think it offers a better approach is to have the needs_implementation method collect up the names of those methods and use method_missing to report that the method needs to be implemented. I mention it here only for completeness, but it definitely is not the best solution to this problem.

Finally, I would like to note that, as far as I can see, there is no way in Ruby to create a callback hook for when a class has been defined. If there was in fact such a hook we could use to it immediately notify the end user that they have forgotten to implement certain methods. Perhaps in Ruby 2.0??? That’s just pure hope on my part.

That’s it. I hope you enjoyed our brief (*cough*) look through implementing Interface and Abstract Classes in Ruby. I hope you’ve enjoyed it.

* PS, yes, I’m aware I didn’t talk about multiple vs. single inheritance in either Java or Ruby, nor did I talk about the fact that in Ruby you can’t really have Abstract Classes. I thought that was all a bit much for an already rather lengthy post as it was. Perhaps another day. :)

How to use a non-singleton version of Configatron

Thursday, November 20th, 2008

Since Configatron has come out it’s become a pretty popular library, and because of that I’ve received several feature requests. Nothing wrong with that. I actually welcome that, because, let’s be honest, that’s how configatron will become even better.

The biggest request I’ve received is from people who want to use Configatron, but they want their own instance of it, and not the global singleton instance of it. Although, I personally don’t see why you would need that, I’m a big enough man to understand that just because I don’t need it, doesn’t mean others don’t.

Last night I was reviewing the code, because I was asked this question again, and in doing so I realized that power has been there all along. It’s actually very simple. When you make a call on Kernel#configatron it returns a singleton of the Configatron class, but after that all it does is return an instance of the Configatron::Store class. So if you want your own instance of Configatron, what you really want is an instance of the Configatron::Store class, which you can do like so:

 

Well, there you go, I hope that helps. Enjoy.

Preview (0.7.0): Building Distributed Application w/ Mack (Screencast!)

Monday, August 18th, 2008

On Monday, August 25th, Mack 0.7.0 will be released. This is an extremely important release for Mack. Why is that you ask? Good question. Well, this is release that finally brings the much talked about distributed feature set to Mack. Distributed routes have been around for quite some time, but distributed views/layouts and distributed objects (models) have been missing. Well, in less than a week, you’ll have them!

Now I know that you’re just as excited about what’s coming as I am, that’s why I’ve prepared the first ever Mack screencast to demostrate these features. The screencast is a little rough around the edges, but it gets the ideas across. 

As always I’ll post more about the 0.7.0 as the release date nears. In the meantime enjoy the screencast:

The Mack Distributed Demo Screencast

Here’s the source code.

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