inchworm

inchworms

Summer of Coding, one inch at a time...

Splatting and Slurping

inchworms - Tue 23 July, 2013, 17:57

As Don Jones points out, where else but the IT industry would one use a word like “splatting” in a serious, professional context? Or “slurping” for that matter. osgx explains it like this:

	In Ruby... [a] parameter of a method may be preceded 
	by an asterisk(*), which is sometimes called the 'splat' 
	operator. This indicates that more parameters may be passed 
	to the function. Those parameters are collected up and an 
	array is created.

	The asterisk operator may also precede an Array argument in 
	a method call. In this case the Array will be expanded and 
	the values passed in as if they were separated by commas.

Here’s an example of what splatting can do:

	def drink(slurp, *flavour)
	  flavour.each { |f| puts "#{f}: #{slurp}" }
	end
	 
	drink("Slurping!", "Chocolate", "Vanilla", "Strawberry")

Will return:

	Chocolate: Slurping!
	Vanilla: Slurping!
	Strawberry: Slurping!

(See Jaco Pretorius for more examples)

The most common usage of the splat operator is, according to Jaco, slurping up all remaining arguments. But we were splatting Sinatra routes (or at least testing Sinatra’s ability to support splat params). Mmmmm. Juicy.

In any case, we’re churning through our tests and learning way more about routes, and what web frameworks need to accomodate in URLs, than we ever anticipated. Konstantin made a nice checklist for us. We are happily ticking off the boxes :-)

Hitzewelle!

inchworms - Mon 22 July, 2013, 17:17

Berlin. 30 degrees in the shade. Everywhere we look Germans are melting. But not our mentor Stefan, the Bjorn Borg of Open Data.

Stefan Wehrmeyer

We met with Stefan in the morning to discuss the EU FarmSubsidy project we’ll work on in the later part of our Summer of Code. We covered a lot of ground, discussing possible libraries to use, different software that might be helpful, alternate visual approaches, and formulated a rough plan for how we should initially proceed. (Carla was also happy to find data about her uncle’s small farm in Sicily).

Then it was back to the Travis CI office to continue with our Sinatra tests.

The coding was 15% more fun today thanks to glistening nail polish provided by @meivx. We are thinking of making her our official inchworms stylist.

We needed more fun because while it may have been the heat, the long list of Sinatra routing tests started to intimidate us. Especially when we realised the list we wrote last week only included the ‘get’ portion of routing requests (not the ‘post’, ‘put’, ‘delete’, ‘head’, ‘options’, ‘patch’, ‘link’, ‘unlink’ requests). Eeek!

We found something Matt called a rabbit hole (to do with disabling Rack protection) and had test results totally splatter our screens with red, as if an RSpec chainsaw had been unleashed.

splatter

Our work continues…

Yield! (to my superior knowledge)

inchworms - Fri 19 July, 2013, 16:38

Meta Matt

Do not doubt this man. He will take a statement like yield and break it into meta-programmed chunks. All before breakfast (smells a lot like RGSoC spirit to us ;-))

Very simply, a yield statement will invoke a block. This is all you really need to know.

we have no idea what we're doing

