


<?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>CantRemembrances &#187; ruby</title>
	<atom:link href="http://blog.cantremember.com/tag/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.cantremember.com</link>
	<description>Memes of a technical vein discovered during CantRemember.com implementation</description>
	<lastBuildDate>Tue, 16 Feb 2010 06:36:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Twitter4R shifts RSpec onto my Front Burner</title>
		<link>http://blog.cantremember.com/twitter4r-shifts-rspec-onto-my-front-burner/</link>
		<comments>http://blog.cantremember.com/twitter4r-shifts-rspec-onto-my-front-burner/#comments</comments>
		<pubDate>Thu, 05 Feb 2009 09:00:33 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=94</guid>
		<description><![CDATA[As usual, my day did not pan out as expected.  But, also as usual, I learned a lot!
Coming Up To Speed on Rspec
So, learning rspec has been on my list for a while.  I finally got around to it.  Nice framework.  I am familiar with EasyMock, and am aware of JMock. [...]]]></description>
			<content:encoded><![CDATA[<p>As usual, my day did not pan out as expected.  But, also as usual, I learned a lot!</p>
<h3>Coming Up To Speed on Rspec</h3>
<p>So, learning <a href="http://rspec.info/"><strong>rspec</strong></a> has been on my list for a while.  I finally got around to it.  Nice framework.  I am familiar with <a href="http://www.easymock.org/">EasyMock</a>, and am aware of <a href="http://www.jmock.org/">JMock</a>.  I never had an opportunity to get into <a href="http://code.google.com/p/mockito/">Mockito</a>, but I&#8217;d give it a glance next time I put on my Java hat.</p>
<p>There is some decent documentation on it out there.  I found these links particularly helpful:</p>
<ul>
<li>The <a href="http://rspec.info/documentation/">formal documentation</a>.</li>
<li>David Chelimsky&#8217;s <a href="http://blog.davidchelimsky.net/articles/2007/05/14/an-introduction-to-rspec-part-i">from-the-ground-up description</a></li>
<li>rspec.info&#8217;s drill-down into <a href="http://rspec.info/documentation/mocks/">Mocks and Stubs</a></li>
<li>Luke Redpath&#8217;s cross-over into <a href="http://www.lukeredpath.co.uk/blog/developing-a-rails-model-using-bdd-and-rspec-part-1.html">usage under Rails</a></li>
</ul>
<p>During my ramping-up, I took the <a href="http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/">usual meta-approach</a> of creating a test suite &#8212; and <em>yaaay</em>, that&#8217;s what <code>rspec</code> is meant for! &#8212; which I then used to test out its own range of capabilities.  The <a href="http://rspec.rubyforge.org/rspec/1.1.12/">Modules in the rdoc</a> which I&#8217;ve found to provide the most value are:</p>
<ul>
<li><strong>Spec::Expectations::ObjectExpectations</strong> for conditionals (eg. <code>should</code> &#038; <code>should_not</code>)</li>
<li><strong>Spec::Matchers</strong> for expectations (eg. <code>equal(<em>value</em>)</code>, <code>be_a(<em>class</em>)</code>, <code>respond_to(<em>method_sym</em>)</code>, <code>raise_error</code>)</li>
<li><strong>Spec::Mocks::Methods</strong> for mock method definition (eg. <code>should_receive(<em>method_sym</em>)</code>)</li>
<li><strong>Spec::Mocks::MessageExpectation</strong> for mock behaviour (eg. <code>with(<em>*args</em>)</code>, <code>once</code>, <code>exactly(<em>n</em>).times</code>, <code>any_number_of_times</code>)</li>
<li><strong>Spec::Mocks::ArgumentConstraints</strong> for mock arguments (eg. <code>an_instance_of(<em>class</em>)</code>, <code>anything</code>)</li>
<li><strong>Spec::Mocks::BaseExpectation</strong> for mock responses (eg. <code>and_return(<em>value</em>)</code>, <code>and_yield(<em>&#038;block</em>)</code>)</li>
</ul>
<p>I won&#8217;t got into the deep details, but here are some examples of conditionals and expectations that I paraphrased into my meta-test:</p>
<div class="pre_wrap">
<pre><code>	specify "knowledge of nil" do
		''.should_not be_nil
	end

	specify "numeric calculations" do
		(355.0 / 113).should be_close(Math::PI, 0.1)
	end

	specify "changes made by a closure" do
		array = []
		lambda {
			array << :a
		}.should change(array, :size)
	end

	specify "equality" do
		5.should eql 5
		5.should equal 5
		[:a].should_not equal [:a]
	end

	specify "raising of errors" do
		#	always construct fresh!!!
		#		otherwise it won't be re-wrappable
		def raiser(s=nil)
			lambda { raise(RuntimeError, s) if s }
		end

		raiser('x').should raise_error
		raiser('y').should raise_error(RuntimeError, 'y')
	end

	specify "closure satisfaction" do
		5.should satisfy {|n| (4..6).include?(n) }
	end

	specify "what lists do" do
		[].should respond_to(:each, :find, :size)
	end</code></code></pre>
</div>
<p>And here&#8217;s a little bit of silly mocking:</p>
<div class="pre_wrap">
<pre><code>	def expect_raise(type=Spec::Mocks::MockExpectationError, &#038;block)
		abort 'block must be provided' unless block_given?
		block.should raise_error(type)
	end

	specify "the basics" do
		@mock.should_receive :hello
		@mock.should_not_receive :goodbye

		@mock.hello
		expect_raise { @mock.stay }
		expect_raise { @mock.goodbye }
	end

	specify "how many times, and with what" do
		@mock.should_receive(:one).once.with(1)
		@mock.one 1

		@mock.should_receive(:string).exactly(1).times.with(an_instance_of(String))
		@mock.string 'a string'

		@mock.should_receive(:anything).exactly(3).times.with(any_args())
		@mock.anything
		@mock.anything :again
		@mock.anything :third, 'time'

		@mock.should_receive(:array_ish).with(duck_type(:each, :find, :size))
		@mock.array_ish [:item]
	end

	specify "what i return, raise or throw" do
		@mock.should_receive(:get_one).and_return(1)
		@mock.should_receive(:put_one).with(1)
		@mock.put_one @mock.get_one

		@mock.should_receive(:increment).any_number_of_times.with(instance_of(Fixnum)).and_return {|i| i + 1 }
		@mock.increment(1).should equal(2)

		@mock.should_receive(:raises_string).and_raise('something runtime')
		expect_raise(RuntimeError) { @mock.raises_string }

		@mock.should_receive(:pitch).and_throw(:ball)
		lambda { @mock.pitch }.should throw_symbol(:ball)
	end

	specify "yielding in a complex fashion" do
		@mock.should_receive(:gimmee).exactly(3).times.and_yield(:x)

		holder = []
		@mock.gimmee {|value| holder << value }
		holder.should eql([:x])
		2.times { @mock.gimmee {|value| holder << value } }
		holder.should eql([:x, :x, :x])
	end

	specify "validation via closure" do
		(@mock.should_receive(:threely) do |value|
			value.to_s.size.should eql(3)
		end).exactly(3).times

		@mock.threely 'x' * 3
		@mock.threely :key
		@mock.threely 333
	end</code></code></pre>
</div>
<p>These are just ways I thought of to exercise the width and breadth of the library.  Very nice.  I hope that these are useful examples for people new to this gem.</p>
<p>I recommend the other references from above for filling in the missing details.  Once you have a <code>context / specify</code> or a <code>describe / it</code> specification set up, you&#8217;ll be good to go.  There&#8217;s much more to the library &#8212; Stories, for instance &#8212; but that&#8217;s <a href="http://blog.emson.co.uk/2008/06/understanding-rspec-stories-a-tutorial/">for another day</a>.</p>
<h3>An Informative Walk through Twitter4R</h3>
<p>No, I didn&#8217;t really <em>want</em> to spend time learning <code>rspec</code> &#8212; I mean heck, I&#8217;m busy &#8212; but I had a personal need to expand the <a href="http://twitter4r.rubyforge.org/"><strong>Twitter4R</strong></a> gem.  Specifically, I wanted to add on some <a href="http://apiwiki.twitter.com/Search+API+Documentation">Twitter search</a> features, and I was very impressed with how this library has been built.  Contribution-wise, the final step that <a href="http://susanpotter.net/">Susan Potter</a> recommends is to craft up some rspec tests.</p>
<p>Of course, mock testing is only as good as the framework you&#8217;re built upon.  The assumption is that <code>Net::HTTP</code> is going to do it&#8217;s job, so mock it up and you can even test your Twitter features offline.  When I built <a href="http://wiki.cantremember.com/Bitly4R"><strong>Bitly4R</strong></a> (given that name, my thinking has clearly been <em>influenced</em>), I did everything as full-on functional tests.  It was easy; <a href="http://bit.ly/">bit.ly</a> has both <code>shorten</code> and <code>expand</code> commands, so I could reverse-test real values without having any fixed expectations.</p>
<p>However, Twitter is <a href="http://twitter.com/public_timeline">live</a> and user-generated, so who knows <em>what</em> you&#8217;ll find.  Mocking covers that for you.  And of course not having to hit the service itself shortest testing time dramatically.</p>
<p>Here&#8217;s one of my tests, again foreshortened:</p>
<div class="pre_wrap">
<pre><code>	before(:each) do
		Twitter::Client.send :public, :create_http_get_request

		@client = Twitter::Client.new
		@client_clone = Twitter::Client.new
	end

	it "produces a querystring with all the crazy stuff Twitter imagined" do
		the_params = nil

		@client.should_receive(:create_http_get_request).and_return {|uri, params|
			the_params = params
			@client_clone.create_http_get_request(uri, params)
		}
		@client.should_receive(:http_connect).and_return Net::HTTPNotFound.mock(:code => '404')

		#	pass through a few we can pick back out
		#	also, side-effect ... nil on invalid response
		@client.search('query_value', :rpp => 3).should be_nil

		the_params.should_not be_nil
		the_params[:q].should eql('query_value')
		the_params[:rpp].should eql(3)
	end</code></code></pre>
</div>
<p>Plus a little mocking of <code>Net::HTTPResponse</code>:</p>
<div class="pre_wrap">
<pre><code>class Net::HTTPResponse
	def self.mock(ops={})
		#	defaults
		ops = {
			:http_version => '1.1',
			:code => '200',
			:message => 'OK',
			:body => nil,
		}.merge(ops || {})

		#	construct
		###clazz = CODE_TO_OBJ[ops[:code]]
		clazz = self
		response = clazz.new(ops[:http_version], ops[:code], ops[:message])

		#	inject
		ops.each do |k, v|
			response.instance_variable_set "@#{k}".to_sym, v
		end

		#	mockulate
		response.instance_eval %q{
			def body; @body; end
		}

		response
	end
end</code></code></pre>
</div>
<p>Nothing like having some good inspiration to get you thinking about maintainability.  I&#8217;m a not a strong adherent to any of the <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> or <a href="http://en.wikipedia.org/wiki/Behavior_driven_development">BDD</a> denominations, but testability itself is close to my heart.  Just ask the folks who&#8217;ll be looking at the micro-assertion Module that I wrote for my <a href="http://www.facebook.com/jobs_puzzles/">Facebook Puzzle</a> submissions (which work locally under test conditions but fail <em>miserably</em> once thrown over their wall).  Then again, I won&#8217;t need to write that (and test that) from scratch again.</p>
<p>So, back to talking glowingly about the <code>Twitter4R</code> architecture.  Yes, I used <strong>that</strong> word.  Yet regardless of that term&#8217;s heavyweightedness, it&#8217;s simply the result of carefully thinking out the formalization of a complex design.  And once a non-author delves into extending an existing implementation, that impl&#8217;s demeanor becomes readily clear :)</p>
<p>Some of the interesting things I saw:</p>
<ul>
<li>An inner <code>bless</code>-ish strategy, to inject the <code>Twitter::Client</code> into instanciated result classes.  I&#8217;ve seen blessing as an OO-Perl-ism, for self-ication, and that metaphor carries over very nicely to this context.</li>
<li>Generous use of blocks / lambdas / closures in methods, for contextual iteration (eg. iterate through each <code>Twitter::Message</code> in a <code>timeline</code> response).  Unnecessary, but an excellent convenience for a language that offers that optional capability in a very disposable fashion (from the caller&#8217;s perspective).</li>
<li>Retroactive sub-object population after construction.  <code>Twitter4R</code> relies upon the <a href="http://json.rubyforge.org/">json</a> gem, which deals primarily in Hashes.  Post-injection, the library itereates through Arrays of Hashes and transforms them into suitable <code>Twiltter::User</code> containers, etc.  A great place to put such logic in the construction chain, and it doesn&#8217;t take long to get really tired of Hash hierarchies.</li>
</ul>
<p>Good stuff, and learning with in a Ruby-centric mindset was invaluable for me.  We all have to start somewhere, eh.</p>
<h3>The Acute Long-Term Pain of Staticness</h3>
<p>There was one issue that I ran into; <em>static configuration</em>.  During my years of using the <a href="http://www.springsource.org/">Spring Framework</a>, my <a href="http://en.wikipedia.org/wiki/Inversion_of_Control">IOC</a>-addled brain started thinking of everything in terms of instances &#8212; Factory Beans, POJOs, Observers &#038; Listeners, Chain-of-Responsibility wrappers.  Static configuration is a common metaphor, and in this case, there&#8217;s a static <code>Twitter::Config</code> instance.  Convenient and centralized.  Makes perfect sense.</p>
<p>I mean, the fact that it was a configurable library <em>at all</em> was awesome.  I was able to easily set up a <code>Twitter::Client</code> to reference <a href="http://search.twitter.com">search.twitter.com</a>.  However, of course as soon as I did that, I whacked the ability for clients to talk to <code>twitter.com</code> in the process.  <em>Oops!</em></p>
<p>On GPs, I refused to modify the original code.  And I wanted to make sure that my superficial tweaks to the library would be thread-safe &#8212; temporarily swaping out the global <code>Twitter::Config</code> in mid-operation would be an issue.  Using <code>Mutex.synchronize</code> seemed like the perfect choice.  After finding that the same thread can&#8217;t lock a <code>Mutex</code> instance twice &#8212; grr!, that&#8217;s a great trick if you can work it &#8212; I overrode the one method that cared the most about <code>@@config</code>:</p>
<div class="pre_wrap">
<pre><code>	@@config_mutex = Mutex.new
	def configuration_mutex
		@@config_mutex
	end

	alias :raw_http_connect :http_connect
	def <strong>http_connect</strong>(*args, &#038;block)
		ops = (Hash === args.last) ? args.pop : {}

		result = nil
		self.configuration_mutex.synchronize do
			ops[:call_before].call if ops[:call_before]
			result = raw_http_connect *args, &#038;block
			ops[:call_after].call if ops[:call_after]
		end

		result
	end

	#
	#	...
	#

	@@SEARCH_CONNECT_HOOKS = {
		:call_before => lambda { self.configure_apply(:search) },
		:call_after => lambda { self.configure_apply(:default) },
	}

	#
	#	...
	#

	#	broken out of closure for mocking
	req = create_http_get_request(uri, params)
	response = http_connect(@@SEARCH_CONNECT_HOOKS) {|conn|	req }
	return nil unless Net::HTTPOK === response

	model = bless_model(Twitter::Search.unmarshal(response.body))</code></code></pre>
</div>
<p>It works like a charm.  Please, everyone just line up to tell me how I could have done it better.  And I don&#8217;t mean <em>quicker</em> or <em>cheaper</em>, I mean better.  Believe me, I would not have sunk the time into this end-around approach, if not for the fact that:</p>
<ol>
<li>I don&#8217;t want to maintain a local gem code modification (even though my impl is closely coupled to the gem impl already)</li>
<li>I intend to follow that practice, so every opportunity to pull and end-around is a Valuable Learning Experience.</li>
</ol>
<p>So, now my local <code>Twitter4R</code> has search capability gracefully latched onto it (and implemented much in the flavor of the library itself).  I have a mass of <code>rspec</code> examples to work off in the future.</p>
<p>Now, I haven&#8217;t spent a great amount of time testing the thread-safeness &#8212; no one in their right mind <em>wants</em> to do that &#8212; but my sundry <code>Twitter::Client</code> instances play nicely together in between searches and normal status operations.</p>
<p>And I had something useful to blog about!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/twitter4r-shifts-rspec-onto-my-front-burner/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Remote Scripting for AWS</title>
		<link>http://blog.cantremember.com/remote-scripting-for-aws/</link>
		<comments>http://blog.cantremember.com/remote-scripting-for-aws/#comments</comments>
		<pubDate>Sat, 24 Jan 2009 20:36:01 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[monitoring]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=73</guid>
		<description><![CDATA[When signing up for Amazon Web Services, you end up generating all of the following identifying information:

Your Account Number
An Access Key
A Secret Access Key
An SSL Certificate file
The Private Key for your SSL Cert

The various AWS command APIs and tools will require you to provide one more more of these pieces of information.  Rather than [...]]]></description>
			<content:encoded><![CDATA[<p>When signing up for <a href="http://aws.amazon.com">Amazon Web Services</a>, you end up generating all of the following identifying information:</p>
<ul>
<li>Your Account Number</li>
<li>An Access Key</li>
<li>A Secret Access Key</li>
<li>An SSL Certificate file</li>
<li>The Private Key for your SSL Cert</li>
</ul>
<p>The various AWS command APIs and tools will require you to provide one more more of these pieces of information.  Rather than actually host all of this information on my instances, I have instead chosen to build Ruby scripts using:</p>
<ul>
<li>Glenn Rempe&#8217;s Amazon EC2 gem (<a href="http://rubyforge.org/projects/amazon-ec2">amazon-ec2</a>)</li>
<li>The <a href="http://rubyforge.org/projects/net-ssh">net-ssh</a> and net-scp gem suite</li>
</ul>
<p>I&#8217;m small-scale for the moment, so I can keep a centralized list of my instance IDs.  Without too much effort, I can look up the instance(s), identify their public DNS (plus everything else), and then open up an ssh connection and push data into a channel&#8217;s environment or upload files for bundling purposes.</p>
<p>Here&#8217;s a few things that I&#8217;ve learned in the process.</p>
<h3>Channels</h3>
<p>Most of your core work gets done on a <code>Net::SSH::Connection::Channel</code>, and sometimes asynchronously (as in the case of my Health Check script).  There are a lot of library shorthands &#8212; the prototypical Hello World example is channel-less:</p>
<div class="pre_wrap">
<pre><code>Net::SSH.start("localhost", "user") do |ssh|
	# 'ssh' is an instance of Net::SSH::Connection::Session
	ssh.exec! "echo Hello World"
end</code></pre>
</div>
<p>But as with all examples, you soon find that surface-level tools won&#8217;t quite do the trick.  The main thing you&#8217;ll need to have all the time is convenient access to the data come back from the channel, asynchronously or otherwise.  So create yourself a simple observer:</p>
<div class="pre_wrap">
<pre><code>def observer_struct
	@observer_struct ||= Struct.new(:channel, :stdout, :stderr, :exit_status, :exit_signal)
end

def observe_channel(ch, ops={})
	observer = observer_struct.new(ch, '', '', 0, nil)
	is_puts = !!ops[:puts]

	#	stdout
	ch.on_data do |ch, data|
		$stdout.print data if is_puts
		observer.stdout &lt;&lt; data
	end
	# only handle stderr
	ch.on_extended_data do |ch, type, data|
		next unless [1, :stderr].include? type
		$stderr.print data if is_puts
		observer.stderr &lt;&lt; data
	end

	ch.on_request("exit-status") do |ch, data|
		observer.exit_status = data.read_long
	end
	ch.on_request("exit-signal") do |ch, data|
		observer.exit_signal = data.read_long
	end

	observer
end

def open_channel(ssh, ops={}, &amp;block)
	ch = if block_given?
		ssh.open_channel &amp;block
	else
		ssh.open_channel
	end

	#	somebody's watching you
	self.observe_channel ch, ops
end</code></pre>
</div>
<p>Then during and after executions, you&#8217;ll have access to all the core information you&#8217;ll need to make conditional decisions, etc.</p>
<h3>Pushing Your Environment</h3>
<p>Many of the AWS tools will recognize specific environment variables.  The usual suspects are:</p>
<ul>
<li>AMAZON_ACCESS_KEY_ID</li>
<li>AMAZON_SECRET_ACCESS_KEY</li>
</ul>
<p>So, you can use <code>Net::SSH::Connection::Channel.<strong>env</strong></code> to inject key-value pairs into your connection.  However, you&#8217;ll need to make some config changes first &#8212; and <em>major thanks</em> to the Net::SSH documentation for clarifying this in its own RDoc:</p>
<blockquote><p>&#8220;Modify <code>/etc/ssh/sshd_config</code> so that it includes an AcceptEnv for each variable you intend to push over the wire&#8221;
</p></blockquote>
<div class="pre_wrap">
<pre>#       accept EC2 config
AcceptEnv  AMAZON_ACCESS_KEY_ID AMAZON_SECRET_ACCESS_KEY
...</pre>
</div>
<p>After you make your changes, make sure to bounce the ssh daemon:</p>
<div class="pre_wrap">
<pre><code>/etc/init.d/sshd restart</code></pre>
</div>
<p>Then your selected environment will shine through.</p>
<h3>Running sudo Remotely</h3>
<p>It&#8217;s reasonable to execute root-level commands using sudo, because you can provide a good amount of granular control.  </p>
<p>The first thing that we&#8217;ll all run into is:</p>
<div class="pre_wrap">
<pre>sudo: sorry, you must have a tty to run sudo</pre>
</div>
<p>Fortunately, there&#8217;s <code>Net::SSH::Connection::Channel.<strong>request_pty</strong></code>:</p>
<div class="pre_wrap">
<pre><code>ch.request_pty do |ch, success|
	raise "could not start a pseudo-tty" unless success

	#	full EC2 environment
	###ch.env 'key', 'value'
	###...

	ch.exec 'sudo echo Hello 1337' do |ch, success|
		raise "could not exec against a pseudo-tty" unless success
	end
end</code></pre>
</div>
<p>I&#8217;ve taken the approach of allowing <code>NOPASSWD</code> execution for everything I do remotely, after making darn sure that I had constrained exactly what could be done under those auspices (HINT: pounds of caution, tons of prevention).  You can configure all of this by editing <code>/etc/sudoers</code>:</p>
<div class="pre_wrap">
<pre># EC2 tool permissions
username  ALL=(ALL)  NOPASSWD: SETENV: /path/to/scripts/*.rb
...</pre>
</div>
<p>Also, if you intend to have those scripts consume the environment variables that you&#8217;ve injected into your channel, you&#8217;ll also need to annotate the line with <code>SETENV</code>, or they won&#8217;t export across into your sudo execution.</p>
<p>If you are more security minded, then there&#8217;s many other variations you can play with <a href="http://www.manpagez.com/man/5/sudoers/"><code>/etc/sudoers</code></a>.  I haven&#8217;t yet experimented within pushing a sudo password across the wire, but that may be where <code>Net::SSH::Connection::Channel.<strong>send_data</strong></code> comes into play.</p>
<h3>Port Forwarding</h3>
<p>I wanted to easily do SSH tunneling / port-forwarding against an instance, referenced by my local shorthand.  So I wrote my usual EC2 instance ID lookup and started an Net::SSH connection.  Here&#8217;s how you put yourself in &#8216;dumb forward&#8217; mode:</p>
<div class="pre_wrap">
<pre><code>def ports, offset = [], 0
# ...

Net::SSH.start(hostname, user, :forward_agent =&gt; true, :verbose =&gt; :warn) do |ssh|
	ports.each do |port|
		ssh.forward.local port + offset, 'localhost', port
	end

	# loop, with an event loop every 0.1s, until Ctrl-C is pressed
	puts "[Ctrl-C] to terminate..."
	interrupted = false
	trap('INT') { interrupted = true }
	ssh.loop(0.1) {
		not interrupted
	}

	ports.each do |port|
		ssh.forward.cancel_local port + offset
	end
end</code></pre>
</div>
<p>And then <code>[Ctrl-C]</code> will break you out.</p>
<h3>Inconsistent EC2 Marshalling</h3>
<p>I&#8217;d gotten all of my EC2 data parsing working great, then I started to expand my capabilities with the Amazon S3 API gem (<a href="http://rubyforge.org/projects/amazon/">aws-s3</a>).  Suddenly and magically, the results coming back from my EC2 queries had taken on a new form.  Moreover, this was <em>not consistent behavior</em> across all operating systems; at least I do not see it on WinXP, under which my health monitoring checks execute.</p>
<p>The Amazon APIs are SOAP-driven, so I <em>guessed</em> that amazon-ec2 (and aws-3) would both leverage <a href="http://rubyforge.org/projects/soap4r">soap4r</a>.  Well, that is in fact <em>not</em> the case; Glenn has commented below on this known issue.  He uses the HTTP Query API, and the cause of the discrepancy are (as of this writing) still undetermined.</p>
<p>Regardless, our job is to get things to work properly.  So for the meanwhile, let&#8217;s use a quick &#038; dirty work-around.  The two core differences are:</p>
<ul>
<li>the data coming back may be wrapped in an additional key-value pair</li>
<li>single value result-sets come back as an Object (vs. an Array with a single Object)</li>
</ul>
<p>So I crafted a little helper singleton, which which still allows me to detect between &#8216;valid&#8217; and &#8216;empty&#8217; requests (<code>nil</code> vs <code>[]</code>):</p>
<div class="pre_wrap">
<pre><code>class SOAPHelper
	class &lt;&lt; self
		def data_from(data, wrapper)
			data[wrapper] || data
		end

		def items_from(set)
			unless set &amp;&amp; set.item
				nil
			else
				items = set.item
				items = [items] unless Array === items
				items
			end
		end
	end
end

data = SOAPHelper.data_from(
	@ec2.describe_instances,
	'DescribeInstancesResponse'
)
reservations = SOAPHelper.items_from(data.reservationSet) || []
...</code></pre>
</div>
<p>That will address our immediate needs for the moment, until a benificent coding Samaritan comes along.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/remote-scripting-for-aws/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Learning Ruby through Assertions and Podcasts</title>
		<link>http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/</link>
		<comments>http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 00:59:34 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Learning]]></category>
		<category><![CDATA[groovy]]></category>
		<category><![CDATA[podcast]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=50</guid>
		<description><![CDATA[I&#8217;ve been working with the Ruby language since March 2008.  So (as of this writing) I&#8217;m still on the n00b path.
Assertions
The first thing I did was to follow the great advice of Dierk Koenig, writer of Groovy in Action and general Groovy / Grails advocate.  The book itself doesn&#8217;t use the typical print-the-result-based [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working with the Ruby language since March 2008.  So (as of this writing) I&#8217;m still on the <a href="http://www.urbandictionary.com/define.php?term=n00b">n00b</a> path.</p>
<h3>Assertions</h3>
<p>The first thing I did was to follow the great advice of <a href="http://www.manning.com/koenig/">Dierk Koenig</a>, writer of <strong>Groovy in Action</strong> and general <a href="http://groovy.codehaus.org/">Groovy</a> / <a href="http://grails.org/">Grails</a> advocate.  The book itself doesn&#8217;t use the typical print-the-result-based code examples; it encourages the reader to learn the language <a href="http://groovy.codehaus.org/Quick+Start">through assertions</a>.  And that&#8217;s how I learned Groovy; I took the examples from the book, paraphrased them, tried variations on a theme, and then asserted that my results were true.  Now when I need to know how to use a language feature, I simply look back at my assertion code to re-edjumicate myself.</p>
<p>I learned the core Ruby language via <a href="http://rubyforge.org/projects/test-unit">Test::Unit</a>.  I spent three weeks (please don&#8217;t laugh) worth of my daily commute writing assertions for the core language, the standard packages, plus ActiveRecord and other common gems.  It allowed me to get a handle on the concepts, syntax, semantics and the sheer range of capabilities of he language.  I frequently look back at my <code>language_test_unit.rb</code> to figure out the best use of <code>Array.collect</code>, <code>catch..throw</code>, <code>Regexp</code> quirks, and using declared <code>lambda</code>s as blocks (etc).  More importantly, I&#8217;ve already written code using all of those techniques, so it&#8217;s just a referesher.</p>
<p>I <em>cannot recommend this technique enough</em> for coming up to speed on a language!</p>
<h3>Podcasts</h3>
<p>With that under my belt, plus some command-line scripts and a solid Rails project, I&#8217;m not spending time back-consuming posts from the following Podcast blogs:</p>
<h4>Rubyology</h4>
<p><a href="http://www.rubyology.com/">Site</a> : <a href="http://feeds.feedburner.com/rubyology">Feed</a></p>
<p>I&#8217;m actively back-consuming a lot of content from this wealth that Chris Matthieu has provided.  There are some great talks on <a href="http://www.rubyology.com/podcasts/show/70">Journeta</a>, using <a href="http://www.rubyology.com/podcasts/show/59">EC2</a>, great tutorials covering <a href="http://www.rubyology.com/podcasts/show/44">basic</a> and <a href="http://www.rubyology.com/podcasts/show/45"> RoR, and some <a href="http://www.rubyology.com/podcasts/show/13">scaling recommendations</a>.</p>
<h4>sd.rb Podcast</h4>
<p><a href="http://podcast.sdruby.com/">Site</a> : <a href="http://feeds.feedburner.com/sdrbpodcast">Feed</a></p>
<p>Straight from the mouth of the San Diego Ruby Users group.  A good variety of topics, focusing more on the Ruby language than on the Rails poster-child itself.  Nice talks on <a href="http://podcast.sdruby.com/2008/6/5/episode-046-rspec-in-15-minutes">rspec</a>, <a href="http://podcast.sdruby.com/2008/4/28/episode-041-mysql-clustering">MySQL clustering</a> and <a href="http://podcast.sdruby.com/2008/9/12/episode-053-ruby-arduino-development-rad">Arduino</a>, amongst many others.</p>
<h4>Railscasts</h4>
<p><a href="http://railscasts.com/">Site</a> : <a href="http://feeds.feedburner.com/railscasts">Feed</a></p>
<p>With 145 postings and counting, there&#8217;s a lot to be consumed here.  However, this is the last on my list, because none of them download to my iPhone 3G :( .  Lots of cross coverage on <a href="http://railscasts.com/episodes/133-capistrano-tasks">Capistrano</a>, <a href="http://railscasts.com/episodes/99-complex-partials">Partials</a>, custom <a href="http://railscasts.com/episodes/70-custom-routes">Routes</a>, <a href="http://railscasts.com/episodes/54-debugging-with-ruby-debug">ruby-debug</a> &#8230; the list goes on.</p>
<h4>Ruby on Rails Podcast</h4>
<p><a href="http://podcast.rubyonrails.org/">Site</a> : <a href="http://feeds.feedburner.com/rubyonrailspodcast">Feed</a></p>
<p>Geoffrey Grosenbach&#8217;s podcasts are seminal.  I&#8217;ll leave it up to the reader to <a href="http://answers.yahoo.com/question/index?qid=20080108230303AARcDfm">pore through</a> the years of accumulated wisdom.  How can you go wrong when you&#8217;re part of the <a href="http://rubyonrails.org">rubyonrails.org</a> domain!</p>
<h3>In Summary</h3>
<p>A number of these feeds provide screencasts and/or video.  A few of the files are old-school QuickTime MOVs which are problematic for the iPhone, which is annoying (definitely not the podcaster&#8217;s fault&#8230; get your head in gear, Apple).  And unfortunately when I break away to write down something in <a href="http://evernote.com/"><strong>Evernote</strong></a><strong>.app</strong>, and there&#8217;s any visuals associated with the cast, the iPhone halts playback.  <em>Grr.</em>  So I&#8217;m getting into the archaic habit of creating a <strong>Notes</strong> page and mailing it to myself :)</p>
<p>I recommend <em>each and all</em> of these podcasts.  Be prepared to sink a lot of time into them, so you might as well upload them onto your iPhone and take them to the beach!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/learning-ruby-through-assertions-and-podcasts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Custom Ruby and RadRails on Mac OS X</title>
		<link>http://blog.cantremember.com/custom-ruby-and-radrails-on-mac-os-x/</link>
		<comments>http://blog.cantremember.com/custom-ruby-and-radrails-on-mac-os-x/#comments</comments>
		<pubDate>Wed, 21 Jan 2009 04:53:37 +0000</pubDate>
		<dc:creator>dfoley</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[aptana]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[gems]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://blog.cantremember.com/?p=29</guid>
		<description><![CDATA[Let&#8217;s break this down, shall we &#8230;
Building Ruby and RubyGems
Many thanks to Dan Benjamin for his excellent posting on doing a custom build of Ruby &#38; RubyGems on OS X.  I was just getting started with using a Mac at the time, and it was a very straight-forward and helpful guide.  For most [...]]]></description>
			<content:encoded><![CDATA[<p>Let&#8217;s break this down, shall we &#8230;</p>
<h3>Building Ruby and RubyGems</h3>
<p>Many thanks to <a href="http://danbenjamin.com/articles/2008/02/ruby-rails-leopard">Dan Benjamin</a> for his <strong>excellent</strong> posting on doing a custom build of Ruby &amp; RubyGems on OS X.  I was just getting started with using a Mac at the time, and it was a very straight-forward and helpful guide.  For most software, I&#8217;ll use <a href="http://www.macports.org/">MacPorts</a> or standard Apple packages, but for Ruby I&#8217;ll make an exception.</p>
<p>For starters, I just want to expand a bit on his excellent tutorial.  I won&#8217;t re-iterate his whole piece, but the outline is:</p>
<ul>
<li>start with OS X Leopard, and XCode (from your Optional Installs DVD)</li>
<li>get /usr/local and its derivatives into your path</li>
<li>set aside a good long-term home for your custom build code</li>
<li>pull down the source for <a href="http://ruby-lang.org">Ruby</a></li>
<li>run ./configure, then build and install with make</li>
<li>pull down the source for <a href="http://rubyforge.org/projects/rubygems/">RubyGems</a>, run its setup.rb</li>
</ul>
<p>After that you can install all of the <a href="http://rubygems.org">gems</a> that your heart desires.  I initially pulled down source for the Ruby 1.9 candidate release, but there are significant enough language changes that it destabilized a lot of tried-and-true gems.  Instead, I went with the latest generation of 1.8.7.</p>
<p>I did however run into a little issue when installing the native mysql gem.  Dan&#8217;s instructions weren&#8217;t valid for my case.  Fortunately, the README.html in the gem suggested building it manually as such:</p>
<div class="pre_wrap">
<pre><code>$ sudo gem install mysql -- --with-mysql-config
  <em>or</em>
$ ruby extconf.rb --with-mysql-config</code></pre>
</div>
<p>That worked well, since I&#8217;d already installed MySQL and my <code>/etc/mysql.cnf</code> was in its standard location.  Hooray!</p>
<h3>Configuring RadRails to use the Custom-Built Componentry</h3>
<p>Since I switch back and forth between Ruby and Java, I chose to stick with the Eclipse IDE.  <a href="http://aptana.com/">Aptana</a> has created a nice development suite called <a href="http://aptana.com/rails">RadRails</a> which is highly componentized, and it works rather well for script development as well.  Yes, if I don&#8217;t use <a href="http://macromates.com/">TextMate</a> I&#8217;m a heretic, but at some point I&#8217;ll hunker down and pony out the bucks for it :)</p>
<p>The install of Eclipse 3.4 Ganymede that I started out with contained several plugins / features from <code>rubypeople.org</code>.  As well intended as they were, I ran into several areas of conflict between them and RadRails.  I thus chose to remove these plugins from Eclipse, and stability ensued.</p>
<p>However, even after removed, I still have two Eclipse sections for &#8216;Ruby&#8217;.  The one for RadRails is the one with fewer sub-sections (also known as &#8216;the one that looks <em>less</em> like the Java language configuration section&#8217;).</p>
<p>Since you&#8217;ve custom built your install of Ruby, you&#8217;ll want to make the following configuration changes to Eclipse / RadRails:</p>
<ul>
<li>Under <strong>Ruby | Interpreters</strong>, add a new Generic Ruby interpreter.  Its executable should be <code>/usr/bin/local/ruby</code>, and the rest will take care of itself (I didn&#8217;t specify any arguments).</li>
<li>Under <strong>Rails</strong>, set up the &#8216;rails&#8217; and &#8216;mongrel_rails&#8217; paths to reference the respective binaries in <code>/usr/local/bin</code>, since that&#8217;s where all of your installed gems will have been exposed.</li>
<li>Under <strong>Java | Build Path | Classpath Variables</strong>, you&#8217;ll want to add <strong>GEM_LIB</strong>, which should reference <code>/usr/local/lib/ruby/gems/1.8/gems</code>.  It seems out of place under &#8216;Java&#8217;, but the IDE was crying out for it loudly.</li>
</ul>
<p>That should address the majority of the IDE configuration.  If anything doesn&#8217;t quite work correctly, you may want to examine the steps that I describe below as being &#8216;optional&#8217;, particularly the one where I created a mock <code>Ruby.framework</code> setup.</p>
<h3>Optional (?) Configuration</h3>
<p>I question whether they&#8217;re mandatory or not because this configuration has been stable on my machine for a little while now, and I have a tendency to get very detail-oriented, not all of which turns out to actually be <em>necessary</em>.  In the spirit of completeness &#8212; yep, there&#8217;s detail-oriented for you right there! &#8212; I&#8217;ll lay out what I have put into play.</p>
<p>I&#8217;ve injected &#8216;/usr/local/bin&#8217; and &#8216;/usr/local/sbin&#8217; into <code>/etc/paths</code>; that works like a charm.</p>
<p>I consistently install gems as root, or else I end up with account-specific discrepancies driven by each <code>~/.gems</code> folder.  I merely point that out to illustrate that such user-specific directories exists :)</p>
<p>I&#8217;ve added the following <i>unnecessary</i> env var:</p>
<div class="pre_wrap">
<pre><code>export GEM_LIB=/usr/local/lib/ruby/gems/1.8/gems</code></pre>
</div>
<p>It matches the Classpath Variable you set in Eclipse (above).  If nothing else, it&#8217;s an easy &#8216;$&#8217; substitution when I need to go spelunking into gem source code.</p>
<p>There&#8217;s been at least once where I have also needed the following env var.  It should be configured to point at the expanded source code of your custom Ruby build.</p>
<div class="pre_wrap">
<pre><code>export RUBY_SOURCE_DIR=...</code></pre>
</div>
<p>I&#8217;ve created the following directory structure:</p>
<div class="pre_wrap">
<pre><code>$ mkdir -p /System/Library/Frameworks/Ruby.framework/Versions/1.8-Current</code></pre>
</div>
<p>Therein I have created a &#8216;usr&#8217; directory structure that matches the one you&#8217;ll find in <code>/System/Library/Frameworks<wbr>/Ruby.framework/Versions/1.8/usr</code> .  It&#8217;s all just symlinks into the appropriate <code>/usr/local</code> hierarchy.  I then co-opted the Current symlink:</p>
<div class="pre_wrap">
<pre><code>$ cd /System/Library/Frameworks/Ruby.framework/Versions
$ ls -l
1.8
1.8-Current
Current -&gt; 1.8
$ rm Current
$ ln -s 1.8-Current Current</code></pre>
</div>
<p>Consider that you may need to mimic certain aspects of the default Ruby framework configuration, which is the inverse of the mock framework setup that I just described.  Specifically, <code>/usr/local/lib/ruby</code> takes after <code>/System/Library/Frameworks<wbr>/Ruby.framework/Versions/Current/usr/lib/ruby</code>.</p>
<p>This is why I ended up with both a &#8216;/usr/local/lib/ruby/site_ruby&#8217; and &#8216;/usr/local/lib/ruby/vendor_ruby&#8217; subdir on my machine.</p>
<p>The standard location for the <code>ruby</code> executable is often used in a she-bang line for <code>bash</code> scripts.  The standard location is:</p>
<div class="pre_wrap">
<pre><code>#!/usr/bin/ruby</code></pre>
</div>
<p>Which of course was still pointing at the default OS X Ruby framework.  I renamed the existing symlink and replaced it with one to <code>/usr/local/bin/ruby</code>.  I did not do this for <code>gem, irb, rdoc</code> (etc.) since I don&#8217;t have she-bang needs for them.</p>
<h3>In Summary</h3>
<p>I hope some of this information is useful to you.  I was sitting at <a href="http://www.cafeinternational.com/">Cafe International</a> and setting up RadRails when the HD on my two-week-old MacBook Pro 2008 went into beachball-of-death mode.  I had to pick back up from there 2+ weeks later on a fresh laptop, which at least allowed me to keep these copious notes.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.cantremember.com/custom-ruby-and-radrails-on-mac-os-x/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
