<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-22641314</id><updated>2024-09-27T09:31:03.949-07:00</updated><category term="gamedev"/><category term="xna"/><category term="code"/><category term="ruby"/><category term="rails"/><category term="activeresource"/><category term="atom"/><category term="collisions"/><category term="erlang"/><category term="gem"/><category term="rake"/><category term="testing"/><title type='text'>Game Dev Journal</title><subtitle type='html'>I&#39;m repurposing this neglected blog to act as a record of my journey into game development.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-22641314.post-9103995623926291444</id><published>2011-09-06T15:31:00.000-07:00</published><updated>2012-02-10T15:33:50.280-08:00</updated><title type='text'>Again</title><content type='html'>This repurposed blog has once again been neglected. I&#39;m &lt;a href=&quot;http://www.codefire.com/&quot;&gt;back doing Ruby&lt;/a&gt; and having great fun. If I do start blogging again, it probably won&#39;t be on blogger and definitely won&#39;t be this blog. :)&lt;br /&gt;
&lt;br /&gt;
Adios</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/9103995623926291444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/9103995623926291444' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/9103995623926291444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/9103995623926291444'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2012/02/again.html' title='Again'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-1292284674009400328</id><published>2011-03-25T20:34:00.000-07:00</published><updated>2011-03-28T01:21:54.629-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="collisions"/><category scheme="http://www.blogger.com/atom/ns#" term="gamedev"/><category scheme="http://www.blogger.com/atom/ns#" term="xna"/><title type='text'>Breakout Week 4: Building a Wall (Part 2)</title><content type='html'>This is part two of my two part post of building the wall in my Breakout game.&lt;br /&gt;
&lt;br /&gt;
With the &lt;a href=&quot;http://seangeo.blogspot.com/2011/03/breakout-week-4-building-wall-part-1.html&quot;&gt;wall in place&lt;/a&gt;, the next step is to make the ball break the bricks as it hits the wall. &amp;nbsp;This bring us back to&amp;nbsp;&lt;a href=&quot;http://seangeo.blogspot.com/2011/03/breakout-week-3-when-balls-collide.html&quot;&gt;collision detection and response again&lt;/a&gt;.&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I did quite a bit of reading on this because there are a number of ways you could do it. &amp;nbsp;The collision detection part can be fairly easy, where you just check if the ball is within the bounds of each brick, but it gets complicated by the fact that once you know a collision occurred, you also need to know which side of the brick the ball hit because it could hit any of the brick&#39;s four sides or corners. &amp;nbsp;You need this in order to know in which direction to bounce the ball after it hits the brick. &amp;nbsp;There seemed to be a couple common techniques for doing this, well common ones I found in a quick google search at least.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The first technique involved looking at the previous position of the ball and it&#39;s position relative to the brick. For example, you create regions based on the edges of the brick and find which region the ball was in before it hit the brick. The regions would like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx8NcodDWaukUfn6cjTdRjUeypQ1h7btlyoJn5UDl8zmgFnZb3AUma43MAgoDk20oghl_2-4AMGDia5EW_xCF6BD1c4HkeNHxgRux9uxNSJ8BMhSkyOdRQKX7fYxe66s2FdkLWKg/s1600/regions.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx8NcodDWaukUfn6cjTdRjUeypQ1h7btlyoJn5UDl8zmgFnZb3AUma43MAgoDk20oghl_2-4AMGDia5EW_xCF6BD1c4HkeNHxgRux9uxNSJ8BMhSkyOdRQKX7fYxe66s2FdkLWKg/s1600/regions.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
If the ball was in the top, bottom, left or right regions then you assume that was the edge that the ball hit. &amp;nbsp;If it was in one of the diagonal regions, then it the corner. &amp;nbsp;The problem with this method is that it doesn&#39;t take into account the direction or velocity of the ball. Consider the case of a ball being in one of the diagonal regions but travelling fast enough and at the right angle that by the end of the frame it was going to hit one of the edges, not the corner. This diagram illustrates this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU_WzAI1LMRtjyIUW0ogLD12ryVv-iNygHmZQjnBzq2gfsrIKk9PUmizJ1k9J2x8ACrgJ4OL4XtzKA4nO9BrVB1XCF_N3MHvQDwexGN35yECeW_8-b-12jGSJtolvC_0eE4r1fjQ/s1600/region_false_corner.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgU_WzAI1LMRtjyIUW0ogLD12ryVv-iNygHmZQjnBzq2gfsrIKk9PUmizJ1k9J2x8ACrgJ4OL4XtzKA4nO9BrVB1XCF_N3MHvQDwexGN35yECeW_8-b-12jGSJtolvC_0eE4r1fjQ/s1600/region_false_corner.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Because this method ignores the direction and speed of the ball it would detect a corner collision here, even though it is clearly hitting on the bottom edge of the brick. This would give you a lot of false corner collisions which would look weird, since a corner collision results in the ball bouncing back the way it came.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Another technique is to, once you know a ball collided with a brick, do a line intersection test between each edge of the brick and the line created by the previous and current position of the ball. So basically if the ball is travelling up we create a line segment from the center of the top edge of the ball&#39;s starting and ending position and see if it it intersects the bottom edge of the brick. Which looks like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbdlEuQx729JB02DluTAv0rVTGUn4uAzB54AqVKnbGFsSSHOBFhmByDWihaB3VE2MeuP9HL2KqOrKK2N42J0UL1tI9kDxv1HebtROgd8rI3gP9HjeMACStqaAEp1vWfDsRu_Ondw/s1600/lineintersection.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbdlEuQx729JB02DluTAv0rVTGUn4uAzB54AqVKnbGFsSSHOBFhmByDWihaB3VE2MeuP9HL2KqOrKK2N42J0UL1tI9kDxv1HebtROgd8rI3gP9HjeMACStqaAEp1vWfDsRu_Ondw/s1600/lineintersection.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;You would then do that for the x-direction as well and which ever edge the ball intersects is the edge on which you reflect the ball&#39;s direction. &amp;nbsp;If you don&#39;t get an intersection then you have hit a corner and you can just reflect back in both x and y directions. &amp;nbsp;This is the method I actually implemented and it works reasonable well, as you can see in this video:&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.blogger.com/video.g?token=AD6v5dzkv2X0Kj-Czmmhynl5SIZADUHp7FMKetqmFar9I33LW692c1WFDjH3NUJdvsoyhSElN38CYHr8QoQ&#39; class=&#39;b-hbp-video b-uploaded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;However, you might notice that occasionally the ball hits what looks like the edge of the brick but bounces back in the opposite direction. This just looks weird and it totally the opposite of what the player would expect. &amp;nbsp;We can see why this happens though by looking at the algorithm for detecting the edge that was hit. &amp;nbsp;Basically, to do the line intersection test we need to pick a point on the edge of the ball that is closest to the brick, the central point of that edge makes the most sense, but in doing that we also increase the threshold for detecting a corner collision. Consider this collision, which clearly occurs between the top edge of the ball and the bottom of the brick (note that Ball A is the starting position and Ball B is the end position of the ball):&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG6qwX9m2rUIxm1lHhM0klBIHkgUFU2-te8CrSgPmMrk6WdU5DVhZ499vnzmHnT70-89W0QZadymR4I5h3CpNOt1DeSMzIit-oENYc5giB9S72EJRL4zNdAj93cwUFouASH177Zg/s1600/ballBrickBottomCol.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG6qwX9m2rUIxm1lHhM0klBIHkgUFU2-te8CrSgPmMrk6WdU5DVhZ499vnzmHnT70-89W0QZadymR4I5h3CpNOt1DeSMzIit-oENYc5giB9S72EJRL4zNdAj93cwUFouASH177Zg/s1600/ballBrickBottomCol.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
The line we would test for a collision on the bottom edge of the brick would run from the center of the top edge of Ball A to the same point of Ball B, which would look like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRD-yr6E03Alo_wdjqxBPX3biUL9RFjifFMp3tFOG_R7zadmPpW0jaTHPAWelgBQwXtzLIk8gw0IhGbbxOxRsQ1yEB4uaQG32AAP16RYCGDS-U6Y8E7l2nyqyKnA9Zg2iJ60OT9g/s1600/ballBrickBottomColBottomTest.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRD-yr6E03Alo_wdjqxBPX3biUL9RFjifFMp3tFOG_R7zadmPpW0jaTHPAWelgBQwXtzLIk8gw0IhGbbxOxRsQ1yEB4uaQG32AAP16RYCGDS-U6Y8E7l2nyqyKnA9Zg2iJ60OT9g/s1600/ballBrickBottomColBottomTest.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
But that is going to miss the bottom edge, &amp;nbsp;which is not what we want. &amp;nbsp;If we say, ok lets also check the center of the left edge, then sure that will intersect but not if the ball is on the other side, so you&#39;d have to check right side as well. &amp;nbsp;So it becomes apparent that what you really need is the&amp;nbsp;&lt;a href=&quot;http://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.php?page=3&quot;&gt;Axis-Aligned Bounding Box Sweep Test&lt;/a&gt;&amp;nbsp;that I talked about a couple of weeks ago (the circle is complete). &amp;nbsp;With the sweep test you can get the exact position at which the collision occurred and then determine which edge was hit by doing the region test based on the collision position. This will be much more accurate and corner hits will only occur when the ball actually does hit the corner, which would be pretty rare. It will also be easier to handle collisions on multiple bricks.&lt;br /&gt;
&lt;br /&gt;
So my next task is to convert my existing code, that uses the line intersection method, to the AABB sweep test. &amp;nbsp;I&#39;ll do that this week. &amp;nbsp;I haven&#39;t included the code from the intersection test in this post because I will pretty much be replacing it next week so it didn&#39;t see worthwhile explaining the guts of it. &amp;nbsp;If anyone is interested, it is available up on GitHub with it&#39;s own tag at&amp;nbsp;&lt;a href=&quot;https://github.com/seangeo/breakout/tree/week4p2&quot;&gt;week4p2&lt;/a&gt;. So you can see the method I was using detail if you want.&lt;br /&gt;
&lt;br /&gt;
Also, if anyone is interested in the details of the line intersection code, I based mine on this &lt;a href=&quot;http://thirdpartyninjas.com/blog/2008/10/07/line-segment-intersection/&quot;&gt;excellent example&lt;/a&gt;&amp;nbsp;from&amp;nbsp;&lt;a href=&quot;http://thirdpartyninjas.com/blog/&quot;&gt;Third Party Ninjas&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&#39;til next week...&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/1292284674009400328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/1292284674009400328' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/1292284674009400328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/1292284674009400328'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2011/03/breakout-week-4-building-wall-part-2.html' title='Breakout Week 4: Building a Wall (Part 2)'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx8NcodDWaukUfn6cjTdRjUeypQ1h7btlyoJn5UDl8zmgFnZb3AUma43MAgoDk20oghl_2-4AMGDia5EW_xCF6BD1c4HkeNHxgRux9uxNSJ8BMhSkyOdRQKX7fYxe66s2FdkLWKg/s72-c/regions.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-7593687825349380850</id><published>2011-03-21T04:02:00.000-07:00</published><updated>2011-03-28T01:22:24.213-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gamedev"/><category scheme="http://www.blogger.com/atom/ns#" term="xna"/><title type='text'>Breakout Week 4: Building a Wall (Part 1)</title><content type='html'>I had a pretty busy week last week, okay that was mostly due to the fact that&amp;nbsp;&lt;a href=&quot;http://dragonage.bioware.com/&quot;&gt;Dragon Age 2&lt;/a&gt;&amp;nbsp;came out and I spent several nights playing and not sleeping. Despite that I did manage to find some time to work on Breakout. The goal for this week was to get the wall drawn and handle the collisions of the ball against the wall. I did manage to get that all working, which I was pretty happy about, but I also came to the conclusion that the way I am handling the collisions is not very good, particularly for the wall.&lt;br /&gt;
&lt;br /&gt;
Because there is a lot to go through with the collision handling and I also want to cover how I setup and draw the wall I&#39;m going to split this week&#39;s post in two. &amp;nbsp;This post will cover the setup and drawing of the wall and it should be relatively short. I&#39;ll write another post around mid this week where I&#39;ll cover handling the collision of the ball against the wall, the problems with my approach and how I&#39;m going to improve it. &amp;nbsp;So for now, lets get stuck into the setup of the wall.&lt;br /&gt;
&lt;br /&gt;
As usual, we have a Wall class that handles the setup and drawing of the wall. Just like the&amp;nbsp;&lt;a href=&quot;http://seangeo.blogspot.com/2011/03/week-2-with-paddle.html&quot;&gt;paddle&lt;/a&gt;&amp;nbsp;and &lt;a href=&quot;http://seangeo.blogspot.com/2011/03/breakout-week-3-when-balls-collide.html&quot;&gt;ball&lt;/a&gt;&amp;nbsp;it is created by the &lt;a href=&quot;https://github.com/seangeo/breakout/blob/c6d2675dd2d8de6060dfa99cef1bf0c7a14534a3/Breakout/Breakout/Breakout.cs#L22&quot;&gt;Breakout&lt;/a&gt;&amp;nbsp;class. Here are the main instance variables of the wall.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp; toolbar: false&quot;&gt;class Wall {
   private const int bricksPerRow = 20;
   private const double wallHeightRatio = 0.20;
   private const int numRows = 7;
   private static readonly Color[] colors = {
     Color.Red, Color.Orange, Color.Yellow, Color.Green, 
     Color.Blue, Color.Indigo, Color.Violet
   };

   private readonly int screenWidth;
   private readonly int screenHeight;
   private float brickHeight;
   private float brickWidth;
   private Rectangle wallBounds;
   private Texture2D sprite;
   private List&amp;lt;Brick&amp;gt; bricks = new List&amp;lt;Brick&amp;gt;();
