Chris@0: # $Id: entry.rb 123 2006-05-18 03:52:38Z blackhedd $ Chris@0: # Chris@0: # LDAP Entry (search-result) support classes Chris@0: # Chris@0: # Chris@0: #---------------------------------------------------------------------------- Chris@0: # Chris@0: # Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved. Chris@0: # Chris@0: # Gmail: garbagecat10 Chris@0: # Chris@0: # This program is free software; you can redistribute it and/or modify Chris@0: # it under the terms of the GNU General Public License as published by Chris@0: # the Free Software Foundation; either version 2 of the License, or Chris@0: # (at your option) any later version. Chris@0: # Chris@0: # This program is distributed in the hope that it will be useful, Chris@0: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@0: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@0: # GNU General Public License for more details. Chris@0: # Chris@0: # You should have received a copy of the GNU General Public License Chris@0: # along with this program; if not, write to the Free Software Chris@0: # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Chris@0: # Chris@0: #--------------------------------------------------------------------------- Chris@0: # Chris@0: Chris@0: Chris@0: Chris@0: Chris@0: module Net Chris@0: class LDAP Chris@0: Chris@0: Chris@0: # Objects of this class represent individual entries in an LDAP Chris@0: # directory. User code generally does not instantiate this class. Chris@0: # Net::LDAP#search provides objects of this class to user code, Chris@0: # either as block parameters or as return values. Chris@0: # Chris@0: # In LDAP-land, an "entry" is a collection of attributes that are Chris@0: # uniquely and globally identified by a DN ("Distinguished Name"). Chris@0: # Attributes are identified by short, descriptive words or phrases. Chris@0: # Although a directory is Chris@0: # free to implement any attribute name, most of them follow rigorous Chris@0: # standards so that the range of commonly-encountered attribute Chris@0: # names is not large. Chris@0: # Chris@0: # An attribute name is case-insensitive. Most directories also Chris@0: # restrict the range of characters allowed in attribute names. Chris@0: # To simplify handling attribute names, Net::LDAP::Entry Chris@0: # internally converts them to a standard format. Therefore, the Chris@0: # methods which take attribute names can take Strings or Symbols, Chris@0: # and work correctly regardless of case or capitalization. Chris@0: # Chris@0: # An attribute consists of zero or more data items called Chris@0: # values. An entry is the combination of a unique DN, a set of attribute Chris@0: # names, and a (possibly-empty) array of values for each attribute. Chris@0: # Chris@0: # Class Net::LDAP::Entry provides convenience methods for dealing Chris@0: # with LDAP entries. Chris@0: # In addition to the methods documented below, you may access individual Chris@0: # attributes of an entry simply by giving the attribute name as Chris@0: # the name of a method call. For example: Chris@0: # ldap.search( ... ) do |entry| Chris@0: # puts "Common name: #{entry.cn}" Chris@0: # puts "Email addresses:" Chris@0: # entry.mail.each {|ma| puts ma} Chris@0: # end Chris@0: # If you use this technique to access an attribute that is not present Chris@0: # in a particular Entry object, a NoMethodError exception will be raised. Chris@0: # Chris@0: #-- Chris@0: # Ugly problem to fix someday: We key off the internal hash with Chris@0: # a canonical form of the attribute name: convert to a string, Chris@0: # downcase, then take the symbol. Unfortunately we do this in Chris@0: # at least three places. Should do it in ONE place. Chris@0: class Entry Chris@0: Chris@0: # This constructor is not generally called by user code. Chris@0: def initialize dn = nil # :nodoc: Chris@0: @myhash = Hash.new {|k,v| k[v] = [] } Chris@0: @myhash[:dn] = [dn] Chris@0: end Chris@0: Chris@0: Chris@0: def []= name, value # :nodoc: Chris@0: sym = name.to_s.downcase.intern Chris@0: @myhash[sym] = value Chris@0: end Chris@0: Chris@0: Chris@0: #-- Chris@0: # We have to deal with this one as we do with []= Chris@0: # because this one and not the other one gets called Chris@0: # in formulations like entry["CN"] << cn. Chris@0: # Chris@0: def [] name # :nodoc: Chris@0: name = name.to_s.downcase.intern unless name.is_a?(Symbol) Chris@0: @myhash[name] Chris@0: end Chris@0: Chris@0: # Returns the dn of the Entry as a String. Chris@0: def dn Chris@0: self[:dn][0] Chris@0: end Chris@0: Chris@0: # Returns an array of the attribute names present in the Entry. Chris@0: def attribute_names Chris@0: @myhash.keys Chris@0: end Chris@0: Chris@0: # Accesses each of the attributes present in the Entry. Chris@0: # Calls a user-supplied block with each attribute in turn, Chris@0: # passing two arguments to the block: a Symbol giving Chris@0: # the name of the attribute, and a (possibly empty) Chris@0: # Array of data values. Chris@0: # Chris@0: def each Chris@0: if block_given? Chris@0: attribute_names.each {|a| Chris@0: attr_name,values = a,self[a] Chris@0: yield attr_name, values Chris@0: } Chris@0: end Chris@0: end Chris@0: Chris@0: alias_method :each_attribute, :each Chris@0: Chris@0: Chris@0: #-- Chris@0: # Convenience method to convert unknown method names Chris@0: # to attribute references. Of course the method name Chris@0: # comes to us as a symbol, so let's save a little time Chris@0: # and not bother with the to_s.downcase two-step. Chris@0: # Of course that means that a method name like mAIL Chris@0: # won't work, but we shouldn't be encouraging that Chris@0: # kind of bad behavior in the first place. Chris@0: # Maybe we should thow something if the caller sends Chris@0: # arguments or a block... Chris@0: # Chris@0: def method_missing *args, &block # :nodoc: Chris@0: s = args[0].to_s.downcase.intern Chris@0: if attribute_names.include?(s) Chris@0: self[s] Chris@0: elsif s.to_s[-1] == 61 and s.to_s.length > 1 Chris@0: value = args[1] or raise RuntimeError.new( "unable to set value" ) Chris@0: value = [value] unless value.is_a?(Array) Chris@0: name = s.to_s[0..-2].intern Chris@0: self[name] = value Chris@0: else Chris@0: raise NoMethodError.new( "undefined method '#{s}'" ) Chris@0: end Chris@0: end Chris@0: Chris@0: def write Chris@0: end Chris@0: Chris@0: end # class Entry Chris@0: Chris@0: Chris@0: end # class LDAP Chris@0: end # module Net Chris@0: Chris@0: