Install software to make software that makes software


I’m watching my terminal as Homebrew installs during my latest episode of yak-shaving. I feel a strange urge to explore the Homebrew site, a step that has nothing to do with the reason why I’m here. Hi, I’m Cliff. You’re here as the result of an unfortunate chain of events. You probably started to wash laundry when you realized you were out of detergent. On your way out the door to get detergent you noticed the handle was slightly loose and decided it needed to be tightened. Somewhere between looking for the screwdriver to fix the door something prompted you to check your email, before long you found yourself on Facebook where my post caught your eye. That’s one possible reason why you’re here. I’m here because some four footed hoofed creature with too much hair demanded my attention.

Hairy four legged beast demanding attention
Hairy four legged beast demanding attention

Extreme Yak Shaving
Have you ever found yourself downloading an OpenGL & SDL framework while watching a tutorial when what you really needed to do was install a missing JDBC driver? Today I found myself in a similar situation where I merely wanted to change a dependency in my Android project. That got me thinking about dependency management on iOS, and hey I just learned about this cool project called CocoaPods. To install Cocoa Pods I need Ruby. I can’t install Ruby the old school way, I’m downloading RVM! RVM’s install directions use the gpg command which isn’t available on Mac OS X. I need Mac Ports or Homebrew to install the Linux package. NO!!! I refuse to get side tracked with Homebrew! I’ll skip the gpg step and just use the curl command to direct install without checking security signatures!! The RVM install completes and while I install Ruby I notice the shell is going out to Homebrew land to automate the install. Gosh, I haven’t looked into Homebrew in over a year… I should check out their webpage to see what’s new. It’s always good to get the latest scoop on long living tech like Homebrew. Yak shaving is the work of doing meta work in order to do actual work. Extreme yak shaving is the distraction that results from work of doing the meta work.

I am installing software (Homebrew) to install software (ruby) to install software (Cocoa Pods) which I’ll use to install my iOS software dependencies. I’m not even getting into the learning curve associated with this major distraction. Am I losing it? (Don’t act like it’s just me! Some of you are waiting on a Unity or gaming engine download right now because you ran out of toilet paper!) How do we get some many layers of abstraction between us and the work we actually intend to do? I’m thinking eventually things will swing in the other direction as they always do. Instead of using systems to manage the install of managers that install frameworks we use to build systems (which ultimately manage the install of managers that install…) we will obsess over slim code and vanilla iOS/Java. Languages like Go are already becoming mainstream I’m waiting for the idea to spill into mobile which has currently gone the way of EJB. Until then I’ll keep watching my progress bar fill while the next software installing software installs.

Ruby mock objects drop parameters


Maybe it’s me but it sure seems like Ruby mocks are dropping the parameters passed in from Objective-C. I’m about to give up on this venture into RSpec for iPhone controller code development. In my mind I see it as a huge possibility and I’m willing to give it a few more shots before I wave the white flag. Here’s what I observed so far. (Keep in mind this is coming from a guy who just learned Objective-C, XCode, Ruby, and RubyCocoa reading Apple docs in the shower this morning!) If I call into a Ruby mock passing an int primitive directly from Objective-C while running under RSpec on the 10th day of the 11th month with 3/4th of my coffee mug occupied with the ol’ black magic juice (sorry but from my mobile experience it’s definitely important to set the stage listing all of your environment variables and making sure the stars are all aligned…) then I get a program crash. If I instead pass an NSNumber object wrapping the int then the parameter is silently ignored. If I call into a simple Ruby object defined inline in the spec then the parameter seems to come through just fine. If I then wrap the Ruby Mock with my own crude inlined mock passing the value from ObjC through my mock and into the Ruby Mock then all is right with the world… abusive husbands across America stop beating their wives while they join hands and sing Koom-by-ya… aggressive drivers let you over in heavy traffic, and the DOW jumps up 200 points. To see what I mean, here’s the updated spec code from my earlier posting:

bowling_controller_spec.rb

require File.dirname(__FILE__) + ‘/test_helper’

require “BowlingController.bundle”
OSX::ns_import :BowlingController
OSX::ns_import :BowlingProtocol

include OSX

class MyMock
attr_accessor :delegate
def roll(num)
puts “Number is #{num}”
puts “Calling delegate #{@delegate}…”
@delegate.roll(num)
puts “Done with delegate…”
end
end

