Using Bundler With Rubymotion
Laurent Sansonetti of HipByte made a big splash last month when he released RubyMotion – a toolset based on MacRuby that allows you to create native iOS applications.
Fun, new constraints!
Since the Apple TOS doesn't allow applications to evaluate code at runtime, RubyMotion puts some limitations on what you can do and when.
The most interesting constraint is that the use of require isn't allowed outside of the Rakefile Instead, all ruby files found in the app directory are compiled into the target executable in alphabetical order.
Libraries
The lack of require is the largest hurdle stopping RubyMotion developers from using the standard set of RubyGems that we know and love. For the most part, this isn't an issue - most ruby libraries have native iOS counterparts that are more appropriate, and the RubyMotion community is quickly replacing them. But this does have a direct impact on how we distribute and use those new libraries.
Vendor everything
The initial solution recommended by the documentation and examples was to simply vendor all libraries, and manage them as git submodules. For each library you want to use, you must add the submodule:
$ git submodule add https://github.com/mattetti/BubbleWrap.git vendor/BubbleWrap
And then specify the files to be compiled in the Rakefile:
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
Motion::Project::App.setup do |app|
app.files += Dir.glob(File.join(app.project_dir, 'vendor/BubbleWrap/lib/**/*.rb'))
#...
The biggest drawbacks of this technique are:
- Versioning is ad-hoc and inconsistent between libraries. Is there a tag I should be tracking? Should I just track master?
- There's no good way of specifying dependencies. Some libraries even included nested submodules, which can quickly become unwieldy.
- Each library must be installed and managed by hand.
Require gems by hand
HipByte quickly realized that the vendored solution wasn't going to scale, and added rudimentary capabilities for releasing RubyMotion-only gems. The process is somewhat improved:
Install the gem via the commandline:
$ gem install bubble-wrap
Require the gem explicitly in your Rakefile:
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
require 'bubble-wrap'
#...
This is definitely an improvement, as we now have dependencies and clear and consistent versions. But the issue of needing to manage versions between each developer on a project, and the fact that each gem must be installed and required manually is a bummer. Feels like a familiar bummer, though…
Use Bundler
Bundler solved all of these issues for Rails developers, and it can solve them for RubyMotion developers as well. Installation needs to only happen once, and is as simple as:
Install bundler:
$ gem install bundler
Require bundler, and call Bundler.require in your Rakefile:
$:.unshift("/Library/RubyMotion/lib")
require 'motion/project'
require 'bundler'
Bundler.require
#...
Now, every gem specified in your Gemfile is available in your compiled application, and the versions and dependencies are ensured to be consistent between teams through the Gemfile.lock file!
Adding a gem is as simple as adding a single line to your Gemfile:
source :rubygems
gem "rake"
gem "bubble-wrap"
gem "motion-cocoapods"
Each developer then runs bundle install and they're good to go.
*Keep it real, we'll erase shit we don't like.* comments powered by Disqus