treequel 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +163 -76
- data/History.rdoc +11 -0
- data/README.rdoc +14 -16
- data/Rakefile +6 -1
- data/bin/treequel +4 -10
- data/bin/treewhat +2 -4
- data/lib/treequel/branch.rb +49 -163
- data/lib/treequel/branchcollection.rb +11 -16
- data/lib/treequel/branchset.rb +24 -17
- data/lib/treequel/control.rb +8 -6
- data/lib/treequel/controls/contentsync.rb +2 -2
- data/lib/treequel/controls/pagedresults.rb +1 -10
- data/lib/treequel/directory.rb +36 -78
- data/lib/treequel/exceptions.rb +1 -2
- data/lib/treequel/filter.rb +3 -8
- data/lib/treequel/mixins.rb +2 -7
- data/lib/treequel/model/errors.rb +1 -4
- data/lib/treequel/model/objectclass.rb +14 -26
- data/lib/treequel/model.rb +18 -64
- data/lib/treequel/monkeypatches.rb +2 -3
- data/lib/treequel/schema/attributetype.rb +0 -5
- data/lib/treequel/schema/objectclass.rb +9 -27
- data/lib/treequel/schema.rb +1 -18
- data/lib/treequel/utils.rb +0 -3
- data/lib/treequel.rb +48 -75
- data/spec/treequel/branchset_spec.rb +24 -0
- data/spec/treequel/monkeypatches_spec.rb +9 -9
- data.tar.gz.sig +0 -0
- metadata +27 -27
- metadata.gz.sig +1 -3
    
        data/lib/treequel/branch.rb
    CHANGED
    
    | @@ -53,11 +53,6 @@ class Treequel::Branch | |
| 53 53 |  | 
| 54 54 |  | 
| 55 55 | 
             
            	### Create a new Treequel::Branch from the given +entry+ hash from the specified +directory+.
         | 
| 56 | 
            -
            	### 
         | 
| 57 | 
            -
            	### @param [LDAP::Entry] entry  The raw entry object the Branch is wrapping.
         | 
| 58 | 
            -
            	### @param [Treequel::Directory] directory  The directory object the Branch is from.
         | 
| 59 | 
            -
            	### 
         | 
| 60 | 
            -
            	### @return [Treequel::Branch]  The new branch object.
         | 
| 61 56 | 
             
            	def self::new_from_entry( entry, directory )
         | 
| 62 57 | 
             
            		entry = Treequel::HashUtilities.stringify_keys( entry )
         | 
| 63 58 | 
             
            		dnvals = entry.delete( 'dn' ) or
         | 
| @@ -77,10 +72,6 @@ class Treequel::Branch | |
| 77 72 | 
             
            	### If the optional +entry+ object is given, it will be used to fetch values from the 
         | 
| 78 73 | 
             
            	### directory; if it isn't provided, it will be fetched from the +directory+ the first
         | 
| 79 74 | 
             
            	### time it is needed.
         | 
| 80 | 
            -
            	### 
         | 
| 81 | 
            -
            	### @param [Treequel::Directory] directory  The directory the Branch belongs to.
         | 
| 82 | 
            -
            	### @param [String] dn  The DN of the entry the Branch is wrapping.
         | 
| 83 | 
            -
            	### @param [LDAP::Entry, Hash] entry  The entry object if it's already been fetched.
         | 
| 84 75 | 
             
            	def initialize( directory, dn, entry=nil )
         | 
| 85 76 | 
             
            		raise ArgumentError, "nil DN" unless dn
         | 
| 86 77 | 
             
            		raise ArgumentError, "invalid DN" unless
         | 
| @@ -111,11 +102,9 @@ class Treequel::Branch | |
| 111 102 |  | 
| 112 103 |  | 
| 113 104 | 
             
            	# The directory the branch's entry lives in
         | 
| 114 | 
            -
            	# @return [Treequel::Directory]
         | 
| 115 105 | 
             
            	attr_reader :directory
         | 
| 116 106 |  | 
| 117 107 | 
             
            	# The DN of the branch.
         | 
| 118 | 
            -
            	# @return [String]
         | 
| 119 108 | 
             
            	attr_reader :dn
         | 
| 120 109 | 
             
            	alias_method :to_s, :dn
         | 
| 121 110 |  | 
| @@ -124,20 +113,15 @@ class Treequel::Branch | |
| 124 113 | 
             
            	alias_method :include_operational_attributes?, :include_operational_attrs?
         | 
| 125 114 |  | 
| 126 115 |  | 
| 127 | 
            -
            	### Change the DN the Branch uses to look up its entry | 
| 128 | 
            -
            	### 
         | 
| 129 | 
            -
            	### @param [String] newdn  The new DN.
         | 
| 130 | 
            -
            	### @return [void]
         | 
| 116 | 
            +
            	### Change the DN the Branch uses to look up its entry to +newdn+.
         | 
| 131 117 | 
             
            	def dn=( newdn )
         | 
| 132 118 | 
             
            		self.clear_caches
         | 
| 133 119 | 
             
            		@dn = newdn
         | 
| 134 120 | 
             
            	end
         | 
| 135 121 |  | 
| 136 122 |  | 
| 137 | 
            -
            	### Enable or disable fetching of operational attributes (RC4512,  | 
| 138 | 
            -
            	### 
         | 
| 139 | 
            -
            	### @param [Boolean] new_setting
         | 
| 140 | 
            -
            	### @return [void]
         | 
| 123 | 
            +
            	### Enable (if +new_setting+ is true) or disable fetching of operational attributes (RC4512, 
         | 
| 124 | 
            +
            	### section 3.4).
         | 
| 141 125 | 
             
            	def include_operational_attrs=( new_setting )
         | 
| 142 126 | 
             
            		self.clear_caches
         | 
| 143 127 | 
             
            		@include_operational_attrs = new_setting ? true : false
         | 
| @@ -145,8 +129,7 @@ class Treequel::Branch | |
| 145 129 | 
             
            	alias_method :include_operational_attributes=, :include_operational_attrs=
         | 
| 146 130 |  | 
| 147 131 |  | 
| 148 | 
            -
            	### Return the attribute/s which make up this Branch's RDN.
         | 
| 149 | 
            -
            	### @return [Hash<Symbol => String>] The Branch's RDN attributes as a Hash.
         | 
| 132 | 
            +
            	### Return the attribute/s which make up this Branch's RDN as a Hash.
         | 
