[SOLUTION] Secret Santas (#2)

A

Ara.T.Howard

this solution parses stdin or an input file. the input may contain blank line
and comments. the input is first hashed last name -> first name -> email
using the Family class. next a Family::GiftPool for the current state of the
Family class is created and all families and their members iterated over; the
pool's 'draw_name' method randomly choses a santa not in the same family and
not the same person - the selection is destructive, meaning after someone has
been chosen they can no longer be chosen again. this method requires one pass
over the data (not counting the copy) and no sorting. mailing also included.



#!/usr/bin/env ruby
require 'net/smtp'

class EmailList < Array
#{{{
def initialize port
#{{{
buf =
if port.respond_to? 'read'
port.read
else
"#{ port }"
end
parse_buf buf
#}}}
end
def parse_buf buf
#{{{
buf.each do |line|
line.gsub! %r/^\s*|\s*$|#.*$/, ''
next if line.empty?
name, address = line.split %r/[<>]/
raise "syntax error in <#{ line }>" unless
name and address
tokens = name.strip.split %r/\s+/
last, first = tokens.pop, tokens.join(' ')
name = [first, last]
self << [name, address]
end
#}}}
end
#}}}
end
class Family < Hash
#{{{
class << self
#{{{
def families last = nil
#{{{
@families ||= {}
if last
@families[last] ||=
Hash::new{|h,last| h[last] ||= Family::new}
else
@families
end
#}}}
end
alias [] families
def each(*a, &b); families.each(*a, &b); end
def gift_pool; GiftPool::new families; end
#}}}
end
class GiftPool
#{{{
def initialize families
#{{{
@pool = Hash::new{|h,k| h[k] = Hash::new}
families.each do |last, members|
members.each do |first, email|
@pool[last][first] = email
end
end
#}}}
end
def draw_name last, first
#{{{
not_in_family = @pool.keys - [last]
family = not_in_family[rand(not_in_family.size)]

members = @pool[family].keys - [first]
member = members[rand(members.size)]

name = [family, member]
email = @pool[family][member]
santa = [name, email]

@pool[family].delete member
@pool.delete family if @pool[family].empty?

santa
#}}}
end
#}}}
end
#}}}
end
module Mailer
#{{{
def self.mail msg, to, from, opts = {}
#{{{
Net::SMTP.start('localhost') do |smtp|
email = ''
opts.each do |k, v|
email << "#{ k.capitalize }: #{ v }\r\n"
end
email << "\r\n#{ msg }"
smtp.send_message email, from, to
end
#}}}
end
#}}}
end


port = (ARGV.empty? ? STDIN : open(ARGV.shift))

list = EmailList::new port

list.each do |name, email|
Family[name.last][name.first] = email
end

gift_pool = Family.gift_pool

Family.each do |last, members|
members.each do |first, email|
santa = gift_pool.draw_name last, first
sname, semail = santa
msg = "you are the secret santa for <#{ sname.join ', ' }>"
Mailer::mail msg, email, nil, 'subject' => 'secret santa'
end
end


-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
B

Brian Schröder

Ara.T.Howard said:
class EmailList < Array
#{{{
[snip]
#}}}
end

hello Ara,

Just out of interest, please do not understand this as an offence:
to which end are you using all those #{{{ comments? Is it to make your
editor understand indentation, or what is its purpose?

Regards,

Brian
 
A

Ara.T.Howard

Ara.T.Howard said:
class EmailList < Array
#{{{
[snip]
#}}}
end

hello Ara,

Just out of interest, please do not understand this as an offence:
to which end are you using all those #{{{ comments? Is it to make your
editor understand indentation, or what is its purpose?

vim is a folding editor. everything inbetween the markers appear as one line
as something like

+-- 3 lines: >> --------------------------------------------

in otherwords each class in my solution looks, to me, as

class Foo
+-- n lines: >> ------------
end

and each method likewise. if you don't use folding i highly reccomend it -
folds can be cut, pasted, operated on, etc. and, of course, it makes 10,000
source file a breeze to navigate.

cheers.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
A

Anders Engström

Ara.T.Howard said:
class EmailList < Array
#{{{
[snip]
#}}}
end

hello Ara,

Just out of interest, please do not understand this as an offence:
to which end are you using all those #{{{ comments? Is it to make your
editor understand indentation, or what is its purpose?

vim is a folding editor. everything inbetween the markers appear as one
line
as something like

+-- 3 lines: >> --------------------------------------------

in otherwords each class in my solution looks, to me, as

class Foo
+-- n lines: >> ------------
end

and each method likewise. if you don't use folding i highly reccomend it -
folds can be cut, pasted, operated on, etc. and, of course, it makes 10,000
source file a breeze to navigate.

That's neat. Would you care to share the relevant lines from your
vimrc?

Best Regards //Anders
 
B

Brian Schröder

Ara.T.Howard said:
class EmailList < Array
#{{{
[snip]
#}}}
end


hello Ara,

Just out of interest, please do not understand this as an offence:
to which end are you using all those #{{{ comments? Is it to make your
editor understand indentation, or what is its purpose?


vim is a folding editor. everything inbetween the markers appear as one
line
as something like

+-- 3 lines: >> --------------------------------------------

in otherwords each class in my solution looks, to me, as

class Foo
+-- n lines: >> ------------
end

and each method likewise. if you don't use folding i highly reccomend it -
folds can be cut, pasted, operated on, etc. and, of course, it makes
10,000
source file a breeze to navigate.

cheers.

-a
--
===============================================================================

| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it. | --Dogen
===============================================================================
Ahh,

thanks for the pointer. I found the same for xemacs. But I think I
personally like hide-show better. Entering this additional comments seem
like too much work to me.

Regards,

Brian
 
A

Ara.T.Howard

That's neat. Would you care to share the relevant lines from your
vimrc?

set foldmethod=marker
set commentstring=#%s

to use: highlight visually using 'shift-v' and motion keys then type

z-f -> fold create
z-o -> fold open
z-c -> fold close
z-d -> fold delete

all the fold command start with z because it looks like a fold ;-)

if you add those settings and open my script you'll see how it works quickly -
because the folds are marked they come up folded.

cheers.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
A

Ara.T.Howard

thanks for the pointer. I found the same for xemacs. But I think I
personally like hide-show better. Entering this additional comments seem
like too much work to me.

but then they are lost when you close the file... if they are 'marked' they
are restored on open.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
G

Gavin Sinclair

but then they are lost when you close the file... if they are 'marked' they
are restored on open.

Isn't it possible to fold based on syntax/indentation, thus getting
automatic Ruby folding without special markers?

Gavin
 
A

Ara.T.Howard

Isn't it possible to fold based on syntax/indentation, thus getting
automatic Ruby folding without special markers?

set foldmethod=syntax

it folds like mad though.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
A

Ara.T.Howard

On Tuesday, October 5, 2004, 7:44:53 AM, Ara wrote:

On Tue, 5 Oct 2004, [UTF-8] Brian Schröder wrote:

thanks for the pointer. I found the same for xemacs. But I think I
personally like hide-show better. Entering this additional comments seem
like too much work to me.

but then they are lost when you close the file... if they are 'marked'they
are restored on open.

Isn't it possible to fold based on syntax/indentation, thus getting
automatic Ruby folding without special markers?
set foldmethod=syntax
it folds like mad though.

Can you impose limits on the madness?

set foldlevel=n

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top