Skip to content

Instantly share code, notes, and snippets.

@alloy-d
Created May 25, 2011 06:04
Show Gist options
  • Save alloy-d/990435 to your computer and use it in GitHub Desktop.
Save alloy-d/990435 to your computer and use it in GitHub Desktop.
Programmer requests complete data from large number of people regarding T-shirt sales.
#!/usr/bin/env ruby
require 'net/smtp'
require 'time'
require 'yaml'
size_map = {
'S' => 'small',
'M' => 'medium',
'L' => 'large',
'XL' => 'extra large',
}
number_map = {
2 => 'two',
}
def wrap_text(s, width=72)
s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
end
if ARGV.length < 2 then
STDERR.puts "Give me an operation and a YAML file!"
exit(-1)
end
people = YAML.load_file ARGV[1]
verify = lambda do
people.each do |p|
shirt_string = ''
if not p['shirts'].nil? then
grammatical_items = p['shirts'].length
p['shirts'].each_with_index do |s, i|
quantity = (s['quantity'] if not s['quantity'].nil?) || 1
known = {
:size => (not s['size'].nil?),
:color => (not s['color'].nil?),
}
if quantity > 1 then
shirt_string += number_map[s['quantity']] + ' '
else
if grammatical_items > 1 then
shirt_string += 'one '
# Call me crazy, but explicitly saying "one" when
# someone only wants one shirt total seems really
# stiff and awkward, but it makes perfect sense
# if they want more than that...
elsif known[:size] and size_map[s['size']][0] == 'e' then
shirt_string += 'an '
else
shirt_string += 'a '
end
end
shirt_string += size_map[s['size']] + ' ' if known[:size]
shirt_string += s['color'] + ' ' if known[:color]
shirt_string += 'shirt'
shirt_string += 's' if quantity > 1
case
when (not known[:size] and not known[:color])
shirt_string += ' of unknown size and color'
when (not known[:size])
shirt_string += ' of unknown size'
when (not known[:color])
shirt_string += ' of unknown color'
end
if i < grammatical_items-1 then
if grammatical_items > 2 then
shirt_string += ', '
shirt_string += 'and ' if i == grammatical_items - 2
else
shirt_string += ' and '
end
end
end
else
shirt_string = 'a shirt'
end
out = p['given'] + ' ' + p['family'] + ' '
out += "<#{p['email']}> " if p['email']
out += 'wants ' + shirt_string + '.'
puts wrap_text(out) + "\n"
end
end
mail = lambda do
people.each do |p|
message = <<EOF
From: Adam Lloyd <[email protected]>
To: #{p['given']} #{p['family']} <#{p['email']}>
Subject: 2011 Congress of Jugglers T-shirts
Date: #{Time.now.rfc2822}
Hi, #{p['given']}!
We are putting together an order for more 2011 Congress shirts.
EOF
shirt_string = ''
unknown_string = ''
if not p['shirts'].nil? then
grammatical_items = p['shirts'].length
p['shirts'].each_with_index do |s, i|
quantity = (s['quantity'] if not s['quantity'].nil?) || 1
known = {
:size => (not s['size'].nil?),
:color => (not s['color'].nil?),
}
if quantity > 1 then
shirt_string += number_map[s['quantity']] + ' '
else
if grammatical_items > 1 then
shirt_string += 'one '
# Call me crazy, but explicitly saying "one" when
# someone only wants one shirt total seems really
# stiff and awkward, but it makes perfect sense
# if they want more than that...
elsif known[:size] and size_map[s['size']][0] == 'e' then
shirt_string += 'an '
else
shirt_string += 'a '
end
end
shirt_string += size_map[s['size']] + ' ' if known[:size]
shirt_string += s['color'] + ' ' if known[:color]
shirt_string += 'shirt'
shirt_string += 's' if quantity > 1
case
when (not known[:size] and not known[:color])
if (quantity == 1) then
unknown_string += 'size and color'
else
unknown_string += 'sizes and colors'
end
when (not known[:size])
unknown_string += 'size'
when (not known[:color])
unknown_string += 'color'
end
if i < grammatical_items-1 then
if grammatical_items > 2 then
shirt_string += ', '
shirt_string += 'and ' if i == grammatical_items - 2
else
shirt_string += ' and '
end
end
end
else
shirt_string = 'a shirt'
unknown_string = 'size and color'
end
if unknown_string != '' then
message += wrap_text <<EOF
At Congress, you signed up for #{shirt_string}, but we need to know what #{unknown_string} you'd like.
EOF
else
message += wrap_text <<EOF
At Congress, you signed up for #{shirt_string}. I'd just like to make sure this is correct before we send off the order.
EOF
end
message += "\n"
message += wrap_text <<EOF
If you'd like to take another look at the shirts, there are pictures available at <http://studentorg.umd.edu/juggling/congress/2011/#shirts>.
EOF
message += "\n" + <<EOF
Thank you!
-Adam Lloyd, UMD Juggling Club
EOF
if (not p['email'].nil?) then
Net::SMTP.start('127.0.0.1', 25) do |smtp|
smtp.send_message(message,
'[email protected]',
p['email'])
end
else
STDERR.puts "#{p['given']} #{p['family']} has no email address!"
end
end
end
if ARGV[0] == "verify" then
verify.call
elsif ARGV[0] == "mail" then
mail.call
end
- given: John
family: Example
email: [email protected]
shirts:
- color: brown
size: M
- color: blue
size: S
quantity: 2
@briandk
Copy link

briandk commented Jun 7, 2011

I like the idea of this. But since

  1. I'm on my iPad and
  2. I'm new to ruby

I can't quite tell what this looks like when it's user-facing. I note, though, that lines 153--156 suggest you're going four levels deep in abstraction. That seems like a lot; like this code is crying out for being broken into smaller utility methods whose individual responsibilities are clearer.

@briandk
Copy link

briandk commented Jun 7, 2011

Also, it seems you tried to be robust and build code to handle "unknown size" and "unknown color." have you written any tests for this?

@alloy-d
Copy link
Author

alloy-d commented Jun 8, 2011

Given the amount of data that needs to be passed around to make sure that sentences are composed to be grammatically correct (or even sensible), "smaller utility methods" would (I think) do more to clutter up the code than make it clearer.

Also, the goal of this is just to get emails out to people. Adding code for "unknown size" and "unknown color" isn't just some goofy attempt at robustness, it's necessary code to account for the fact that, astoundingly, not everyone who wants a shirt supplies the information required to get one. (But to answer your question, the "test" is the actual list of shirt requests, in combination with my proofreading of the final emails.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment