Posted on October 15, 2011
If you have a lot of private gems that are packaged using Bundler then there is always the fear of someone accidentaly running rake release and pushing all of your fancy enterprise code to RubyGems. Let’s prevent this from happening!
First, add the following to your Rakefile, just below the require statements.
class Rake::Task
def kill!
@actions.clear
prerequisites.clear
enhance { puts "This task is not allowed!" }
end
end
This snippet adds a kill method to all Rake tasks, even those that are defined outside of the Rakefile.
Now, whenever you want to prevent a task from being used you can kill it using the following invocation:
Rake::Task[:release].kill!
When you invoke the release task after calling kill! on it you will be presented with a warning:
$ rake release
This task is not allowed!
Of course you can use it to kill nested tasks too:
Rake::Task[:"db:drop"].kill!
In this example the Ruby on Rails db:drop task is killed.
Replacing tasks
Normally, when you create a task entry for a task that already exists the given block will be appended to the task. This means that vanilla Rake only has the ability to add work to a given task, not replace it.
However, if we clear the actions first and then append a new block to the list of actions (this is what the enhance call does) we can still manage to replace the entire task.
Here’s an example:
class Rake::Task
def replace &block
@actions.clear
prerequisites.clear
enhance &block
end
end
Rake::Task[:release].replace do
puts "Put your own release code here"
end
Permalink - nnn comments
Posted on August 24, 2011
Whenever you create a new project in Xcode there are a couple of Objective-C files automatically generated, such as the application delegate. One thing in particular that bothers me about these files is the messy coding style.
One example of this is the inconsistent placing of the opening curly braces. On methods the opening brace is placed on a new line below the method declaration, and on if statements and the like they are placed on the same line.
Most of the templates also have a lot of trailing whitespace, and the Xcode editor itself is rather sloppy when it comes to cleaning that up.
Because I primarily use Vim for my editing needs, I wrote a little function that cleans things up. You can put it in your .vimrc.
function! TransformObjC()
" correct the code style of an Xcode Objective-C file
silent! execute "%s/- (/-(/"
silent! execute "%s/+ (/+(/"
silent! execute "%s/\\n{\\n/ {\\r/"
silent! execute "%s/\\ \\+$//"
endfunction
This function does the following:
- Remove the space between the plus or minus and the return type parenthesis on method signatures.
- Place the opening curly brace on the same line as the method signature.
- Clean up any trailing whitespace.
Because these regular expressions only do minor corrections you can call the function as an auto command when you load a new Objective-C file. This can be done as follows in the .vimrc:
autocmd! BufRead *.m call TransformObjC()
Now you can easily mix edits in Vim and Xcode without being annoyed by sloppy formatting. Just remember to reload buffers when going from Xcode to Vim.
Permalink - nnn comments
Posted on August 15, 2011
For Mac and iOS development the weapon of choice is Xcode. And it’s pretty good for what it does (if you disregard the current stability issues with Lion) when you are just making simple apps. In my own projects, however, things usually get more complex and I need to put a lot of stuff in static libraries and juggle these around in all the projects that use them. It turns out that using Xcode for this library management is quite cumbersome, so let’s see what we can do to automate this.
When you look at a typical Xcode project you see a bunch of code assets and a projectname.xcodeproj file. This file is actually a directory in disguise and contains all the project metadata. Most of this metadata is just settings for the Xcode user interface and is not directly related to our code.
The file that we are interested in is called project.pbxproj. This file contains the entire Xcode project structure. The project is described as an object graph, meaning that every entity in the project is a node that has an identifier, a type and zero or more references to other entities. The ideal representation for such a graph is a list of key-value pairs, and indeed the pbxproj file resembles this. Users of document oriented databases such as MongoDB should feel right at home.
Now when you open the pbxproj file in a text editor you see that the file has a syntax that is somewhat reminiscent of JSON. What you are looking at is in fact a plist file in the ancient (and even deprecated) NeXTSTEP ASCII format. Why Apple still uses this format for Xcode remains a mystery to me.
There are a couple of Ruby gems available to parse and manipulate pbxproj files. However, I find all of these gems too bloated for what they do. We can apply a bit of DRY by utilizing two existing tools.
On OS X there is a command line utility called plutil that, accoording to the manual page, is supposed to be used for syntax checking and plist format conversion. Of notable interest is that it can convert plist files to JSON, which we can parse using Ruby’s own JSON parser. Another interesting thing is that it can read all types of plist formats, including the NeXTSTEP format we are interested in.
This means that a simple pbxproj parser can be shrunk down to a single line of code:
def parse_pbxproj filename
JSON.parse(`plutil -convert json -o - "#{filename}"`)
end
This function returns a Hash object containing the entire object graph which you can then manipulate in whatever way you want. When the time comes to save the changes you can make use of these extra methods:
class String
alias to_plist to_json
end
class Array
def to_plist
items = map { |item| "#{item.to_plist}" }
"( #{items.join ","} )"
end
end
class Hash
def to_plist
items = map { |key, value| "#{key.to_plist} = #{value.to_plist};"
"{ #{items.join} }"
end
end
def save_pbxproj filename, hash
File.open(filename, "w") do |file|
file.write hash.to_plist
end
end
Now remember that the only types that you should use in a plist are strings, arrays and hashes. If you have anything else, like an integer, you will have to convert it to a string.
The methods above have been tested on about ten different projects using Xcode 4.1 and 4.2 beta and work perfectly. For best results reload your Xcode project after manipulating the pbxproj file with an external program, especially when developing for iOS.
Of course, this is just the beginning. I have used this parser myself to build a tool that can synchronize Xcode projects and GNU makefiles with good success. What will you do to accelerate your workflow?
Permalink - nnn comments
Posted on July 17, 2011
I am currently working on a synthesizer for the iPad. An important thing here is that the sound rendering callback must be as fast as possible so that you can reduce the audio buffer size and thus get a lower latency.
This means that, if you want to do anything more than a stupid non-bandlimited monosynth with horrible sound quality (such as the currently trending free Core Synth, but there are many others), you will have to spend a lot of time optimizing the renderer. This is especially important when you want to build a polyphonic synthesizer, where rendering time scales linear with the amount of concurrently playing notes.
Recently I discovered that Clang optimizes differently depending on whether you use single or double precision floating point numbers. The result of this is something you would not expect. Today I want to focus on a single aspect which might slow a lot of things down. Suppose you have this piece of code:
Any sane programmer would convert this to machine code by evaluating the exponential function during compilation and writing down a single load-constant operation in the compiled program. In other words, the compiler would treat the exponential function as a const function. That is a function that produces an output value that only depends on the input, meaning that there are no side effects and every invocation of the function with a constant input value will always result in the same output value.
However, it turns out that Clang can only optimize away some of these functions when they are called with constant parameters. So I’ve made a little table which tells you what functions you can safely use with constants. The functions that have a “no” will be compiled to a normal function call even when the input is a constant, so they should be replaced with precomputed constants if possible.
So here’s the table. Measurements were done using the Apple LLVM 3.0 compiler which is found in the XCode 4.2 beta.
| Function |
float |
double |
| sin |
yes |
yes |
| cos |
yes |
yes |
| tan |
no |
yes |
| asin |
no |
no |
| acos |
no |
no |
| atan |
no |
yes |
| atan2 |
no |
yes |
| sinh |
no |
yes |
| cosh |
no |
yes |
| tanh |
no |
yes |
| exp |
no |
yes |
| exp2 |
no |
no |
| expm1 |
no |
no |
| log |
no |
yes |
| log2 |
no |
no |
| log10 |
no |
yes |
| log1p |
no |
no |
| fmod |
no |
yes |
| fabs |
yes |
yes |
| sqrt |
yes |
yes |
| pow |
no |
no |
| ceil |
no |
yes |
| floor |
no |
yes |
| rint |
no |
no |
| round |
no |
no |
| trunc |
no |
no |
When you write your own functions you can give Clang a hint that this function is a const function and has no side effects. This helps Clang to optimize away instances which are called with constants. In order to help Clang you have to modify your function declaration to be as follows:
int __attribute__ ((const)) myfunction(int arg) {
return 42 + arg;
}
This trick originates from GCC, so more documentation about function attributes can be found in the GCC documentation.
Permalink - nnn comments
Posted on July 09, 2011
Consider the following piece of Python code:
import math
class RCFilter:
def __init__(self, decaytime):
self.output = 0.0
self.coeff = 1.0 - math.exp(-1.0 / decaytime)
def apply(self, input):
self.output += self.coeff * (input - self.output)
return self.output
This is a simple one-pole lowpass RC-filter, frequently used as a smoother for parameters that change over time but should never be changed instantly. You instantiate the class with a time coefficient which indicates how many samples it it should take to reach a ratio of 1 / e between the old and the new value. After that you can call apply to smooth out an input signal.
Now, we want to test the behaviour of this filter with a given signal. This can be done as follows:
filter = RCFilter(10.0)
for i in xrange(40):
print filter.apply(1.0)
for i in xrange(80):
print filter.apply(0.0)
Now we have generated 120 samples, but from the numbers alone it is hard to see what is happening. However, we can use some command line magicks to turn this into a plot. For this we are going to use Gnuplot, which should be available in your favourite package manager.
In order to make the plotting as simple as possible, we want to invoke it as a command line script that reads numbers from standard input and presents a plot on screen. This way we can pipe any program we write directly to our plot script.
The hard part is getting Gnuplot to read stuff from the standard input stream of the invoking script. This is not trivial because Gnuplot flushes its own input stream and assumes that standard input is the same stream as the one that is used to enter the plot commands. That means we can only get this working if we concatenate the script and standard input. The Gnuplot commands to plot data from what Gnuplot considers the input stream are like this:
set term pdfcairo enhanced color solid \
font "Helvetica Neue,8" lw 5 size 8,6;
plot "-" with lines title "";
These commands tell Gnuplot to produce a PDF file which has been rendered using Cairo. This gives us the best visual result. If you want to use PNG output you can use the pngcairo engine instead, although I recommend using a tool like ImageMagick for the conversion because it generates better antialiased results and can handle transparency if you need it. We also set some good looking appearance settings, such as font, line width and output size (in inches at 72 dpi). The second line is the actual plot line and can of course be modified if you want a bar chart instead of a line chart or whatever.
Using these commands directly will not work because we have not yet concatenated anything. To do that we will wrap the Gnuplot commands in a Bash script, like this:
#/bin/bash
(
echo "
set term pdfcairo enhanced color solid \
font \"Helvetica Neue,8\" lw 5 size 8,6;
plot \"-\" with lines title \"\"";
cat -
) | gnuplot | open -f -a Preview
Now we have our plot commands concatenated with the script’s standard input and pipe that to Gnuplot. This produces a PDF file in standard output which we can pipe to our favourite display program. The open command is Mac OS X specific and giving it the -f -a Preview argument tells it to write standard input to a temporary file and open that file with Preview. For Linux you can use display, xdg-open, eog or whatever.
Now when we run our Python filter script and pipe it to this plot script we get the following window:

Because the generated PDF file contains a vector representation of the plot, you can resize the plot to whatever size you need without any loss of detail.
Permalink - nnn comments
Want more? Check the archives!