Module: MitStalker
- Defined in:
- lib/mit_stalker.rb
Overview
Fetch publicly available information about MIT students.
Class Attribute Summary collapse
-
.finger_timeout ⇒ Object
The number of seconds to wait for a finger result.
Class Method Summary collapse
-
.finger(request, host) ⇒ Object
Issues a finger request to a server.
-
.flip_full_name(name) ⇒ Object
Flips an official full-name (e.g. Costan, Victor-Marius) to its normal form.
-
.from_user_name(user_name, finger_timeout = 10) ⇒ Object
Retrieves information about an MIT student from an Athena username.
-
.full_name_from_user_name(user_name) ⇒ Object
Retrieves an MIT student’s full name, based on the Athena username.
-
.name_vector(name) ⇒ Object
Computes a name vector from a full name.
-
.parse_mitdir_response(response) ⇒ Object
Parses a MIT directory response into users.
-
.refine_mitdir_response_by_email(users, user_name) ⇒ Object
Narrows down a MIT directory response to a single user.
-
.refine_mitdir_response_by_name(users, full_name) ⇒ Object
Narrows down a MIT directory response to a single user.
Class Attribute Details
.finger_timeout ⇒ Object
The number of seconds to wait for a finger result.
11 12 13 |
# File 'lib/mit_stalker.rb', line 11 def finger_timeout @finger_timeout end |
Class Method Details
.finger(request, host) ⇒ Object
Issues a finger request to a server.
Returns a string containing the finger response, or nil if something went wrong.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/mit_stalker.rb', line 19 def self.finger(request, host) begin Timeout.timeout(self.finger_timeout) do client = TCPSocket.open host, 'finger' client.send request + "\n", 0 # 0 means standard packet result = client.readlines.join client.close return result end rescue Timeout::Error return nil rescue return nil end end |
.flip_full_name(name) ⇒ Object
Flips an official full-name (e.g. Costan, Victor-Marius) to its normal form.
123 124 125 |
# File 'lib/mit_stalker.rb', line 123 def self.flip_full_name(name) name.split(',', 2).map(&:strip).reverse.join(' ') end |
.from_user_name(user_name, finger_timeout = 10) ⇒ Object
Retrieves information about an MIT student from an Athena username.
Returns a hash containing user information, or nil if the user was not found.
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/mit_stalker.rb', line 131 def self.from_user_name(user_name, finger_timeout=10) user_name = user_name.downcase full_name = full_name_from_user_name user_name if full_name users = parse_mitdir_response finger(full_name, 'mitdir.mit.edu') else users = [] end if users.empty? users = parse_mitdir_response finger(user_name, 'mitdir.mit.edu') end user = refine_mitdir_response_by_name(users, full_name) if full_name user = refine_mitdir_response_by_email(users, user_name) unless user return nil unless user user.merge :full_name => (full_name || flip_full_name(user[:name])) end |
.full_name_from_user_name(user_name) ⇒ Object
Retrieves an MIT student’s full name, based on the Athena username.
Returns a string containing the full name, or nil if the Athena username is not recognized.
40 41 42 43 44 45 |
# File 'lib/mit_stalker.rb', line 40 def self.full_name_from_user_name(user_name) athena_data = finger user_name.downcase, 'athena.dialup.mit.edu' return nil if athena_data.nil? match = /(N|n)ame\: (.*)$/.match athena_data match and match[2].strip end |
.name_vector(name) ⇒ Object
Computes a name vector from a full name.
The same name, in different formats, should yield the same vector. Different names should yield different vectors.
77 78 79 |
# File 'lib/mit_stalker.rb', line 77 def self.name_vector(name) name.gsub(/\W/, ' ').gsub(/ +/, ' ').split.sort end |
.parse_mitdir_response(response) ⇒ Object
Parses a MIT directory response into users.
Returns a (possibly empty) array of hashes, with one hash per user. A hash has the directory information for the user, using symbols as keys, e.g. => ‘Victor Costan’, :year => ‘1’
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/mit_stalker.rb', line 52 def self.parse_mitdir_response(response) return [] if response.nil? lines = response.split("\r\n").reverse users = [] user = {} lines.each do |line| if line.empty? users << user unless user.empty? user = {} next end match = /([^:]*):(.+)/.match line break unless match user[match[1].strip.downcase.gsub(' ', '_').to_sym] = match[2].strip end users end |
.refine_mitdir_response_by_email(users, user_name) ⇒ Object
Narrows down a MIT directory response to a single user.
Returns a single user information hash, or nil if no user has the given e-mail.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/mit_stalker.rb', line 103 def self.refine_mitdir_response_by_email(users, user_name) user_name = user_name.downcase users.each do |user| if user[:email] next unless user[:email].split('@').first.downcase == user_name users = parse_mitdir_response finger(user[:alias], 'mitdir.mit.edu') return users && users.first else users = parse_mitdir_response finger(user[:alias], 'mitdir.mit.edu') next unless users user = users.first if user[:email] and user[:email].split('@').first == user_name return user end end end nil end |
.refine_mitdir_response_by_name(users, full_name) ⇒ Object
Narrows down a MIT directory response to a single user.
Returns a single user information hash, or nil if no user has the given full name.
85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/mit_stalker.rb', line 85 def self.refine_mitdir_response_by_name(users, full_name) vector = name_vector(full_name) user_base_info = users.find { |user| name_vector(user[:name]) == vector } return nil unless user_base_info # Don't make an extra request for the same info. return users.first if users.length == 1 # Requesting by alias should return a single name. users = parse_mitdir_response finger(user_base_info[:alias], 'mitdir.mit.edu') users and users.first end |