Technology Agnostic Rubyist : Open Source Lights The Way

Friday, June 21, 2013

Two line HTTP Server with Rack

Working APIs often has its own set of challenges. One of these that I've come across often enough to blog about is composing an initial request to the API and tracking down errors.

To test if the problem arises from a malformed querystring or the http header, I needed to mock the http_request and echo the http_response.

To compose an HTTP requests I like to use the CURL library.

To echo the full HTTP request back to the requester, I wrote a simple two line HTTP Server.
require 'rack'
echo = lambda { |env| [200, {}, env.map{|k,v|"#{k}:\t#{v}\n"} ] }

To run the server, simply fire up an IRB console and copy/paste the code above and type.
Rack::Server.start :app => echo, :Port => 8080

That's it, you're ready to see it in action! curl an HTTP request.
curl -v http://localhost:8080/show_me_the_money?in_small_unmarked_bills=100bills

And you'll get a full echo of the HTTP request.
* About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /show_me_the_money?in_small_unmarked_bills=100bills HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
> 
< HTTP/1.1 200 OK 
< Server: WEBrick/1.3.1 (Ruby/1.9.3/2013-05-15)
< Date: Fri, 21 Jun 2013 14:22:32 GMT
< Content-Length: 703
< Connection: Keep-Alive
< 
GATEWAY_INTERFACE: CGI/1.1
PATH_INFO: /show_me_the_money
QUERY_STRING: in_small_unmarked_bills=100bills
REMOTE_ADDR: ::1
REMOTE_HOST: localhost
REQUEST_METHOD: GET
REQUEST_URI: http://localhost:8080/show_me_the_money?in_small_unmarked_bills=100bills
SCRIPT_NAME:
SERVER_NAME: localhost
SERVER_PORT: 8080
SERVER_PROTOCOL: HTTP/1.1
SERVER_SOFTWARE: WEBrick/1.3.1 (Ruby/1.9.3/2013-05-15)
HTTP_USER_AGENT: curl/7.29.0
HTTP_HOST: localhost:8080
HTTP_ACCEPT: */*
rack.version: [1, 1]
rack.input: #<StringIO:0x007f84131738d0>
rack.errors: #<IO:0x007f841306f420>
rack.multithread: true
rack.multiprocess: false
rack.run_once: false
rack.url_scheme: http
HTTP_VERSION: HTTP/1.1

REQUEST_PATH: /show_me_the_money

Thursday, January 17, 2013

instance.method(:split).source_location

Discover monkey-patched code by invoking source_location via IRB,
r = 'some string'
r.method(:split).source_location
 => nil # String.split method code is not monkey patched

Then, via IRB
r = 'some string'
class String
  def split(e)
    puts 'what?'
  end
end
r.method(:split).source_location
 => what?
 => ["(irb)", 38] # Now I know where the method lives!

Reference, The split is not enough whitespace shenanigans for rubyists



Tuesday, December 18, 2012

begin #dosomething rescue false end

I'm becoming a fan of the following Ruby code idiom, where a single line of code evaluates whether something is true or false.

def interrogative_function?(args)
    begin 1==1 rescue false end
end

Monday, December 3, 2012

Oracle Data Modeler, unsigned apps, and OSX Mountain Lion

I am loving this new macbook pro. As with any new computer, I've been installing most of the open source programs that I've gotten used to without a hitch. But today I came across an issue installing Oracle Data Modeler. The default security settings in OS/X 10.8 prevent installing unsigned apps and Oracle Data Modeler is one such unsigned app.

For all the noobs including me, the solution is to adjust the security settings in Apple's new Gatekeeper.

Here's a link to an explanation by that Jeff Smith => http://is.gd/Z8KuoO.

Saturday, June 23, 2012

Rails['2.0'..'3.x'].each do |learning|

I am porting an old RoR site I built in 2005/6 over to latest version of rails.

It took me days of effort to figure out why templates wouldn't render inside of the application layout.

It was b/c I was using <%= @content_for_layout %> in my application.html.erb file and it's been deprecated in favor of a simple <%= yield %>. #refactoring! hindsight is 20/20!

This script by John Nunemaker was useful for renaming my old view files from .erb to .html.erb.

Monday, February 22, 2010

reverse engineering and acts_as_state_machine

I started using railroad to help me understand (by way of reverse engineering) a complex system I'm working on.

I really like the fact that it generates .dot files which can be opened and manipulated using Omnigraffle, but it was failing on AASM due to complicated dependencies which I don't care to resolve.

Today I discovered that I can use ruby-graphviz to make pretty drawings of complex state machine events in my models. I highly recommend it.

Tuesday, November 3, 2009

Fresh Cucumber

I've been putting together a little project using Rspec and Cucumber. It's a way of coding called Behaviour Driven Development and I'm loving it.

Here is Aslak Hellesøy's excellent backgrounder on Cucumber: BDD that talks to domain experts first and code second

.

Thursday, September 10, 2009

API Changes

I decided to read the eBay API Developer Newsletter today and was reminded why this API can be difficult to work with. The reason is not because it is complex or difficult to master. It is because the API is constantly evolving (good), and often the evolutionary changes cause previous working code to fail (not good).

After glancing past the Developer Success Stories I found this valuable nugget:
The eBay API team is considering changing the case of the appinfo tags found in various wsdls—specifically, changing from upper to lowercase on the first letter only. For example, CallName could become callName, RequiredInput could become requiredInput, and MaxLength could become maxLength.
In stark contrast, a quote from the home page of rubyonrails.org:
Ruby on Rails is an open source web framework that's optimized for programmer happiness and sustainable productivity. It lets you write beautiful code by favoring convention over configuration.
Can an API be designed in such a way as to make programmers Happy and Productive?

.

Friday, July 31, 2009

country_select and my country of origin inflector method

Making use of the string class add-on that I developed at the recent Goruco conference.

I've put together a simple little app and a domain where some of the code is available to anyone who can use it.

Please contact me if you are interested any part of this.

Saturday, May 30, 2009

Extending the String class

Feeling inspired after 2009 Gotham Ruby Conference, I finally wrote this.

class String

def nationalize
# retrieve a full xml list of countries and attributes
# if string matches the country name on the list return the
# nationality of the goods that originate from that country
# may not be the most efficient way, but it sure is extensible
@xml = open('http://originify.us/originify.us.xml')
country = REXML::Document.new(@xml)
country.elements.each('/countries/country') do |p|
return p.attributes['nationality'] if self.to_s == p.text.to_s
end
# returns self or superclass
self || super
end

end

It's an extension of the String class. I wanted to present the idea at the Reject Conference session but I'm glad I didn't. There were about 10 reject presentations and some were really good.

The way it works is simple. Just take any text string and use the nationalize method on it. For example, "France".nationalize => "French", "Switzerland".nationalize => "Swiss", "Australia".nationalize => "Australian".

This could be useful. Suppose you are a clothing retailer and have data for sweater in your database. The sweater has been assigned the attributes "Wool" and originating from "Australia" or "Switzerland" using a dropdown.

In describing the sweater on a web site, one might want to say that it is made of Swiss Wool.

This could be refactored.

Friday, April 3, 2009

Take away the RAD tools, TDD and BDD may be the best way to ensure good specifications before commencing a project.

Tuesday, March 31, 2009

Ruby on Rails Inflector for Nationality

I've given myself until midnight to complete the task I wrote about on November 25th.

The idea is for a Ruby Gem that provides a nationalize method for the String Class.

Any country code would be nationalized by simply typing something akin to "France".nationalize => "French" likewise "US".nationalize => "American"

As soon as I found a list country codes... I also realized I wouldn't have enough time to write the code and Gemify it. So I started hacking away at an Environment.rb file.

That got me something like this:
class String
# list of countries derived from http://www.internetworldstats.com/list2.htm#af
def nationalize
{
:Afghanistan => "Afghani",
:Africa => "African",
:Albania => "Albanian",
:Algeria => "Algerian",
:Andorra => "Andorra",
:Angola => "Angolan",
:Anguilla => "Anguilla",
:Antarctica => "Antarctic",
...
}[self.gsub(/_id$/, "").to_sym] || super
end


I decided this was getting a little cumbersome. Especially when I realized that any country with a space (char(32)) or other odd character in the name would need to be typecast as a :symbol in order for my code to work.

Options:
1) Devise out a work around, or
2) Plug away at the entire list of 230+ ISO country names and code for the exceptions

Of course one would prefer a more elegant and flexible solution. Have only two choices seemed awkward. So I did a little bit more research and found an XML list of countries.

This enabled another option:
3) Modify an XML country list to include nationality adjectives.

Now that I've modified the XML country list the data can be parsed, utlized, and published however one sees fit, in any computer program.

This is a flexible solution and completely language agnostic. I like it that way.

While I was thinking about this, I registered the domain name http://originfy.us. I will upload the XML file that I created to that domain.

Tuesday, January 13, 2009

No more email campaigns for me

Today I taught my client how to send email blasts. It was a BLAST.

Tuesday, November 25, 2008

Write a nationality gem or plugin

This is just a reminder to self to write something that ties in with Ruby inflectors and the country_select helper.

Friday, November 14, 2008

Dirty numbers

/$#@!

This is a pretty basic programming concept but I haven't touched this blog in a while here we go...

Say you're working with numbers in a database field. Those numbers were keyed in by people using a different system, and the other system somehow stored non-numeric values in a numeric field.

Since Ruby does not have strong typing, an easy way to check and see if a field is an integer is to compare its integer value with its actual value.

if (somefield.to_i == somefield)

For example:
n = 1234567
if (n.to_i==n) => true

If the value of n is not keyed properly the equality test returns false
n = "12345x67"
if (n.to_i=="12345x67") => false

Easy!

Monday, March 24, 2008

Web site maintenance - global message

About once a week we upload and update all of the products in the database.

This intensive process takes about 15 minutes, during which time any pages that requires database access may time out.

There has to be a simple way to establish a "web site maintenance" message on the site while these processes run. Additionally cached pages need to be expired if they contain updated products.

I'm still working on a way to achieve this result.

Monday, February 25, 2008

SSL Plugin for Rails

I'm using the acts_as_authenticated plugin for ruby on rails.

Unforunately it falls short in a few key areas for an ecommerce site. An obvious one is that it does not ensure all login pages are SSL encrypted.

So I wrote the simple method (explained below) and put it in the application.rb file.

in application.rb...
def redirect_to_ssl

redirect_to :protocol => "https://" unless (request.ssl? or local_request? or request.server_port.to_i!=80)

end

The reason for the last check of the server port != 80 is twofold. First, if the server port is equal to 80 then I am probably running in production mode. However if the server port is not 80 then I am either running a development box, or I'm already on port 443. Ports 80 and 443 are the standard port used in HTTP and SSL.

Any time I want to ensure that a page is SSL encrypted, I put the following bit of code in my controller as a before_filter.

in my SSL protected controller...
class MySslController < ApplicationController

before_filter :redirect_to_ssl, :except => actions_that_do_not_require_ssl




Voila! (or "Wahla!" as we americans like to say) it works.

Friday, February 22, 2008

State abbreviations in a database

I use an excellent state_select Ruby plugin to generate nice looking dropdown lists for web pages.

Unfortunately this plugin uses full state names instead of abbeviations, both in the view and in the values that are submitted to the database.

I want
<option value="NY">New York

instead of
<option value="New York">New York

The change I want is easy to achieve by modifying /lib/state_select.rb

Comment out the values for US_STATES and add this bit of code instead. Note Puerto Rico and outlying territories have been omitted, since these are considered international locations in my program.
US_STATES=[
[ "Alabama", "AL" ],
[ "Alaska", "AK" ],
[ "Arizona", "AZ" ],
[ "Arkansas", "AR" ],
[ "California", "CA" ],
[ "Colorado", "CO" ],
[ "Connecticut", "CT" ],
[ "Delaware", "DE" ],
[ "District Of Columbia", "DC" ],
[ "Florida", "FL" ],
[ "Georgia", "GA" ],
[ "Hawaii", "HI" ],
[ "Idaho", "ID" ],
[ "Illinois", "IL" ],
[ "Indiana", "IN" ],
[ "Iowa", "IA" ],
[ "Kansas", "KS" ],
[ "Kentucky", "KY" ],
[ "Louisiana", "LA" ],
[ "Maine", "ME" ],
[ "Maryland", "MD" ],
[ "Massachusetts", "MA" ],
[ "Michigan", "MI" ],
[ "Minnesota", "MN" ],
[ "Mississippi", "MS" ],
[ "Missouri", "MO" ],
[ "Montana", "MT" ],
[ "Nebraska", "NE" ],
[ "Nevada", "NV" ],
[ "New Hampshire", "NH" ],
[ "New Jersey", "NJ" ],
[ "New Mexico", "NM" ],
[ "New York", "NY" ],
[ "North Carolina", "NC" ],
[ "North Dakota", "ND" ],
[ "Ohio", "OH" ],
[ "Oklahoma", "OK" ],
[ "Oregon", "OR" ],
[ "Pennsylvania", "PA" ],
[ "Rhode Island", "RI" ],
[ "South Carolina", "SC" ],
[ "South Dakota", "SD" ],
[ "Tennessee", "TN" ],
[ "Texas", "TX" ],
[ "Utah", "UT" ],
[ "Vermont", "VT" ],
[ "Virginia", "VA" ],
[ "Washington", "WA" ],
[ "West Virginia", "WV" ],
[ "Wisconsin", "WI" ],
[ "Wyoming", "WY" ] ] unless const_defined?("US_STATES")
But what happens to the data that has already started been saved with long unabbreviated state names? I need to update that too. I could have written a migration file to do this - but instead just used quick and dirty sql update statements.

This is the code that I used. It's very straightforward, but I'm posting it here anyway with the hope that someone can copy/paste it and save themself the hassle of writing 50+ updates from scratch.
update addresses set state = 'AL' where [state]= 'Alabama'
update addresses set state = 'AK' where [state]= 'Alaska'
update addresses set state = 'AZ' where [state]= 'Arizona'
update addresses set state = 'AR' where [state]= 'Arkansas'
update addresses set state = 'CA' where [state]= 'California'
update addresses set state = 'CO' where [state]= 'Colorado'
update addresses set state = 'CT' where [state]= 'Connecticut'
update addresses set state = 'DE' where [state]= 'Delaware'
update addresses set state = 'DC' where [state]= 'District Of Columbia'
update addresses set state = 'FL' where [state]= 'Florida'
update addresses set state = 'GA' where [state]= 'Georgia'
update addresses set state = 'HI' where [state]= 'Hawaii'
update addresses set state = 'ID' where [state]= 'Idaho'
update addresses set state = 'IL' where [state]= 'Illinois'
update addresses set state = 'IN' where [state]= 'Indiana'
update addresses set state = 'IA' where [state]= 'Iowa'
update addresses set state = 'KS' where [state]= 'Kansas'
update addresses set state = 'KY' where [state]= 'Kentucky'
update addresses set state = 'LA' where [state]= 'Louisiana'
update addresses set state = 'ME' where [state]= 'Maine'
update addresses set state = 'MD' where [state]= 'Maryland'
update addresses set state = 'MA' where [state]= 'Massachusetts'
update addresses set state = 'MI' where [state]= 'Michigan'
update addresses set state = 'MN' where [state]= 'Minnesota'
update addresses set state = 'MS' where [state]= 'Mississippi'
update addresses set state = 'MO' where [state]= 'Missouri'
update addresses set state = 'MT' where [state]= 'Montana'
update addresses set state = 'NE' where [state]= 'Nebraska'
update addresses set state = 'NV' where [state]= 'Nevada'
update addresses set state = 'NH' where [state]= 'New Hampshire'
update addresses set state = 'NJ' where [state]= 'New Jersey'
update addresses set state = 'NM' where [state]= 'New Mexico'
update addresses set state = 'NY' where [state]= 'New York'
update addresses set state = 'NC' where [state]= 'North Carolina'
update addresses set state = 'ND' where [state]= 'North Dakota'
update addresses set state = 'OH' where [state]= 'Ohio'
update addresses set state = 'OK' where [state]= 'Oklahoma'
update addresses set state = 'OR' where [state]= 'Oregon'
update addresses set state = 'PA' where [state]= 'Pennsylvania'
update addresses set state = 'RA' where [state]= 'Rhode Island'
update addresses set state = 'SC' where [state]= 'South Carolina'
update addresses set state = 'SD' where [state]= 'South Dakota'
update addresses set state = 'TN' where [state]= 'Tennessee'
update addresses set state = 'TX' where [state]= 'Texas'
update addresses set state = 'UT' where [state]= 'Utah'
update addresses set state = 'VT' where [state]= 'Vermont'
update addresses set state = 'VA' where [state]= 'Virginia'
update addresses set state = 'WA' where [state]= 'Washington'
update addresses set state = 'WV' where [state]= 'West Virginia'
update addresses set state = 'WI' where [state]= 'Wisconsin'
update addresses set state = 'WY' where [state]= 'Wyoming'

Visually impaired software development

This is my work blog.

I will present ideas (very) informally, as well as shortcuts and tips that I learn and use for application development.

Since working at Lighthouse International during 2006 and 2007 I have become enamored with Ruby as a programming language. Mainly I love the fact that it's open source, though I'm still using Microsoft SQL Server for the databased operations and have been happy with this database server for a long time.

The idea for Ruby on Braille came to me when as a team, we three developers, (Mike Hill, Rathnavel Kandaswami, and myself) were toying with the idea of building something new, a program that had never been built before. As is often the case with open source software there are a lot of free resources, but it can be hard to separate signal from noise and often as developers we must simply "roll our own" code, modify existing programs, and evaluate the effectiveness and reliability of free solutions.

So while I don't plan on offering any free solutions I will tell you about my experience as a software developer.

Tweets

Contributors