Two amazing tools that focus on improving how tests are run rather than written in Ruby on Rails are Zeus and Guard. So what are they?
Zeus will preload a Ruby on Rails application so that you don’t have to whenever running rake, spec, or server commands.
Guard monitors the file system and executes tasks whenever files are change.
Follow this example Gemfile configured to work with growl, guard, rspec, cucumber and capybara:
group :development do
gem 'growl'
gem 'guard'
gem 'guard-bundler'
gem 'guard-cucumber'
gem 'guard-rspec'
gem 'guard-zeus'
gem 'rb-inotify', require: false
gem 'rb-fsevent', require: false
gem 'rb-fchange', require: false
end
group :test do
gem 'capybara'
gem 'capybara-webkit'
gem 'rspec-rails'
gem 'cucumber-rails', require: false
end
Follow this example Guardfile configured for cucumber and rspec:
guard 'bundler' do
watch('Gemfile')
end
guard 'cucumber', command_prefix: 'zeus', bundler: false do
watch(%r{^features/.+\.feature$})
watch(%r{^features/support/.+$}) { 'features' }
watch(%r{^features/step.+/.+$}) { 'features' }
end
guard 'rspec', zeus: true, bundler: false do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.slim|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
watch('app/controllers/application_controller.rb') { "spec/controllers" }
watch(%r{^app/views/(.+)/.*\.(erb|slim|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
end
It is possible to
bundle install
gem install zeus
zeus start
bundle exec guard
Over the past few iterations of iOS and Cocoa Apple has fundamentally changed the language and improved nearly every aspect. The removal of memory management (and replacement with ARC) has solved more than a few headaches. The addition of short form expressions and blocks means code can be refactored greatly. Here’s a snippet to show what an improvement it has been:
Old:
- (void)userSignupSuccess:(User *)user
{
...
}
- (void)userSignupFailure:(NSError *)error
{
...
}
- (void)signup
{
NSArray *objects = [NSArray arrayWithObjects:@"Kevin", [NSNumber numberWithInt:24], [NSDate date]];
NSArray *keys = @"name", @"age", @"modified";
NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
UserProcessor *up = [[UserProcessor alloc] init];
up.delegate = self;
[up create:params];
[up release];
}
New:
- (void)signup
{
[User create:@{ @"name" : @"Kevin", @"age" : @24 }
withSuccess:^(User *user) { ... }
andFailure:^(NSError *error) { ... }];
}
This isn’t the best of it though. An amazing new package manager has taken off that follows a similar format to the Ruby and Python equivalents. It is called CocoaPods and it rocks! Special thanks to Apple for making developers lives that much better and a huge thanks to all the open source developers who work for free every day to improve the ecosystem!
Step 1: Modify Your Gemfile
#ruby=jruby-1.7.0 ruby '1.9.3', engine: 'jruby', engine_version: '1.7.0' gem 'puma' gem 'rails', '3.2.9' gem 'puma' gem 'jruby-openssl', platforms: :jruby gem 'activerecord-jdbcpostgresql-adapter', platforms: :jruby gem 'therubyrhino', platforms: :jruby
Step 2: Modify Your Procfile
web: bundle exec rails server puma -p $PORT -e $RACK_ENV
Step 3: Configure Your Application
heroku create heroku config:set PATH=bin:/app/vendor/bundle/jruby/1.9/bin:/usr/local/bin:/usr/bin:/bin heroku config:set GEM_PATH=vendor/bundle/jruby/1.9
Step 4: Deploy
git push heroku master
Step 1: Install Xcode
Step 2: Install XQuartz
Step 3: Install Everything
Finished version can be found here: http://gethearts.com/.
I’ve been a practicing iOS and Mac developer for a few years and I love many aspects of Apple’s platforms. Apple’s interface design software is incredible, programs run fast even on mobile devices, and the debugging tools are fantastic. However, with experience comes bitterness. My “grass is always greener” beliefs comes from having also been writing Ruby (on Rails) code as well. Rails has introduced me to a variety of conventions that I think should be in the Cocoa frameworks. So, I’ve decided to compare and contrast a few snippets of Cocoa and Rails and list my two biggest issues.
The first issue with Mac development is the language. Objective-C might have been the hottest thing in town in the 1980’s but it has cooled off over the last 20 years. One of my biggest frustrations is with the amount of code required to get started. For example, compare these two class declarations:
Ruby:
class Person
attr_accessor :name
end
Objective-C:
#import "Foundation/Foundation.h"
@interface Person : NSObject
{
NSString *name;
}
@property (nonatomic, retain) NSString *name;
@end
#import "Person.h"
@implementation Person
@synthesize name;
- (void)dealloc
{
[name release];
name = nil;
[super dealloc];
}
@end
The above code explains where my frustration stems from. Having lots of code is a pain. It is difficult to read, difficult to troubleshoot, and easy to do wrong. I often struggle with programming in Objective-C and follow DRY (don’t repeat yourself) paradigm.
The second problem with developing in Cocoa is that the framework designers went in with some questionable goals. I first learned Cocoa by watching presentations from Apple Engineers and can remember hearing “Cocoa makes the easy things easy and the hard things possible” as a mantra. As Robert Martin stated in his 2009 Rails Conference presentation in “What Killed Smalltalk Could Kill Ruby Too” this is insane. The real motto should be something along the lines of “make the easy things trivial and the hard things easy”.
A great example of making hard things easy can be found in how Rails handles persistent storage. Active Record was integrated into Rails to make saving, storing and updating database records a breeze. Core Data was designed by Apple to torture developers. For example, see some of the steps required to make the previous example persistent:
Rails:
Person.all.each do |person|
puts "Hi #{person.name}"
end
Cocoa:
NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@"model.mod"]];
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] init];
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:@"data.sqlite"] options:nil error:NULL];
[managedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinator];
NSFetchRequest *request;
NSEntityDescription *entity;
request = [[NSFetchRequest alloc] init];
entity = [NSEntityDescription entityForName:@"Person" inManagedObjectContext:context];
[request setEntity:entity];
NSArray *people = [context executeFetchRequest:request error:NULL];
for (Person person in people)
{
NSLog(@"Hi %@", person);
}
[request release];
[managedObjectContext release];
[persistentStoreCoordinator release];
[managedObjectContext release];
This isn’t a language limitation, this is a framework problem. Core Data could have been designed to give developers the same one line access to data that Rails has, but good defaults were never selected. As such flexibility was created at the cost of many developers time. Apple should have set out with a set of goals for doing basic CRUD operations without ever having to look through copious amounts of documentation.
I don’t hate Apple; let me assure you that the opposite is true. I understand that the hardware and software shipped by the company over the past five years will be marked as some of the best ever created. I just hope that someone in Cupertino is thinking about the developers as the frameworks and languages continue to progress.
I am finishing in the process of finishing up a project and have started to question the ‘correctness’ of grid systems. Although they are extremely powerful I see a few things I wish were better:
New Markup Grid systems require the introduction of new markup into the HTML (adding ‘grid-1’, ‘grid-2’, ‘grid-3’, etc. to divs, etc.). This is terrible HTML to inject because it is non-semantic (adds no meaning). A workaround is to switch to using smarter stylesheets with SASS and Compass, however for many projects this isn’t an option.
Annoying Layouts Grid systems rely on having ‘gutters’ between elements. Unfortunately this can make integrating with non grid system elements a pain. One solution is to switch to using a more precise grid system.
Commitment Issues The last criticism of grid systems pertains more to design decisions. Once a designer (or developer) starts using grid systems they get hooked. Just because the grid system can format a beautiful about page, does not mean it should be used within the core of an application.
Conclusion Although the above issues are serious, life is much better with grid systems. Use them, but use them carefully.
Concept logo for online video portfolio site.
I recently needed a small project to test out Platypus, a tool used to create simple native Mac applications. After only 30 minutes I managed to create a container for OptiPNG, a PNG compression library (download DMG or Zip). The icon was found on Icon Finder and was designed by Louise Harobe. The DMG was created using DMG Canvas.