Our first gem: Motion Launchpad

For our first real exercise in RubyMotion, there is no better place to start than writing our very first gem. We'll be creating a gem called 'motion-launchpad' that I'll open source and release for others to use, providing a simple schedule interface based on launch counts, for performing tasks in your app.

If you want to just view the gem directly and skip this tutorial (shame on you) you're welcome to check out the project on github.

Getting Started

The first thing we are going to need to do is create a git repo and the basic gem structure for a RM project. That means a folder with the following structure:

- app
- Gemfile
- lib/
  - motion/
    - launchpad.rb
    - version.rb
  - motion-launchpad.rb
- motion-launchpad.gemspec
- spec/

A good way to get going is by installing the excellent gem release command and using gem bootstrap [gem_name] as a starting point. This applies to any Ruby gem and is not RM specific.

We'll start by creating the contents of our lib/motion-launchpad.rb file:

unless defined?(Motion::Project::Config)
  raise "This file must be required within a RubyMotion project Rakefile."
end

lib_dir_path = File.dirname(File.expand_path(__FILE__))
Motion::Project::App.setup do |app|
  gem_files = Dir.glob(File.join(lib_dir_path, "motion/**/*.rb"))
  app.files.unshift(gem_files).flatten!
end

We'll also want to ensure that the project Rakefile is updated for a RM project. At this point in our progress you can check out the first commit in our repo.

Configuring RM App Delegate

For our test suite to run, we'll need a UIApplication delegate that just returns true and doesn't worry about anything else, allowing our unit tests to run.

We're not including anything in the app directory as the contents of our gem, they're strictly there for the test suite to have a valid application to run against.

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    return true if RUBYMOTION_ENV == 'test'
  end
end

Checking our Progress

At this point, you should be able to just run rake from the Terminal and open the simulator with a black screen. We have not created a window, rootViewController or anything else in our delegate and don't need to.

You can play in REPL and see that we have our modules and classes defined and that they are accessible.

Motion::Launchpad.new
=> #<Motion::Launchpad:0x8e8a050>

Write our First Test

Now that we have a basic structure and can use REPL, we're ready to write our first test and add our functionality.

describe Motion::Launchpad do

  it "should return an instance" do
    Motion::Launchpad.configure.should.be.instance_of Motion::Launchpad
  end

  it "should return the same instance twice" do
    instance = Motion::Launchpad.configure
    instance.should.be.equal Motion::Launchpad.configure
  end
end

And the code that makes this test pass:

module Motion
  class Launchpad

    class << self
      attr_accessor :instance

      def configure(&block)
        self.instance = new if instance.nil?
        instance
      end
    end
  end
end

You can read more about the rspec-ish syntax of MacBacon here.

Wrapping up

For speed sake, we're just going to reference the project on github for the finished gem.

Our finished product provides a nice and clean DSL for configuring events, such as:

class AppDelegate
  def application(app, didFinishLaunchingWithOptions: options)

    setup_schedule
    Motion::Launchpad.run!
  end

  private

  def setup_schedule
    Motion::Launchpad.configure do |config|
      config.on :every do
        # maybe track app launch with analytics?
      end

      config.on 1 do
        # first launch, maybe show user a tutorial?
      end
    end
  end

  # You can call `configure` multiple times
  Motion::Launchpad.configure do |config|
    config.on 5 do
      # ask user to rate your app? Hate doing that, but best I could come up with
    end
  end
end

You can check out the complete Motion::Launchpad::Schedule class here, the Motion::Launchpad::Event class here, and the module showing some cooler meta programming methods in ruby here.

Releasing the gem is as easy as running gem release --tag from the directory, which I've already done. Enjoy and send a pull request if you have feedback, questions or improvements!

Up Next

In the next article we'll be taking a into meta-programming in RubyMotion and also be taking a look into the new AVSpeechSynthesizer class which debuted in iOS 7.

Ready to have a chat?

Contact us to chat with our founder
so we can learn about you and your project.