The rest of the day we spent writing the routing spec for our Sinatra testing and refactoring it all into beautifully contextualised syntax. Here’s a list of the remaining Sinatra routing tests we need to write:

  • allows using unicode
  • it handles encoded slashes correctly
  • overrides the content-type in error handlers
  • matches empty PATH_INFO to “/” if no route is defined for “”
  • matches empty PATH_INFO to “” if a route is defined for “”
  • takes multiple definitions of a route
  • exposes params with indifferent hash
  • merges named params and query string params in params
  • supports optional named params like /?:foo?/?:bar?
  • supports named captures like %r{/hello/(?[^/?+ ]+)} on Ruby >= 1.9
  • supports optional named captures like %r{/page(?.[^/?+ ]+)?} on Ruby >= 1.9
  • does not concatinate params with the same name
  • supports single splat params like /*
  • supports mixing multiple splat params like //foo//*
  • supports mixing named and splat params like /:foo/*
  • matches a dot (‘.’) as part of a named param
  • matches a literal dot (‘.’) outside of named params
  • literally matches dollar sign in paths
  • literally matches plus sign in paths
  • does not convert plus sign into space as the value of a named param
  • literally matches parens in paths
  • supports basic nested params
  • exposes nested params with indifferent hash
  • exposes params nested within arrays with indifferent hash
  • supports arrays within params
  • supports deeply nested params
  • preserves non-nested params
  • matches paths that include spaces encoded with %20
  • matches paths that include spaces encoded with +
  • matches paths that include ampersands
  • URL decodes named parameters and splats
  • supports regular expressions
  • makes regular expression captures available in params[:captures]
  • supports regular expression look-alike routes
  • raises a TypeError when pattern is not a String or Regexp
  • returns response immediately on halt
  • halts with a response tuple
  • halts with an array of strings
  • sets response.status with halt
  • transitions to the next matching route on pass
  • transitions to 404 when passed and no subsequent route matches
  • transitions to 404 and sets X-Cascade header when passed and no subsequent route matches
  • uses optional block passed to pass as route block if no other route is found
  • passes when matching condition returns false
  • does not pass when matching condition returns nil
  • passes to next route when condition calls pass explicitly
  • passes to the next route when host_name does not match
  • passes to the next route when user_agent does not match
  • treats missing user agent like an empty string
  • makes captures in user agent pattern available in params[:agent]
  • matches mime_types with dots, hyphens and plus signs
  • filters by accept header
  • filters by current Content-Type
  • allows multiple mime types for accept header
  • respects user agent preferences for the content type
  • accepts generic types
  • prefers concrete over partly generic types
  • prefers concrete over fully generic types
  • prefers partly generic over fully generic types
  • respects quality with generic types
  • supplies a default quality of 1.0
  • orders types with equal quality by parameter count
  • ignores the quality parameter when ordering by parameter count
  • properly handles quoted strings in parameters
  • accepts both text/javascript and application/javascript for js
  • accepts both text/xml and application/xml for xml
  • passes a single url param as block parameters when one param is specified
  • passes multiple params as block parameters when many are specified
  • passes regular expression captures as block parameters
  • supports mixing multiple splat params like //foo//* as block parameters
  • raises an ArgumentError with block arity > 1 and too many values
  • raises an ArgumentError with block param arity > 1 and too few values
  • succeeds if no block parameters are specified
  • passes all params with block param arity -1 (splat args)
  • allows custom route-conditions to be set via route options
  • raises an ArgumentError with block param arity 1 and no values
  • raises an ArgumentError with block param arity 1 and too many values
  • matches routes defined in superclasses
  • matches routes in subclasses before superclasses
  • adds hostname condition when it is in options
  • allows using call to fire another request internally
  • plays well with other routing middleware
  • returns the route signature
  • sets env[‘sinatra.route’] to the matched route

See you sometime next decade…

Getting Get Requests

inchworms - Thu 18 July, 2013, 14:30

First of all, Cecilia from #rgsoc-teams, we hope you’re feeling more yourself.

cecilia

Secondly, when trying to communicate (to someone remotely) what you’re actually inputing into your terminal, it’s possible to make a video capture of your screen online and send a link to your remote buddy. Just use ascii.io.

We weren’t able to access our localhost server using telnet so sent this to Konstantin:

Our mistake was failing to simply enter an empty line…

Why were we doing this? Because yesterday we started writing tests for Sinatra, focusing initially on all the HTTP requests. Using telnet is one way of seeing what the server response is. Useful for us to see what we would be testing for.

Actually Konstantin hand drew some requests/responses for us yesterday.

We also did a bit of reading at lunch from Sinatra: Up and Running. It has a nice little example app in Chapter 1 that lets you play Rock Paper Scissors with your computer. It’s super simple, but very instructive!

books for lunch

AND we wrote a few tests: GET returns 200 as a status, returns body as string, returns body as array; GET /hello returns the exected route.

More tomorrow.

Don't Unleash the Stubs!

inchworms - Wed 17 July, 2013, 16:21

Today we watched the rest of Part 2 of PeepCode’s excellent RSpec video tutorial. This one covered:

The three stages of testing

  • Automated testing with RSpec
  • Manual Testing with QA testing
  • Production deployment with customers

API discovery

  • Writing an example to describe expected output
  • Learning how an API works by writing examples
  • Using XPath syntax with Nokogiri (although @svenfuchs suggested using CSS instead)
  • Extracting the author name from an RSS feed

Custom Matcher

  • Extracting a post’s publication date
  • Parsing an XML date into a Ruby object
  • Writing a custom matcher (see David Chelimsky’s wiki)
  • Verifying the parsing of the date object

Configuration Options

  • Creating a .rpsec file
  • Understanding the options in the rspec command
  • Using an alternate report formatter
  • Setting custom options as the default

Retrieving Data

  • Retreiving data from an external server
  • Organising network code for easier testing

Stubs & Mocks

  • Understanding stubs and mocks
  • Using paceholder code to make your examples faster and more consistent
  • Intercepting network calls with a stub
  • Expecting specific methods to be called with a mock

Stub Syntax:

	# Syntax
	my_object.stub(:my_method).and_return(my_data)

	# Usage in this tutorial
	client.stub(:get).and_return(xml)

But don’t forget:

stubs

Context, Edge Cases, Corner Cases

  • Writing examples for non-successful edge and corner cases
  • Organising examples into success and error contexts
  • Learning to think about ways things could go wrong
  • Discovering errors and anticipating them in your code