&lt;/pre&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
There are some constants at the top of the class that define the number of rows of bricks we will show and the number of bricks per row, height of the wall as fraction of the screen height and the color of each row, in this case it will be a rainbow. We also store the screen and the brick size and wall bounds which will be calculated in the constructor. And lastly there is our brick texture, which is just a white square and our list of bricks that make up the wall.&lt;br /&gt;
&lt;br /&gt;
This is what the constructor does:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp; toolbar: false&quot;&gt;public Wall(int screenWidth, int screenHeight) {
    this.screenWidth = screenWidth;
    this.screenHeight = screenHeight;

    double wallHeight = screenHeight * wallHeightRatio;
    wallBounds = new Rectangle(0, (int)(wallHeight / 2),
                screenWidth, (int)(wallHeight + wallHeight / 2));
    brickHeight = wallBounds.Height / numRows;
    brickWidth = screenWidth / bricksPerRow;
}
&lt;/pre&gt;&lt;br /&gt;
The important parts to point out here is how we calculate the wall height as the fraction of the screen height defined by wallHeightRatio, the brick height as the wall height divided by the number of rows of bricks and the brick width as the screen width divided by the number of bricks per row. This means that the wall size will scale with the screen size and we can tweak to constants to get different wall configurations.&lt;br /&gt;
&lt;br /&gt;
Lets move on to the InitialiseBricks method. This method is responsible for filling the list of bricks that make up the wall using the parameters we calculated in the constructor. It is called by the LoadContent method after we load the texture for the bricks.&lt;br /&gt;
&lt;br /&gt;
Actually, before we look at that, here is the Brick class:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp; toolbar: false&quot;&gt;class Brick {
    public enum BrickState { ALIVE, BROKEN };
    private readonly int column;
    private readonly int row;
    private Rectangle bounds;
    private BrickState state;

    public int Row {
        get { return row; }
    }

    public Rectangle Bounds {
        get { return bounds; }
    }

    public BrickState State { get; set; }

    public Brick(int row, int column, float x, float y, float w, float h) {
        this.state = BrickState.ALIVE;
        this.row = row;
        this.column = column;
        this.bounds = new Rectangle((int) x, (int) y, (int) w, (int) h);
    }
}
&lt;/pre&gt;&lt;br /&gt;
As you can see it is really simple. It just stores the brick&#39;s row and column position, its bounding box and its state, i.e. whether it is alive or has been &quot;broken&quot; by the ball. &amp;nbsp;So now, back to the InitialiseBricks method:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp; toolbar: false&quot;&gt;private void InitialiseBricks() {
    for (int i = 0; i &amp;lt; numRows * bricksPerRow; i++) {
        int row = i / bricksPerRow;
        int column = i % bricksPerRow;
        bricks.Add(new Brick(
                row, column,
                column * brickWidth, 
                wallBounds.Top + (row * brickHeight), 
                brickWidth, 
                brickHeight));
    }
}
&lt;/pre&gt;&lt;br /&gt;
So what happens here is that, for each brick we need to create, which is determined by the number of bricks per row multiplied by the number of rows, we figure out it is row and column and the then its screen position. The screen x-position is done by multiplying the column position by the brick width and the screen y-position is determined by adding its row position time the brick height to the walls top position. Once this is done, our bricks list is full of all the bricks we need to draw the wall, which, of course, is done in the wall&#39;s Draw method:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp; toolbar: false&quot;&gt;internal void Draw(GameTime gameTime, SpriteBatch spriteBatch) {
    foreach (Brick brick in bricks) {
        if (brick.State == Brick.BrickState.ALIVE) {
            spriteBatch.Draw(sprite, brick.Bounds,
                  colors[colors.Length - brick.Row - 1]);
        }
    }
}
&lt;/pre&gt;&lt;br /&gt;
So all we need to do here is loop through the bricks and for each brick that is alive we draw it. We use the overload of SpriteBatch#Draw that takes a rectangle and colour. We grab the colour from the wall&#39;s colour array, using the colour at the index of the brick&#39;s row, but reversed so the top row is draw with the last colour and the bottom row is draw with the first. Passing in the brick&#39;s bounds as the destination rectangle will ensure that the right place in the screen is filled for that brick and our texture will automatically get scaled and coloured to fill the brick&#39;s rectangle. &amp;nbsp;That&#39;s it, here is what it looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSbxrLMgceC3NcvKfMXJDdYxMAo8rsMEtPUarm7VIcYbhn-d8Ns74up2RJ_XFk1gqCQyDecp8Doqo0tB23Jok-jnS8rZby77gE_0_-M7znNc-YVoN5n2669ay0tpiU1bzJv520pQ/s1600/BreakoutWeek4p1.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;203&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSbxrLMgceC3NcvKfMXJDdYxMAo8rsMEtPUarm7VIcYbhn-d8Ns74up2RJ_XFk1gqCQyDecp8Doqo0tB23Jok-jnS8rZby77gE_0_-M7znNc-YVoN5n2669ay0tpiU1bzJv520pQ/s320/BreakoutWeek4p1.PNG&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Isn&#39;t that pretty, well my 3 year old daughter thinks so at least.&lt;br /&gt;
&lt;br /&gt;
That&#39;s it for part 1 of week for. &amp;nbsp;It was pretty light but I think worth covering for completeness. &amp;nbsp;Later in the week I&#39;ll put up the post on wall collision detection which will probably take me longer to put together than this did. &amp;nbsp;I hope this was useful to someone though. As usual the code is up on the Github, if you want to see this part of week 4, the pre-collision detection stuff, checkout the&amp;nbsp;&lt;a href=&quot;https://github.com/seangeo/breakout/blob/week4p2/Breakout/Breakout/Breakout.cs&quot;&gt;week4p1&lt;/a&gt;&amp;nbsp;tag.</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/7593687825349380850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/7593687825349380850' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/7593687825349380850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/7593687825349380850'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2011/03/breakout-week-4-building-wall-part-1.html' title='Breakout Week 4: Building a Wall (Part 1)'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSbxrLMgceC3NcvKfMXJDdYxMAo8rsMEtPUarm7VIcYbhn-d8Ns74up2RJ_XFk1gqCQyDecp8Doqo0tB23Jok-jnS8rZby77gE_0_-M7znNc-YVoN5n2669ay0tpiU1bzJv520pQ/s72-c/BreakoutWeek4p1.PNG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-2012622458501131183</id><published>2011-03-12T01:33:00.000-08:00</published><updated>2011-03-12T01:38:19.278-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gamedev"/><category scheme="http://www.blogger.com/atom/ns#" term="xna"/><title type='text'>Breakout Week 3: When Balls Collide</title><content type='html'>This week was all about collision detection and collision response. &amp;nbsp;The plan was to add the ball to the Breakout game, get it moving around the screen and bouncing off the walls and the paddle. &amp;nbsp;I probably did much more research than was required this week since I spent a lot of time reading about various&amp;nbsp;&lt;a href=&quot;http://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.php&quot;&gt;collision detection&lt;/a&gt;&amp;nbsp;algorithms and the &lt;a href=&quot;http://chrishecker.com/Rigid_Body_Dynamics&quot;&gt;physics of collision response&lt;/a&gt;. &amp;nbsp;It turns out that didn&#39;t actually use any of the techniques I read about since a very simple technique works well enough for Breakout. &amp;nbsp;It was worthwhile reading all that though, if for no other reason than I now have a much better appreciation for what I need to learn.&lt;br /&gt;
&lt;br /&gt;
So, research aside, the coding up of the ball itself was very easy, it only took about an hour and half and most of that was spent tweaking various parameters to get the &quot;feel&quot;&amp;nbsp;right. So on to the code.&lt;br /&gt;
&lt;br /&gt;
As with the&amp;nbsp;&lt;a href=&quot;http://seangeo.blogspot.com/2011/03/week-2-with-paddle.html&quot;&gt;paddle&lt;/a&gt;, there is a class for the &lt;a href=&quot;https://github.com/seangeo/breakout/blob/72318aa78f18d6fecbc134883986878bd874b26a/Breakout/Breakout/Breakout.cs#L58&quot;&gt;Ball&lt;/a&gt; with LoadContent, Update and Draw methods that are called by the &lt;a href=&quot;https://github.com/seangeo/breakout/blob/72318aa78f18d6fecbc134883986878bd874b26a/Breakout/Breakout/Breakout.cs#L14&quot;&gt;Breakout&lt;/a&gt;&amp;nbsp;class. &amp;nbsp;The Ball tracks it&#39;s own state in these instance variables:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp&quot;&gt;private Texture 2D sprite;
private Vector2 position;
private Vector2 direction;
private int speed;
&lt;/pre&gt;&lt;br /&gt;
This is slightly different to the paddle in that we store the speed as a scalar value and the direction as a vector. &amp;nbsp;The direction is a unit vector so it contains no speed information, which is why we need the speed as a separate variable. &amp;nbsp;The reason I did it this way is that the ball can move in both x and y directions, unlike the paddle, so using a unit vector allows use to calculate directional changes for the ball without needing to worry about the length of the vector, since it will always be 1.&lt;br /&gt;
&lt;br /&gt;
The ball also has a few other instance variables that hold initial states, ranges of speed and position and whether the ball is currently active or dead.&lt;br /&gt;
&lt;br /&gt;
So, once again, all the interesting stuff happens in the Update method:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp;&quot;&gt;internal void Update(GameTime gameTime) {
    if (state == State.Active) {
        UpdatePosition(gameTime);

        if (position.Y &amp;gt; screenHeight) {
            state = State.Dead;
        } else {
            HandleCollisions();
        }
    } else if (state == State.Dead &amp;amp;&amp;amp; 
           Keyboard.GetState().IsKeyDown(Keys.Space)) {
        LaunchBall();
    }
}
&lt;/pre&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
The first thing the update method does is check if the ball is active or not. &amp;nbsp;If it is isn&#39;t the player can launch a new ball by pressing the space key. The&amp;nbsp;&lt;a href=&quot;https://github.com/seangeo/breakout/blob/72318aa78f18d6fecbc134883986878bd874b26a/Breakout/Breakout/Breakout.cs#L158&quot;&gt;LaunchBall&lt;/a&gt;&amp;nbsp;method just sets the state to active and initialises the position and velocity of the ball, so I won&#39;t cover it here. &amp;nbsp;If the ball is active, the first thing we do is update it&#39;s position:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp&quot;&gt;private void UpdatePosition(GameTime gameTime) {
    float time = gameTime.ElapsedGameTime.TotalSeconds;
    position = position + direction *&amp;nbsp;(float)(speed * time);
}
&lt;/pre&gt;&lt;br /&gt;
This is the familiar motion equation we used for the paddle, so nothing new here, except that the velocity vector is split up into direction and speed components so we need to multiply them back together here.&lt;br /&gt;
&lt;br /&gt;
Once that is done, the Update method checks if the ball has gone of the bottom of the screen and should become dead, if not it then checks for the collisions. The &lt;a href=&quot;https://github.com/seangeo/breakout/blob/72318aa78f18d6fecbc134883986878bd874b26a/Breakout/Breakout/Breakout.cs#L169&quot;&gt;HandleCollisions&lt;/a&gt;&amp;nbsp;method first calls HandleBoardCollisions which checks if the ball has hit either the top, left or right edges of the screen.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp&quot;&gt;private void HandleBoardCollisions() {
    if (position.Y &amp;lt; 0) {
        position.Y = 0;
        direction.Y = -direction.Y;
    }

    if (position.X &amp;lt; 0) {
        position.X = 0;
        direction.X = -direction.X;
    } else if (position.X + sprite.Width &amp;gt; screenWidth) {
        position.X = screenWidth - sprite.Height;
        direction.X = -direction.X;
    }
}
&lt;/pre&gt;&lt;br /&gt;
So here all we do is check if the ball has gone off the screen on each axis and if so we reverse the direction of the ball along that axis and move it&#39;s position back into the screen. &amp;nbsp;This will ensure that the ball doesn&#39;t get stuck on the edge and reversing the direction on the axis gives us a realistic reflection off the wall so that the angle of incidence is maintained.&lt;br /&gt;
&lt;br /&gt;
Once this is done, when then check to see if the ball hits the paddle. &amp;nbsp;This was what most of my reading and my research went into. I already new that it was pretty easy to check if a rectangle intersects another but I was worried about the movement of the ball. For example, consider this case:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghB48yq7tonVboxLdDqzFqjkXwzWA293bvVVmutweWLZ_Wpkb_u0-6ZVfloh8Zg3vAhHAP2snNqH1PQXNXx8ZYk5yL5TeXsxYtQ8b0Jm0eevrDWGjAnNVNpfKH3ukSpEpETpCNiA/s1600/straightthrough.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghB48yq7tonVboxLdDqzFqjkXwzWA293bvVVmutweWLZ_Wpkb_u0-6ZVfloh8Zg3vAhHAP2snNqH1PQXNXx8ZYk5yL5TeXsxYtQ8b0Jm0eevrDWGjAnNVNpfKH3ukSpEpETpCNiA/s1600/straightthrough.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;The ball starts the frame at position A but after it&#39;s position is updated it ends the frame at position B. &amp;nbsp;If we do a bounding box check against the paddle at either position we are not going to get a collision, but clearly the ball has hit the paddle. &amp;nbsp;There are algorithms for solving this called sweep tests where basically you create a geometry for the moving object that covers its movement through the entire frame, so the above situation becomes this:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAWLO8RmPxioYEKdxP8jSDYKPSqKrHPr5kCm4H8RTizcuh8xGeQcyFsLF_vbcH3Zs2Y6wVvQsp0U3rMxJrx339cRTPp87BIQ2uYLr4WmbtJf3545sU__fSU7QU4ZZwOrBwCUuz8w/s1600/aabb.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAWLO8RmPxioYEKdxP8jSDYKPSqKrHPr5kCm4H8RTizcuh8xGeQcyFsLF_vbcH3Zs2Y6wVvQsp0U3rMxJrx339cRTPp87BIQ2uYLr4WmbtJf3545sU__fSU7QU4ZZwOrBwCUuz8w/s1600/aabb.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;And we check whether those two geometries intersect and at what time within the frame they would. &amp;nbsp;The most appropriate algorithm for this particular case seems to be the &lt;a href=&quot;http://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.php?page=3&quot;&gt;Axis-Aligned Bounding Box sweep test&lt;/a&gt;.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;However, this is only really an issue for small fast moving objects. &amp;nbsp;If the object is going to be moving less than it&#39;s dimensions on each axis in each frame then it is not an issue. &amp;nbsp;I wasn&#39;t sure if it was going to be an issue for my ball and paddle collisions so I decided to start with the simplest case and see how it looks. The simplest case is just a standard bounding box test and it seems to work well enough, the ball doesn&#39;t pass through the paddle even when it is travelling at pretty high speeds. Of course if the frame rate dropped or we changed size of the ball or paddle this might change, so I wouldn&#39;t be surprised if I end up implementing a sweep test anyway.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;This type of collision detection was really easy to do in XNA, well it&#39;s pretty easy anyway but XNA makes it very easy. The Rectangle class has an Intersects method that checks whether the rectangle intersects with another. This is what we use in the HandlePaddleCollisions method of the Ball class:&lt;/div&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp&quot;&gt;private void HandlePaddleCollision() {
    if (direction.Y &amp;gt; 0 &amp;amp;&amp;amp; paddle.Bounds.Intersects(this.Bounds)) {
        direction.Y = -direction.Y;
        position.Y = paddle.Bounds.Y - sprite.Height;

        direction.X = ((float)Bounds.Center.X - paddle.Bounds.Center.X) / 
                      (paddle.Bounds.Width / 2);
        direction = Vector2.Normalize(direction);

        // Increase the speed when the ball is hit
        speed += speedIncrement;
        speed = Math.Min(speed, maxSpeed);
    }
}
&lt;/pre&gt;&lt;br /&gt;
Line 2 of this method does the check. &amp;nbsp;Also notice that we only do this check if the ball is moving in a downward direction. This is important because we don&#39;t want to check if the ball is moving up, since it is both a waste and could lead to bugs where the ball gets trapped inside the paddle.&lt;br /&gt;
&lt;br /&gt;
So once we know there is a collision, we need to do something about it. This is where I spent some time reading about collision response, in particular, the sections on collision response in my copy of&amp;nbsp;&lt;a href=&quot;http://oreilly.com/catalog/9780596000066&quot;&gt;Physics for Game Programmers&lt;/a&gt;&amp;nbsp;(that I have had for almost 10 years and not read enough of) and Chris Hecker&#39;s excellent article on&amp;nbsp;&lt;a href=&quot;http://chrishecker.com/images/e/e7/Gdmphys3.pdf&quot;&gt;collision response&lt;/a&gt;. This stuff is really interesting and is definitely something I want to get explore more, maybe even for the Breakout game later on. &amp;nbsp;But in the interest of getting the ball working this week I opted for a simpler solution. This is implemented in the body of the HandlePaddleCollision method.&lt;br /&gt;
&lt;br /&gt;
First of all we need to reverse the y direction of the ball, this &quot;bounces&quot; it up and sends towards to top of the screen.&amp;nbsp;We also need to move the ball outside of the paddle so it doesn&#39;t get stuck. This is done on line 4.&lt;br /&gt;
&lt;br /&gt;
Then comes my cheat for not having proper physics. &amp;nbsp;If you just change the y direction the ball will always be travelling straight up and down, which will lead to a very boring Breakout game. The player needs to have some control over the direction of the ball. &amp;nbsp;I did a bit of research into how other people have implemented this, I found a few references to splitting the paddle up into thirds and setting the x direction to a fixed number based on which third it hits, sort of like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8pdns0jAOk53MuDeCTXS_aesbBH0zsfy9bpNfFOfYX2CI0lmY5QVHOZ2vH8BEGXqkMtUXs9yHzBQu0OTZeIVGcyyKS_hPqgG6DFQts1dQsg3VaUpy5XkCi27pbWGooyO6umAjRg/s1600/3bounce.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8pdns0jAOk53MuDeCTXS_aesbBH0zsfy9bpNfFOfYX2CI0lmY5QVHOZ2vH8BEGXqkMtUXs9yHzBQu0OTZeIVGcyyKS_hPqgG6DFQts1dQsg3VaUpy5XkCi27pbWGooyO6umAjRg/s1600/3bounce.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
But that would be a bit boring and predictable.&lt;br /&gt;
&lt;br /&gt;
Looking at some old &lt;a href=&quot;http://www.youtube.com/watch?v=JRAPnuwnpRs&quot;&gt;Breakout videos&lt;/a&gt;&amp;nbsp;it looks like the angle of the ball is based on the distance from the paddles center, the further from the center the sharper the angle. &amp;nbsp;So I ended up using this formula:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;xDirection = ballCenter - paddleCenter 
             -------------------------
                 paddleWidth / 2
