<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Merbist &#187; macruby</title>
	<atom:link href="http://merbist.com/tag/macruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://merbist.com</link>
	<description>Random thoughts of a software developer</description>
	<lastBuildDate>Sat, 05 May 2012 14:16:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Data safety and GIL removal</title>
		<link>http://merbist.com/2011/10/18/data-safety-and-gil-removal/</link>
		<comments>http://merbist.com/2011/10/18/data-safety-and-gil-removal/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 23:19:17 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[Misc]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[gil]]></category>
		<category><![CDATA[macruby]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=1188</guid>
		<description><![CDATA[After my recent RubyConf talk and follow up post addressing the Ruby &#38; Python&#8217;s Global Interpreter Lock (aka GVL/Global VM Lock). a lot of people asked me to explain what I meant by &#8220;data safety&#8221;. While my point isn&#8217;t to defend one approach or the other, I spent a lot of time explaining why C [...]]]></description>
			<content:encoded><![CDATA[<p>After my recent <a title="RubyConf 2011 slides" href="http://rubyconf11.merbist.com" target="_blank">RubyConf talk</a> and <a title="About concurrency and the GIL" href="http://merbist.com/2011/10/03/about-concurrency-and-the-gil/" target="_blank">follow up post addressing the Ruby &amp; Python&#8217;s Global Interpreter Lock</a> (aka GVL/Global VM Lock). a lot of people asked me to explain what I meant by &#8220;data safety&#8221;. While my point isn&#8217;t to defend one approach or the other, I spent a lot of time explaining why C Ruby and C Python use a GIL and where it matters and where it matters less. As a reminder and as mentioned by Matz himself, the main reason why C Ruby still has a GIL is data safety. But if this point isn&#8217;t clear to you, you might be missing the main argument supporting the use of a GIL.</p>
<p>Showing obvious concrete examples of data corruption due to unsafe threaded code isn&#8217;t actually as easy at it sounds. First of all, even with a GIL, developers can write unsafe threaded code. So we need to focus only on the safety problems raised by removing the GIL. To demonstrate what I mean, I will try to create some race conditions and show you the unexpected results you might get. Again, before you go crazy on the comments, remember that threaded code is indeterministic and the code below might potentially work on your machine and that&#8217;s exactly why it is hard to demonstrate. Race conditions depend on many things, but in this case I will focus on race conditions affecting basic data structures since it might be the most surprising.</p>
<h2>Example:</h2>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">@<span style="color:#CC0066; font-weight:bold;">array</span>, threads = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>, <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
<span style="color:#006666;">4</span>.<span style="color:#9900CC;">times</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  threads <span style="color:#006600; font-weight:bold;">&amp;</span>lt;<span style="color:#006600; font-weight:bold;">&amp;</span>lt; <span style="color:#CC00FF; font-weight:bold;">Thread</span>.<span style="color:#9900CC;">new</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span>..<span style="color:#006666;">100</span>_000<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>n<span style="color:#006600; font-weight:bold;">|</span> @<span style="color:#CC0066; font-weight:bold;">array</span> <span style="color:#006600; font-weight:bold;">&amp;</span>lt;<span style="color:#006600; font-weight:bold;">&amp;</span>lt; n<span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
threads.<span style="color:#9900CC;">each</span><span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>t<span style="color:#006600; font-weight:bold;">|</span> t.<span style="color:#9900CC;">join</span> <span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#CC0066; font-weight:bold;">puts</span> @<span style="color:#CC0066; font-weight:bold;">array</span>.<span style="color:#9900CC;">size</span></pre></div></div>

<p>In the above example, I&#8217;m creating an instance variable of Array type and I start 4 threads. Each of these threads adds 100,000 items to the array. We then wait for all the threads to be done and check the size of the array.</p>
<p>If you run this code in C Ruby the end result will be as expected:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#006666;">400000</span></pre></div></div>

<p>Now if you switch to JRuby you might be surprised by the output. If you are lucky you will see the following:</p>
<pre>ConcurrencyError: Detected invalid array contents due to unsynchronized modifications with concurrent users
        &lt;&lt; at org/jruby/RubyArray.java:1147
  __file__ at demo.rb:3
      each at org/jruby/RubyRange.java:407
  __file__ at demo.rb:3
      call at org/jruby/RubyProc.java:274
      call at org/jruby/RubyProc.java:233</pre>
<p>This is actually a good thing. JRuby detects that you are unsafely modifying an instance variable across threads and that data corruption will occur. However, the exception doesn&#8217;t always get raised and you will potentially see results such as:</p>
<pre>335467
342397
341080</pre>
<p>This is a sign that the data was corrupted but that JRuby didn&#8217;t catch the unsynchronized modification. On the other hand MacRuby and Rubinius 2 (dev) won&#8217;t raise any exceptions and will just corrupt the data, outputting something like:</p>
<pre>294278
285755
280704
279865</pre>
<p>In other words, if not manually synchronized, shared data can easily be corrupted. You might have two threads modifying the value of the same variable and one of the two threads will step on top of the other leaving you with a race condition. You only need 2 threads accessing the same instance variable at the same time to get a race condition. My example uses more threads and more mutations to make the problem more obvious. Note that TDD wouldn&#8217;t catch such an issue and even extensive testing will provide very little guarantee that your code is thread safe.</p>
<p>&nbsp;</p>
<h2>So what? Thread safety isn&#8217;t a new problem.</h2>
<p>That&#8217;s absolutely correct, ask any decent Java developer out there, he/she will tell how locks are used to &#8220;easily&#8221; synchronize objects to make your code thread safe. They might also mention the deadlocks and other issues related to that, but that&#8217;s a different story. One might also argue that when you write web apps, there is very little shared data and the chances of corrupting data across concurrent requests is very small since most of the data is kept in a shared data store outside of the process.</p>
<p>All these arguments are absolutely valid, the challenge is that you have a large community and a large amount of code out there that expects a certain behavior. And removing the GIL does change this behavior. It might not be a big deal for you because you know how to deal with thread safety, but it might be a big deal for others and C Ruby is by far the most used Ruby implementation. It&#8217;s basically like saying that automatic cars shouldn&#8217;t be made and sold, and everybody has to switch to stick shifts. They have better gas mileage, I personally enjoy driving then and they are cheaper to build. Removing the GIL is a bit like that. There is a cost associated with this decision and while this cost isn&#8217;t insane, the people in charge prefer to not pay it.</p>
<p>&nbsp;</p>
<h2>Screw that, I&#8217;ll switch to Node.js</h2>
<p>I heard a lot of people telling me they were looking into using Node.js because it has a better design and no GIL. While I like Node.js and if I were to implement a chat room or an app keeping connections for a long time, I would certainly compare it closely to EventMachine, I also think that this argument related to the GIL is absurd. First, you have other Ruby implementations which don&#8217;t have a GIL and are really stable (i.e: JRuby) but then Node basically works the same as Ruby with a GIL. Yes, Node is evented and single threaded but when you think about it, it behaves the same as Ruby 1.9 with its GIL. Many requests come in and they are handled one after the other and because IO requests are non-blocking, multiple requests can be processed concurrently but not in parallel. Well folks, that&#8217;s exactly how C Ruby works too, and unlike popular believe, most if not all the popular libraries making IO requests are non blocking (when using 1.9). So, next time you try to justify you wanting to toy with Node, please don&#8217;t use the GIL argument.</p>
<p>&nbsp;</p>
<h2>What should I do?</h2>
<p>As always, evaluate your needs and see what makes sense for your project. Start by making sure you are using Ruby 1.9 and your code makes good use of threading. Then look at your app and how it behaves, is it CPU-bound or IO-bound. Most web apps out there are IO-bound (waiting for the DB, redis or API calls), and when doing an IO call, Ruby&#8217;s GIL is released allowing another thread to do its work. In that case, not having a GIL in your Ruby implementation won&#8217;t help you. However, if your app is CPU-bound, then switching to JRuby or Rubinius might be beneficial. However, don&#8217;t assume anything until you proved it and remember that making such a change will more than likely require some architectural redesign, especially if using JRuby.  But, hey, it might totally be worth it as many proved it in the past.</p>
<p>&nbsp;</p>
<p>I hope I was able to clarify things a bit further. If you wish to dig further, I would highly recommend you read the many discussions the Python community had in the last few years.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2011/10/18/data-safety-and-gil-removal/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>About concurrency and the GIL</title>
		<link>http://merbist.com/2011/10/03/about-concurrency-and-the-gil/</link>
		<comments>http://merbist.com/2011/10/03/about-concurrency-and-the-gil/#comments</comments>
		<pubDate>Tue, 04 Oct 2011 05:23:54 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[ruby]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[fibers]]></category>
		<category><![CDATA[gil]]></category>
		<category><![CDATA[jruby]]></category>
		<category><![CDATA[macruby]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[rubinius]]></category>
		<category><![CDATA[rubyconf]]></category>
		<category><![CDATA[threads]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=1146</guid>
		<description><![CDATA[During RubyConf 2011, concurrency was a really hot topic. This is not a new issue, and the JRuby team has been talking about true concurrency for quite a while . The Global Interpreter Lock has also been in a subject a lot of discussions in the Python community and it&#8217;s not surprising that the Ruby [...]]]></description>
			<content:encoded><![CDATA[<p>During RubyConf 2011, concurrency was a really hot topic. This is not a new issue, and the JRuby team has been talking about true concurrency for quite a while . The Global Interpreter Lock has also been in a subject a<a href="http://wiki.python.org/moin/GlobalInterpreterLock" target="_blank"> lot of discussions in the Python community</a> and it&#8217;s not surprising that the Ruby community experiences the same debates since the evolution of their implementations are somewhat similar. (There might also be some tension between <a href="http://engineyard.com" target="_blank">EngineYard</a> hiring the JRuby and Rubinius teams and <a href="http://heroku.com" target="_blank">Heroku</a> which <a href="http://blog.heroku.com/archives/2011/7/12/matz_joins_heroku/" target="_blank">recently hired Matz</a> (Ruby&#8217;s creator) and <a href="https://github.com/nobu" target="_blank">Nobu</a>, the #1 C Ruby contributor)</p>
<p>The GIL was probably even more of a hot topic now that <a href="http://rubini.us/" target="_blank">Rubinius</a> is about the join <a href="http://jruby.org" target="_blank">JRuby</a> and <a href="http://macruby.org" target="_blank">MacRuby</a> in the realm of GIL-less Ruby implementations.</p>
<p>During my RubyConf talk (<a href="http://rubyconf11.merbist.com/">slides here</a>), I tried to explain how C Ruby works and why some decisions like having a GIL were made and why the Ruby core team isn&#8217;t planning on removing this GIL anytime soon. The GIL is something a lot of Rubyists love to hate, but a lot of people don&#8217;t seem to question why it&#8217;s here and why Matz doesn&#8217;t want to remove it. Defending the C Ruby decision isn&#8217;t quite easy for me since I spend my free time working on an alternative Ruby implementation which doesn&#8217;t use a GIL (MacRuby). However, I think it&#8217;s important that people understand why the MRI team (C Ruby team) and some Pythonistas feels so strongly about the GIL.</p>
<p><strong>What is the GIL?</strong></p>
<p>Here is a quote from the <a href="http://wiki.python.org/moin/GlobalInterpreterLock" target="_blank">Python wiki</a>:</p>
<blockquote><p>In CPython, the <strong>global interpreter lock</strong>, or <strong>GIL</strong>, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython&#8217;s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.) [...] The GIL is controversial because it prevents multithreaded CPython programs from taking full advantage of multiprocessor systems in certain situations. Note that potentially blocking or long-running operations, such as I/O, image processing, and <a href="http://wiki.python.org/moin/NumPy">NumPy</a> number crunching, happen <em>outside</em> the GIL. Therefore it is only in multithreaded programs that spend a lot of time inside the GIL, interpreting CPython bytecode, that the GIL becomes a bottleneck.</p></blockquote>
<p>The same basically applies to C Ruby. To illustrate the quote above, here is a diagram representing two threads being executed by C Ruby:</p>
<p style="text-align: center;"><a href="http://rubyconf11.merbist.com/#44"><img class="aligncenter" title="Ruby fair thread scheduling" src="http://rubyconf11.merbist.com/images/thread_scheduling.023.jpg" alt="Fair thread scheduling in Ruby by Matt Aimonetti" width="614" height="461" /></a></p>
<p>Such a scheduling isn&#8217;t a problem at all when you only have 1 cpu, since a cpu can only execute a piece of code at a time and context switching happens all the time to allow the machine to run multiple processes/threads in parallel. The problem is when you have more than 1 CPU because in that case, if you were to only run 1 Ruby process, then you would most of the time only use 1 cpu at a time. If you are running on a 8 cpu box, that&#8217;s not cool at all! A lot of people stop at this explanation and imagine that their server can only handle one request at a time and they they rush to sign Greenpeace petitions asking Matz to make Ruby greener by optimizing Ruby and saving CPU cycles. Well, the reality is slightly different, I&#8217;ll get back to that in a minute. Before I explain &#8220;ways to achieve true concurrency with CRuby, let me explain why C Ruby uses a GIL and why each implementation has to make an important choice and in this case both CPython and C Ruby chose to keep their GIL.</p>
<p>&nbsp;</p>
<h3>Why a GIL in the first place?</h3>
<ul>
<li>It makes developer&#8217;s lives easier (it&#8217;s harder to corrupt data)</li>
<li>It avoids race conditions within C extensions</li>
<li>It makes C extensions development easier (no write barriers..)</li>
<li>Most of the C libraries which are wrapped are not thread safe</li>
<li>Parts of Ruby&#8217;s implementation aren&#8217;t threadsafe (Hash for instance)</li>
</ul>
<div>As you can see the arguments can be organized in two main categories: data safety and C extensions/implementation. An implementation which doesn&#8217;t rely too much on C extensions (because they run a bit slow, or because code written in a different language is preferred) is only faced with one argument: data safety.</div>
<p>&nbsp;</p>
<h3></h3>
<h3>Should C Ruby remove its GIL?</h3>
<ul>
<li>No: it potentially makes Ruby code unsafe(r)</li>
<li>No: it would break existing C extensions</li>
<li>No: it would make writing C extensions harder</li>
<li>No: it&#8217;s a lot of work to change make C Ruby threadsafe</li>
<li>No: Ruby is fast enough in most cases</li>
<li>No: Memory optimization and GC is more important to tackle first</li>
<li>No: C Ruby code would run slower</li>
<li>Yes: we really need better/real concurrency</li>
<li>Yes: <a href="https://plus.google.com/107994348420168435683/posts/993U42yVbfk" target="_blank">Rubber boots analogy (Gustavo Niemeyer)</a></li>
</ul>
<div>Don&#8217;t count the amount of pros/cons to jump to the conclusion that removing the GIL is a bad idea. A lot of the arguments for removing the GIL are related. At the end of the day it boils down to data safety. During the Q&amp;A section of my RubyConf talk, Matz came up on stage and said data safety was the main reason why C Ruby still has a GIL. Again, this is a topic which was discussed at length in the Python community and I&#8217;d encourage you to read arguments from the <a href="http://www.jython.org/" target="_blank">Jython</a> (the equivalent of JRuby for Python) developers, <a href="http://codespeak.net/pypy/dist/pypy/doc/faq.html#does-pypy-have-a-gil-why" target="_blank">the PyPy</a> (the equivalent of Rubinius in the Python community) and CPython developers. (a good collection of arguments are actually available in the comments related to the <a href="https://plus.google.com/107994348420168435683/posts/993U42yVbfk" target="_blank">rubber boots post mentioned earlier</a>)</div>
<p>&nbsp;</p>
<h3>How can true concurrency be achieved using CRuby?</h3>
<div>
<ul>
<li>Run multiple processes (which you probably do if you use Thin, Unicorn or Passenger)</li>
<li>Use event-driven programming with a process per CPU</li>
<li>MultiVMs in a process. Koichi presented his plan to run multiple VMs within a process.  Each VM would have its own GIL and inter VM communication would be faster than inter process. This approach would solve most of the concurrency issues but at the cost of memory.</li>
</ul>
<div>Note:  forking a process only saves memory when using REE since it implements a GC patch that makes the forking process Copy on Write friendly. The Ruby core team worked on a patch for Ruby 1.9 to achieve the same result. <a href="http://twitter.com/#!/nari_en" target="_blank">Nari</a> &amp; <a href="http://twitter.com/#!/yukihiro_matz" target="_blank">Matz</a> are currently working on improving the implementation to make sure overall performance isn&#8217;t affected.</div>
</div>
<p>Finally, when developing web applications, each thread spend quite a lot of time in IOs which, as mentioned above won&#8217;t block the thread scheduler. So if you receive two quasi-concurrent requests you might not even be affected by the GIL as illustrated in <a href="http://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/" target="_blank">this diagram from Yehuda Katz</a>:</p>
<p><img class="aligncenter" title="rails threads" src="http://yehudakatz.com/wp-content/uploads/2010/08/Untitled.002.png" alt="" width="768" height="432" /></p>
<p>This is a simplified diagram but you can see that a good chunk of the request life cycle in a Ruby app doesn&#8217;t require the Ruby thread to be active (CPU Idle blocks) and therefore these 2 requests would be processed almost concurrently.</p>
<div>
<p>To boil it down to something simplified, when it comes to the GIL, an implementor has to chose between data safety and memory usage. But it is important to note that context switching between threads is faster than context switching between processes and data safety can and is often achieved in environments without a GIL, but it requires more knowledge and work on the developer side.</p>
<p>&nbsp;</p>
<h3>Conclusion</h3>
<div>The decision to keep or remove the GIL is a bit less simple that it is often described. I respect Matz&#8217; decision to keep the GIL even though, I would personally prefer to push the data safety responsibility to the developers. However, I do know that many Ruby developers would end up shooting themselves in the foot and I understand that Matz prefers to avoid that and work on other ways to achieve true concurrency without removing the GIL. What is great with our ecosystem is that we have some diversity, and if you think that a GIL less model is what you need, we have some great alternative implementations that will let you make this choice. I hope that this article will help some Ruby developers understand and appreciate C Ruby&#8217;s decision and what this decision means to them on a daily basis.</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2011/10/03/about-concurrency-and-the-gil/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Hey Apple, please be nice and share</title>
		<link>http://merbist.com/2011/03/07/hey-apple-please-be-nice-and-share/</link>
		<comments>http://merbist.com/2011/03/07/hey-apple-please-be-nice-and-share/#comments</comments>
		<pubDate>Mon, 07 Mar 2011 17:00:56 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=996</guid>
		<description><![CDATA[My name is Matt Aimonetti, and in my free time I work on Apple&#8217;s open source Ruby implementation named MacRuby. I&#8217;m also the author of O&#8217;Reilly&#8217;s MacRuby book. As you can imagine, I&#8217;m very thankful that Apple initiated the MacRuby project a few years ago and have been an avid supporter. MacRuby is awesome to [...]]]></description>
			<content:encoded><![CDATA[<p>My name is Matt Aimonetti, and in my free time I work on Apple&#8217;s open source <a href="http://www.ruby-lang.org" target="_blank">Ruby</a> implementation named <a href="http://macruby.org" target="_blank">MacRuby</a>. I&#8217;m also the author of <a href="http://oreilly.com/catalog/0636920000723" target="_blank">O&#8217;Reilly&#8217;s MacRuby book</a>. As you can imagine, I&#8217;m very thankful that Apple initiated the MacRuby project a few years ago and have been an avid supporter. MacRuby is awesome to develop OS X native applications using the Ruby language and even allows you to compile down your apps to machine code. It&#8217;s a great alternative to Objective-C.</p>
<p><a href="http://www.apple.com/macosx/lion/"><img class="aligncenter" title="Lion" src="https://img.skitch.com/20111012-kyiy9nhx5n9h9wafucyh8p3knx.jpg" alt=""/></a></p>
<p>MacRuby is so awesome that Apple is even <a href="http://twitter.com/GeorgeBellos/status/41595085179203584" target="_blank">using it in its upcoming OS</a>. The only problem is that Apple apparently decided to not share MacRuby with other OS X developers and put <a href="http://yfrog.com/h8hhlydj" target="_blank">MacRuby in the OS private frameworks</a>. While this doesn&#8217;t affect the project itself, it does affect OS X developers like myself who can&#8217;t link to <a href="http://www.apple.com/macosx/lion/" target="_blank">Lion</a>&#8216;s private MacRuby framework and are forced to embed MacRuby with their applications.</p>
<p>That&#8217;s why I have opened a <a href="http://bugreporter.apple.com/" target="_blank">ticket on Apple radar system</a> to ask that MacRuby be made a public framework.</p>
<p>If you also want Apple to make this change, <a href="http://bugreporter.apple.com/" target="_blank">please take a minute and let them know</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2011/03/07/hey-apple-please-be-nice-and-share/feed/</wfw:commentRss>
		<slash:comments>49</slash:comments>
		</item>
		<item>
		<title>Automatically generating BridgeSupport files</title>
		<link>http://merbist.com/2011/02/19/bridgesupport-build/</link>
		<comments>http://merbist.com/2011/02/19/bridgesupport-build/#comments</comments>
		<pubDate>Sun, 20 Feb 2011 00:29:07 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>
		<category><![CDATA[BridgeSupport]]></category>
		<category><![CDATA[objective-c]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=974</guid>
		<description><![CDATA[Today I was helping someone write an Objective-C framework around cocos2d. C/Objective-C code can be called directly from MacRuby. However the Obj-C code you would like to use might be using some ANSI C symbols that are non-object-oriented items such as constants, enumerations, structures, and functions. To make these items available to our MacRuby code, [...]]]></description>
			<content:encoded><![CDATA[<p>Today I was helping someone write an Objective-C framework around <a href="http://cocos2d.org/">cocos2d</a>.</p>
<p>C/Objective-C code can be called directly from MacRuby. However the Obj-C code you would like to use might be using some ANSI C symbols that are non-object-oriented items such as constants, enumerations, structures, and functions. To make these items available to our MacRuby code, you need to generate a <a href="http://ofps.oreilly.com/titles/9781449380373/ch03.html#_using_objective_c_or_c_code" target="_blank">BridgeSupport file as explained in this section of my book</a>.</p>
<p>In our case, we were working on the framework and I didn&#8217;t feel like manually having to regenerate the BridgeSupport file every single time I would compile our code. So instead I added a new build phase in our target.</p>
<p style="text-align: center;">
<div class="wp-caption aligncenter" style="width: 751px"><a href="https://img.skitch.com/20110220-b685ag2cef8qm69uwn73e3equ4.png"><img class=" " title="Xcode3-MacRuby-framework" src="https://img.skitch.com/20110220-b685ag2cef8qm69uwn73e3equ4.png" alt="" width="741" height="407" /></a><p class="wp-caption-text">Adding a new step to our build</p></div>
<p>And I added the following script to run at the end of the build:</p>
<p><code><br />
# This step generated the bridgesupport file for the framework<br />
PATH="$PATH:/usr/local/bin"<br />
mkdir -p $TARGET_BUILD_DIR/$PROJECT_NAME.framework/Resources/BridgeSupport/<br />
gen_bridge_metadata --64-bit -f $TARGET_BUILD_DIR/$PROJECT_NAME.framework/ -o $TARGET_BUILD_DIR/$PROJECT_NAME.framework/Resources/BridgeSupport/$PROJECT_NAME.bridgesupport<br />
</code></p>
<p>Th<code>e script just executes the steps required to add the BridgeSupport file to your framework. I can now rebuild my framework without having to worry about BridgeSupport.<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2011/02/19/bridgesupport-build/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MacRuby book update</title>
		<link>http://merbist.com/2011/01/15/macruby-book-update/</link>
		<comments>http://merbist.com/2011/01/15/macruby-book-update/#comments</comments>
		<pubDate>Sat, 15 Jan 2011 19:48:05 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>
		<category><![CDATA[book]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=839</guid>
		<description><![CDATA[I just pushed a major update to my MacRuby book. If you already purchased  an electronic copy (thank you!), go to your product page and download an update. Note that if you are on an iPhone or iPad and you click on the .epub link, the file will automatically load in iBooks, same thing if [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://oreilly.com/catalog/0636920000723/"><img class="alignleft" title="Cover of the MacRuby Book" src="http://covers.oreilly.com/images/0636920000723/rc_cat.gif" alt="" width="180" height="236" /></a> I just pushed a major update to my <a href="http://oreilly.com/catalog/0636920000723/">MacRuby book</a>.</p>
<p>If you already purchased  an electronic copy (thank you!), go to <a href="https://members.oreilly.com/account/emedia/index" target="_blank">your product page</a> and download an update. Note that if you are on an iPhone or iPad and you click on the .epub link, the file will automatically load in iBooks, same thing if you have the kindle app installed and you are clicking on the .mobi file.</p>
<p>If you haven&#8217;t purchased an electronic version yet, you can still read the book in HTML format <a href="http://ofps.oreilly.com/titles/9781449380373/" target="_blank">here</a>. If you choose to do so, please still think about leaving a review on the <a href="http://oreilly.com/catalog/9781449302054/" target="_blank">O&#8217;Reilly site</a> to<span style="text-decoration: underline;"> show your support to myself and to my publisher</span>.
<div><br/<br/></div>
<h2>What&#8217;s new in this update?</h2>
<p><div class="wp-caption aligncenter" style="width: 388px"><a href="https://github.com/mattetti/MacRuby--The-Definitive-Guide/tree/master/chapter_2"><img src="https://img.skitch.com/20101217-gsx1f85swynag75eq9auid6u83.preview.jpg" alt="" width="378" height="358" /></a><p class="wp-caption-text">App built in chapter 2</p></div><br />
</br></p>
<ol>
<li>I refactored the introduction to the book, you know have a <span style="text-decoration: underline;">new Chapter 2</span> which introduces you to <span style="text-decoration: underline;">GUI app development</span> and lets you build a full app right away to give you an idea of what is available.</li>
<li>Chapter 3 <span style="text-decoration: underline;">covers more advanced concepts</span> and was updated to <span style="text-decoration: underline;">reflect changes made on trunk</span>.</li>
<li>The <span style="text-decoration: underline;">chapter on Core Data</span> is now almost done, I will soon push an update with the end of the chapter, but between the chapter content and the example app, you should be good to go today.</li>
<li><a href="https://github.com/mattetti/MacRuby--The-Definitive-Guide/" target="_blank">GitHub repo</a> with the code used in the book. (work in progress, I need to move more code there)</li>
<li>The book is now divided in two parts, one more theoretical and more practical. Even if part 2 isn&#8217;t written yet, the table of contents shows some of the examples I will cover. I hope to have some of these chapters written in a few weeks.</li>
<li><span style="text-decoration: underline;">Lots of small fixes and updates</span> thanks to the readers comments and to my editor.</li>
</ol>
<p><br/><br />
<div class="wp-caption aligncenter" style="width: 388px"><a href="https://github.com/mattetti/MacRuby--The-Definitive-Guide/tree/master/chapter_7"><img title="core data macruby example" src="https://img.skitch.com/20110110-c6q3dxf8dqb1xj9xk26s1ifxi7.preview.jpg" alt="" width="378" height="283" /></a><p class="wp-caption-text">App built in the Core Data chapter</p></div><br />
<br/></p>
<p>Finally if you are interested in pre-ordering the book, Amazon runs a great deal on the book:</p>
<div class="aligncenter" style="text-align:center">
<a href="https://www.amazon.com/dp/1449380379?tag=merbist-20&#038;camp=213381&#038;creative=390973&#038;linkCode=as4&#038;creativeASIN=1449380379&#038;adid=0WJ1SC6VAJ1Q2KMWQSMK&#038;"><img src="https://img.skitch.com/20110115-jb6uc1635g21bb4eti3pt66wwd.png"/></a>
</div>
<p>Thank you for your support!</p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2011/01/15/macruby-book-update/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Writing an open licensed book</title>
		<link>http://merbist.com/2010/05/09/writing-an-open-licensed-book/</link>
		<comments>http://merbist.com/2010/05/09/writing-an-open-licensed-book/#comments</comments>
		<pubDate>Mon, 10 May 2010 06:40:06 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[O'Reilly]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=767</guid>
		<description><![CDATA[To celebrate last week&#8217;s release of MacRuby 0.6, O&#8217;Reilly and I started publishing the draft of my MacRuby book online: http://macruby.labs.oreilly.com/ I started thinking about working on &#8220;MacRuby: The Definitive Guide&#8221; last year when I realized that the project had a great future but there was a serious lack of documentation. With the support of [...]]]></description>
			<content:encoded><![CDATA[<p>To celebrate last week&#8217;s release of <a href="http://www.macruby.org/blog/2010/04/30/macruby06.html">MacRuby 0.6</a>, O&#8217;Reilly and I started publishing the draft of my MacRuby book online: <a title="MacRuby Book" href="http://macruby.labs.oreilly.com/" target="_blank">http://macruby.labs.oreilly.com/</a></p>
<p>I started thinking about working on &#8220;<a href="http://macruby.labs.oreilly.com/" target="_blank">MacRuby: The Definitive Guide</a>&#8221; last year when I realized that the project had a great future but there was a serious lack of documentation. With the support of the MacRuby team, I worked on a table of contents and a pitch. The next step was to decide what we wanted to do with the book.</p>
<p>I know a lot of technical book authors and most of them will tell you the same thing: if you think that you are going to make money writing a book, you are wrong. Even if your book sells well, because of the time invested in writing the book, you are probably better off doing consulting work and charging by the hour.</p>
<p>So since day one, I knew that this project would not make me rich. The goal was to share knowledge not to reimburse my mortgage or save California from bankruptcy. While publishing a web book is great, distribution is quite limited, especially if you try to reach people outside of your network. That&#8217;s why I decided to start talking to a few publishers. Most publishers I talked to were interested in working on the book, however they were not really keen on publishing a <a href="http://creativecommons.org/licenses/by-nc-nd/3.0/us/" target="_top">Creative Commons Attribution-Noncommercial-No Derivative</a> licensed book.</p>
<p>Let me explain why I think releasing technical books under a CC license is important. As you might know (or have figured out by now), I am not a native English speaker. I actually learned my first English words thanks to the computer my dad had at home. The problem when you don&#8217;t live in an English speaking country and you want to learn about the cutting edge technology is that you have to understand English.  Thanks to the Internet, learning and practicing English is now much easier that it used to be. However, if you want to have access to books, most of the time you have to wait until someone translates the book and publishes it in your country or you have to manage to get an English version delivered to your country. This is often a pain because of national credit card limitations, international delivery restrictions etc&#8230; If you manage to find a way to get a copy, the book ends up costing a lot of money.</p>
<p>What does that mean in practice? Most of the technical books are first available in the English speaking western world, then slowly translated and/or distributed around the world. By the time you get a legal copy in Bolivia, Algeria or Vietnam, a new edition is probably out in the US probably because the technology evolved. Maybe that explains some of the book piracy worldwide?</p>
<p>Think about it for a minute: knowledge is power and time is money. And what do we do? We delay knowledge distribution. This is why I am a big fan of the <a href="http://khanacademy.org/" target="_blank">Khan Academy</a> and its awesome free online courses.</p>
<p>Turns out <a href="http://oreilly.com/" target="_blank">O&#8217;Reilly</a> shares my vision and has already published a lot of books under various open licenses: <a href="http://oreilly.com/openbook/" target="_blank">http://oreilly.com/openbook/</a> I was also interested in publishing the content of my book ASAP so people could access it right away even though there would be lots of typos and missing content. This is also something O&#8217;Reilly has already done with the <a href="http://books.couchdb.org/relax/" target="_blank">CouchDB</a> and the <a href="http://labs.oreilly.com/ofps.html" target="_blank">Scala</a> books.</p>
<p>Talking with <a href="http://twitter.com/janl" target="_blank">Jan Lehnardt</a> about his experience working with O&#8217;Reilly on the <a href="http://books.couchdb.org/relax/" target="_blank">&#8216;CouchDB: The definitive guide&#8217;</a> book, I realized that we seem to have some shared interests. I contacted Jan&#8217;s editor and we decided to start working on the MacRuby book. The book will be available later on in all the usual commercial formats and I hope people will show their support so O&#8217;Reilly will be encouraged in their choice to continue publishing CC licensed book. At the end of the day, purchasing a CC licensed book helps supporting the authors, the publishers but also all the people who can&#8217;t have access to the latest technical books.</p>
<p>Finally, working on a book is not an easy thing, especially when you have to write it in a language that&#8217;s not yours. But I have to say that the community support has been amazing. Even <a href="http://daringfireball.net/linked/2010/05/03/macruby-aimonetti" target="_blank">John Gruber sent a fireball my way</a>. And since the announcement was made, I have received a lot of <a href="http://macruby.labs.oreilly.com/comments/feed?id=book" target="_blank">comments</a>, tweets, emails etc&#8230; It is very encouraging and it gives me the motivation needed to work on the book after a long work day.</p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2010/05/09/writing-an-open-licensed-book/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Undo/Redo in MacRuby</title>
		<link>http://merbist.com/2010/02/02/undoredo-in-macruby/</link>
		<comments>http://merbist.com/2010/02/02/undoredo-in-macruby/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 10:19:44 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>
		<category><![CDATA[foundation]]></category>
		<category><![CDATA[NSUndoManager]]></category>
		<category><![CDATA[redo]]></category>
		<category><![CDATA[undo]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=719</guid>
		<description><![CDATA[As I&#8217;m working on my upcoming O&#8217;Reilly MacRuby book, I&#8217;m writing quite a lot of example code. I have spent the last few weeks digging through most of the Foundation framework classes to hopefully make Cocoa more accessible to Ruby developers. In some instances things might look quite weird to someone new to Cocoa in [...]]]></description>
			<content:encoded><![CDATA[<p>As I&#8217;m working on my upcoming O&#8217;Reilly MacRuby book, I&#8217;m writing quite a lot of example code. I have spent the last few weeks digging through most of the Foundation framework classes to hopefully make Cocoa more accessible to Ruby developers.</p>
<p>In some instances things might look quite weird to someone new to Cocoa in some cases, things seem almost too easy. Here is an example implementing a undo/redo functionality using Foundations&#8217; <em><a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSUndoManager_Class/Reference/Reference.html">NSUndoManager</a></em>.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">framework <span style="color:#996600;">'Foundation'</span>
<span style="color:#9966CC; font-weight:bold;">class</span> Player
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:x</span>, <span style="color:#ff3333; font-weight:bold;">:y</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize
    <span style="color:#0066ff; font-weight:bold;">@x</span> = <span style="color:#0066ff; font-weight:bold;">@y</span> = <span style="color:#006666;">0</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> undo_manager
    <span style="color:#0066ff; font-weight:bold;">@manager</span> <span style="color:#006600; font-weight:bold;">||</span>= NSUndoManager.<span style="color:#9900CC;">alloc</span>.<span style="color:#9900CC;">init</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> left
    undo_manager.<span style="color:#9900CC;">prepareWithInvocationTarget</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">self</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">right</span>
    <span style="color:#0066ff; font-weight:bold;">@x</span> <span style="color:#006600; font-weight:bold;">-</span>= <span style="color:#006666;">1</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> right
    undo_manager.<span style="color:#9900CC;">prepareWithInvocationTarget</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">self</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">left</span>
    <span style="color:#0066ff; font-weight:bold;">@x</span> <span style="color:#006600; font-weight:bold;">+</span>= <span style="color:#006666;">1</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Which you can use as such:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">&nbsp;
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara = Player.<span style="color:#9900CC;">new</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&lt;</span>Player:0x200267c80 <span style="color:#0066ff; font-weight:bold;">@y</span>=<span style="color:#006666;">0</span> <span style="color:#0066ff; font-weight:bold;">@x</span>=<span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&gt;</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">undo_manager</span>.<span style="color:#9900CC;">canUndo</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span> <span style="color:#008000; font-style:italic;"># normal since we did not do anything yet</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">left</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">1</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">x</span> <span style="color:#008000; font-style:italic;"># -1</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">1</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">undo_manager</span>.<span style="color:#9900CC;">canUndo</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#008000; font-style:italic;"># now we can undo, so let's try</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">undo_manager</span>.<span style="color:#9900CC;">undo</span> <span style="color:#008000; font-style:italic;"># undo back to initial position</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&lt;NSUndoManager:0x200257560&gt;</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">x</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">0</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">undo_manager</span>.<span style="color:#9900CC;">canUndo</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span> <span style="color:#008000; font-style:italic;"># we can't anymore which makes sense </span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">undo_manager</span>.<span style="color:#9900CC;">canRedo</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#008000; font-style:italic;"># however we can redo what we just undone</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">undo_manager</span>.<span style="color:#9966CC; font-weight:bold;">redo</span> <span style="color:#008000; font-style:italic;"># redo to before we called undo</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#008000; font-style:italic;">#&lt;NSUndoManager:0x200257560&gt;</span>
<span style="color:#006600; font-weight:bold;">&gt;&gt;</span> lara.<span style="color:#9900CC;">x</span>
<span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">1</span></pre></div></div>

<p>The above example was tested in macirb but as you can see, actions can be undone and redone very very easily. This is just a quick preview of what you can do using Ruby + Cocoa and hopefully it will give you some cool ideas to implement.</p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2010/02/02/undoredo-in-macruby/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>How to detect Cylons with MacRuby</title>
		<link>http://merbist.com/2010/01/18/how-to-detect-cylons-with-macruby/</link>
		<comments>http://merbist.com/2010/01/18/how-to-detect-cylons-with-macruby/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 00:13:37 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>
		<category><![CDATA[cylon technology]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=696</guid>
		<description><![CDATA[Over the weekend, MacRuby&#8217;s trunk became version 0.6 and the bug fixing is currently done in both the 0.5 branch and trunk. Based on MacRuby&#8217;s usual release cycle I would expect a 0.5 beta3 or 0.5 final to be released soon so most of the work can be focused on trunk. I&#8217;ll let you check [...]]]></description>
			<content:encoded><![CDATA[<p>Over the weekend, MacRuby&#8217;s trunk became version 0.6 and the bug fixing is currently done in both the 0.5 branch and trunk. Based on MacRuby&#8217;s usual release cycle I would expect a 0.5 beta3 or 0.5 final to be released soon so most of the work can be focused on trunk.</p>
<p>I&#8217;ll let you check on the <a title="MacRuby's TODO list" href="http://svn.macosforge.org/repository/ruby/MacRuby/trunk/TODO" target="_blank">TODO list</a> to see what was done in 0.5 and what is in the plan for 0.6.</p>
<p>However, there is one feature in 0.6 that I know lots of you will just love! The good news is that Laurent already committed a very early version of his work so I figured, I should share the good news with you:</p>
<h3>Introducing MacRuby&#8217;s debugger!</h3>
<p>If you were expecting to read: &#8220;a Cylon detector!&#8221;, keep on reading.</p>
<p>Again, this feature is in really early development since it&#8217;s scheduled for 0.6 and 0.5 final is not out yet. But if you install MacRuby using the <a href="http://macruby.icoretech.org/" target="_blank">nightly builds</a> or build from trunk, you can already play with the debugger.</p>
<p>Let me give you a really quick tour of the debugger.<br/></p>
<p><img src="http://img.skitch.com/20100118-qn7yuq9h2ce61yxt6kwag9pnbt.jpg" alt="BSG75Logo posted by Matt Aimonetti" title="BSG75Logo posted by Matt Aimonetti"/></p>
<p>Let&#8217;s imagine that we were given the task to debug the cylon detector written by Gaius Baltar which looks like that:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">characters = <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">&#123;</span>Adama Apollo Baltar Roslin StarBuck Six<span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">def</span> cylon?<span style="color:#006600; font-weight:bold;">&#40;</span>character<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#0000FF; font-weight:bold;">false</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
characters.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>character<span style="color:#006600; font-weight:bold;">|</span>
  <span style="color:#9966CC; font-weight:bold;">if</span> cylon?<span style="color:#006600; font-weight:bold;">&#40;</span>character<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;#{character} is a Cylon!&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">else</span>
    <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;#{character} is not a cylon.&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Here is what happens when I execute the script:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ macruby cylon_detector.rb 
Adama is not a cylon.
Apollo is not a cylon.
Baltar is not a cylon.
Roslin is not a cylon.
StarBuck is not a cylon.
Six is not a cylon.</pre></div></div>

<p>The only problem is that we all know that Six is a Cylon, the detector isn&#8217;t working right so let&#8217;s debug it:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ macrubyd cylon_detector.rb
Starting program.
cylon_detector.rb:1&gt; b cylon_detector.rb:8 if character == 'Six'
Added breakpoint 1.
cylon_detector.rb:1&gt; c
Adama is not a cylon.
Apollo is not a cylon.
Baltar is not a cylon.
Roslin is not a cylon.
StarBuck is not a cylon.
cylon_detector.rb:8&gt; p cylon?(character)
=&gt; false
cylon_detector.rb:8&gt; p &quot;This detector is broken!&quot;
=&gt; &quot;This detector is broken!&quot;
cylon_detector.rb:8&gt; p def cylon?(character); character == 'Six'; end
=&gt; nil
cylon_detector.rb:8&gt; p cylon?(character)
=&gt; true
cylon_detector.rb:8&gt; p cylon?('Matt')
=&gt; false
cylon_detector.rb:8&gt; c
Six is a Cylon!
Program exited.</pre></div></div>

<p>The first thing we do is to add a conditional breakpoint:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">b cylon_detector.<span style="color:#9900CC;">rb</span>:<span style="color:#006666;">8</span> <span style="color:#9966CC; font-weight:bold;">if</span> character == <span style="color:#996600;">'Six'</span></pre></div></div>

<p>Basically, the debugger will add a breakpoint at line 8 which will only be active when the value of &#8216;character&#8217; is equal to &#8216;Six&#8217;.<br />
Now that the breakpoint added, we can continue the program execution and just wait until we reach the defined condition.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">cylon_detector.<span style="color:#9900CC;">rb</span>:<span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&gt;</span> c</pre></div></div>

<p>Once we reach the breakpoint, we evaluate the result of &#8220;cylon?(character)&#8221; by using the p command. We see that the result is &#8220;false&#8221; when we know for sure that it should be true since the value of the character variable is &#8216;Six&#8217; and she is a cylon. At this point, you might have guessed that somewhat acted as a cylon agent and I pretended to fix the problem by overwriting the &#8220;cylon?&#8221; method:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">cylon_detector.rb:8&gt; p def cylon?(character); character == 'Six'; end</pre></div></div>

<p>Now that the method is overwritten, I can check that Six is recognized as being a cylon:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">cylon_detector.rb:8&gt; p cylon?(character)
=&gt; true</pre></div></div>

<p>and also check that I am not detected a cylon:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">cylon_detector.rb:8&gt; p cylon?('Matt')
=&gt; false</pre></div></div>

<p>I can now continue the execution of the program and see that Six is detected as a Cylon!</p>
</hr>
<p>Of course this is just a very early version of the debugger and we will see lots of improvement in the next few weeks. Who knows someone might even create a GUI for the debugger and/or a Xcode integration. </p>
<p>Anyway, the point being that MacRuby developers should expect a lot of awesome stuff coming up their way soon. (also be careful about the skin jobs around you, cylon detectors can&#8217;t be trusted!)</p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2010/01/18/how-to-detect-cylons-with-macruby/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Controlling iTunes with MacRuby</title>
		<link>http://merbist.com/2010/01/17/controlling-itunes-with-macruby/</link>
		<comments>http://merbist.com/2010/01/17/controlling-itunes-with-macruby/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 03:54:19 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>
		<category><![CDATA[itunes]]></category>
		<category><![CDATA[scriptingbridge]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=684</guid>
		<description><![CDATA[Since Mac OS X v10.5, Apple added a technology called Scripting Bridge which allows to control and communicate with scriptable applications such as Mail, iChat or iTunes. A few weeks back, I showed how to control iChat with MacRuby. This time I&#8217;m going to show you how to control iTunes. Here is a small script [...]]]></description>
			<content:encoded><![CDATA[<p>Since Mac OS X v10.5, Apple added a technology called Scripting Bridge which allows to control and communicate with scriptable applications such as Mail, iChat or iTunes.</p>
<p>A few weeks back, <a href="http://merbist.com/2009/12/31/im-new-year-count-down-with-macruby/" target="_blank">I showed how to control iChat</a> with MacRuby. This time I&#8217;m going to show you how to control iTunes.</p>
<p>Here is a small script that I wrote to wake me up in music every morning.</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#008000; font-style:italic;">#!/usr/local/bin/macruby</span>
framework <span style="color:#996600;">'Foundation'</span>
framework <span style="color:#996600;">'ScriptingBridge'</span>
&nbsp;
itunes = SBApplication.<span style="color:#9900CC;">applicationWithBundleIdentifier</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;com.apple.itunes&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
load_bridge_support_file <span style="color:#996600;">'iTunes.bridgesupport'</span>
itunes.<span style="color:#9900CC;">run</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> SBElementArray
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#40;</span>value<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">objectWithName</span><span style="color:#006600; font-weight:bold;">&#40;</span>value<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
itunes.<span style="color:#9900CC;">stop</span>
playlist = itunes.<span style="color:#9900CC;">sources</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;Library&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">userPlaylists</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;morning&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
playlist.<span style="color:#9900CC;">playOnce</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">false</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">if</span> playlist</pre></div></div>

<p>The idea is that I have a Mac Mini streaming music through speakers connected to an AirportExpress in my bedroom.</p>
<p>Let&#8217;s go through the script quickly.</p>
<p>We start by loading two frameworks, Foundation and ScriptingBridge.<br />
Now that we have ScriptingBridge loaded, we can control iTunes. To do that, we use:<br />
SBApplication.applicationWithBundleIdentifier(&#8220;com.apple.itunes&#8221;)<br />
We then load a bridgesupport file that contains the enumerated constants from the iTunes scriptable dictionary.</p>
<p>We make sure iTunes is running by calling #run on the application object.</p>
<p>Before using iTune scriptable interface, we are making the API a bit nicer, it&#8217;s totally unnecessary but it makes our code look better.</p>
<p>itunes.sources returns an instance of <a href="http://developer.apple.com/mac/library/documentation/cocoa/Reference/SBElementArray_Class/SBElementArray/SBElementArray.html " target="_blank">SBElementArray</a> which is not really an array nor a hash.</p>
<p>The rest of the code is pretty simple, we find the library, find the playlist called &#8216;morning&#8217; and play it if found.</p>
<p>So you might wonder two things:</p>
<ul>
<li>What is the iTunes.bridgesupport file?</li>
<li>How do you know what methods are available to control iTunes?</li>
</ul>
<h4>bridgesupport file</h4>
<p>The bridgesupport file is important since it defines the required constants.<br />
Apple provides a metadata generator called gen_bridge_metadata which generates a bridgesupport file.</p>
<p>Here is what the documentation says:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ man gen_bridge_metadata</pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">NAME
gen_bridge_metadata -- Objective-C Bridges Metadata Generator
&nbsp;
SYNOPSIS
gen_bridge_metadata [options...] headers...
&nbsp;
DESCRIPTION
gen_bridge_metadata is a tool that generates bridging metadata information for a given framework or set of head-
ers. The Objective-C bridges supported in Mac OS X, such as RubyCocoa (Ruby) and PyObjC (Python), read this
information at runtime.
&nbsp;
Metadata files describe the parts of an Objective-C framework that the bridges cannot automatically handle. These
are primarily the ANSI C elements of the framework -- functions, constants, enumerations, and so on -- but also
include special cases such as functions or methods that accept pointer-like arguments. These special cases must
be manually specified in separate files called exceptions. The gen_bridge_metadata tool can then read in the
exceptions file when it generates the framework metadata.
&nbsp;
The file extension used for metadata files should be .bridgesupport.
&nbsp;
Certain elements, such as inline functions, cannot be described in the metadata files. It is therefore required
to generate a dynamic library in order to make the bridges use them. The gen_bridge_metadata tool can take care
of that for you.
&nbsp;
The file extension for the dynamic libraries should be .dylib.
&nbsp;
You should install metadata files in one of three filesystem locations. For example, for a framework named
MyFramework that is installed as /Library/Frameworks/MyFramework.framework, you can install the
MyFramework.bridgesupport and MyFramework.dylib files in one of the following possible locations, in order of
priority:
&nbsp;
o   /Library/Frameworks/MyFramework/Resources/BridgeSupport
&nbsp;
o   /Library/BridgeSupport
&nbsp;
o   ~/Library/BridgeSupport</pre></div></div>

<p>The problem is that we don&#8217;t have a framework or header file to generate a bridgesupport file for.<br />
So, what we need a header file for iTunes, turns out we have a tool to do that:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ sdef /Applications/iTunes.app | sdp -fh --basename iTunes</pre></div></div>

<p>I won&#8217;t go in the details of what sdef and sdp do, just check their manual page.<br />
Running the command above will create a iTunes.h which we can use to create a bridgesupport file.<br />
Here is the generated header file: http://gist.github.com/279657</p>
<p>Now, let&#8217;s create a bidgesupport file:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">$ gen_bridge_metadata -c '-I.' iTunes.h &amp;gt; iTunes.bridgesupport</pre></div></div>

<p>An that&#8217;s how we get the bridgesupport file. (see file: <a href="http://gist.github.com/279698">http://gist.github.com/279698</a>)</p>
<h4>iTunes Documentation</h4>
<p>The easiest way to understand what&#8217;s available to you is to open iTunes&#8217; dictionary in the AppleScript Editor.</p>
<p style="text-align: center;"><img class="aligncenter" title="itunes scriptable API" src="http://img.skitch.com/20100118-fe5c3224jd8xfhciwqxpy4hptc.jpg" alt="iTunes API by Matt Aimonetti" title='iTunes API by Matt Aimonetti' width="511" height="295" /></p>
<p>Otherwise you can study the iTunes.h file.</p>
<p>I wrote a very dumb parser to give you an idea of the methods and properties available when controlling iTunes via ScriptingBridge, here is the  output:</p>

<div class="wp_syntax"><div class="code"><pre class="shell" style="font-family:monospace;">Class: iTunesPrintSettings
Properties:
copies (the number of copies of a document to be printed)
collating (Should printed copies be collated?)
startingPage (the first page of the document to be printed)
endingPage (the last page of the document to be printed)
pagesAcross (number of logical pages laid across a physical page)
pagesDown (number of logical pages laid out down a physical page)
errorHandling (how errors are handled)
requestedPrintTime (the time at which the desktop printer should print the document)
printerFeatures (printer specific options)
faxNumber (for fax number)
targetPrinter (for target printer)
&nbsp;
Method: printPrintDialog:(BOOL)printDialog withProperties:(iTunesPrintSettings *)withProperties kind:(iTunesEKnd)kind theme:(NSString *)theme
Returned: void
Print the specified object(s)
----
Method: close
Returned: void
Close an object
----
Method: delete
Returned: void
Delete an element from an object
----
Method: duplicateTo:(SBObject *)to
Returned: SBObject
Duplicate one or more object(s)
----
Method: exists
Returned: BOOL
Verify if an object exists
----
Method: open
Returned: void
open the specified object(s)
----
Method: playOnce:(BOOL)once
Returned: void
play the current track or the specified track or file.
----
&nbsp;
Class: iTunesApplication
Properties:
currentEncoder (the currently selected encoder (MP3, AIFF, WAV, etc.))
currentEQPreset (the currently selected equalizer preset)
currentPlaylist (the playlist containing the currently targeted track)
currentStreamTitle (the name of the current song in the playing stream (provided by streaming server))
currentStreamURL (the URL of the playing stream or streaming web site (provided by streaming server))
currentTrack (the current targeted track)
currentVisual (the currently selected visual plug-in)
EQEnabled (is the equalizer enabled?)
fixedIndexing (true if all AppleScript track indices should be independent of the play order of the owning playlist.)
frontmost (is iTunes the frontmost application?)
fullScreen (are visuals displayed using the entire screen?)
name (the name of the application)
mute (has the sound output been muted?)
playerPosition (the player’s position within the currently playing track in seconds.)
playerState (is iTunes stopped, paused, or playing?)
selection (the selection visible to the user)
soundVolume (the sound output volume (0 = minimum, 100 = maximum))
version (the version of iTunes)
visualsEnabled (are visuals currently being displayed?)
visualSize (the size of the displayed visual)
&nbsp;
Method: browserWindows
Returned: SBElementArray
----
Method: encoders
Returned: SBElementArray
----
Method: EQPresets
Returned: SBElementArray
----
Method: EQWindows
Returned: SBElementArray
----
Method: playlistWindows
Returned: SBElementArray
----
Method: sources
Returned: SBElementArray
----
Method: visuals
Returned: SBElementArray
----
Method: windows
Returned: SBElementArray
----
Method: printPrintDialog:(BOOL)printDialog withProperties:(iTunesPrintSettings *)withProperties kind:(iTunesEKnd)kind theme:(NSString *)theme
Returned: void
Print the specified object(s)
----
Method: run
Returned: void
run iTunes
----
Method: quit
Returned: void
quit iTunes
----
Method: add:(NSArray *)x to:(SBObject *)to
Returned: iTunesTrack
add one or more files to a playlist
----
Method: backTrack
Returned: void
reposition to beginning of current track or go to previous track if already at start of current track
----
Method: convert:(NSArray *)x
Returned: iTunesTrack
convert one or more files or tracks
----
Method: fastForward
Returned: void
skip forward in a playing track
----
Method: nextTrack
Returned: void
advance to the next track in the current playlist
----
Method: pause
Returned: void
pause playback
----
Method: playOnce:(BOOL)once
Returned: void
play the current track or the specified track or file.
----
Method: playpause
Returned: void
toggle the playing/paused state of the current track
----
Method: previousTrack
Returned: void
return to the previous track in the current playlist
----
Method: resume
Returned: void
disable fast forward/rewind and resume playback, if playing.
----
Method: rewind
Returned: void
skip backwards in a playing track
----
Method: stop
Returned: void
stop playback
----
Method: update
Returned: void
update the specified iPod
----
Method: eject
Returned: void
eject the specified iPod
----
Method: subscribe:(NSString *)x
Returned: void
subscribe to a podcast feed
----
Method: updateAllPodcasts
Returned: void
update all subscribed podcast feeds
----
Method: updatePodcast
Returned: void
update podcast feed
----
Method: openLocation:(NSString *)x
Returned: void
Opens a Music Store or audio stream URL
----
&nbsp;
Class: iTunesItem
Properties:
container (the container of the item)
index (The index of the item in internal application order.)
name (the name of the item)
persistentID (the id of the item as a hexidecimal string. This id does not change over time.)
&nbsp;
Method: id
Returned: NSInteger
the id of the item
----
Method: printPrintDialog:(BOOL)printDialog withProperties:(iTunesPrintSettings *)withProperties kind:(iTunesEKnd)kind theme:(NSString *)theme
Returned: void
Print the specified object(s)
----
Method: close
Returned: void
Close an object
----
Method: delete
Returned: void
Delete an element from an object
----
Method: duplicateTo:(SBObject *)to
Returned: SBObject
Duplicate one or more object(s)
----
Method: exists
Returned: BOOL
Verify if an object exists
----
Method: open
Returned: void
open the specified object(s)
----
Method: playOnce:(BOOL)once
Returned: void
play the current track or the specified track or file.
----
Method: reveal
Returned: void
reveal and select a track or playlist
----
&nbsp;
Class: iTunesPlaylist
Properties:
duration (the total length of all songs (in seconds))
name (the name of the playlist)
parent (folder which contains this playlist (if any))
shuffle (play the songs in this playlist in random order?)
size (the total size of all songs (in bytes))
songRepeat (playback repeat mode)
specialKind (special playlist kind)
time (the length of all songs in MM:SS format)
visible (is this playlist visible in the Source list?)
&nbsp;
Method: tracks
Returned: SBElementArray
----
Method: moveTo:(SBObject *)to
Returned: void
Move playlist(s) to a new location
----
Method: searchFor:(NSString *)for_ only:(iTunesESrA)only
Returned: iTunesTrack
search a playlist for tracks matching the search string. Identical to entering search text in the Search field in iTunes.
----
&nbsp;
Class: iTunesAudioCDPlaylist
Properties:
artist (the artist of the CD)
compilation (is this CD a compilation album?)
composer (the composer of the CD)
discCount (the total number of discs in this CD’s album)
discNumber (the index of this CD disc in the source album)
genre (the genre of the CD)
year (the year the album was recorded/released)
&nbsp;
Method: audioCDTracks
Returned: SBElementArray
----
&nbsp;
Class: iTunesDevicePlaylist
Method: deviceTracks
Returned: SBElementArray
----
&nbsp;
Class: iTunesLibraryPlaylist
Method: fileTracks
Returned: SBElementArray
----
Method: URLTracks
Returned: SBElementArray
----
Method: sharedTracks
Returned: SBElementArray
----
&nbsp;
Class: iTunesRadioTunerPlaylist
Method: URLTracks
Returned: SBElementArray
----
&nbsp;
Class: iTunesSource
Properties:
capacity (the total size of the source if it has a fixed size)
freeSpace (the free space on the source if it has a fixed size)
kind ()
&nbsp;
Method: audioCDPlaylists
Returned: SBElementArray
----
Method: devicePlaylists
Returned: SBElementArray
----
Method: libraryPlaylists
Returned: SBElementArray
----
Method: playlists
Returned: SBElementArray
----
Method: radioTunerPlaylists
Returned: SBElementArray
----
Method: userPlaylists
Returned: SBElementArray
----
Method: update
Returned: void
update the specified iPod
----
Method: eject
Returned: void
eject the specified iPod
----
&nbsp;
Class: iTunesTrack
Properties:
album (the album name of the track)
albumArtist (the album artist of the track)
albumRating (the rating of the album for this track (0 to 100))
albumRatingKind (the rating kind of the album rating for this track)
artist (the artist/source of the track)
bitRate (the bit rate of the track (in kbps))
bookmark (the bookmark time of the track in seconds)
bookmarkable (is the playback position for this track remembered?)
bpm (the tempo of this track in beats per minute)
category (the category of the track)
comment (freeform notes about the track)
compilation (is this track from a compilation album?)
composer (the composer of the track)
databaseID (the common, unique ID for this track. If two tracks in different playlists have the same database ID, they are sharing the same data.)
dateAdded (the date the track was added to the playlist)
objectDescription (the description of the track)
discCount (the total number of discs in the source album)
discNumber (the index of the disc containing this track on the source album)
duration (the length of the track in seconds)
enabled (is this track checked for playback?)
episodeID (the episode ID of the track)
episodeNumber (the episode number of the track)
EQ (the name of the EQ preset of the track)
finish (the stop time of the track in seconds)
gapless (is this track from a gapless album?)
genre (the music/audio genre (category) of the track)
grouping (the grouping (piece) of the track. Generally used to denote movements within a classical work.)
kind (a text description of the track)
longDescription ()
lyrics (the lyrics of the track)
modificationDate (the modification date of the content of this track)
playedCount (number of times this track has been played)
playedDate (the date and time this track was last played)
podcast (is this track a podcast episode?)
rating (the rating of this track (0 to 100))
ratingKind (the rating kind of this track)
releaseDate (the release date of this track)
sampleRate (the sample rate of the track (in Hz))
seasonNumber (the season number of the track)
shufflable (is this track included when shuffling?)
skippedCount (number of times this track has been skipped)
skippedDate (the date and time this track was last skipped)
show (the show name of the track)
sortAlbum (override string to use for the track when sorting by album)
sortArtist (override string to use for the track when sorting by artist)
sortAlbumArtist (override string to use for the track when sorting by album artist)
sortName (override string to use for the track when sorting by name)
sortComposer (override string to use for the track when sorting by composer)
sortShow (override string to use for the track when sorting by show name)
size (the size of the track (in bytes))
start (the start time of the track in seconds)
time (the length of the track in MM:SS format)
trackCount (the total number of tracks on the source album)
trackNumber (the index of the track on the source album)
unplayed (is this track unplayed?)
videoKind (kind of video track)
volumeAdjustment (relative volume adjustment of the track (-100% to 100%))
year (the year the track was recorded/released)
&nbsp;
Method: artworks
Returned: SBElementArray
----
&nbsp;
Class: iTunesFileTrack
Properties:
location (the location of the file represented by this track)
&nbsp;
Method: refresh
Returned: void
update file track information from the current information in the track’s file
----
&nbsp;
Class: iTunesURLTrack
Properties:
address (the URL for this track)
&nbsp;
Method: download
Returned: void
download podcast episode
----
&nbsp;
Class: iTunesUserPlaylist
Properties:
shared (is this playlist shared?)
smart (is this a Smart Playlist?)
&nbsp;
Method: fileTracks
Returned: SBElementArray
----
Method: URLTracks
Returned: SBElementArray
----
Method: sharedTracks
Returned: SBElementArray
----</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2010/01/17/controlling-itunes-with-macruby/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>IM new year countdown with MacRuby</title>
		<link>http://merbist.com/2009/12/31/im-new-year-count-down-with-macruby/</link>
		<comments>http://merbist.com/2009/12/31/im-new-year-count-down-with-macruby/#comments</comments>
		<pubDate>Thu, 31 Dec 2009 18:25:50 +0000</pubDate>
		<dc:creator>Matt Aimonetti</dc:creator>
				<category><![CDATA[macruby]]></category>
		<category><![CDATA[ichat]]></category>
		<category><![CDATA[scriptingbridge]]></category>

		<guid isPermaLink="false">http://merbist.com/?p=662</guid>
		<description><![CDATA[Here is the geekiest way I found to wish Happy New Year to my IM contacts: framework 'ScriptingBridge' app = SBApplication.applicationWithBundleIdentifier&#40;&#34;com.apple.iChat&#34;&#41; original_status = app.statusMessage new_year = Time.mktime&#40;2010, 1, 1, 0, 0&#41; &#160; loop do now = Time.now time_left = &#40;new_year - now&#41;.ceil if time_left &#62; 0 app.statusMessage = &#34;#{time_left} seconds left until 2010 (EST)&#34; else [...]]]></description>
			<content:encoded><![CDATA[<p>Here is the geekiest way I found to wish Happy New Year to my IM contacts:</p>
<p><img class="aligncenter" title="IM" src="http://img.skitch.com/20091231-c9t2n9889rxiinux6qsfhqtxfq.jpg" alt="" width="279" height="61" /></p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">framework <span style="color:#996600;">'ScriptingBridge'</span>
app = SBApplication.<span style="color:#9900CC;">applicationWithBundleIdentifier</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;com.apple.iChat&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
original_status = app.<span style="color:#9900CC;">statusMessage</span>
new_year = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">mktime</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">2010</span>, <span style="color:#006666;">1</span>, <span style="color:#006666;">1</span>, <span style="color:#006666;">0</span>, <span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
<span style="color:#CC0066; font-weight:bold;">loop</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  now = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>
  time_left = <span style="color:#006600; font-weight:bold;">&#40;</span>new_year <span style="color:#006600; font-weight:bold;">-</span> now<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">ceil</span>
  <span style="color:#9966CC; font-weight:bold;">if</span> time_left <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#006666;">0</span>
    app.<span style="color:#9900CC;">statusMessage</span> = <span style="color:#996600;">&quot;#{time_left} seconds left until 2010 (EST)&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">else</span>
    app.<span style="color:#9900CC;">statusMessage</span> = <span style="color:#996600;">&quot;Happy New Year 2010!&quot;</span>
    <span style="color:#CC0066; font-weight:bold;">exit</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#CC0066; font-weight:bold;">sleep</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>If you are alone at home playing WOW,  you can also trigger iTunes to play a mp3 file with crowd noise and people shouting &#8216;<strong>Happy New Year 2010</strong>&#8216;!</p>
<p><img class="aligncenter" title="new year IM" src="http://img.skitch.com/20091231-c5j9dhhy46t76gh26fu6a26h7c.jpg" alt="" width="279" height="58" /></p>
]]></content:encoded>
			<wfw:commentRss>http://merbist.com/2009/12/31/im-new-year-count-down-with-macruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

