Home > objc-shorthand

objc-shorthand

Objc-shorthand is a project mainly written in RUBY and SHELL, based on the MIT license.

A Ruby DSL for writing boilerplate Objective-C concisely.

Objective-C Shorthand in Ruby

This tiny library allows boilerplate Objective-C code (in particular, property synthesis and memory management code) to be produced from a very compact Ruby DSL-ish representation of the class.

For example:

#!/usr/bin/env ruby
require 'objc_shorthand'

objc_class :PersonController do
    framework 'AppKit'
    import 'PersonControllerDelegate.h'

    name
    surname
    marriedTo :Person, :will_set
    displayLabel :NSTextField, :outlet
    delegate 'id <PersonControllerDelegate>'
end

describes a class whose generated header, once expanded from shorthand, is:

// ----------------------------
// AUTOGENERATED FROM:
// /Users/millenomi/BLAHBLAH/Shorthand/x.m.rb
// ----------------------------

#import <AppKit/AppKit.h>

#import "PersonControllerDelegate.h"

@interface PersonController : NSObject

@property(assign,nonatomic)  id <PersonControllerDelegate> delegate;
@property(retain,nonatomic)  id surname;
@property(retain,nonatomic)  Person* marriedTo;
- (void) marriedToWillChangeToValue:(Person*) aNewValue fromValue:(Person*) anOldValue;
@property(retain,nonatomic) IBOutlet NSTextField* displayLabel;
@property(retain,nonatomic)  id name;

@end

and a corresponding implementation file. marriedToWillChangeToValue:fromValue: will be called as part of the setter of marriedTo, as you might imagine, and note how delegate is declared assign by convention. Files generated by expanding shorthand scripts are meant to be used with the generation gap organizational strategy, and provide override points for your actual subclass (like the willChange… method above).

A more complete example is found in the examples directory.

To expand shorthand, just run the objc_generate_from_shorthand.rb script passing your shorthand script as argument, ie.

$ ruby -I. objc_generate_from_shorthand.rb my_class.m.rb

A shorthand file may contain multiple classes; expanding will produce dedicated .hs and .ms for each.

Dependencies

This library the most recent version of the mustache gem.

Reference

objc_class(name) do …

  • name: (anything responding to to_s)
  • returns: an ObjCClass instance

Produces a new Objective-C class definition. You must pass a block, which will execute within the context of a ObjCClass instance.

ObjCClass.framework(name), ObjCClass.import(name)

These methods add an import statement at the top of the class's file. If you specify no framework imports, Foundation will be imported by default.

You need only specify the framework's name, without repeating; ie.

framework 'Cocoa'

ObjCClass.subclass_of(name)

Sets the superclass of this class. If not used, the class will inherit from NSObject. For example:

subclass_of :UIViewController

You might need to use framework or import to make sure the superclass's interface is imported.

ObjCClass.ivar(name, type = nil, *options)

  • name: (anything responding to to_s)
  • type: (a String or Symbol)
  • options: (an array of Symbols or special objects; see below)

Creates a new instance variable and property pair for this class with the specified arguments. Note that ObjCClass implements method_missing so that:

ivar :name, :NSString, :copy

can be shortened to

name :NSString, :copy

whenever the ivar name does not conflict with another ObjCClass method.

The name you give is the name of the property, whereas the name of the backing instance variable will be name followed by an underscore (eg name_). Ivars generated this way are @protected.

The type can be a symbol, in which case it's generally regarded to as a method name, or a string, which will be used verbatim. Special symbols you can pass are:

  • :int: short for "NSInteger"
  • :uint: short for "NSUInteger"
  • :str: short for :NSString
  • :bool: short for "BOOL"
  • :id and :Class

The type passed in will be considered an object type if you used a symbol (other than those above) or if you used "id" or "id<…>" as the string (with any amount of spacing). You can force types to be used as object types (useful for eg. block types); see below.

The rest of the parameters form the options for the ivar. The generator understands the following options:

  • :retain, :copy, :assign: Force a particular memory management mode for a property. If none is specified, the expander will try to infer a mode (eg. non-object types will get assign; properties named delegate or …Delegate will get assign etc.).

  • :ro will cause the property to be created readonly.

  • :object: Require the type to be treated as an ObjC object type. This may be useful if you're dealing with Core Foundation or typedef'd block types.

  • :atomic: Marks a property as atomic. By default, all properties are generated nonatomic. You can't mix this and :will_set, :did_set or anything else that requires generating an explicit accessor.

  • :will_set, :did_set: Generate override points before and after a property's ivar is assigned in the setter. This will generate an explicit setter accessor implementation (not @synthesize).

  • :will_get: Generate override point before the property accessor will return the property's value. This will generate an explicit getter accessor implementation (not @synthesize).

  • getter(name): Indicates that you want the getter to have a different name. Note that this is a function call, not a symbol. Eg:

      clean :bool, :did_set, getter(:isClean)
Previous:test