&lt;/pre&gt;&lt;br /&gt;
This will set the x direction to a value between -1 and 1 based on the position it hit the paddle. So you get a range like this on the paddle:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBtXCoE5RyVSyObV99TK1aULVHiRLEMziZdu512Nv4PEoS0vSCDz4g1GOgUaWfEixVaBwpV8aaMTB8ZnuTLxb7XHBeWqTQiAjhfhG5bbvrkG7m7tuKNxAeqn84d7jX4pRYonFxTw/s1600/rangeOfPaddle.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBtXCoE5RyVSyObV99TK1aULVHiRLEMziZdu512Nv4PEoS0vSCDz4g1GOgUaWfEixVaBwpV8aaMTB8ZnuTLxb7XHBeWqTQiAjhfhG5bbvrkG7m7tuKNxAeqn84d7jX4pRYonFxTw/s1600/rangeOfPaddle.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
Once the X value of the direction vector is set on line 6 we need to normalise the vector again on line 8 so it remains a unit vector.&lt;br /&gt;
&lt;br /&gt;
There is one downside to this approach, since the Y value of the direction is always going to -1 or 1 and the range of the X value can be is -1 to 1, this means that you only have a range of angles of +/- 45 degrees. This might not be that big a deal though, the range can always by increased by adding some constant to the denominator of the xDirection formula anyway.&lt;br /&gt;
&lt;br /&gt;
Once the direction has been set we increment the speed on lines 11 and 12 so it gets a bit harder as the player keeps the ball alive. &amp;nbsp;And that does it for ball movement, this is what it looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.blogger.com/video.g?token=AD6v5dzpmtqJS0oySUNB8d1eSjCfE1BbO2FgD-a0LkJGvQZvexpmu5OqWO9FlsCWLMXAtxjZacsd_3sxxWg&#39; class=&#39;b-hbp-video b-uploaded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
I can assure the framerate is much better in real life. I might have to find some better screen capturing software, if anyone can recommend some please do in the comments.&lt;br /&gt;
&lt;br /&gt;
Handling collisions like this is not without its problems though. You can have the situation where the ball hits the side of the paddle but then gets propelled out of the top of the paddle, since we are just checking that the ball is within the paddle. To resolve this you would probably need some sort of sweep test followed by an intersection test to find which edge of the paddle the ball hit and then reflect it off that edge instead of always assuming it hit the top edge. I&#39;ll leave this for later though.&lt;br /&gt;
&lt;br /&gt;
Next week I&#39;ll start implementing the wall of bricks. This should cover more collision detection, dynamic drawing of sprites and maybe some particle effects.</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/2012622458501131183/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/2012622458501131183' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/2012622458501131183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/2012622458501131183'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2011/03/breakout-week-3-when-balls-collide.html' title='Breakout Week 3: When Balls Collide'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghB48yq7tonVboxLdDqzFqjkXwzWA293bvVVmutweWLZ_Wpkb_u0-6ZVfloh8Zg3vAhHAP2snNqH1PQXNXx8ZYk5yL5TeXsxYtQ8b0Jm0eevrDWGjAnNVNpfKH3ukSpEpETpCNiA/s72-c/straightthrough.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-4231964035636360523</id><published>2011-03-04T20:54:00.000-08:00</published><updated>2011-03-04T21:17:28.102-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gamedev"/><category scheme="http://www.blogger.com/atom/ns#" term="xna"/><title type='text'>Week 2: With a Paddle</title><content type='html'>With all the installation and setup out of the way, this week I finally got to write some code.&lt;br /&gt;
&lt;br /&gt;
I decided that the goal for this week was to get some initial classes laid out for the Breakout game and implement the basics of the Paddle. &amp;nbsp;Let&#39;s start with the class design.&lt;br /&gt;
&lt;br /&gt;
When you create an XNA project, it auto-generates a&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.game.aspx&quot;&gt;Game&lt;/a&gt;&amp;nbsp;class for you. This class is the core of your Game. In it you implement methods for loading content, updating state and drawing a frame. &amp;nbsp;However, I don&#39;t think it is the best place to put much game logic. I&#39;ve always tried to avoid pointing too much custom code into classes that extend from framework classes since it makes it harder to test your own code in isolation and it means large amounts of you own code could break if the framework changes.&amp;nbsp;The Game class will act mainly as glue between my game implementation and the XNA framework&#39;s game loop. To this end,&amp;nbsp;I created a&amp;nbsp;&lt;a href=&quot;http://github.com/seangeo/breakout/blob/master/Breakout/Breakout/Breakout.cs&quot;&gt;Breakout&lt;/a&gt;&amp;nbsp;class which is instantiated by the generated Game class. &amp;nbsp;Here is what it looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp; toolbar: false; ruler: false;&quot;&gt;public class Breakout {
    private SpriteBatch spriteBatch;
    private Paddle paddle;
    private Ball ball;
    private Wall wall;
    private int screenHeight;
    private int screenWidth;

    public Breakout(SpriteBatch spriteBatch) {
        this.spriteBatch = spriteBatch;
        this.screenWidth = spriteBatch.GraphicsDevice.Viewport.Width;
        this.screenHeight = spriteBatch.GraphicsDevice.Viewport.Height;
        this.ball = new Ball();
        this.paddle = new Paddle(screenWidth, screenHeight);
        this.wall = new Wall();
    }
}
&lt;/pre&gt;&lt;br /&gt;
It&#39;s pretty straight forward, Breakout has a Paddle, a Ball and a Wall, just as you would expect. &amp;nbsp;The Breakout constructor is passed in a&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritebatch.aspx&quot;&gt;SpriteBatch&lt;/a&gt;&amp;nbsp;instance which it will use to draw all the graphics for the game. The SpriteBatch is created in the Game class&#39;s Initialize method, where the Breakout object is also created, like so:&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp;toolbar: false&quot;&gt;protected override void Initialize() {
    breakout = new Breakout(new SpriteBatch(GraphicsDevice));
    base.Initialize();
 }
