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