| 150 133 | 
             
            	def rdn_attributes
         | 
| 151 134 | 
             
            		return make_rdn_hash( self.rdn )
         | 
| 152 135 | 
             
            	end
         | 
| @@ -155,8 +138,6 @@ class Treequel::Branch | |
| 155 138 | 
             
            	### Return the LDAP::Entry associated with the receiver, fetching it from the
         | 
| 156 139 | 
             
            	### directory if necessary. Returns +nil+ if the entry doesn't exist in the
         | 
| 157 140 | 
             
            	### directory.
         | 
| 158 | 
            -
            	### 
         | 
| 159 | 
            -
            	### @return [LDAP::Entry]  The entry wrapped by the Branch.
         | 
| 160 141 | 
             
            	def entry
         | 
| 161 142 | 
             
            		@entry ||= self.lookup_entry
         | 
| 162 143 | 
             
            	end
         | 
| @@ -164,38 +145,32 @@ class Treequel::Branch | |
| 164 145 |  | 
| 165 146 | 
             
            	### Returns <tt>true</tt> if there is an entry currently in the directory with the
         | 
| 166 147 | 
             
            	### branch's DN.
         | 
| 167 | 
            -
            	### @return [Boolean]
         | 
| 168 148 | 
             
            	def exists?
         | 
| 169 149 | 
             
            		return self.entry ? true : false
         | 
| 170 150 | 
             
            	end
         | 
| 171 151 |  | 
| 172 152 |  | 
| 173 153 | 
             
            	### Returns +true+ if the Branch's entry has been fetched from the directory.
         | 
| 174 | 
            -
            	### @return [Boolean]
         | 
| 175 154 | 
             
            	def loaded?
         | 
| 176 155 | 
             
            		return @entry ? true : false
         | 
| 177 156 | 
             
            	end
         | 
| 178 157 |  | 
| 179 158 |  | 
| 180 159 | 
             
            	### Return the RDN of the branch.
         | 
| 181 | 
            -
            	### @return [String]
         | 
| 182 160 | 
             
            	def rdn
         | 
| 183 161 | 
             
            		return self.split_dn( 2 ).first
         | 
| 184 162 | 
             
            	end
         | 
| 185 163 |  | 
| 186 164 |  | 
| 187 | 
            -
            	### Return the receiver's DN as an Array of attribute=value pairs. 
         | 
| 188 | 
            -
            	### 
         | 
| 189 | 
            -
            	###  | 
| 190 | 
            -
            	###     are split from the DN, and the remainder will be returned as the last 
         | 
| 191 | 
            -
            	###     element.
         | 
| 165 | 
            +
            	### Return the receiver's DN as an Array of attribute=value pairs. If the optional +limit+ is
         | 
| 166 | 
            +
            	### non-zero, only the <code>limit-1</code> first pairs are split from the DN, and the 
         | 
| 167 | 
            +
            	### remainder will be returned as the last element.
         | 
| 192 168 | 
             
            	def split_dn( limit=0 )
         | 
| 193 169 | 
             
            		return self.dn.split( /\s*,\s*/, limit )
         | 
| 194 170 | 
             
            	end
         | 
| 195 171 |  | 
| 196 172 |  | 
| 197 173 | 
             
            	### Return the LDAP URI for this branch
         | 
| 198 | 
            -
            	### @return [URI]
         | 
| 199 174 | 
             
            	def uri
         | 
| 200 175 | 
             
            		uri = self.directory.uri
         | 
| 201 176 | 
             
            		uri.dn = self.dn
         | 
| @@ -204,7 +179,6 @@ class Treequel::Branch | |
| 204 179 |  | 
| 205 180 |  | 
| 206 181 | 
             
            	### Return the DN of this entry's parent, or nil if it doesn't have one.
         | 
| 207 | 
            -
            	### @return [String]
         | 
| 208 182 | 
             
            	def parent_dn
         | 
| 209 183 | 
             
            		return nil if self.dn == self.directory.base_dn
         | 
| 210 184 | 
             
            		return '' if self.dn.index( ',' ).nil?
         | 
| @@ -213,36 +187,27 @@ class Treequel::Branch | |
| 213 187 |  | 
| 214 188 |  | 
| 215 189 | 
             
            	### Return the Branch's immediate parent node.
         | 
| 216 | 
            -
            	### @return [Treequel::Branch]
         | 
| 217 190 | 
             
            	def parent
         | 
| 218 191 | 
             
            		pardn = self.parent_dn or return nil
         | 
| 219 192 | 
             
            		return self.class.new( self.directory, pardn )
         | 
| 220 193 | 
             
            	end
         | 
| 221 194 |  | 
| 222 195 |  | 
| 223 | 
            -
            	### Perform a search with the specified +scope+, +filter+, and +parameters+ 
         | 
| 224 | 
            -
            	###  | 
| 225 | 
            -
            	### 
         | 
| 226 | 
            -
            	### @param scope      (see Trequel::Directory#search)
         | 
| 227 | 
            -
            	### @param filter     (see Trequel::Directory#search)
         | 
| 228 | 
            -
            	### @param parameters (see Trequel::Directory#search)
         | 
| 229 | 
            -
            	### @param block      (see Trequel::Directory#search)
         | 
| 230 | 
            -
            	### 
         | 
| 231 | 
            -
            	### @return [Array<Treequel::Branch>] the search results
         | 
| 196 | 
            +
            	### Perform a search with the specified +scope+, +filter+, and +parameters+ using the 
         | 
| 197 | 
            +
            	### receiver as the base. See Trequel::Directory#search for details. Returns an Array of
         | 
| 198 | 
            +
            	### Treequel::Branch objects.
         | 
| 232 199 | 
             
            	def search( scope=:subtree, filter='(objectClass=*)', parameters={}, &block )
         | 
| 233 200 | 
             
            		return self.directory.search( self, scope, filter, parameters, &block )
         | 
| 234 201 | 
             
            	end
         | 
| 235 202 |  | 
| 236 203 |  | 
| 237 204 | 
             
            	### Return the Branch's immediate children as Treeque::Branch objects.
         | 
| 238 | 
            -
            	### @return [Array<Treequel::Branch>]
         | 
| 239 205 | 
             
            	def children
         | 
| 240 206 | 
             
            		return self.search( :one, '(objectClass=*)' )
         | 