&lt;/pre&gt;&lt;br /&gt;
The LoadContent, Update and Draw methods, which are called by the Game class, just pass the calls onto the respective methods of the Ball, Paddle and Wall, so each component of the game is responsible for loading, updating and drawing itself; all cleanly separated. &amp;nbsp;You could go even further down the dependency injection path and provide an abstraction layer for the SpriteBatch class, but I&#39;m not going to bother at this point.&lt;br /&gt;
&lt;br /&gt;
The next step was to implement the Paddle. &amp;nbsp;I started by applying my graphic design skills to come up with this fantastic piece of art:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinZHk0QE3zsNJrou90YWddxPffGYxZGz6bYHPCkmMqRBpOEgOlkxvGu1I6iDGkNhX9GRvLTCOglPiKec_xla5j2wbvA16VtO5nU-9bp1yW_CE5aQehNalj4RMlKPRezdgK9rI-NQ/s1600/paddle.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinZHk0QE3zsNJrou90YWddxPffGYxZGz6bYHPCkmMqRBpOEgOlkxvGu1I6iDGkNhX9GRvLTCOglPiKec_xla5j2wbvA16VtO5nU-9bp1yW_CE5aQehNalj4RMlKPRezdgK9rI-NQ/s1600/paddle.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
There are two paddle images there, the bottom will be used for flashing when the ball hits it, but we&#39;ll ignore it for now.&lt;br /&gt;
&lt;br /&gt;
It turns out that adding and loading graphics into an XNA game is remarkably simple. Visual Studio generates a GameContent project that is referenced by your main game project. &amp;nbsp;To add an image to this you simply drag and drop it into the project. &amp;nbsp;The image can then be loaded in the LoadContent method. This is how the paddle image is loaded by the Paddle class like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp; toolbar: false&quot;&gt;sprite = contentManager.Load&amp;lt;Texture2d&amp;gt;(&quot;paddle&quot;);&lt;/pre&gt;&lt;br /&gt;
That is almost too good to be true. The last time I dabbled in Windows game development was back in 2000, I was using DirectX 5 and reading&amp;nbsp;&lt;a href=&quot;http://www.amazon.com/Windows-Programming-Dummies-Andr%C3%A9-LaMothe/dp/0764503375&quot;&gt;Windows Game Programming for Dummies&lt;/a&gt;. There is a big section in that book, and there was a big section of my code, that dealt with manually loading sprites from bmp files and handling colour palettes etc. Reading in encoded file formats was not even dealt with in the book because it was deemed to complex. &amp;nbsp;Having a single line of code do it for you is pretty great. &amp;nbsp;Makes me wonder what the catch is, or at the very least I need to read up on the XNA content pipeline some more to find out what formats it supports and what its limitations are.&lt;br /&gt;
&lt;br /&gt;
Anyway, back to the Paddle class.&amp;nbsp;The Paddle class has some state that it uses to keep track of the position and movement of the paddle, these are stored in instance variables as &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.vector2.aspx&quot;&gt;Vector2&lt;/a&gt;&amp;nbsp;objects. After the sprite is loaded in the LoadContent method we also initialise the position of the paddle so that it sits 10 pixels from the bottom of the screen in the middle of the X-axis. This is done like so:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp;toolbar: false&quot;&gt;int x = screenWidth - (screenWidth / 2) - (sprite.Width / 2);
 int y = screenHeight - PADDLE_OFFSET - PADDLE_HEIGHT;
 this.position = new Vector2(x, y);
 this.minPosition = new Vector2(0, y);
 this.maxPosition = new Vector2(screenWidth - sprite.Width, y);
&lt;/pre&gt;&lt;br /&gt;
x, which is the paddle&#39;s starting position on the horizontal axis, is calculated by finding the center of the screen and then moving to the left by half the width of the paddle&#39;s sprite. y, which is the vertical position just places to bottom of the sprite 10 pixels from the bottom of the screen. We also calculate the min and max horizontal positions of the paddle, this will be used later to make sure that the paddle doesn&#39;t go off the edge of the screen.&lt;br /&gt;
&lt;br /&gt;
I think the most interesting part of the Paddle class is how it handles the movement of the paddle in response to the user input. The goal of the movement is that when the user presses the left or right arrow keys, the paddle will move to the left or right. If they hold the key down the paddle should accelerate so the longer you hold the key down the faster it goes. &lt;br /&gt;
&lt;br /&gt;
To do this we just use the the classic equations of motion:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;v = velocity
 u = initial velocity
 a = acceleration
 t = time
 s = distance travelled

 v = u + at
 s = vt
&lt;/pre&gt;&lt;br /&gt;
This is implemented in the Update method like so:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp;toolbar: false&quot;&gt;internal void Update(GameTime gameTime) {
    float time = (float)gameTime.ElapsedGameTime.TotalSeconds;
    KeyboardState keyboard = Keyboard.GetState();

    if (keyboard.IsKeyDown(Keys.Left) &amp;amp;&amp;amp; !previousKeyboard.IsKeyDown(Keys.Left)) {
        velocity = new Vector2(-INITIAL_SPEED, 0);
    } else if (keyboard.IsKeyDown(Keys.Right) &amp;amp;&amp;amp; !previousKeyboard.IsKeyDown(Keys.Right)) {
        velocity = new Vector2(INITIAL_SPEED, 0);
    } else if (keyboard.IsKeyDown(Keys.Left) &amp;amp;&amp;amp; previousKeyboard.IsKeyDown(Keys.Left)) {
        velocity = velocity + (-ACCELERATION * time);
    } else if (keyboard.IsKeyDown(Keys.Right) &amp;amp;&amp;amp; previousKeyboard.IsKeyDown(Keys.Right)) {
        velocity = velocity + (ACCELERATION * time);
    } else {
        velocity = Vector2.Zero;
    }

    position = position + (velocity * time);
    position = Vector2.Clamp(position, minPosition, maxPosition);
    
    previousKeyboard = keyboard;
 }
