March 11, 2010 at 10:39am
Expectations on method calls within a block in RSpec
At Lexer, we are using Solr (via SunSpot) to perform full text searches on our data. We have a Rails app that has a feature where a user can dynamically build a query and submit it via an AJAX call with the query itself represented as a JSON array of conditions.
The server side receives this JSON array, and passes it through module called JsonToSunspot which executes the equivalent Sunspot search.
So I’d receive a set of conditions as JSON that look something like this:
[
{'with' => {'some_attribute' => 'foo'}},
{'with_not' => {'some_other_attribute' => 'bar'}}
]
And translate them into a Sunspot invokation like this:
Sunspot.search(MyModel) do
with(:some_attribute, 'foo')
with_not(:some_other_attribute, 'bar')
end
Ideally, I’d like to unit test all of this without actually bringing up Sunspot. The problem was, I couldn’t see how to mock ‘self’ within the context of the block in order to set expectations that ‘with’ and ‘with_not’ were called with appropriate arguments.
Turns our you can do this with RSpec’s ‘and_yield’ method like so:
Sunspot.should_receive(:search).with(MyModel).and_yield do |context|
context.should_receive(:with).with(:some_attribute, 'foo')
context.should_receive(:with_not).with(:some_other_attribute, 'bar')
end
The key here is the ‘context’ variable. It is a mockable version of self. Pretty awesome huh?! Now when my JSON-to-Sunspot code executes, I can actually test that it invokes Sunspot correctly without having it running.
Special thanks to @robertpostill for the tip.
February 18, 2010 at 9:31am
Ignite Sydney
Lexer’s very own Andrew Harvey will be presenting at Ignite Sydney 4 on Tuesday 2nd March. While he won’t be talking about anything to do with the products we’re building, we’re looking forward to seeing what comes out of his talk titled “Your best camera is the one you have with you”.
Apparently there are only limited tickets left (they’re free!), so register now!
February 13, 2010 at 12:35pm
Installing pyactivemq on OS X
Some of our apps need to have high performance messaging queues to hand data between various processes in an efficient manner. We decided after a lot of research to go with ActiveMQ, which has been an excellent choice, but installing the python bindings on OS X proved a challenge. Here is how we got it done.
Note that pyactivemq is only compatible with ActiveMQ-CPP 2.x.x. Don’t bother installing 3.x.x.
It will only make you cry.
Download the latest ActiveMQ-CPP 2.x.x build. Apache has annoying redirects from http downloads so
it is generally just easier to get the subversion checkout. For me that meant doing this:
svn co https://svn.apache.org/repos/asf/activemq/activemq-cpp/tags/activemq-cpp-2.2.6
Having done that, it’s just a matter of a straight build, except for a mysteriously missing config
directory. We’ll create that first.
cd activemq-cpp-2.2.6
mkdir config
./autogen.sh
./configure
make
sudo make install
Now, that was easy enough. Here comes the fun. I’m assuming you’re using python installed with
MacPorts into the default location. Something funky happens with the symlinks there, so we’re going
to hack around with the Apple install of Python so it points back at the MacPorts one.
cd /System/Library/Frameworks/Python.framework/Versions
sudo mv 2.6 2.6.apple
sudo ln -s /opt/local/Library/Frameworks/Python.framework/Versions/2.6 2.6
Sweet. I’m not sure of the full implications of doing this, but it doesn’t appear to have broken
anything for me yet, but I only use my MacPorts build of Python, not the Apple one.
Now let’s install boost. It takes forever, so go do something with yourself while waiting.
sudo port install boost +python26
Now for pyactivemq.
svn co http://pyactivemq.googlecode.com/svn/tags/pyactivemq-0.1.0
cd pyactivemq-0.1.0
Now you would think it’s just a matter of running setup.py and installing? No. We have to mess around
with it because it has some nasty hard-coded paths. I’m assuming you let ActiveMQ-CPP install into
the standard path (/usr/local/lib), so those are the paths I used, but you will have to work out
your own paths if you did it differently.
This is the patch from the changes I made to setup.py, replacing nasty hard-coded paths with more
nasty hard-coded paths.
Index: setup.py
===================================================================
--- setup.py (revision 208)
+++ setup.py (working copy)
@@ -67,19 +67,21 @@
]
else:
include_dirs = [
- '/opt/activemq-cpp-2.2.1/include/activemq-cpp-2.2.1'
+ '/usr/local/include/activemq-cpp-2.2.6',
+ '/opt/local/include'
]
libraries = [
'activemq-cpp',
'uuid',
- 'boost_python'
+ 'boost_python-mt'
]
library_dirs = [
- '/opt/activemq-cpp-2.2.1/lib'
+ '/usr/local/lib',
+ '/opt/local/lib'
]
extra_compile_args = []
extra_link_args = [
- '-Wl,-rpath,/opt/activemq-cpp-2.2.1/lib'
+ '-Wl,-rpath,/usr/local/lib'
]
define_macros = [
('BOOST_PYTHON_NO_PY_SIGNATURES', 1),
There you have it. Assuming all your paths match up, you can go ahead and build and install.
sudo python setup.py install
Then load up your python interpreter and make sure the module imports happily.
~/Projects/pyactivemq-0.1.0 $ python
Python 2.6.4 (r264:75706, Jan 5 2010, 09:51:33)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyactivemq
>>> pyactivemq
<module 'pyactivemq' from '/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/pyactivemq.so'>
February 12, 2010 at 11:38am
First post.
As the description says, Lexer is a startup building a suite of apps to measure and increase marketing efficiency. This is where we’re going to share some thoughts, tricks we’ve discovered along the way and things we think are cool.
Stay tuned for more!