describe BowlingController do
before(:each) do
@controller = BowlingController.new
@bowling = mock(‘BowlingProtocol’)
@text_field = mock(‘Pins’)
@text_field.stub!(:intValue).and_return(10)
@controller.pins = @text_field
end

it “should roll a ball” do
@controller.roll
end

it “should roll a ball and get the value from the pins outlet” do
@text_field.should_receive(:intValue).and_return(0)
@controller.roll
end

it “should be an OSX::NSObject” do
@controller.is_a?(OSX::NSObject).should == true
end

it “should have an outlet to a bowling object” do
@controller.bowling = @bowling
end

it “should send the pin value to the bowling object” do
mock = MyMock.new
puts “Setting delegate to #{@bowling}”
mock.delegate = @bowling
puts “Now passing mock into real code…”
@controller.bowling = mock
# @controller.bowling = @bowling
@bowling.should_receive(:roll).with(NSNumber.numberWithInt(10))

@controller.roll
end
end

I updated the controller to use a protocol:
BowlingController.h

//
// BowlingController.h
// BowlingController
//
// Created by FIXME on 2008-11-10.
// Copyright 2008 FIXME. All rights reserved.
//

#import

@class UITextField;
@protocol BowlingProtocol;

@interface BowlingController : NSObject {
UITextField* pins;
id bowling;
}
@property (nonatomic, retain) UITextField* pins;
@property (nonatomic, retain) id bowling;

-(void) roll;
@end

bowling_controller_spec.rb

//
// BowlingController.h
// BowlingController
//
// Created by FIXME on 2008-11-10.
// Copyright 2008 FIXME. All rights reserved.
//

#import “BowlingController.h”
#import “BowlingProtocol.h”

@implementation BowlingController
@synthesize pins;
@synthesize bowling;

-(void) roll{
int val = [self.pins intValue];
[self.bowling roll:[NSNumber numberWithInt:10]];
}

@end

// This initialization function gets called when we import the Ruby module.
// It doesn’t need to do anything because the RubyCocoa bridge will do
// all the initialization work.
// The rbiphonetest test framework automatically generates bundles for
// each objective-c class containing the following line. These
// can be used by your tests.
void Init_BowlingController() { }

BowlingProtocol.h

@protocol BowlingProtocol
-(void) roll:(NSNumber*)pins;
@end

More on this later as I explore…

The Backward Guide to Ruby Cocoa


First pretend you’re an Objective C professional and jump into iPhone development. (It helps to have absolutely no experience at this step.) Next, act over zealous about Test Driven Design and find the only unit testing framework that’ll half run against an iPhone project, one that just happens to be implemented in Ruby. Throw in a deadline just for fun You now have a recipe for achieve great feats in all things Ruby/Cocoa related and can now complain to your coworkers how stoopid Ruby is because it can only seem to intermittently find your method that is OBVIOUSLY defined on an objective C class you wrote moments ago.

Dumb Ruby programmers! How can anybody claim this technology is superior? Who cares that you didn’t read the documentation? Didn’t Joel say somewhere that users don’t read docs? Why can’t this stuff be easy enough to just pick up and use out of the box? After all if this were Java or Groovy you’d be finished by now!

Mumble a few more obscenities or discouraging words of condemnation toward the ultimately inferior platforms written by those who label themselves Rubyists or Cocoaists or whatever and then Google the thing you’re trying to do. What’s that towards the top of the page about how Ruby/Cocoa bridges work? Paraphrased:

The average idiot will note that RubyCocoa uses the Libffi library to call the Objective-C methods implementations. That means the first method call will go through the #method_missing mechanism, you moron, and then the Ruby method will be defined on the Ruby proxy class, thus allowing all (initial queries to Obj C classes to not know about the method while) further calls to be direct, and faster.

The best way to drive a developer nutz is to tell him something doesn’t exists when he/she is absolutely certain of the contrary. Go against logic. 1+1!=2, set a = b and (a == b) == false, function fooBar cannot be found because function fooBar is defined. There are plenty of other examples I’m sure.