| 241 207 | 
             
            	end
         | 
| 242 208 |  | 
| 243 209 |  | 
| 244 210 | 
             
            	### Return a Treequel::Branchset that will use the receiver as its base.
         | 
| 245 | 
            -
            	### @return [Treequel::Branchset]
         | 
| 246 211 | 
             
            	def branchset
         | 
| 247 212 | 
             
            		return Treequel::Branchset.new( self )
         | 
| 248 213 | 
             
            	end
         | 
| @@ -250,8 +215,6 @@ class Treequel::Branch | |
| 250 215 |  | 
| 251 216 | 
             
            	### Returns a human-readable representation of the object suitable for
         | 
| 252 217 | 
             
            	### debugging.
         | 
| 253 | 
            -
            	### 
         | 
| 254 | 
            -
            	### @return [String]
         | 
| 255 218 | 
             
            	def inspect
         | 
| 256 219 | 
             
            		return "#<%s:0x%0x %s @ %s entry=%p>" % [
         | 
| 257 220 | 
             
            			self.class.name,
         | 
| @@ -264,7 +227,6 @@ class Treequel::Branch | |
| 264 227 |  | 
| 265 228 |  | 
| 266 229 | 
             
            	### Return the entry's DN as an RFC1781-style UFN (User-Friendly Name).
         | 
| 267 | 
            -
            	### @return [String]
         | 
| 268 230 | 
             
            	def to_ufn
         | 
| 269 231 | 
             
            		if LDAP.respond_to?( :dn2ufn )
         | 
| 270 232 | 
             
            			return LDAP.dn2ufn( self.dn )
         | 
| @@ -298,7 +260,6 @@ class Treequel::Branch | |
| 298 260 |  | 
| 299 261 |  | 
| 300 262 | 
             
            	### Return the Branch as an LDAP::LDIF::Entry.
         | 
| 301 | 
            -
            	### @return [String]
         | 
| 302 263 | 
             
            	def to_ldif( width=DEFAULT_LDIF_WIDTH )
         | 
| 303 264 | 
             
            		ldif = "dn: %s\n" % [ self.dn ]
         | 
| 304 265 |  | 
| @@ -316,8 +277,6 @@ class Treequel::Branch | |
| 316 277 |  | 
| 317 278 |  | 
| 318 279 | 
             
            	### Return the Branch as a Hash.
         | 
| 319 | 
            -
            	### @see Treequel::Branch#[]
         | 
| 320 | 
            -
            	### @return [Hash]  the entry as a Hash with converted values
         | 
| 321 280 | 
             
            	def to_hash
         | 
| 322 281 | 
             
            		entry = self.entry || self.valid_attributes_hash
         | 
| 323 282 | 
             
            		self.log.debug "  making a Hash from an entry: %p" % [ entry ]
         | 
| @@ -334,12 +293,11 @@ class Treequel::Branch | |
| 334 293 |  | 
| 335 294 |  | 
| 336 295 | 
             
            	### Fetch the value/s associated with the given +attrname+ from the underlying entry.
         | 
| 337 | 
            -
            	### @return [Array, String]
         | 
| 338 296 | 
             
            	def []( attrname )
         | 
| 339 297 | 
             
            		attrsym = attrname.to_sym
         | 
| 340 298 |  | 
| 341 299 | 
             
            		if @values.key?( attrsym )
         | 
| 342 | 
            -
            			self.log.debug "  value for %p is cached (%p)." % [ attrname, @values[attrsym] ]
         | 
| 300 | 
            +
            			# self.log.debug "  value for %p is cached (%p)." % [ attrname, @values[attrsym] ]
         | 
| 343 301 | 
             
            		else
         | 
| 344 302 | 
             
            			self.log.debug "  value for %p is NOT cached." % [ attrsym ]
         | 
| 345 303 | 
             
            			value = self.get_converted_object( attrsym )
         | 
| @@ -354,10 +312,10 @@ class Treequel::Branch | |
| 354 312 | 
             
            	end
         | 
| 355 313 |  | 
| 356 314 |  | 
| 357 | 
            -
            	### Fetch one or more values from the entry.
         | 
| 358 | 
            -
            	### | 
| 359 | 
            -
            	###  | 
| 360 | 
            -
            	###  | 
| 315 | 
            +
            	### Fetch one or more values for the specified +attributes+ from the entry.
         | 
| 316 | 
            +
            	###
         | 
| 317 | 
            +
            	###    branch.values_at( :cn, :objectClass )
         | 
| 318 | 
            +
            	###    => [["sysadmin"], ["top", "posixGroup", "apple-group"]]
         | 
| 361 319 | 
             
            	def values_at( *attributes )
         | 
| 362 320 | 
             
            		return attributes.collect do |attribute|
         | 
| 363 321 | 
             
            			self[ attribute ]
         | 
| @@ -366,9 +324,6 @@ class Treequel::Branch | |
| 366 324 |  | 
| 367 325 |  | 
| 368 326 | 
             
            	### Set attribute +attrname+ to a new +value+.
         | 
| 369 | 
            -
            	### 
         | 
| 370 | 
            -
            	### @param [Symbol, String] attrname  attribute name
         | 
| 371 | 
            -
            	### @param [Object] value  the attribute value
         | 
| 372 327 | 
             
            	def []=( attrname, value )
         | 
| 373 328 | 
             
            		value = [ value ] unless value.is_a?( Array )
         | 
| 374 329 | 
             
            		value.collect! {|val| self.get_converted_attribute(attrname, val) }
         | 
| @@ -380,9 +335,8 @@ class Treequel::Branch | |
| 380 335 |  | 
| 381 336 |  | 
| 382 337 | 
             
            	### Make the changes to the entry specified by the given +attributes+.
         | 
| 383 | 
            -
            	### | 
| 384 | 
            -
            	###  | 
| 385 | 
            -
            	### @return [TrueClass] if the merge succeeded
         | 
| 338 | 
            +
            	###
         | 
| 339 | 
            +
            	###   branch.merge( :description => ['The syadmin group'], :cn => ['sysadmin'] )
         | 
| 386 340 | 
             
            	def merge( attributes )
         | 
| 387 341 | 
             
            		self.directory.modify( self, attributes )
         | 
| 388 342 | 
             
            		self.clear_caches
         | 
| @@ -392,20 +346,19 @@ class Treequel::Branch | |
| 392 346 | 
             
            	alias_method :modify, :merge
         | 
| 393 347 |  | 
| 394 348 |  | 
| 395 | 
            -
            	### Delete the specified attributes | 
| 396 | 
            -
            	### 
         | 
| 397 | 
            -
            	###  | 
| 398 | 
            -
            	###     attribute names (in which case all values of the attribute are deleted) or
         | 
| 399 | 
            -
            	###     Hashes of attributes and the Array of value/s which should be deleted.
         | 
| 349 | 
            +
            	### Delete the specified +attributes+, which are the attributes to delete either as
         | 
| 350 | 
            +
            	### attribute names (in which case all values of the attribute are deleted), or
         | 
| 351 | 
            +
            	### Hashes of attributes and the Array of value/s which should be deleted.
         | 
| 400 352 | 
             
            	### 
         | 
| 401 | 
            -
            	###  | 
| 353 | 
            +
            	###     # Delete all 'description' attributes
         | 
| 402 354 | 
             
            	###     branch.delete( :description )
         | 
| 403 | 
            -
            	### | 
| 355 | 
            +
            	###
         | 
| 356 | 
            +
            	###     # Delete the 'inetOrgPerson' and 'posixAccount' objectClasses from the entry
         | 
| 404 357 | 
             
            	###     branch.delete( :objectClass => [:inetOrgPerson, :posixAccount] )
         | 
| 405 | 
            -
            	### | 
| 358 | 
            +
            	###
         | 
| 359 | 
            +
            	###     # Delete any blank 'description' or 'cn' attributes:
         | 
| 406 360 | 
             
            	###     branch.delete( :description => '', :cn => '' )
         | 
| 407 361 | 
             
            	### 
         | 
| 408 | 
            -
            	### @return [TrueClass] if the delete succeeded
         | 
| 409 362 | 
             
            	def delete( *attributes )
         | 
| 410 363 |  | 
| 411 364 | 
             
            		# If no attributes are given, delete the whole entry
         | 
| @@ -443,9 +396,12 @@ class Treequel::Branch | |
| 443 396 |  | 
| 444 397 |  | 
| 445 398 | 
             
            	### Create the entry for this Branch with the specified +attributes+. The +attributes+ should,
         | 
| 446 | 
            -
            	### at a minimum, contain the pair `:objectClass => :someStructuralObjectClass`.
         | 
| 447 | 
            -
            	### | 
| 448 | 
            -
            	###  | 
| 399 | 
            +
            	### at a minimum, contain the pair `:objectClass => [:someStructuralObjectClass]`.
         | 
| 400 | 
            +
            	###
         | 
| 401 | 
            +
            	###     groups = dir.ou( :groups )
         | 
| 402 | 
            +
            	###     newgroup = groups.cn( :staff )
         | 
| 403 | 
            +
            	###     newgroup.create( :objectClass => ['posixGroup'], :gidNumber => 2100 )
         | 
| 404 | 
            +
            	###     # => #<Treequel::Branch:0x1086a0ac8 cn=staff,ou=groups,dc=example,dc=com>
         | 
| 449 405 | 
             
            	def create( attributes={} )
         | 
| 450 406 | 
             
            		self.directory.create( self, attributes )
         | 
| 451 407 | 
             
            		self.clear_caches
         | 
| @@ -455,10 +411,6 @@ class Treequel::Branch | |
| 455 411 |  | 
| 456 412 | 
             
            	### Copy the entry for this Branch to a new entry with the given +newdn+ and merge in the
         | 
| 457 413 | 
             
            	### specified +attributes+.
         | 
| 458 | 
            -
            	### 
         | 
| 459 | 
            -
            	### @param [String] newdn  the dn of the new entry
         | 
| 460 | 
            -
            	### @param [Hash<String, Symbol => Object>] attributes  merge attributes
         | 
| 461 | 
            -
            	### @return [Treequel::Branch] a Branch for the new entry
         | 
| 462 414 | 
             
            	def copy( newdn, attributes={} )
         | 
| 463 415 |  | 
| 464 416 | 
             
            		# Fully-qualify RDNs
         | 
| @@ -479,9 +431,6 @@ class Treequel::Branch | |
| 479 431 | 
             
            	### Move the entry associated with this branch to a new entry indicated by +rdn+. If 
         | 
| 480 432 | 
             
            	### any +attributes+ are given, also replace the corresponding attributes on the new
         | 
| 481 433 | 
             
            	### entry with them.
         | 
| 482 | 
            -
            	### 
         | 
| 483 | 
            -
            	### @param [String] rdn  
         | 
| 484 | 
            -
            	### @param [Hash<String, Symbol => Object>] attributes 
         | 
| 485 434 | 
             
            	def move( rdn )
         | 
| 486 435 | 
             
            		self.log.debug "Asking the directory to move me to an entry called %p" % [ rdn ]
         | 
| 487 436 | 
             
            		self.directory.move( self, rdn )
         | 
| @@ -491,11 +440,8 @@ class Treequel::Branch | |
| 491 440 | 
             
            	end
         | 
| 492 441 |  | 
| 493 442 |  | 
| 494 | 
            -
            	### Comparable interface: Returns -1 if other_branch is less than, 0 if other_branch is 
         | 
| 495 | 
            -
            	### equal to, and +1 if other_branch is greater than the receiving Branch.
         | 
| 496 | 
            -
            	### 
         | 
| 497 | 
            -
            	### @param [Treequel::Branch] other_branch
         | 
| 498 | 
            -
            	### @return [Fixnum]
         | 
| 443 | 
            +
            	### Comparable interface: Returns -1 if other_branch is less than, 0 if +other_branch+ is 
         | 
| 444 | 
            +
            	### equal to, and +1 if +other_branch+ is greater than the receiving Branch.
         | 
| 499 445 | 
             
            	def <=>( other_branch )
         | 
| 500 446 | 
             
            		# Try the easy cases first
         | 
| 501 447 | 
             
            		return nil unless other_branch.respond_to?( :dn ) &&
         | 
| @@ -517,9 +463,6 @@ class Treequel::Branch | |
| 517 463 |  | 
| 518 464 | 
             
            	### Fetch a new Treequel::Branch object for the child of the receiver with the specified
         | 
| 519 465 | 
             
            	### +rdn+.
         | 
| 520 | 
            -
            	### 
         | 
| 521 | 
            -
            	### @param [String] rdn  The RDN of the child to fetch.
         | 
| 522 | 
            -
            	### @return [Treequel::Branch]
         | 
| 523 466 | 
             
            	def get_child( rdn )
         | 
| 524 467 | 
             
            		self.log.debug "Getting child %p from base = %p" % [ rdn, self.dn ]
         | 
| 525 468 | 
             
            		newdn = [ rdn, self.dn ].reject {|part| part.empty? }.join( ',' )
         | 
| @@ -529,9 +472,6 @@ class Treequel::Branch | |
| 529 472 |  | 
| 530 473 | 
             
            	### Addition operator: return a Treequel::BranchCollection that contains both the receiver
         | 
| 531 474 | 
             
            	### and +other_branch+.
         | 
| 532 | 
            -
            	### 
         | 
| 533 | 
            -
            	### @param [Treequel::Branch] other_branch  
         | 
| 534 | 
            -
            	### @return [Treequel::BranchCollection]
         | 
| 535 475 | 
             
            	def +( other_branch )
         | 
| 536 476 | 
             
            		return Treequel::BranchCollection.new( self.branchset, other_branch.branchset )
         | 
| 537 477 | 
             
            	end
         | 
| @@ -540,11 +480,8 @@ class Treequel::Branch | |
| 540 480 | 
             
            	### Return Treequel::Schema::ObjectClass instances for each of the receiver's
         | 
| 541 481 | 
             
            	### objectClass attributes. If any +additional_classes+ are given, 
         | 
| 542 482 | 
             
            	### merge them with the current list of the current objectClasses for the lookup.
         | 
| 543 | 
            -
            	### 
         | 
| 544 | 
            -
            	### @param [Array<String, Symbol>] additional_classes 
         | 
| 545 | 
            -
            	### @return [Array<Treequel::Schema::ObjectClass>]
         | 
| 546 483 | 
             
            	def object_classes( *additional_classes )
         | 
| 547 | 
            -
            		self.log.debug "Fetching object classes for %s" % [ self.dn ]
         | 
| 484 | 
            +
            		# self.log.debug "Fetching object classes for %s" % [ self.dn ]
         | 
| 548 485 | 
             
            		schema = self.directory.schema
         | 
| 549 486 |  | 
| 550 487 | 
             
            		oc_oids = self[:objectClass] || []
         | 
| @@ -558,14 +495,12 @@ class Treequel::Branch | |
| 558 495 | 
             
            			oclasses << oc
         | 
| 559 496 | 
             
            		end
         | 
| 560 497 |  | 
| 561 | 
            -
            		self.log.debug "  found %d objectClasses: %p" % [  oclasses.length, oclasses.map(&:name) ]
         | 
| 498 | 
            +
            		# self.log.debug "  found %d objectClasses: %p" % [  oclasses.length, oclasses.map(&:name) ]
         | 
| 562 499 | 
             
            		return oclasses.uniq
         | 
| 563 500 | 
             
            	end
         | 
| 564 501 |  | 
| 565 502 |  | 
| 566 503 | 
             
            	### Return the receiver's operational attributes as attributeType schema objects.
         | 
| 567 | 
            -
            	###
         | 
| 568 | 
            -
            	### @return [Array<Treequel::Schema::AttributeType>]  the operational attributes
         | 
| 569 504 | 
             
            	def operational_attribute_types
         | 
| 570 505 | 
             
            		return self.directory.schema.operational_attribute_types
         | 
| 571 506 | 
             
            	end
         | 
| @@ -586,19 +521,9 @@ class Treequel::Branch | |
| 586 521 | 
             
            	### include the MUST attributeTypes for them as well. This can be used to predict what
         | 
| 587 522 | 
             
            	### attributes would need to be present for the entry to be saved if it added the
         | 
| 588 523 | 
             
            	### +additional_object_classes+ to its own.
         | 
| 589 | 
            -
            	### 
         | 
| 590 | 
            -
            	### @param [Array<String, Symbol>] additional_object_classes 
         | 
| 591 | 
            -
            	### @return [Array<Treequel::Schema::AttributeType>]
         | 
| 592 524 | 
             
            	def must_attribute_types( *additional_object_classes )
         | 
| 593 | 
            -
            		types = []
         | 
| 594 525 | 
             
            		oclasses = self.object_classes( *additional_object_classes )
         | 
| 595 | 
            -
            		 | 
| 596 | 
            -
            		 	[ oclasses.map(&:name) ]
         | 
| 597 | 
            -
             | 
| 598 | 
            -
            		oclasses.each do |oc|
         | 
| 599 | 
            -
            			self.log.debug "  adding %p from %p" % [ oc.must.map(&:name), oc.name ]
         | 
| 600 | 
            -
            			types |= oc.must
         | 
| 601 | 
            -
            		end
         | 
| 526 | 
            +
            		types = oclasses.map( &:must ).flatten.uniq
         | 
| 602 527 |  | 
| 603 528 | 
             
            		return types
         | 
| 604 529 | 
             
            	end
         | 
| @@ -609,9 +534,6 @@ class Treequel::Branch | |
| 609 534 | 
             
            	### include the OIDs of the MUST attributes for them as well. This can be used to predict 
         | 
| 610 535 | 
             
            	### what attributes would need to be present for the entry to be saved if it added the
         | 
| 611 536 | 
             
            	### +additional_object_classes+ to its own.
         | 
| 612 | 
            -
            	### 
         | 
| 613 | 
            -
            	### @param [Array<String, Symbol>] additional_object_classes 
         | 
| 614 | 
            -
            	### @return [Array<String, Symbol>] oid strings and symbols
         | 
| 615 537 | 
             
            	def must_oids( *additional_object_classes )
         | 
| 616 538 | 
             
            		return self.object_classes( *additional_object_classes ).
         | 
| 617 539 | 
             
            			collect {|oc| oc.must_oids }.flatten.uniq.reject {|val| val == '' }
         | 
| @@ -621,9 +543,6 @@ class Treequel::Branch | |
| 621 543 | 
             
            	### Return a Hash of the attributes required by the Branch's objectClasses. If 
         | 
| 622 544 | 
             
            	### any +additional_object_classes+ are given, include the attributes that would be
         | 
| 623 545 | 
             
            	### necessary for the entry to be saved with them.
         | 
| 624 | 
            -
            	### 
         | 
| 625 | 
            -
            	### @param [Array<String, Symbol>] additional_object_classes 
         | 
| 626 | 
            -
            	### @return [Hash<String => String>]
         | 
| 627 546 | 
             
            	def must_attributes_hash( *additional_object_classes )
         | 
| 628 547 | 
             
            		attrhash = {}
         | 
| 629 548 |  | 
| @@ -648,9 +567,6 @@ class Treequel::Branch | |
| 648 567 | 
             
            	### include the MAY attributeTypes for them as well. This can be used to predict what
         | 
| 649 568 | 
             
            	### optional attributes could be added to the entry if the +additional_object_classes+ 
         | 
| 650 569 | 
             
            	### were added to it.
         | 
| 651 | 
            -
            	### 
         | 
| 652 | 
            -
            	### @param [Array<String, Symbol>] additional_object_classes 
         | 
| 653 | 
            -
            	### @return [Array<Treequel::Schema::AttributeType>]
         | 
| 654 570 | 
             
            	def may_attribute_types( *additional_object_classes )
         | 
| 655 571 | 
             
            		return self.object_classes( *additional_object_classes ).
         | 
| 656 572 | 
             
            			collect {|oc| oc.may }.flatten.uniq
         | 
| @@ -662,9 +578,6 @@ class Treequel::Branch | |
| 662 578 | 
             
            	### include the OIDs of the MAY attributes for them as well. This can be used to predict 
         | 
| 663 579 | 
             
            	### what optional attributes could be added to the entry if the +additional_object_classes+ 
         | 
| 664 580 | 
             
            	### were added to it.
         | 
| 665 | 
            -
            	### 
         | 
| 666 | 
            -
            	### @param [Array<String, Symbol>] additional_object_classes 
         | 
| 667 | 
            -
            	### @return [Array<String, Symbol>]  oid strings and symbols
         | 
| 668 581 | 
             
            	def may_oids( *additional_object_classes )
         | 
| 669 582 | 
             
            		return self.object_classes( *additional_object_classes ).
         | 
| 670 583 | 
             
            			collect {|oc| oc.may_oids }.flatten.uniq
         | 
| @@ -674,9 +587,6 @@ class Treequel::Branch | |
| 674 587 | 
             
            	### Return a Hash of the optional attributes allowed by the Branch's objectClasses. If 
         | 
| 675 588 | 
             
            	### any +additional_object_classes+ are given, include the attributes that would be
         | 
| 676 589 | 
             
            	### available for the entry if it had them.
         | 
| 677 | 
            -
            	### 
         | 
| 678 | 
            -
            	### @param [Array<String, Symbol>] additional_object_classes 
         | 
| 679 | 
            -
            	### @return [Hash<String => String>]
         | 
| 680 590 | 
             
            	def may_attributes_hash( *additional_object_classes )
         | 
| 681 591 | 
             
            		entry = self.entry
         | 
| 682 592 | 
             
            		attrhash = {}
         | 
| @@ -702,8 +612,6 @@ class Treequel::Branch | |
| 702 612 |  | 
| 703 613 | 
             
            	### Return Treequel::Schema::AttributeType instances for the set of all of the receiver's
         | 
| 704 614 | 
             
            	### MUST and MAY attributeTypes plus the operational attributes.
         | 
| 705 | 
            -
            	### 
         | 
| 706 | 
            -
            	### @return [Array<Treequel::Schema::AttributeType>]
         | 
| 707 615 | 
             
            	def valid_attribute_types
         | 
| 708 616 | 
             
            		return self.must_attribute_types |
         | 
| 709 617 | 
             
            		       self.may_attribute_types  |
         | 
| @@ -714,8 +622,6 @@ class Treequel::Branch | |
| 714 622 | 
             
            	### Return a uniqified Array of OIDs (numeric OIDs as Strings, named OIDs as Symbols) for
         | 
| 715 623 | 
             
            	### the set of all of the receiver's MUST and MAY attributeTypes plus the operational
         | 
| 716 624 | 
             
            	### attributes.
         | 
| 717 | 
            -
            	### 
         | 
| 718 | 
            -
            	### @return [Array<String, Symbol>]
         | 
| 719 625 | 
             
            	def valid_attribute_oids
         | 
| 720 626 | 
             
            		return self.must_oids | self.may_oids
         | 
| 721 627 | 
             
            	end
         | 
| @@ -725,9 +631,6 @@ class Treequel::Branch | |
| 725 631 | 
             
            	### attributeTypes for the receiver given its objectClasses, return the 
         | 
| 726 632 | 
             
            	### AttributeType object that corresponds with it. If it isn't valid, return nil.
         | 
| 727 633 | 
             
            	### Includes operational attributes.
         | 
| 728 | 
            -
            	###
         | 
| 729 | 
            -
            	### @param [String,Symbol] attroid  a numeric OID (as a String) or a named OID (as a Symbol)
         | 
| 730 | 
            -
            	### @return [Treequel::Schema::AttributeType] the validated attributeType
         | 
| 731 634 | 
             
            	def valid_attribute_type( attroid )
         | 
| 732 635 | 
             
            		return self.valid_attribute_types.find {|attr_type| attr_type.valid_name?(attroid) }
         | 
| 733 636 | 
             
            	end
         | 
| @@ -735,9 +638,6 @@ class Treequel::Branch | |
| 735 638 |  | 
| 736 639 | 
             
            	### Return +true+ if the specified +attrname+ is a valid attributeType given the
         | 
| 737 640 | 
             
            	### receiver's current objectClasses. Does not include operational attributes.
         | 
| 738 | 
            -
            	### 
         | 
| 739 | 
            -
            	### @param [String, Symbol] the OID (numeric or name) of the attribute in question
         | 
| 740 | 
            -
            	### @return [Boolean]
         | 
| 741 641 | 
             
            	def valid_attribute?( attroid )
         | 
| 742 642 | 
             
            		return !self.valid_attribute_type( attroid ).nil?
         | 
| 743 643 | 
             
            	end
         | 
| @@ -746,9 +646,6 @@ class Treequel::Branch | |
| 746 646 | 
             
            	### Return a Hash of all the attributes allowed by the Branch's objectClasses. If
         | 
| 747 647 | 
             
            	### any +additional_object_classes+ are given, include the attributes that would be
         | 
| 748 648 | 
             
            	### available for the entry if it had them.
         | 
| 749 | 
            -
            	### 
         | 
| 750 | 
            -
            	### @param [Array<String, Symbol>] additional_object_classes 
         | 
| 751 | 
            -
            	### @return [Hash<String => String>]
         | 
| 752 649 | 
             
            	def valid_attributes_hash( *additional_object_classes )
         | 
| 753 650 | 
             
            		self.log.debug "Gathering a hash of all valid attributes:"
         | 
| 754 651 | 
             
            		must = self.must_attributes_hash( *additional_object_classes )
         | 
| @@ -766,7 +663,6 @@ class Treequel::Branch | |
| 766 663 |  | 
| 767 664 | 
             
            	### Proxy method: call #traverse_branch if +attribute+ is a valid attribute
         | 
| 768 665 | 
             
            	### and +value+ isn't +nil+.
         | 
| 769 | 
            -
            	### @see Treequel::Branch#traverse_branch
         | 
| 770 666 | 
             
            	def method_missing( attribute, value=nil, additional_attributes={} )
         | 
| 771 667 | 
             
            		return super( attribute ) if value.nil?
         | 
| 772 668 | 
             
            		return self.traverse_branch( attribute, value, additional_attributes )
         | 
| @@ -774,23 +670,18 @@ class Treequel::Branch | |
| 774 670 |  | 
| 775 671 |  | 
| 776 672 | 
             
            	### If +attribute+ matches a valid attribute type in the directory's
         | 
| 777 | 
            -
            	### schema, return a new Branch for the RDN of +attribute+ and +value | 
| 778 | 
            -
            	### +additional_attributes+ if it's a multi-value RDN.
         | 
| 673 | 
            +
            	### schema, return a new Branch for the RDN of +attribute+ and +value+ and 
         | 
| 674 | 
            +
            	### +additional_attributes+ (if it's a multi-value RDN).
         | 
| 779 675 | 
             
            	###
         | 
| 780 | 
            -
            	###  | 
| 781 | 
            -
            	###  | 
| 782 | 
            -
            	###  | 
| 783 | 
            -
            	### 
         | 
| 784 | 
            -
            	###  | 
| 785 | 
            -
            	### | 
| 786 | 
            -
            	### | 
| 787 | 
            -
            	### | 
| 788 | 
            -
            	### | 
| 789 | 
            -
            	###   # => 'uid=chester+employeeType=admin,ou=people,dc=acme,dc=com'
         | 
| 790 | 
            -
            	### 
         | 
| 791 | 
            -
            	### @return [Treequel::Branch]  the Branch for the specified child
         | 
| 792 | 
            -
            	### @raise [NoMethodError] if the +attribute+ or any +additional_attributes+ are
         | 
| 793 | 
            -
            	###                        not valid attributeTypes.
         | 
| 676 | 
            +
            	###     # (Called via #method_missing)
         | 
| 677 | 
            +
            	###     branch = Treequel::Branch.new( directory, 'ou=people,dc=acme,dc=com' )
         | 
| 678 | 
            +
            	###     branch.uid( :chester ).dn
         | 
| 679 | 
            +
            	###     # => 'uid=chester,ou=people,dc=acme,dc=com'
         | 
| 680 | 
            +
            	###     branch.uid( :chester, :employeeType => 'admin' ).dn
         | 
| 681 | 
            +
            	###     # => 'uid=chester+employeeType=admin,ou=people,dc=acme,dc=com'
         | 
| 682 | 
            +
            	### 
         | 
| 683 | 
            +
            	### Raises a NoMethodError if the +attribute+ or any +additional_attributes+ are
         | 
| 684 | 
            +
            	### not valid attributeTypes.
         | 
| 794 685 | 
             
            	def traverse_branch( attribute, value, additional_attributes={} )
         | 
| 795 686 | 
             
            		valid_types = self.directory.schema.attribute_types
         | 
| 796 687 |  | 
| @@ -854,8 +745,8 @@ class Treequel::Branch | |
| 854 745 | 
             
            	### and return it.
         | 
| 855 746 | 
             
            	def get_converted_attribute( attrsym, object )
         | 
| 856 747 | 
             
            		if attribute = self.directory.schema.attribute_types[ attrsym ]
         | 
| 857 | 
            -
            			self.log.debug "converting %p object (a %p) to a % | 
| 858 | 
            -
            				[ attrsym, object.class, attribute. | 
| 748 | 
            +
            			self.log.debug "converting %p object (a %p) to a %s attribute" %
         | 
| 749 | 
            +
            				[ attrsym, object.class, attribute.syntax.desc ]
         | 
| 859 750 | 
             
            			return self.directory.convert_to_attribute( attribute.syntax_oid, object )
         | 
| 860 751 | 
             
            		else
         | 
| 861 752 | 
             
            			self.log.info "no attributeType for %p" % [ attrsym ]
         | 
| @@ -865,7 +756,6 @@ class Treequel::Branch | |
| 865 756 |  | 
| 866 757 |  | 
| 867 758 | 
             
            	### Clear any cached values when the structural state of the object changes.
         | 
| 868 | 
            -
            	### @return [void]
         | 
| 869 759 | 
             
            	def clear_caches
         | 
| 870 760 | 
             
                    self.log.debug "Clearing entry and values caches."
         | 
| 871 761 | 
             
            		@entry = nil
         | 
| @@ -914,10 +804,6 @@ class Treequel::Branch | |
| 914 804 |  | 
| 915 805 | 
             
            	### Make LDIF for the given +attribute+ and its +values+, wrapping at the given
         | 
| 916 806 | 
             
            	### +width+.
         | 
| 917 | 
            -
            	### 
         | 
| 918 | 
            -
            	### @param [String] attribute  the attribute
         | 
| 919 | 
            -
            	### @param [Array<String>] values  the values for the given +attribute+
         | 
| 920 | 
            -
            	### @param [Fixnum] width  the maximum width of the lines to return
         | 
| 921 807 | 
             
            	def ldif_for_attr( attribute, value, width )
         | 
| 922 808 | 
             
            		unsplit_line = "#{attribute}:"
         | 
| 923 809 |  | 
| @@ -44,7 +44,6 @@ class Treequel::BranchCollection | |
| 44 44 | 
             
            	### Create a delegator that will return an instance of the receiver
         | 
| 45 45 | 
             
            	### created with the results of iterating over the branchsets and calling
         | 
| 46 46 | 
             
            	### the delegated method.
         | 
| 47 | 
            -
            	### @param [Array<Symbol>] symbols  The methods to define
         | 
| 48 47 | 
             
            	def self::def_cloning_delegators( *symbols )
         | 
| 49 48 | 
             
            		symbols.each do |methname|
         | 
| 50 49 | 
             
            			# Create the method body
         | 
| @@ -72,9 +71,8 @@ class Treequel::BranchCollection | |
| 72 71 | 
             
            	###	I N S T A N C E   M E T H O D S
         | 
| 73 72 | 
             
            	#################################################################
         | 
| 74 73 |  | 
| 75 | 
            -
            	### Create a new Treequel::BranchCollection that will operate on the given +branchsets | 
| 76 | 
            -
            	###  | 
| 77 | 
            -
            	###       combined in the BranchCollection.
         | 
| 74 | 
            +
            	### Create a new Treequel::BranchCollection that will operate on the given +branchsets+, which
         | 
| 75 | 
            +
            	### can be either Treequel::Branchset or Treequel::Branch objects.
         | 
| 78 76 | 
             
            	def initialize( *branchsets )
         | 
| 79 77 | 
             
            		@branchsets = branchsets.flatten.collect do |obj|
         | 
| 80 78 | 
             
            			if obj.respond_to?( :each )
         | 
| @@ -86,12 +84,16 @@ class Treequel::BranchCollection | |
| 86 84 | 
             
            	end
         | 
| 87 85 |  | 
| 88 86 |  | 
| 89 | 
            -
            	 | 
| 90 | 
            -
            	 | 
| 87 | 
            +
            	##
         | 
| 88 | 
            +
            	# Delegator methods that clone the receiver with the results of mapping
         | 
| 89 | 
            +
            	# the branchsets with the delegated method.
         | 
| 90 | 
            +
             | 
| 91 91 | 
             
            	def_cloning_delegators :filter, :scope, :select, :select_all, :select_more, :timeout,
         | 
| 92 92 | 
             
            		:without_timeout
         | 
| 93 93 |  | 
| 94 | 
            -
            	 | 
| 94 | 
            +
            	##
         | 
| 95 | 
            +
            	# Delegators that some methods through the collection directly
         | 
| 96 | 
            +
             | 
| 95 97 | 
             
            	def_method_delegators :branchsets, :include?
         | 
| 96 98 |  | 
| 97 99 |  | 
| @@ -107,7 +109,6 @@ class Treequel::BranchCollection | |
| 107 109 |  | 
| 108 110 |  | 
| 109 111 | 
             
            	### Return a human-readable string representation of the object suitable for debugging.
         | 
| 110 | 
            -
            	### @return [String]
         | 
| 111 112 | 
             
            	def inspect
         | 
| 112 113 | 
             
            		"#<%s:0x%0x %d branchsets: %p>" % [
         | 
| 113 114 | 
             
            			self.class.name,
         | 
| @@ -120,7 +121,6 @@ class Treequel::BranchCollection | |
| 120 121 |  | 
| 121 122 | 
             
            	### Iterate over the Treequel::Branches found by each member branchset, yielding each 
         | 
| 122 123 | 
             
            	### one in turn.
         | 
| 123 | 
            -
            	### @yield [Treequel::Branch]
         | 
| 124 124 | 
             
            	def each( &block )
         | 
| 125 125 | 
             
            		raise LocalJumpError, "no block given" unless block
         | 
| 126 126 | 
             
            		self.branchsets.each do |bs|
         | 
| @@ -130,7 +130,6 @@ class Treequel::BranchCollection | |
| 130 130 |  | 
| 131 131 |  | 
| 132 132 | 
             
            	### Return the first Treequel::Branch that is returned from the collection's branchsets.
         | 
| 133 | 
            -
            	### @return [Treequel::Branch]
         | 
| 134 133 | 
             
            	def first
         | 
| 135 134 | 
             
            		branch = nil
         | 
| 136 135 |  | 
| @@ -143,14 +142,12 @@ class Treequel::BranchCollection | |
| 143 142 |  | 
| 144 143 |  | 
| 145 144 | 
             
            	### Return +true+ if none of the collection's branches match any entries.
         | 
| 146 | 
            -
            	### @return [Boolean]
         | 
| 147 145 | 
             
            	def empty?
         | 
| 148 146 | 
             
            		return self.branchsets.all? {|bs| bs.empty? } ? true : false
         | 
| 149 147 | 
             
            	end
         | 
| 150 148 |  | 
| 151 149 |  | 
| 152 150 | 
             
            	### Overridden to support Branchset#map
         | 
| 153 | 
            -
            	### @param (see Treequel::Branchset#map)
         | 
| 154 151 | 
             
            	def map( attribute=nil, &block )
         | 
| 155 152 | 
             
            		if attribute
         | 
| 156 153 | 
             
            			if block
         | 
| @@ -181,7 +178,6 @@ class Treequel::BranchCollection | |
| 181 178 | 
             
            	### Return either a new Treequel::BranchCollection that includes both the receiver's 
         | 
| 182 179 | 
             
            	### Branchsets and those in +other_object+ (if it responds_to #branchsets), or the results
         | 
| 183 180 | 
             
            	### from executing the BranchCollection's search with +other_object+ appended if it doesn't.
         | 
| 184 | 
            -
            	### @param [Object] other_object
         | 
| 185 181 | 
             
            	def +( other_object )
         | 
| 186 182 | 
             
            		if other_object.respond_to?( :branchsets )
         | 
| 187 183 | 
             
            			return self.class.new( self.branchsets + other_object.branchsets )
         | 
| @@ -193,9 +189,8 @@ class Treequel::BranchCollection | |
| 193 189 | 
             
            	end
         | 
| 194 190 |  | 
| 195 191 |  | 
| 196 | 
            -
            	### Return the results from each of the receiver's Branchsets without the +other_object | 
| 197 | 
            -
            	###  | 
| 198 | 
            -
            	### @return [Array<Treequel::Branch>]
         | 
| 192 | 
            +
            	### Return the results from each of the receiver's Branchsets without the +other_object+, 
         | 
| 193 | 
            +
            	### which must respond to #dn.
         | 
| 199 194 | 
             
            	def -( other_object )
         | 
| 200 195 | 
             
            		other_dn = other_object.dn
         | 
| 201 196 | 
             
            		return self.reject {|branch| branch.dn == other_dn }
         |