&lt;/pre&gt;&lt;br /&gt;
I&#39;ve just used a constant acceleration in this initial version to keep it simple, but I might play around with it later if it doesn&#39;t feel right.&lt;br /&gt;
&lt;br /&gt;
Right off the bat, I don&#39;t like those conditional statements, they are a bit hard to read.  Essentially what they do is the first two check if the left or right key has been pressed for the first time, i.e. it wasn&#39;t pressed in the last frame, and the second two check if the left or right buttons have been held down. I&#39;ll refactor this out into a clean input class next week I think, but for now we&#39;ll have to deal with it.&lt;br /&gt;
&lt;br /&gt;
So lets go through the code line by line.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;On line 2, we grab the number of seconds that have elasped since the last frame. This becomes our &lt;code&gt;t&lt;/code&gt; in the motion equations.&lt;/li&gt;
&lt;li&gt;On line 3 we get the current keyboard state.&lt;/li&gt;
&lt;li&gt;Lines 5 - 15 deal with calculating our new velocity.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Line 5 checks to see if the Left arrow key has been pressed for the first time, if so, on line 6 we set the next velocity to the negative of the initial speed. It&#39;s negative because we are going left.&lt;/li&gt;
&lt;li&gt;Likewise, line 7 checks if we are going right for the first time and line 8 sets the velocity to the initial velocity, positive this time because we are going right.&lt;/li&gt;
&lt;li&gt;On line 9 we check if the Left arrow key has been held down. If so, on line 10 we increase our velocity by the negative of the acceleration * time. This is the &lt;code&gt;v = u + at&lt;/code&gt; in our motion equations. &lt;/li&gt;
&lt;li&gt;Likewise on line 11 we check if Right has been held down and on line 12 we do the &lt;code&gt;v = u + at&lt;/code&gt; again, this time in the positive direction.&lt;/li&gt;
&lt;li&gt;And finally, if neither Left or Right are held down, then we set the velocity to 0 on line 14.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Once we have our velocity we can calculate our new position. We know distance travelled is simply &lt;code&gt;v * t&lt;/code&gt; so we can just add that the current position on line 17.&lt;/li&gt;
&lt;li&gt;Then on line 18, we make sure the position isn&#39;t outside the screen bounds&lt;/li&gt;
&lt;li&gt;And finally save the keyboard state to check against in the next frame.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;So that&#39;s it, pretty simple but it was pretty fun to do something based on actual physics formulae. I particularly like the way the XNA Vector2 structure, provides operator overloading here, it makes the code much more readable than having a bunch of nested methods calls like Add or Multiply.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Once we have the new position we can draw the paddle in the Paddle class&#39;s Draw method like this:&lt;/div&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: c-sharp;toolbar: false&quot;&gt;internal void Draw(GameTime gameTime, SpriteBatch spriteBatch) {
    spriteBatch.Draw(sprite, position, source, Color.White);
}
&lt;/pre&gt;&lt;br /&gt;
All done. &amp;nbsp;The paddle now shows up on the screen and responds to the keyboard input. This is what it looks like (well slightly better than this low-res video at least):&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.blogger.com/video.g?token=AD6v5dyA8ag2AHb36o0WglqfNWXKrp6k0atiF0UzCWbNpOgH28bRcgWTNvArc_SBvKGbn8ERr04FcWRY4hI&#39; class=&#39;b-hbp-video b-uploaded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
As usual the code is up on&amp;nbsp;&lt;a href=&quot;http://github.com/seangeo/breakout&quot;&gt;Github&lt;/a&gt;&amp;nbsp;if anyone is interested. &amp;nbsp;Next week I&#39;ll be cleaning up the input detection a bit and implementing the ball, so more graphics and 2D motion this time and maybe some collision detection.&lt;br /&gt;
&lt;br /&gt;
And before I forget, I found&amp;nbsp;&lt;a href=&quot;http://www.xnadevelopment.com/tutorials.shtml&quot;&gt;these tutorials&lt;/a&gt;&amp;nbsp;by&amp;nbsp;&lt;a href=&quot;http://twitter.com/#!/clingermangw&quot;&gt;George Clingerman&lt;/a&gt;&amp;nbsp;really useful to get up to speed on 2D graphics in XNA, so thanks George!!</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/4231964035636360523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/4231964035636360523' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/4231964035636360523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/4231964035636360523'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2011/03/week-2-with-paddle.html' title='Week 2: With a Paddle'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinZHk0QE3zsNJrou90YWddxPffGYxZGz6bYHPCkmMqRBpOEgOlkxvGu1I6iDGkNhX9GRvLTCOglPiKec_xla5j2wbvA16VtO5nU-9bp1yW_CE5aQehNalj4RMlKPRezdgK9rI-NQ/s72-c/paddle.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-3047932192258014533</id><published>2011-02-25T21:37:00.000-08:00</published><updated>2011-02-27T22:22:25.656-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gamedev"/><category scheme="http://www.blogger.com/atom/ns#" term="xna"/><title type='text'>Week 1: Setting up and Installeering</title><content type='html'>This week was not the most exciting in terms of this project, but necessary nonetheless. &amp;nbsp;It was all about setting up my development environment and a bit of troubleshooting to get things working.&lt;br /&gt;
&lt;br /&gt;
First of all, I grabbed a copy of Windows 7 professional and installed that into a Bootcamp partition on my iMac. &amp;nbsp;This didn&#39;t exactly go without a hitch, Windows 7 doesn&#39;t seem to include the right ATI driver for the graphics card in the late 2009 iMacs. So when you get to the third stage of the installation, the screen goes blank... not very helpful. &amp;nbsp;Thankfully there is a pretty simple&amp;nbsp;&lt;a href=&quot;http://discussions.apple.com/message.jspa?messageID=10686896&quot;&gt;work around&lt;/a&gt;&amp;nbsp;that involves booting up in repair mode and deleting the ATI driver. This forces Windows to use a generic driver, but one that actually works. &amp;nbsp;So with that done I could complete the installation and then install the boot camp drivers to get a proper ATI driver for the graphics card.&lt;br /&gt;
&lt;br /&gt;
From there it was a matter of installing some development tools. &amp;nbsp;I got &lt;a href=&quot;http://create.msdn.com/en-us/home/getting_started&quot;&gt;Visual Studio Express Edition with Windows Phone Developer Tools&lt;/a&gt;, which in fact contains XNA Game Studio, not that you would know by the product name. &amp;nbsp;The install for this went without a hitch. &amp;nbsp;I also installed&amp;nbsp;&lt;a href=&quot;http://code.google.com/p/gitextensions/&quot;&gt;Git Extensions&lt;/a&gt;, however for some reason the Visual Studio plugin didn&#39;t work, I&#39;m not too fussed about that though since I&#39;ll probably use the command line most of the time.&lt;br /&gt;
&lt;br /&gt;
With all that setup, I fired up Visual Studio and created a new Windows game project, called Breakout, that I&#39;ll use for building my first game. This was simple enough but there was one hitch, I wasn&#39;t able to run the game within Parallels, I got an error saying there was no suitable device support HiDef. &amp;nbsp;Fortunately the Internet came to the rescue again. &amp;nbsp;Apparently this is caused by Parallels only supporting DirectX 9. &lt;a href=&quot;http://leeyuentuen.byethost15.com/blog/?p=1393&quot;&gt;The fix&lt;/a&gt;&amp;nbsp;is pretty simple, you just need to right click on the Game project, select P&lt;i&gt;roperties&lt;/i&gt;, then change the &lt;i&gt;Game Profile&lt;/i&gt;&amp;nbsp;to &quot;&lt;i&gt;Use Reach ...&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;&quot;, the game should now run and display a beautiful cornflower blue screen.&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;I also tried out VMWare Fusion as an alternative to Parallels, it also suffered from the same HiDef support problem, so there wasn&#39;t really any reason to switch. &amp;nbsp;I&#39;ll see how it goes with Parallels for while, I do get the sense that I&#39;m eventually either going to need more RAM, or I&#39;m going to have to reboot into Windows more often, but I&#39;ll see how it goes.&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;---&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
In order to get up to speed with C# I read through&amp;nbsp;&lt;a href=&quot;http://create.msdn.com/en-US/education/catalog/article/intro_to_c_sharp&quot;&gt;Intro to C# from Objective-C and Java&lt;/a&gt;. I&#39;ve gotta say, it&#39;s not the best document. &amp;nbsp;I realise it is only 24 pages, but it seems to really skim over important language features at the expensive of talking about the CLR platform. &amp;nbsp;For example, it has a list of about 15 items that Java has but are different in C# or that C# has but Java doesn&#39;t, like indexers, different inheritance syntax, access restrictions on overriden members, clashing interface inheritance but it doesn&#39;t actually discuss how C# does it. &amp;nbsp;And yet there is a page and half on garbage collection, which is essentially the same between the two platforms. &amp;nbsp;Oh well, I&#39;m sure I cope.&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;---&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;I&#39;ve also setup a Github project at&amp;nbsp;&lt;a href=&quot;http://github.com/seangeo/breakout&quot;&gt;http://github.com/seangeo/breakout&lt;/a&gt;. It&#39;s a public project so anyone can grab the code, although at this stage there isn&#39;t much to see, hopefully it will get more interesting.&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: normal;&quot;&gt;Next week I&#39;m going to start getting familiar with the XNA API and draw some sprites. &amp;nbsp;If I get time I might make them move across the screen!&lt;/span&gt;&lt;/i&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/3047932192258014533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/3047932192258014533' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/3047932192258014533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/3047932192258014533'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2011/02/week-1-setting-up-and-installeering.html' title='Week 1: Setting up and Installeering'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-6715187613506427464</id><published>2011-02-19T20:11:00.000-08:00</published><updated>2011-03-04T21:03:38.271-08:00</updated><title type='text'>Refurbished and Repurposed</title><content type='html'>I&#39;ve decided to repurpose this blog as a journal for my foray into game programming.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve always loved video games and they have always been a big part of my life. &amp;nbsp;When I decided to to return to university after a brief stint as a sound engineer, my main motivation for doing computer science was to end up as a game programmer. I even&amp;nbsp;&lt;a href=&quot;http://www.adellion.com/&quot;&gt;dabbled&lt;/a&gt;&amp;nbsp;in building a MMORPG in my second and third years. &amp;nbsp;However, at some point I took a different direction. &amp;nbsp;I don&#39;t really know why, probably a combination of factors: a lack of local jobs and not wanting to move state again, the idea of another industry being &lt;i&gt;the&lt;/i&gt;&amp;nbsp;industry that the best people work in (at least in Adelaide) and some sense that it was time for me to grow up and act like an adult; probably why I cut my hair and started wearing button up shirts.&lt;br /&gt;
&lt;br /&gt;
It&#39;s just over 8 years since I graduated. I&#39;ve never been short of work and I&#39;ve had some&amp;nbsp;&lt;a href=&quot;http://doc.winnowtag.org/&quot;&gt;great&lt;/a&gt;&amp;nbsp;&lt;a href=&quot;http://www.consunet.com.au/index2.html&quot;&gt;jobs&lt;/a&gt;&amp;nbsp;with some great people. However, I still have a nagging regret when it comes to game programming. &amp;nbsp;I keep wondering what would have happened had I kept my sights on that goal and worked towards it. And most of all, game development is still something I really want to do. &amp;nbsp;Basically I don&#39;t want to be in the position 8 years from now where I&#39;m wondering the same thing, only it would be even harder to do something about it.&lt;br /&gt;
&lt;br /&gt;
So, this marks a turning point, my hair is long again and I prefer t-shirts.&lt;br /&gt;
&lt;br /&gt;
To have any chance at a game development career, I need to learn game programming techniques, libraries and platforms, because at the moment, my game development knowledge is pretty minimal, I&#39;ve spent all my time doing business/commercial development. It&#39;s not going to be easy or quick and I have a lot to learn, but really I have nothing to lose. I still need to work and make a living so I need something I can do in my spare time and with a plan that keeps me focussed.&amp;nbsp;I&#39;m going to put about 3 hours a week into building small tech demos or games that will teach me something about game programming. I&#39;ll also write a weekly blog post that outlines what I did, what I learnt and what I plan to do next week. &amp;nbsp;If I can stick to this I should learn a decent amount in a reasonable amount of time, but most importantly have a set of demos for a portfolio and a journal to go with it. And from there, we&#39;ll have to see.&lt;br /&gt;
&lt;br /&gt;
Which brings me to the first little project. &amp;nbsp;I&#39;ve spent a bit of time reading and thinking about where to start,&amp;nbsp;&amp;nbsp;it does make sense to use Windows for the project initially though, even though I normally use a Mac and have an iPhone I could develop for, however, the games I would want to work on are PC or console games and most game jobs require C/C++ on Windows, so Windows just makes sense.&amp;nbsp;I don&#39;t want to get overwhelmed and discouraged so starting reasonably small would be a good idea, which makes me think starting with&amp;nbsp;&lt;a href=&quot;http://create.msdn.com/en-US/&quot;&gt;XNA Game Studio&lt;/a&gt;&amp;nbsp;is a good way to get my feet wet with XBox 360 and Windows development, rather than jumping into the deep-end with DirectX. Even if it is C# as opposed to C/C++, I&#39;m not too worried about that just yet.&lt;br /&gt;
&lt;br /&gt;
I&#39;m going to start by developing a &lt;a href=&quot;http://en.wikipedia.org/wiki/Breakout_(video_game)&quot;&gt;Breakout&lt;/a&gt;&amp;nbsp;clone for Windows. This fits the reasonably small criteria but should cover a enough new areas that it should be interesting. &amp;nbsp;I expect to learn about at the least following:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Setup of development environment and building and running a Windows game.&lt;/li&gt;
&lt;li&gt;Simple 2D graphics.&lt;/li&gt;
&lt;li&gt;Simple UI components.&lt;/li&gt;
&lt;li&gt;Simple 2D vector math, trigonometry and animation of the ball and paddle.&lt;/li&gt;
&lt;li&gt;Timing of animation.&lt;/li&gt;
&lt;li&gt;Keyboard input.&lt;/li&gt;
&lt;li&gt;Collision detection.&lt;/li&gt;
&lt;li&gt;Simple audio playback.&lt;/li&gt;
&lt;li&gt;Simple particle effects.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;I&#39;ll be storing all the code for the project in&amp;nbsp;&lt;a href=&quot;http://github.com/seangeo&quot;&gt;my github account.&lt;/a&gt;&amp;nbsp;So if anyone wants to see how I&#39;m progressing in terms of the code, check it out. (I&#39;ll post a link to the actual repository when I get it set up next week.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;That&#39;s all for this week, next week I&#39;ll post about setting up the XNA Game Studio in Windows.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/6715187613506427464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/6715187613506427464' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/6715187613506427464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/6715187613506427464'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2011/02/refurbished-and-repurposed.html' title='Refurbished and Repurposed'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-6633881117310110223</id><published>2008-05-03T00:17:00.000-07:00</published><updated>2008-05-03T00:19:20.349-07:00</updated><title type='text'>rAtom 0.3.5 released</title><content type='html'>This is just a maintenance release, nothing too exciting:&lt;div&gt;&lt;br /&gt;&lt;br /&gt;== 0.3.5 2008-05-03&lt;br /&gt;&lt;br /&gt;* Make sure atom:entries appears last.&lt;br /&gt;* Better examples in the documentation.&lt;/div&gt;&lt;div&gt;* Docs for Feed and Entry list attributes.&lt;br /&gt;* Gave Feeds authors and contributors.&lt;br /&gt;* Fixed a couple warnings.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/6633881117310110223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/6633881117310110223' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/6633881117310110223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/6633881117310110223'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2008/05/ratom-035-released.html' title='rAtom 0.3.5 released'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-7684957224594894720</id><published>2008-04-14T18:13:00.000-07:00</published><updated>2008-04-14T19:04:25.398-07:00</updated><title type='text'>Using rAtom in Rails</title><content type='html'>Some &lt;a href=&quot;http://seangeo.blogspot.com/2008/04/ratom-030-released.html?showComment=1208001480000#c4174573861575860339&quot;&gt;mysterious anonymous person&lt;/a&gt; asked me for a tutorial on using rAtom within Rails.  So I&#39;ll show you all how I do it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Firstly, the big difference is that I treat it more like ActiveRecord#to_xml instead of like a *.builder view. So I&#39;ll start with an example.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Assuming you have a blog application with a Post model class, you can add a #to_atom method to your class like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_model&quot;&gt;&lt;span class=&quot;meta meta_class meta_class_ruby&quot;&gt;&lt;span class=&quot;keyword keyword_control keyword_control_class keyword_control_class_ruby&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby&quot;&gt;Post&lt;span class=&quot;entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby&quot;&gt; &lt;span class=&quot;punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby&quot;&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;  &lt;br /&gt;&lt;span class=&quot;meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby&quot;&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_def keyword_control_def_ruby&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_function entity_name_function_ruby&quot;&gt;to_atom&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Atom&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Entry&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|entry|&lt;br /&gt;      entry.title     = &lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.title&lt;br /&gt;      entry.updated   = &lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.updated_at&lt;br /&gt;      entry.published = &lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.created_at&lt;br /&gt;      entry.author    = &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Atom&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Person&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.author)&lt;br /&gt;      entry.links    &amp;lt;&amp;lt; &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Atom&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Link&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;rel&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;alternate&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;                                    &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;href&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/posts/&lt;span class=&quot;source source_ruby source_ruby_embedded source_ruby_embedded_source&quot;&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.id&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;      entry.content   = &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Atom&lt;/span&gt;::&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Content&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Html&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.content)&lt;br /&gt;    &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;  &lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The advantage of returning a rAtom object here is that the atom representation is then composable, for example if you have a Blog class that has many posts you can do this:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_model&quot;&gt;&lt;span class=&quot;meta meta_class meta_class_ruby&quot;&gt;&lt;span class=&quot;keyword keyword_control keyword_control_class keyword_control_class_ruby&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby&quot;&gt;Blog&lt;span class=&quot;entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby&quot;&gt; &lt;span class=&quot;punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby&quot;&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;support support_function support_function_activerecord support_function_activerecord_rails&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;posts&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;&lt;span class=&quot;meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby&quot;&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_def keyword_control_def_ruby&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_function entity_name_function_ruby&quot;&gt;to_atom&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Atom&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Feed&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|feed|&lt;br /&gt;      feed.title = &lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.title&lt;br /&gt;      feed.links &amp;lt;&amp;lt; &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Atom&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Link&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;rel&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;alternate&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;                                &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;href&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/blogs/&lt;span class=&quot;source source_ruby source_ruby_embedded source_ruby_embedded_source&quot;&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.id&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;      &lt;br /&gt;      &lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.posts.each &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|post|&lt;br /&gt;        feed.entries &amp;lt;&amp;lt; post.to_atom&lt;br /&gt;      &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To get this atom representation out via HTTP, you would do this in the controller:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_controller&quot;&gt;&lt;span class=&quot;meta meta_class meta_class_ruby&quot;&gt;&lt;span class=&quot;keyword keyword_control keyword_control_class keyword_control_class_ruby&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby&quot;&gt;BlogsController&lt;/span&gt;&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ApplicationController&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby&quot;&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_def keyword_control_def_ruby&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_function entity_name_function_ruby&quot;&gt;show&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby&quot;&gt;@&lt;/span&gt;blog&lt;/span&gt; = &lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Blog&lt;/span&gt;.find(params[&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;id&lt;/span&gt;])&lt;br /&gt;    respond_to &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|format|&lt;br /&gt;      format.atom {&lt;span class=&quot;meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block&quot;&gt; &lt;/span&gt;&lt;span class=&quot;support support_function support_function_actionpack support_function_actionpack_rails&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;xml&lt;/span&gt; =&amp;gt; &lt;span class=&quot;variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby&quot;&gt;@&lt;/span&gt;blog&lt;/span&gt;.to_atom.to_xml }&lt;br /&gt;    &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This has been really useful in an application that I am working on because we are using Atom as the main communication format between a bunch of different components, so this composability comes in really handy. For a simple blog it might be overkill, but at least you get the much better performance of libxml-ruby.&lt;br /&gt;&lt;br /&gt;You&#39;ll probably notice a bit of ugliness in the to_atom methods, specifically this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_model&quot;&gt;      entry.links    &amp;lt;&amp;lt; &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Atom&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Link&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;rel&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;alternate&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;                                    &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;href&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/posts/&lt;span class=&quot;source source_ruby source_ruby_embedded source_ruby_embedded_source&quot;&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;variable variable_language variable_language_ruby&quot;&gt;self&lt;/span&gt;.id&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The URL is hard-coded here because url_for is not available in a model.  This is a bit of trade-off between the composability and strict MVC here, if you really wanted to you could pass the URL in as a parameter, or add a block that generates URLs or whatever, it&#39;s up to you.  &lt;br /&gt;&lt;br /&gt;For some applications, like a simple blog, the composability might not be too important, and you might prefer the syntax of atom_feed in Rails, or at least want to be able to render the atom in a view.  In this case it would probably be nice to have a rAtom based template format, so you could add a view like &quot;blogs/show.atom.ratom&quot; which allowed you to move the to_atom method into a view and call url_for directly from the view.  I&#39;d like to add this at some stage, but it hasn&#39;t happened yet, due to time and priorities, but if anyone would like to submit a patch for it I&#39;d gladly accept it.</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/7684957224594894720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/7684957224594894720' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/7684957224594894720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/7684957224594894720'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2008/04/using-ratom-in-rails.html' title='Using rAtom in Rails'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-7477289664041114701</id><published>2008-04-01T18:35:00.000-07:00</published><updated>2008-04-01T18:54:27.141-07:00</updated><title type='text'>rAtom 0.3.0 Released</title><content type='html'>&lt;p&gt;I&#39;ve just release rAtom 0.3.0.  This version adds support for &lt;a href=&quot;http://www.atomenabled.org/developers/syndication/atom-format-spec.php#simple.extension.elements&quot;&gt;simple extension elements&lt;/a&gt; and also checks that content is in UTF-8 before serializing to XML.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As defined in the Atom Syndication Format, simple extension elements consist of XML elements from a non-Atom namespace that have no attributes or child elements, i.e. they are empty or only contain text content.  These elements are treated as a name value pair where the element namespace and local name make up the key and the content of the element is the value, empty elements will be treated as an empty string.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To access extension elements use the [] method on the Feed or Entry. For example, if we are parsing the follow Atom document with extensions:&lt;/p&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source&quot;&gt;&lt;span class=&quot;text text_xml&quot;&gt;&lt;span class=&quot;meta meta_tag meta_tag_preprocessor meta_tag_preprocessor_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_xml&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;entity entity_other entity_other_attribute-name entity_other_attribute-name_xml&quot;&gt; version&lt;/span&gt;=&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_xml&quot;&gt;&quot;&lt;/span&gt;1.0&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_xml&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;meta meta_tag meta_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml&quot;&gt;feed&lt;/span&gt; &lt;span class=&quot;entity entity_other entity_other_attribute-name entity_other_attribute-name_localname entity_other_attribute-name_localname_xml&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_xml&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2005/Atom&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_xml&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;entity entity_other entity_other_attribute-name entity_other_attribute-name_namespace entity_other_attribute-name_namespace_xml&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;entity entity_other entity_other_attribute-name entity_other_attribute-name_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_separator punctuation_separator_namespace punctuation_separator_namespace_xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity entity_other entity_other_attribute-name entity_other_attribute-name_localname entity_other_attribute-name_localname_xml&quot;&gt;ex&lt;/span&gt;=&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_xml&quot;&gt;&quot;&lt;/span&gt;http://example.org&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_xml&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;meta meta_tag meta_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Feed with extensions&lt;span class=&quot;meta meta_tag meta_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;meta meta_tag meta_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_namespace entity_name_tag_namespace_xml&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_separator punctuation_separator_namespace punctuation_separator_namespace_xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml&quot;&gt;myelement&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Something important&lt;span class=&quot;meta meta_tag meta_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_namespace entity_name_tag_namespace_xml&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_separator punctuation_separator_namespace punctuation_separator_namespace_xml&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml&quot;&gt;myelement&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;meta meta_tag meta_tag_xml&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml&quot;&gt;feed&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;We could then access the extension element on the feed using:&lt;/p&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source&quot;&gt;&lt;span class=&quot;source source_ruby&quot;&gt;&amp;gt; feed[&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;http://example.org&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;myelement&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;  =&amp;gt; [&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;Something important&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Note that the return value is an array. This is because XML allows multiple instances of the element.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To set an extension element you append to the array:&lt;/p&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source&quot;&gt;&lt;span class=&quot;source source_ruby&quot;&gt;&amp;gt; feed[&lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;http://example.org&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;myelement&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;] &amp;lt;&amp;lt; &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;Something less important&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;=&amp;gt; [&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;Something important&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;Something less important&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;You can then call to_xml and rAtom will serialize the extension elements into xml.&lt;/p&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source&quot;&gt;&lt;span class=&quot;source source_ruby&quot;&gt;&amp;gt; puts feed.to_xml&lt;br /&gt;&amp;lt;&lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;?x&lt;/span&gt;ml version=&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;1.0&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;feed xmlns=&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;http://www.w3.org/2005/Atom&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;myelement xmlns=&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;http://example.org&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Something&lt;/span&gt; important&amp;lt;/myelement&amp;gt;&lt;br /&gt;  &amp;lt;myelement xmlns=&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;http://example.org&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;Something&lt;/span&gt; less important&amp;lt;/myelement&amp;gt;&lt;br /&gt;&amp;lt;/feed&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Notice that the output repeats the xmlns attribute for each of the extensions, this is semantically the same the input XML, just a bit ugly.  It seems to be a limitation of the libxml-Ruby API. But if anyone knows a work around I&#39;d gladly accept a patch (or even advice).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You can get rAtom via gem:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;&amp;gt; gem install ratom&lt;/code&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;or from &lt;a href=&quot;http://github.com/seangeo/ratom/tree/master&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/7477289664041114701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/7477289664041114701' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/7477289664041114701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/7477289664041114701'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2008/04/ratom-030-released.html' title='rAtom 0.3.0 Released'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-8595761109705937373</id><published>2008-03-08T19:03:00.000-08:00</published><updated>2008-03-08T19:38:35.165-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="atom"/><category scheme="http://www.blogger.com/atom/ns#" term="code"/><category scheme="http://www.blogger.com/atom/ns#" term="gem"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>rAtom 0.2.1 Gem released</title><content type='html'>rAtom is a Ruby Gem for working with the Atom Syndication Format and the Atom Publishing Protocol (APP).&lt;br /&gt;&lt;br /&gt;rAtom was originally built to support the communication between a number of applications built by Peerworks[http://peerworks.org], via the Atom Publishing protocol.  However, it supports, or aims to support, all the Atom Syndication Format and Publication Protocol and can be used to access Atom feeds or to script publishing entries to a blog supporting APP.&lt;br /&gt;&lt;br /&gt;Features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Uses libxml-ruby so it is _much_ faster than a REXML based library.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Uses the libxml pull parser so it has much lighter memory usage.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Supports RFC 5005 (http://www.ietf.org/rfc/rfc5005.txt) for feed pagination.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;You can install via gem using:&lt;br /&gt;&lt;code&gt;# sudo gem install ratom&lt;/code&gt;&lt;br /&gt;&lt;h2&gt;Usage&lt;/h2&gt;To fetch and parse an Atom Feed you can simply:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;feed = Atom::Feed.load_feed(URI.parse(&quot;http://example.com/feed.atom&quot;))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And then iterate over the entries in the feed using:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;feed.each_entry do |entry|&lt;br /&gt; # do cool stuff&lt;br /&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;To construct a Feed&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;feed = Atom::Feed.new do |feed|&lt;br /&gt; feed.title = &quot;My Cool Feed&quot;&lt;br /&gt; feed.id = &quot;http://example.com/my_feed.atom&quot;&lt;br /&gt; feed.updated = Time.now&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;To output a Feed as XML use to_xml&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&gt; puts feed.to_xml&lt;br /&gt;&amp;lt;feed xmlns=&quot;http://www.w3.org/2005/Atom&quot;&amp;gt;&lt;br /&gt; &amp;lt;title&amp;gt;My Cool Feed&amp;lt;/title&amp;gt;&lt;br /&gt; &amp;lt;id&amp;gt;http://example.com/my_feed.atom&amp;lt;/id&amp;gt;&lt;br /&gt; &amp;lt;updated&amp;gt;2008-03-03T23:19:44+10:30&amp;lt;/updated&amp;gt;&lt;br /&gt;&amp;lt;/feed&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Publishing&lt;/h2&gt;To publish to a remote feed using the Atom Publishing Protocol, first you need to create a collection to publish to:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;collection = Atom::Pub::Collection.new(:href =&gt; &#39;http://example.org/myblog&#39;)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Then create a new entry:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;entry = Atom::Entry.new do |entry|&lt;br /&gt; entry.title = &quot;I have discovered rAtom&quot;&lt;br /&gt; entry.authors &lt;&lt; name =&quot;&quot;&gt; &#39;A happy developer&#39;)&lt;br /&gt; entry.updated = Time.now&lt;br /&gt; entry.id = &quot;http://example.org/myblog/newpost&quot;&lt;br /&gt; entry.content = Atom::Content::Html.new(&quot;&amp;lt;p&amp;gt;rAtom lets me post to my blog using Ruby, how cool!&amp;lt;/p&amp;gt;&quot;)&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And publish it to the Collection:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;published_entry = collection.publish(entry)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;More Information&lt;/h2&gt;See &lt;a href=&quot;http://ratom.rubyforge.org/&quot;&gt;http://ratom.rubyforge.org&lt;/a&gt; for more information.</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/8595761109705937373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/8595761109705937373' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/8595761109705937373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/8595761109705937373'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2008/03/ratom-021-gem-released.html' title='rAtom 0.2.1 Gem released'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-8827410976060723073</id><published>2007-09-26T03:09:00.000-07:00</published><updated>2007-10-04T15:54:55.184-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="code"/><category scheme="http://www.blogger.com/atom/ns#" term="erlang"/><category scheme="http://www.blogger.com/atom/ns#" term="rake"/><title type='text'>Building Erlang with Rake</title><content type='html'>I&#39;ve recently started using Erlang on a project.  This is my first foray into Erlang and I&#39;m using Joe Armstong&#39;s new book &lt;a href=&quot;http://www.pragmaticprogrammer.com/titles/jaerlang/&quot;&gt;Programming Erlang&lt;/a&gt; as introductory material. It is a great introduction to the language, although I wish it covered more of the OTP.  I suppose there is the &lt;a href=&quot;http://www.erlang.org/doc/design_principles/part_frame.html&quot;&gt;OTP Design Principles&lt;/a&gt; guide but sometimes a good paper book written in conversational style is better when you are learning.&lt;br /&gt;&lt;br /&gt;In the book Joe describes building an Erlang project using make and most of the downloadable bits of Erlang code use make too; this makes sense, make is virtually ubiquitous.  However the other components of this project are Ruby on Rails applications and make heavy use of &lt;a href=&quot;http://rake.rubyforge.org&quot;&gt;Rake&lt;/a&gt;, so I figure why subject myself to Make when I can use the beautiful Rake.&lt;br /&gt;&lt;br /&gt;Here is my Rakefile for building an Erlang project.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby&quot;&gt;&lt;span class=&quot;meta meta_require meta_require_ruby&quot;&gt;&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;rake/clean&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;INCLUDE&lt;/span&gt; = &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;include&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ERLC_FLAGS&lt;/span&gt; = &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;-I&lt;span class=&quot;source source_ruby source_ruby_embedded source_ruby_embedded_source&quot;&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;INCLUDE&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;}&lt;/span&gt;&lt;/span&gt; +warn_unused_vars +warn_unused_import&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;SRC&lt;/span&gt; = &lt;span class=&quot;support support_class support_class_ruby&quot;&gt;FileList&lt;/span&gt;[&lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;src/*.erl&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;OBJ&lt;/span&gt; = &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;SRC&lt;/span&gt;.pathmap(&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;%{src,ebin}X.beam&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;CLEAN&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;ebin/*.beam&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;directory &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;ebin&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;rule &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;.beam&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; =&amp;gt;  [&lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;%{ebin,src}X.erl&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;] &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|t|&lt;br /&gt;  sh &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;erlc -pa ebin -W &lt;span class=&quot;source source_ruby source_ruby_embedded source_ruby_embedded_source&quot;&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ERLC_FLAGS&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;}&lt;/span&gt;&lt;/span&gt; -o ebin &lt;span class=&quot;source source_ruby source_ruby_embedded source_ruby_embedded_source&quot;&gt;&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;#{&lt;/span&gt;t.source&lt;span class=&quot;punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;task &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;compile&lt;/span&gt; =&amp;gt; [&lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;ebin&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;] + &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;OBJ&lt;/span&gt;&lt;br /&gt;task &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;default&lt;/span&gt; =&amp;gt; &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;compile&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This gives you &lt;code&gt;rake compile&lt;/code&gt; which builds all the &lt;code&gt;.erl&lt;/code&gt; files in the &lt;code&gt;src&lt;/code&gt; subdirectory into the &lt;code&gt;.beam&lt;/code&gt; files in the &lt;code&gt;ebin&lt;/code&gt; directory. Files will only be built if they have changes since the last build.  You also get &lt;code&gt;rake clean&lt;/code&gt; which deletes all the &lt;code&gt;.beam&lt;/code&gt; files from the &lt;code&gt;ebin&lt;/code&gt; directory.&lt;br /&gt;&lt;br /&gt;I much prefer this over the equivalent Makefile and it is much easier to extend since you have the full power of Ruby at your disposal.&lt;br /&gt;&lt;br /&gt;Enjoy.&lt;br /&gt;&lt;br /&gt;Update: Fixed bug when compile many files from after clean.</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/8827410976060723073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/8827410976060723073' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/8827410976060723073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/8827410976060723073'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2007/09/building-erlang-with-rake.html' title='Building Erlang with Rake'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-6281894991469010181</id><published>2007-09-03T17:11:00.000-07:00</published><updated>2007-09-03T18:29:37.204-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="activeresource"/><category scheme="http://www.blogger.com/atom/ns#" term="code"/><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="testing"/><title type='text'>Testing ActiveResource</title><content type='html'>I recently started using &lt;a href=&quot;http://bloggingrailsconf.com/articles/2006/06/25/david-heinemeier-hansson-keynote&quot;&gt;ActiveResource&lt;/a&gt; on a project.  ActiveResource is the client side of the REST picture, that is it can consume the REST style web services you get with Rails, think of it as ActiveRecord for HTTP.&lt;br /&gt;&lt;br /&gt;One of the difficult parts of using ActiveResource is testing. You don&#39;t want to run it over a real HTTP connection, for one it would significantly slow down your tests and secondly you don&#39;t know what horrible side effects it might have.  So you need some way to fake a HTTP connection and HTTP requests and responses.  Enter the HttpMock class.&lt;br /&gt;&lt;br /&gt;HttpMock is a fairly nice class put together by the Rails folk that allows you to register a bunch of request and response pairs for a fake HTTP connection.  When you call a method on an ActiveResource in a test, it calls the HttpMock class instead of trying to create a real connection.  It is fairly easy to use, although there is no documentation the blogging community has come to the &lt;a href=&quot;http://www.movesonrails.com/articles/2007/07/04/testing-a-rest-full-activeresource&quot;&gt;rescue&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is a quick example:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_unit_test&quot;&gt;  &lt;span class=&quot;variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby&quot;&gt;@&lt;/span&gt;matz&lt;/span&gt;  = {&lt;span class=&quot;meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block&quot;&gt; &lt;/span&gt;&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; &lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;name&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;Matz&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; }.to_xml(&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;root&lt;/span&gt; =&amp;gt; &lt;span class=&quot;string string_quoted string_quoted_single string_quoted_single_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&#39;&lt;/span&gt;person&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;  &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ActiveResource&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;HttpMock&lt;/span&gt;.respond_to &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|mock|&lt;br /&gt;    mock.get &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/people/1.xml&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class=&quot;variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby&quot;&gt;@&lt;/span&gt;matz&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This creates a request response pair so that when ActiveResource tries to GET /people/1.xml it gets back the xml for the @matz hash.  Pretty simple.&lt;br /&gt;&lt;br /&gt;However there is a problem.  HttpMock is misnamed - HttpMock is a &lt;a href=&quot;http://martinfowler.com/articles/mocksArentStubs.html&quot;&gt;stub not a mock&lt;/a&gt;.  But the difference is more than semantic, a mock object, like those provided by the excellent &lt;a href=&quot;http://mocha.rubyforge.org&quot;&gt;Mocha&lt;/a&gt; library, will allow you to set expectations on a object. An expectation is like saying &quot;for this test to pass, this method with these arguments must be called on this object&quot;.  HttpMock doesn&#39;t do that, instead it is just a stub that returns a value when a method is called with a certain argument, there is no verification that the method is actually called.&lt;br /&gt;&lt;br /&gt;To show why this is bad, lets look at the test for resource deletion from the ActiveResource unit tests themselves.&lt;br /&gt;&lt;br /&gt;Firstly, in the setup method we use HttpMock to create response for the delete method used on the &quot;/people/1.xml&quot; path:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_unit_test&quot;&gt;  &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ActiveResource&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;HttpMock&lt;/span&gt;.respond_to &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|mock|&lt;br /&gt;    mock.delete &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/people/1.xml&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class=&quot;constant constant_language constant_language_ruby&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;200&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here is the test_delete method:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&#39;linenum&#39;&gt;    1&lt;/span&gt; &lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_unit_test&quot;&gt;&lt;span class=&quot;meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby&quot;&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_def keyword_control_def_ruby&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_function entity_name_function_ruby&quot;&gt;test_delete&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#39;linenum&#39;&gt;    2&lt;/span&gt;     assert &lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Person&lt;/span&gt;.delete(&lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;&lt;span class=&#39;linenum&#39;&gt;    3&lt;/span&gt;     &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ActiveResource&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;HttpMock&lt;/span&gt;.respond_to &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|mock|&lt;br /&gt;&lt;span class=&#39;linenum&#39;&gt;    4&lt;/span&gt;       mock.get &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/people/1.xml&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class=&quot;constant constant_language constant_language_ruby&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;404&lt;/span&gt;&lt;br /&gt;&lt;span class=&#39;linenum&#39;&gt;    5&lt;/span&gt;     &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class=&#39;linenum&#39;&gt;    6&lt;/span&gt;     assert_raises(&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ActiveResource&lt;/span&gt;::&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ResourceNotFound&lt;/span&gt;) {&lt;span class=&quot;meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block&quot;&gt; &lt;/span&gt;&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Person&lt;/span&gt;.find(&lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;1&lt;/span&gt;) }&lt;br /&gt;&lt;span class=&#39;linenum&#39;&gt;    7&lt;/span&gt;   &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So what is happening here?  Firstly on line 2 of the test_delete method we call the Person classes delete method. The delete method is a nice one-liner:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_controller&quot;&gt;&lt;span class=&quot;meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby&quot;&gt;      &lt;span class=&quot;keyword keyword_control keyword_control_def keyword_control_def_ruby&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_function entity_name_function_ruby&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable variable_parameter variable_parameter_function variable_parameter_function_ruby&quot;&gt;id, options = {}&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        connection.delete(element_path(id, options))&lt;br /&gt;      &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can assume here that the the content of the delete method is sending a delete request to &quot;/people/#{id}.xml&quot;, that makes sense. The rest of the test_delete method creates a request response pair that returns a 404 error when &quot;/people/1.xml&quot; is requested, all that does is test that ActiveResource::Base.find correctly handles 404.&lt;br /&gt;&lt;br /&gt;So what ensures that the delete method does the right thing, all the test does is ensure that it returns something other than nil or false.  Lets change the method and see if we can break the test.  We&#39;ll just return true in the delete method:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_controller&quot;&gt;&lt;span class=&quot;meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby&quot;&gt;      &lt;span class=&quot;keyword keyword_control keyword_control_def keyword_control_def_ruby&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_function entity_name_function_ruby&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;variable variable_parameter variable_parameter_function variable_parameter_function_ruby&quot;&gt;id, options = {}&lt;/span&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;constant constant_language constant_language_ruby&quot;&gt;true&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After this change I re-ran the tests and they all passed.  This can&#39;t be good. If you can effectively remove the body of a method you are testing and the tests still pass you don&#39;t have a very good test.  So how can we fix it? &lt;br /&gt;&lt;br /&gt;Well if HttpMock was truely a mock we could ensure that the HTTP delete method is called on the &quot;/people/1.xml&quot; path.  Fortunately HttpMock stores every request it recieves in a class variable.  So we can check that the request was received with an assertion.  &lt;br /&gt;&lt;br /&gt;Here is a new test_delete:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_unit_test&quot;&gt;&lt;span class=&quot;meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby&quot;&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_def keyword_control_def_ruby&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;entity entity_name entity_name_function entity_name_function_ruby&quot;&gt;test_delete&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    assert &lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Person&lt;/span&gt;.delete(&lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;1&lt;/span&gt;)&lt;br /&gt;    assert &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ActiveResource&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;HttpMock&lt;/span&gt;.requests.include?(&lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ActiveResource&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;Request&lt;/span&gt;.&lt;span class=&quot;keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;constant constant_other constant_other_symbol constant_other_symbol_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby&quot;&gt;:&lt;/span&gt;delete&lt;/span&gt;, &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/people/1.xml&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;constant constant_language constant_language_ruby&quot;&gt;nil&lt;/span&gt;, {}))&lt;br /&gt;  &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This one now fails when the body of the delete method is removed and passes when it is put back in, so this way we know that the tests is actually testing the functionality of the method.  However it is a bit ugly isn&#39;t it?  It would be nice if HttpMock allowed you to do this:&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;textmate-source vibrant_ink&quot;&gt;&lt;span class=&quot;source source_ruby source_ruby_rails&quot;&gt;&lt;span class=&quot;meta meta_rails meta_rails_unit_test&quot;&gt;    &lt;span class=&quot;variable variable_other variable_other_constant variable_other_constant_ruby&quot;&gt;ActiveResource&lt;/span&gt;::&lt;span class=&quot;support support_class support_class_ruby&quot;&gt;HttpMock&lt;/span&gt;.expects &lt;span class=&quot;keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block&quot;&gt;do &lt;/span&gt;|http|&lt;br /&gt;      http.delete &lt;span class=&quot;string string_quoted string_quoted_double string_quoted_double_ruby&quot;&gt;&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby&quot;&gt;&quot;&lt;/span&gt;/people/1.xml&lt;span class=&quot;punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class=&quot;constant constant_language constant_language_ruby&quot;&gt;nil&lt;/span&gt;, &lt;span class=&quot;constant constant_numeric constant_numeric_ruby&quot;&gt;200&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;keyword keyword_control keyword_control_ruby&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But I&#39;ll leave that for another blog post.</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/6281894991469010181/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/6281894991469010181' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/6281894991469010181'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/6281894991469010181'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2007/09/testing-activeresource.html' title='Testing ActiveResource'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-757702374302679940</id><published>2007-05-28T18:41:00.000-07:00</published><updated>2007-05-29T13:19:14.112-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="code"/><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Index Ruby Objects by an Attribute</title><content type='html'>&lt;code&gt;&lt;pre&gt;&lt;br /&gt;class Array&lt;br /&gt;  def hash_by(attribute)&lt;br /&gt;    self.inject({}) do |hash, e|&lt;br /&gt;      hash[e.send(attribute)] = e&lt;br /&gt;      hash&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/757702374302679940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/757702374302679940' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/757702374302679940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/757702374302679940'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2007/05/index-ruby-objects-by-attribute.html' title='Index Ruby Objects by an Attribute'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-114615158984995050</id><published>2006-04-27T07:56:00.000-07:00</published><updated>2006-04-27T08:31:54.346-07:00</updated><title type='text'>Why GET should always be idempotent: A lesson from Del.icio.us and Sage</title><content type='html'>This evening I downloaded &lt;a href=&quot;http://sage.mozdev.org&quot;&gt;Sage&lt;/a&gt;, a RSS/Atom feed reader extension for &lt;a href=&quot;http://www.getfirefox.com&quot;&gt;Firefox&lt;/a&gt;.  It is quite a nice feed reader and a big improvement over Firefox&#39;s Live Bookmarks which I find hard to use with lots of feeds and IMO over Google&#39;s Personalised Homepage which I find doesn&#39;t scale too well with lots of feeds and doesn&#39;t provide previews of the content.&lt;br /&gt;&lt;br /&gt;Sage had a particularly cool feature that jumped out at me, the &#39;Discover Feeds&#39; feature.  This allows you to find all the feeds referenced in a page, rather than just the feed in a link tag in the header.  It seems that what it does is follow links that may be potential feeds and checks if they are.  You then get a list of all the feeds in the page and can add them to your &#39;watched&#39; feeds in Sage.&lt;br /&gt;&lt;br /&gt;This got me thinking, since I use alot of different computers it is pain trying to manage my list of feeds on each computer, exporting them and copying them around is just asking to get them out of sync and frankly too much effort. ;) So since I already have a &lt;a href=&quot;http://del.icio.us&quot;&gt;Del.icio.us&lt;/a&gt; account where I keep my bookmarks I could bookmark all the feeds I care about and tag them with &#39;feed&#39; in Del.icio.us.  Then I just need to navigate to the page for the &#39;feed&#39; tag click on the Discover Feeds button in Sage and all my bookmarked feeds are there to be added to Sage! Yay online storage of feed links that can easily be added to my feed reader of choice from any computer!!!&lt;br /&gt;&lt;br /&gt;Or so I thought.  It just so happens that the Delicious &#39;Delete Bookmark&#39; link is one of the links that Sage follows when it searches for feeds.  This has the unfortunate side effect of deleting all my bookmarks in the feed tag.  The ideal fix is that Delicious delete action needs to be changed to only respond to a HTTP POST method. This would be comformant with &lt;a href=&quot;http://www.w3.org/2001/tag/doc/whenToUseGet.html&quot;&gt;W3C Recommandations&lt;/a&gt; too.&lt;br /&gt;&lt;br /&gt;I&#39;ve submitted this bug to Delicious but for now the dream of online bookmarking of feeds to be accessed by Sage remains elusive.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Tags: &lt;a href=&quot;http://technorati.com/tag/Delicious&quot; rel=&quot;tag&quot;&gt;Delicious&lt;/a&gt; &lt;a href=&quot;http://technorati.com/tag/HTTP&quot; rel=&quot;tag&quot;&gt;HTTP&lt;/a&gt; &lt;a href=&quot;http://technorati.com/tag/Firefox&quot; rel=&quot;tag&quot;&gt;Firefox&lt;/a&gt; &lt;a href=&quot;http://technorati.com/tag/Blogs&quot; rel=&quot;tag&quot;&gt;Blogs&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/114615158984995050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/114615158984995050' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114615158984995050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114615158984995050'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2006/04/why-get-should-always-be-idempotent.html' title='Why GET should always be idempotent: A lesson from Del.icio.us and Sage'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-114586015704996827</id><published>2006-04-23T23:13:00.000-07:00</published><updated>2006-04-23T23:46:02.170-07:00</updated><title type='text'>Calling Web Services From Rails</title><content type='html'>I&#39;ve notice a &lt;a href=&quot;http://www.leonsays.com/2006/04/23/can-ruby-on-rails-consume-web-services/&quot;&gt;few&lt;/a&gt; &lt;a href=&quot;http://www.leonsays.com/2006/04/23/can-ruby-on-rails-consume-web-services/&quot;&gt;places&lt;/a&gt; where people have asked whether &lt;a href=&quot;http://www.rubyonrails.com&quot;&gt;Ruby On Rails&lt;/a&gt; supports the consumption of web services.  Rails itself doesn&#39;t. I have found the easiest thing to use is &lt;a href=&quot;http://dev.ctor.org/soap4r&quot;&gt;SOAP4R&lt;/a&gt;, which according to its web page comes bundled with Ruby 1.8.3 and above.&lt;br /&gt;&lt;br /&gt;SOAP4R is really easy to use, it simply generates Ruby stubs from a WSDL which will call the web service for you.  You just call the stubs as though they were a Ruby API.&lt;br /&gt;&lt;br /&gt;If you have ever used any Java or .NET web service clients, it is pretty much the exact same concept.&lt;br /&gt;&lt;br /&gt;Tags: &lt;a href=&quot;http://technorati.com/tags/SOAP&quot; rel=&quot;tag&quot;&gt;SOAP&lt;/a&gt; &lt;a href=&quot;http://technorati.com/tags/Web+Services&quot; rel=&quot;tag&quot;&gt;Web Services&lt;/a&gt; &lt;a href=&quot;http://technorati.com/tags/Rails&quot; rel=&quot;tag&quot;&gt;Rails&lt;/a&gt; &lt;a href=&quot;http://technorati.com/tags/Ruby&quot; rel=&quot;tag&quot;&gt;Ruby&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/114586015704996827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/114586015704996827' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114586015704996827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114586015704996827'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2006/04/calling-web-services-from-rails.html' title='Calling Web Services From Rails'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-114194896905442664</id><published>2006-03-09T15:56:00.000-08:00</published><updated>2006-03-09T16:02:49.066-08:00</updated><title type='text'>Javascript Graph Visualisation</title><content type='html'>I just found this new &lt;a href=&quot;http://aslakhellesoy.com/articles/tag/canvas&quot;&gt;graphing library&lt;/a&gt; for Javascript.  I&#39;ve been looking for something that does this for a while so I can visualise relationships represented in RDF.  The last thing I was looking at was &lt;a href=&quot;http://www.foafnaut.org&quot;&gt;Foafnaut&lt;/a&gt; which doesn&#39;t seem to be very active and only supports foaf information.&lt;br /&gt;&lt;br /&gt;This Javascript library looks really promising though since you should be able update the graph using Ajax which would be really cool.  It&#39;s just in the beginning stages now but I&#39;ll definately be keeping an eye on it.&lt;br /&gt;&lt;p&gt;Technorati: &lt;a href=&quot;http://www.technorati.com/tag/semantic+web&quot; rel=&quot;tag&quot;&gt;semantic web&lt;/a&gt; &lt;a href=&quot;http://www.technorati.com/tag/Javascript&quot; rel=&quot;tag&quot;&gt;Javascript&lt;/a&gt; &lt;a href=&quot;http://www.technorati.com/tag/RDF&quot; rel=&quot;tag&quot;&gt;RDF&lt;/a&gt; &lt;a href=&quot;http://www.technorati.com/tag/Canvas&quot; rel=&quot;tag&quot;&gt;Canvas&lt;/a&gt; &lt;a href=&quot;http://www.technorati.com/tag/SVG&quot; rel=&quot;tag&quot;&gt;SVG&lt;/a&gt; &lt;a href=&quot;http://www.technorati.com/tag/Firefox&quot; rel=&quot;tag&quot;&gt;Firefox&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/114194896905442664/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/114194896905442664' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114194896905442664'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114194896905442664'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2006/03/javascript-graph-visualisation.html' title='Javascript Graph Visualisation'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-114035209879596102</id><published>2006-02-19T04:01:00.000-08:00</published><updated>2006-02-19T05:05:10.673-08:00</updated><title type='text'>Active Ontology for Ruby on Rails</title><content type='html'>Obie Fernandaz has some &lt;a href=&quot;http://jroller.com/page/obie?entry=more_about_ontologies&quot;&gt;ideas&lt;/a&gt; for a Ontology based &lt;a href=&quot;http://wiki.rubyonrails.org/rails/pages/ActiveRecord&quot;&gt;ActiveRecord&lt;/a&gt; alternative.&lt;br /&gt;&lt;br /&gt;This is a really interesting idea, something I&#39;ve also been thinking about for a while. One of the tricky things in doing this would be determining what properties a class has.  In a RDBMS table you declare that a table (class) has a number of columns (attributes) the mapping to an object model is fairly obvious.&lt;br /&gt;&lt;br /&gt;However with &lt;a href=&quot;http://www.w3.org/TR/owl-features/&quot;&gt;OWL&lt;/a&gt; and &lt;a href=&quot;http://www.w3.org/RDF/&quot;&gt;RDF&lt;/a&gt; you declare a class and you declare properties, however properties are independant of classes.  You can, in RDFS, say that a property has the domain of a specific class, which means that if a Resource has that property it is a member of that class.  This is different to RDBMS/OO land where you declare that a class has a property.  The difference is subtle but important as it allows you to say things like:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;There is a Employee class.&lt;/li&gt;&lt;li&gt;There is a Manager class which is a subclass of Employee.&lt;/li&gt;&lt;li&gt;There is a manages property that has domain Manager.&lt;/li&gt;&lt;li&gt;We can then infer that the manages property also has Employee as its domain since all Managers and Employees. (Note that this the opposite of OO where properties and inherited down the class heirarchy).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;We can then create an instance of Employee.  It is valid to give that Employee a manages property pointing at another Employee instance. We can then infer that the Employee is also a manager.&lt;/li&gt;&lt;/ol&gt;When you want to map this to OO though, which class gets the manages property?  It is correct to give it Employee since we infered that Employee is a valid domain for manages.  &lt;span style=&quot;font-weight: bold;&quot;&gt;Except any Employee who manages someone is a Manager too.  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is one of the tricky things that will arise out of the differences between Ontologies and OO.  A couple of the others are multiple inheritence and multiple class membership.&lt;br /&gt;&lt;br /&gt;Most of these issues could be worked out after the initial functionality is there, but it should interesting to see how they are tackled.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Update: &lt;/span&gt;Man I really need to look at dates before I respond to blogs.&lt;br /&gt;&lt;p&gt;Technorati: &lt;a href=&quot;http://www.technorati.com/tag/semantic+web&quot; rel=&quot;tag&quot;&gt;semantic web&lt;/a&gt;, &lt;a href=&quot;http://www.technorati.com/tag/Rails&quot; rel=&quot;tag&quot;&gt;Rails&lt;/a&gt; &lt;a href=&quot;http://www.technorati.com/tag/Ruby&quot; rel=&quot;tag&quot;&gt;Ruby&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/114035209879596102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/114035209879596102' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114035209879596102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114035209879596102'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2006/02/active-ontology-for-ruby-on-rails.html' title='Active Ontology for Ruby on Rails'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-114032772616665027</id><published>2006-02-18T21:31:00.000-08:00</published><updated>2006-02-18T21:47:47.673-08:00</updated><title type='text'>RDF Schema Generator</title><content type='html'>I&#39;ve release my first &lt;a href=&quot;http://www.rubyonrails.com&quot;&gt;Rails&lt;/a&gt; generator on &lt;a href=&quot;http://rubyforge.org&quot;&gt;Ruby Forge&lt;/a&gt;.  &lt;a href=&quot;http://rubyforge.org/projects/rdfsgen/&quot;&gt;RDF Schema Generator&lt;/a&gt; builds a Ruby Module from an RDFS file.  The module contains constants for each of the properties and classes in the Schema. If you are using Rails to build RDF based applications you might find it useful.&lt;br /&gt;&lt;br /&gt;Install it using &lt;code&gt;gem install rdf_schema_generator&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Once it is installed you can run &lt;blockquote&gt;&lt;code&gt;ruby script/generate rdf_schema &amp;lt;prefix&amp;gt; &amp;lt;rdfs_url&amp;gt;&lt;/code&gt;&lt;/blockquote&gt; and a class called &lt;prefix&gt; will be generated in the lib directory containing a module with all the classes and properties for the RDFS file retreived from &amp;lt;rdfs_url&amp;gt;.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Tags: &lt;a href=&quot;http://technorati.com/blogs/Ruby&quot; rel=&quot;tag directory&quot;&gt;Ruby&lt;/a&gt; &lt;a href=&quot;http://technorati.com/blogs/Rails&quot; rel=&quot;tag directory&quot;&gt;Rails&lt;/a&gt; &lt;a href=&quot;http://technorati.com/blogs/RDF&quot; rel=&quot;tag directory&quot;&gt;RDF&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/114032772616665027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/114032772616665027' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114032772616665027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114032772616665027'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2006/02/rdf-schema-generator.html' title='RDF Schema Generator'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22641314.post-114027313967598705</id><published>2006-02-18T06:26:00.000-08:00</published><updated>2006-02-18T06:32:19.683-08:00</updated><title type='text'>First Post</title><content type='html'>Well, this is my first ever blog post.&lt;br /&gt;&lt;br /&gt;By way of introduction - my name is Sean Geoghegan,  I&#39;m a geek, I work as a computer programmer.  I&#39;m currently into &lt;a href=&quot;http://www.rubyonrails.com&quot;&gt;Ruby on Rails&lt;/a&gt; and really want to write a Rails based web application in the guise of &lt;a href=&quot;http://www.flickr.com&quot;&gt;flickr&lt;/a&gt; or &lt;a href=&quot;http://www.43things.com&quot;&gt;43things&lt;/a&gt; that becomes hugely popular, I just need an idea, if you have one post it in a comment.</content><link rel='replies' type='application/atom+xml' href='http://seangeo.blogspot.com/feeds/114027313967598705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/22641314/114027313967598705' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114027313967598705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22641314/posts/default/114027313967598705'/><link rel='alternate' type='text/html' href='http://seangeo.blogspot.com/2006/02/first-post.html' title='First Post'/><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE2rXhInBqo5WqOWhlxdxDcF0iVVRr5W_R-bquHDw_JYu8TwvYYE2JOW2deXPtsV0QfGmmGRhvtiM7qHkAfgdX-nWFNCVf85xokypYQln2qvRQRD7Cieckt-hDw_udLcg/s1600/Sean_Geoghegan.jpeg'/></author><thr:total>0</thr:total></entry></feed>