Yes genius, you are attempting to learn Ruby Cocoa from the ass end. You know this but you are too arrogant to admit it, even to your significant other. Sure you’ll lie in bed and discuss things like how was work. The typical conversation leads you into a rambling session beginning with, “I had a bad day…” with you trying to explain to your incoherent loved one why things are getting you down. You can’t admit failure at this point as your loved one is lying, waiting for your to reveal weakness… any weakness that will serve as ammo in the next argument when you forget to cut the grass or have to run partially clad after the trash truck that powers away mercilessly from your residence because you had too many Bud Ice’s the prior night and passed out with that uncomfortable feeling that you knew you needed perform some important task but what the heck is it? No need to explain that you can’t perform your job because you skipped the fundamental steps required (actually learning the technology) to be productive in any capacity.

No worry, you can learn this stuff after you’ve used it. Learning is for sissies anyway, right? Who takes a class on starting an IV before declaring themselves a qualified Phd? That’s utter nonsense isn’t it? Just jam the damned needle somewhere close to the greenish looking line thing running down the arm and you’re all good! After the lawsuite begin you can enrol in Lincoln Tech and figure out why the deadly infection began in your first and only client. Yes we learn after we’ve trash talked the entire industry because it’s everyone else’s fault by now. The APIs should be written in a way that require no knowledge acquisition!

Disclaimer: The entirety of this article is meant tongue in cheek, while I appreciate all feedback positive and especially negative, don’t waste your time claiming Ruby and/or Cocoa is the best thing since Parish Smith got back with Eric Sermon. As a lover/consumer/advocate of anything programming related you’ll be preaching to the choir or buttering the tub of Land ‘o Lakes… you’ll be mowing the lawn mower… spray painting the brush, redundantly repeating the repetitive, repeatedly, or threading the thread spool. Save your keystrokes and don’t respond.

Ruby Calls ObjC!


I think I got it now! The other day I mentioned a problem with assert_responds_to in Ruby as you call into an ObjC controller. Today I had a different experience calling the “respond_to?” method on Object. Or so I thought the experience was different. Here’s what I observed, using autotest sometimes the assertion would pass. In my other example I was wsing the respond_to? message instead but sending this message after actually calling the method on the controller. Here’s what I mean.

This fails:

  def test_my_model_can_request_my_data
	myModel = MapModel.alloc.init
	assert mapModel.respond_to?("requestMyData"), "MyModel should define a requestMyData method"
	assert_not_nil myModel.requestMyData
  end

This passes:

  def test_my_model_can_request_my_data
	myModel = MapModel.alloc.init
	assert_not_nil myModel.requestMyData
	assert mapModel.respond_to?("requestMyData"), "MyModel should define a requestMyData method"
  end

It’s as if you have to send the message first before Ruby knows if the message is defined. That was sort of the thing I saw the other day. Adding the comment then removing the comment on an assert over a defined method gave different results. I’m going to try some introspection next, I’m just a little excited on figuring things out.

RBIPhoneTest Oddities?


Of course I don’t expect things to work 100% so it’s no surprise that I found an oddity in the RBIPhoneTest project (brought to you by Dr. Nic). No discredit at all toward Dr. Nic, as he did a fantastic job with what little Apple gives you. Maybe it’s my misunderstanding of Ruby testing and the ZenTest autotest thing but I got autotest running since finishing that screencast last night and I noticed that inserting a simple “assert_respond_to” call started showing a test failure when I thought it should pass. I then found something even funnier. After commenting the failing “assert_respond_to” call the test passed! Yes, that’s not really funny but get this. I uncommented the very same line that was failing and got the test to pass!! Now that’s funny! not in the “haha” sense of funny but more in the “things that make you go hmm…” Arseniol Hall kinda funny. It’s repeatable as well. I change the message name in the responds to assertion to make it fail, change it back to make it right but it still fails, comment the line to make it pass, uncomment and it still passes! More on this later…

iPhone Unit? TDD?


Thank God for people like Dr Nic. I managed to test drive a simple calculator project on the iPhone using his screencast. Just a quick note if you don’t come from the Ruby camp, (you know, like you spend most of your time obsessing over the JVM and toy with Groovy on the weekends):

You’ll want to install rubigen to get his example to work.

sudo gem install rubigen

You’ll also find that since the project renaming iphoneruby doesn’t work. Instead “gem install rbiphonetest”. My only question is why doesn’t my calculator respond to the reset method after I completed the screencast walk through and added the reset method to the object?

assert_respond_to calc, :reset

fails for me! Must be another one of those iPhone/ObjC inconsistencies that I’ll learn along the way.