Maybe some of you know that I am planning to get marry the next year. If not know you know =).
Well maybe is not your case, but for me and my fiancee it has not been so easy to decide who we will invite to our wedding. Mainly because we have a limited number of people to invite and because we also have friends and family that are that live in different states or outside the country that maybe will not attend.
Because I am to geek to make this work in excel, I decided to build a little program that will help with our decision. Well I am also to geek to make the program just once, so I build it two times with two different “styles”.
I will share the two programs here. So you can use the one that you like the most (or just read them).
One of the things that I wanted was the ability to enter the names of the people in and easy way. I think the easiest way form me to enter the data is using my editor, VIM =). Thats why the way to enter the data is with a ruby data structure like in the next example.
GROUPS = {
# each hash key is the a group name that will have an array of "families" o invitations
"Familia Sandoval" => [
["pepe", "ilia", "daniel"], # each invitation or family
["abuelita"], # a family or invitation can have just one member
["alan", "norely"]
#....
],
"Friends" => [
["chuy", "sonia"],
["cheo", "silvia"],
["alejandro", "bety"],
["miguel", "mireya"],
]
#....
}
You can enter the data with a hash called GROUPS, where each key is the name of the group, for example “Work Friends”, “Family”, “School Friends”, etc.
With this info you will get a report with the total number of people, the total number of invitations and the total number of tables (I am expecting that a table has 10 places).
But the cool part (or at least the cool part for me) is that you can also filter “families” and also get some numbers about them.
You have two filters, :remove
, that I am using for the “families” that maybe
I will not invite because I have not enough places, and :will_not_go
for “families” that I find very hard that they can attend.
You can use these filters in the next way..
GROUPS = {
"Familia Sandoval" => [
[:remove, "pepe", "ilia", "daniel"],
["abuelita"],
[:will_not_go, "alan", "norely"]
#....
],
#....
}
With these filters you will get data about the number of people, tables
and invitations that you have :removed
or that :will_not_go
.
GROUPS = {} # Define your groups here
module All
def self.people_count
GROUPS.values.map { |group| Group.people_count(group) }.reduce(:+)
end
def self.families_count
GROUPS.values.map { |group| Group.families_count(group) }.reduce(:+)
end
def self.tables_count
GROUPS.values.map { |group| Group.tables_count(group) }.reduce(:+).ceil
end
end
module Group
def self.original_people_count(group)
group.map { |family| Family.members_count(family) }.reduce(:+)
end
def self.removed_people_count(group)
removed_families(group).map { |family| Family.members_count(family) }.reduce(0, :+)
end
def self.will_not_go_people_count(group)
will_not_go_families(group).map { |family| Family.members_count(family) }.reduce(0, :+)
end
def self.people_count(group)
original_people_count(group) - removed_people_count(group) - will_not_go_people_count(group)
end
def self.original_families_count(group)
group.count
end
def self.removed_families_count(group)
removed_families(group).count
end
def self.will_not_go_families_count(group)
will_not_go_families(group).count
end
def self.families_count(group)
original_families_count(group) - removed_families_count(group) - will_not_go_families_count(group)
end
def self.removed_families(group)
group.select { |family| Family.removed?(family) }
end
def self.will_not_go_families(group)
group.select { |family| Family.will_not_go?(family) }
end
def self.removed_families?(group)
removed_families(group).any? || will_not_go_families(group).any?
end
def self.original_tables_count(group)
original_people_count(group) / 10.0
end
def self.removed_tables_count(group)
removed_people_count(group) / 10.0
end
def self.will_not_go_tables_count(group)
will_not_go_people_count(group) / 10.0
end
def self.tables_count(group)
people_count(group) / 10.0
end
end
module Family
def self.removed?(family)
family.first == :remove
end
def self.will_not_go?(family)
family.first == :will_not_go
end
def self.members_count(family)
family.reject { |member| [:remove, :will_not_go].include?(member) }.count
end
end
puts ""
puts ""
puts ""
puts "---------------------------"
puts "---- Invitados Boduqui ----"
puts "---------------------------"
puts ""
puts ""
GROUPS.each do |name, group|
puts "#{name}"
if Group.removed_families?(group)
puts " - Total original de personas: #{Group.original_people_count(group)}"
puts " - Total de personas removidas: #{Group.removed_people_count(group)}"
puts " - Total de personas removidas porque no asistiran: #{Group.will_not_go_people_count(group)}"
puts " -------------------------------------------------"
puts " - Total de personas: #{Group.people_count(group)}"
puts ""
puts " - Total original de mesas: #{Group.original_tables_count(group)}"
puts " - Total de mesas removidas: #{Group.removed_tables_count(group)}"
puts " - Total de mesas removidas porque no asistiran: #{Group.will_not_go_tables_count(group)}"
puts " -----------------------------------------------"
puts " - Total de mesas: #{Group.tables_count(group)}"
puts ""
puts " - Total original de invitaciones: #{Group.original_families_count(group)}"
puts " - Total de invitaciones removidas: #{Group.removed_families_count(group)}"
puts " - Total de invitaciones removidas porque no asistiran: #{Group.will_not_go_families_count(group)}"
puts " ------------------------------------------------------"
puts " - Total de invitaciones: #{Group.families_count(group)}"
else
puts " - Total de personas: #{Group.people_count(group)}"
puts " - Total de invitaciones: #{Group.families_count(group)}"
puts " - Total de mesas: #{Group.tables_count(group)}"
end
puts ""
end
puts "Total"
puts "-----"
puts " - Numero total de personas: #{All.people_count}"
puts " - Numero total de invitaciones: #{All.families_count}"
puts " - Numero total de mesas: #{All.tables_count}"
puts ""
puts ""
GROUPS = {} # Define your groups here
module Groups
def self.build(data)
Groups.new(GROUPS.map { |name, families|
Group.new(name, families.map { |family_data|
Family.new(family_data)
})
})
end
class Groups
include Enumerable
def initialize(all)
@all = all
end
def each(&block)
all.each(&block)
end
def people_count
all.map { |group| group.expected.people_count }.reduce(:+)
end
def tables_count
all.map { |group| group.expected.tables_count }.reduce(:+)
end
def families_count
all.map { |group| group.expected.families_count }.reduce(:+)
end
private
attr_reader :all
end
class Group
attr_reader :name, :original
def initialize(name, original)
@name = name
@original = Families.new(original)
end
def has_removed?
removed.any? || will_not_go.any?
end
def removed
Families.new(original.select(&:removed?))
end
def will_not_go
Families.new(original.select(&:will_not_go?))
end
def expected
Families.new(original.reject(&:removed?).reject(&:will_not_go?))
end
end
class Families
include Enumerable
def initialize(all)
@all = all
end
def each(&block)
all.each(&block)
end
def people_count
all.map(&:members).reduce(0, :+)
end
def families_count
all.count
end
def tables_count
people_count / 10.0
end
private
attr_reader :all
end
class Family
def initialize(data)
@data = data
end
def removed?
data.first == :remove
end
def will_not_go?
data.first == :will_not_go
end
def members
data.reject { |member| [:remove, :will_not_go].include?(member) }.count
end
private
attr_reader :data
end
end
puts ""
puts ""
puts ""
puts "---------------------------"
puts "---- Invitados Boduqui ----"
puts "---------------------------"
puts ""
puts ""
groups = Groups.build(GROUPS)
groups.each do |group|
puts "#{group.name}"
if group.has_removed?
puts " - Total original de personas: #{group.original.people_count}"
puts " - Total de personas removidas: #{group.removed.people_count}"
puts " - Total de personas removidas porque no asistiran: #{group.will_not_go.people_count}"
puts " -------------------------------------------------"
puts " - Total de personas: #{group.expected.people_count}"
puts ""
puts " - Total original de mesas: #{group.original.tables_count}"
puts " - Total de mesas removidas: #{group.removed.tables_count}"
puts " - Total de mesas removidas porque no asistiran: #{group.will_not_go.tables_count}"
puts " -----------------------------------------------"
puts " - Total de mesas: #{group.expected.tables_count}"
puts ""
puts " - Total original de invitaciones: #{group.original.families_count}"
puts " - Total de invitaciones removidas: #{group.removed.families_count}"
puts " - Total de invitaciones removidas porque no asistiran: #{group.will_not_go.families_count}"
puts " ------------------------------------------------------"
puts " - Total de invitaciones: #{group.expected.families_count}"
else
puts " - Total de personas: #{group.expected.people_count}"
puts " - Total de invitaciones: #{group.expected.families_count}"
puts " - Total de mesas: #{group.expected.tables_count}"
end
puts ""
end
puts "Total"
puts "-----"
puts " - Numero total de personas: #{groups.people_count}"
puts " - Numero total de invitaciones: #{groups.families_count}"
puts " - Numero total de mesas: #{groups.tables_count}"
puts ""
puts ""
I am sorry because the output is in spanish… But if for some weird reason you actually use this program and you don’t speak spanish I hope you can understand it with the help of google translate or the names of the variables =).
Also if for some weird reason you are reading this =) and you have an opinion about which option is better. I will be very happy if you comment which option you prefer and why.
I send an email each week, trying to share knowledge and fixes to common problems and struggles for ruby on rails developers, like How to fetch the latest-N-of-each record or How to test that an specific mail was sent or a Capybara cheatsheet. You can see more examples on Most recent posts or All post by topic.