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/branchset.rb
    CHANGED
    
    | @@ -185,10 +185,8 @@ class Treequel::Branchset | |
| 185 185 |  | 
| 186 186 |  | 
| 187 187 | 
             
            	### If given another Branchset or a BranchCollection, return a BranchCollection that includes
         | 
| 188 | 
            -
            	### them both. If given anything else, execute the search and return 
         | 
| 189 | 
            -
            	###  | 
| 190 | 
            -
            	###                                                       with
         | 
| 191 | 
            -
            	### @return [Treequel::BranchCollection, Array<Treequel::Branch>]
         | 
| 188 | 
            +
            	### them both. If given anything else, execute the search and return the results plus
         | 
| 189 | 
            +
            	### +other+ in an Array.
         | 
| 192 190 | 
             
            	def +( other )
         | 
| 193 191 | 
             
            		if other.is_a?( Treequel::BranchCollection ) || other.is_a?( Treequel::Branchset )
         | 
| 194 192 | 
             
            			return Treequel::BranchCollection.new( self, other )
         | 
| @@ -199,8 +197,6 @@ class Treequel::Branchset | |
| 199 197 |  | 
| 200 198 |  | 
| 201 199 | 
             
            	### Return the results of executing the search without the +other_object+.
         | 
| 202 | 
            -
            	### @param [#dn] other_object  the object to omit from the results; must respond_to #dn.
         | 
| 203 | 
            -
            	### @return [Array<Treequel::Branch>]
         | 
| 204 200 | 
             
            	def -( other_object )
         | 
| 205 201 | 
             
            		other_dn = other_object.dn
         | 
| 206 202 | 
             
            		return self.reject {|branch| branch.dn.downcase == other_dn.downcase }
         | 
| @@ -224,17 +220,24 @@ class Treequel::Branchset | |
| 224 220 | 
             
            	end
         | 
| 225 221 |  | 
| 226 222 |  | 
| 227 | 
            -
            	### Fetch the first  | 
| 228 | 
            -
            	### the object that is set as the +branch+ (e.g., Treequel::Branch).
         | 
| 229 | 
            -
            	 | 
| 230 | 
            -
             | 
| 223 | 
            +
            	### Fetch the first +n+ entries which matches the current criteria and return them as 
         | 
| 224 | 
            +
            	### instances of the object that is set as the +branch+ (e.g., Treequel::Branch). If +n+ is
         | 
| 225 | 
            +
            	### +nil+, returns just the first object in the Array.
         | 
| 226 | 
            +
            	def first( n=nil )
         | 
| 227 | 
            +
            		results = self.branch.search( self.scope, self.filter,
         | 
| 231 228 | 
             
            			:selectattrs => self.select,
         | 
| 232 229 | 
             
            			:timeout => self.timeout,
         | 
| 233 230 | 
             
            			# :sortby => self.order,
         | 
| 234 231 | 
             
            			:client_controls => self.get_client_controls,
         | 
| 235 232 | 
             
            			:server_controls => self.get_server_controls,
         | 
| 236 | 
            -
            			:limit => 1
         | 
| 237 | 
            -
            		  ) | 
| 233 | 
            +
            			:limit => n || 1
         | 
| 234 | 
            +
            		  )
         | 
| 235 | 
            +
             | 
| 236 | 
            +
            		if n
         | 
| 237 | 
            +
            			return results.first( n )
         | 
| 238 | 
            +
            		else
         | 
| 239 | 
            +
            			return results.first
         | 
| 240 | 
            +
            		end
         | 
| 238 241 | 
             
            	end
         | 
| 239 242 |  | 
| 240 243 |  | 
| @@ -307,10 +310,7 @@ class Treequel::Branchset | |
| 307 310 | 
             
            	end
         | 
| 308 311 |  | 
| 309 312 |  | 
| 310 | 
            -
            	### Add an alternate filter to an existing filter by ORing  | 
| 311 | 
            -
            	### @param filterspec  the filter spec to OR with the existing filter
         | 
| 312 | 
            -
            	### @raises [Treequel::InvalidOperation]  if there is no existing filter
         | 
| 313 | 
            -
            	### @see Treequel::Filter.new  for specifics on what +filterspec+ can be
         | 
| 313 | 
            +
            	### Add an alternate filter to an existing filter by ORing it with +filterspec+.
         | 
| 314 314 | 
             
            	def or( *filterspec )
         | 
| 315 315 | 
             
            		opts = self.options
         | 
| 316 316 | 
             
            		existing_filter = self.filter
         | 
| @@ -324,6 +324,14 @@ class Treequel::Branchset | |
| 324 324 | 
             
            	end
         | 
| 325 325 |  | 
| 326 326 |  | 
| 327 | 
            +
            	### Add a clause made from a negated +filterspec+ to an existing filter.
         | 
| 328 | 
            +
            	def not( *filterspec )
         | 
| 329 | 
            +
            		self.log.debug "cloning %p with negated filterspec: %p" % [ self, filterspec ]
         | 
| 330 | 
            +
            		notfilter = Treequel::Filter.new( :not, *filterspec )
         | 
| 331 | 
            +
            		return self.clone( :filter => self.filter + notfilter )
         | 
| 332 | 
            +
            	end
         | 
| 333 | 
            +
             | 
| 334 | 
            +
             | 
| 327 335 | 
             
            	### If called with no argument, returns the current scope of the Branchset. If 
         | 
| 328 336 | 
             
            	### called with an argument (which should be one of the keys of 
         | 
| 329 337 | 
             
            	### Treequel::Constants::SCOPE), returns a clone of the receiving Branchset
         | 
| @@ -427,7 +435,6 @@ class Treequel::Branchset | |
| 427 435 |  | 
| 428 436 | 
             
            	### Return a clone of the receiving Branchset that will perform its search from
         | 
| 429 437 | 
             
            	### +other_dn+ instead of its own.
         | 
| 430 | 
            -
            	### @param [String, #dn]  other_dn  the new base DN of the search
         | 
| 431 438 | 
             
            	def from( other_dn )
         | 
| 432 439 | 
             
            		newset = self.clone
         | 
| 433 440 | 
             
            		other_dn = other_dn.dn if other_dn.respond_to?( :dn )
         | 
    
        data/lib/treequel/control.rb
    CHANGED
    
    | @@ -8,13 +8,15 @@ require 'treequel' | |
| 8 8 |  | 
| 9 9 | 
             
            # Virtual interface methods for Control modules.
         | 
| 10 10 | 
             
            #
         | 
| 11 | 
            -
            #  | 
| 12 | 
            -
            # | 
| 13 | 
            -
            # | 
| 14 | 
            -
            # | 
| 15 | 
            -
            # | 
| 11 | 
            +
            # == Subclassing
         | 
| 12 | 
            +
            # To make a concrete derivative, include this module in a module that
         | 
| 13 | 
            +
            # implements either #get_client_controls or #get_server_controls and #each. 
         | 
| 14 | 
            +
            # Your implementation of #each should +super+ with a block that does the 
         | 
| 15 | 
            +
            # necessary extraction of the result controls and yields back to the original
         | 
| 16 | 
            +
            # block.
         | 
| 16 17 | 
             
            # 
         | 
| 17 | 
            -
            #  | 
| 18 | 
            +
            # == Examples
         | 
| 19 | 
            +
            #
         | 
| 18 20 | 
             
            #   module Treequel::MyControl
         | 
| 19 21 | 
             
            #       include Treequel::Control
         | 
| 20 22 | 
             
            #   
         | 
| @@ -34,8 +34,8 @@ require 'treequel/constants' | |
| 34 34 | 
             
            #       # 
         | 
| 35 35 | 
             
            #   end
         | 
| 36 36 | 
             
            # 
         | 
| 37 | 
            -
            #  | 
| 38 | 
            -
            # | 
| 37 | 
            +
            # See http://deveiate.org/projects/Treequel/ticket/6  Ticket: Add support for 
         | 
| 38 | 
            +
            # the RFC4533 Content Sync operation.
         | 
| 39 39 | 
             
            # 
         | 
| 40 40 | 
             
            module Treequel::ContentSyncControl
         | 
| 41 41 | 
             
            	include Treequel::Control,
         | 
| @@ -63,10 +63,7 @@ module Treequel::PagedResultsControl | |
| 63 63 | 
             
            	attr_accessor :paged_results_cookie
         | 
| 64 64 |  | 
| 65 65 |  | 
| 66 | 
            -
            	### Clone the Branchset with a paged results control | 
| 67 | 
            -
            	### @param [Fixnum] setsize  The size of each result set. If this is nil or 0, removes 
         | 
| 68 | 
            -
            	###                          paging from the Branchset.
         | 
| 69 | 
            -
            	### @return [Treequel::Branchset]  a clone of the receiver with paging set to +setsize+
         | 
| 66 | 
            +
            	### Clone the Branchset with a paged results control with paging set to +setsize+.
         | 
| 70 67 | 
             
            	def with_paged_results( setsize=DEFAULT_PAGE_SIZE )
         | 
| 71 68 | 
             
            		self.log.warn "This control will likely not work in ruby-ldap versions " +
         | 
| 72 69 | 
             
            			" <= 0.9.9. See http://code.google.com/p/ruby-activeldap/issues/" +
         | 
| @@ -87,7 +84,6 @@ module Treequel::PagedResultsControl | |
| 87 84 |  | 
| 88 85 |  | 
| 89 86 | 
             
            	### Clone the Branchset without paging and return it.
         | 
| 90 | 
            -
            	### @return [Treequel::Branchset]  a clone of the receiver, stripped of its paging
         | 
| 91 87 | 
             
            	def without_paging
         | 
| 92 88 | 
             
            		copy = self.clone
         | 
| 93 89 | 
             
            		copy.without_paging!
         | 
| @@ -96,7 +92,6 @@ module Treequel::PagedResultsControl | |
| 96 92 |  | 
| 97 93 |  | 
| 98 94 | 
             
            	### Remove any paging control associated with the receiving Branchset.
         | 
| 99 | 
            -
            	### @return [void]
         | 
| 100 95 | 
             
            	def without_paging!
         | 
| 101 96 | 
             
            		self.paged_results_cookie = nil
         | 
| 102 97 | 
             
            		self.paged_results_setsize = nil
         | 
| @@ -105,7 +100,6 @@ module Treequel::PagedResultsControl | |
| 105 100 |  | 
| 106 101 | 
             
            	### Returns +true+ if the first page of results has been fetched and there are
         | 
| 107 102 | 
             
            	### more pages remaining.
         | 
| 108 | 
            -
            	### @return [Boolean]
         | 
| 109 103 | 
             
            	def has_more_results?
         | 
| 110 104 | 
             
            		return true unless self.done_paging?
         | 
| 111 105 | 
             
            	end
         | 
| @@ -113,7 +107,6 @@ module Treequel::PagedResultsControl | |
| 113 107 |  | 
| 114 108 | 
             
            	### Returns +true+ if results have yet to be fetched, or if they have all been 
         | 
| 115 109 | 
             
            	### fetched.
         | 
| 116 | 
            -
            	### @return [Boolean]
         | 
| 117 110 | 
             
            	def done_paging?
         | 
| 118 111 | 
             
            		return self.paged_results_cookie == ''
         | 
| 119 112 | 
             
            	end
         | 
| @@ -121,7 +114,6 @@ module Treequel::PagedResultsControl | |
| 121 114 |  | 
| 122 115 | 
             
            	### Override the Enumerable method to update the cookie value each time a page 
         | 
| 123 116 | 
             
            	### is fetched.
         | 
| 124 | 
            -
            	### @yieldparam [Treequel::Branch] branch  the branch that's a result of the search.
         | 
| 125 117 | 
             
            	def each( &block )
         | 
| 126 118 | 
             
            		super do |branch|
         | 
| 127 119 | 
             
            			if paged_control = branch.controls.find {|control| control.oid == OID }
         | 
| @@ -145,7 +137,6 @@ module Treequel::PagedResultsControl | |
| 145 137 |  | 
| 146 138 | 
             
            	### Treequel::Control API -- Get the set of server controls currently configured for 
         | 
| 147 139 | 
             
            	### the receiver.
         | 
| 148 | 
            -
            	### @return [Array<LDAP::Control>]  the configured controls
         | 
| 149 140 | 
             
            	def get_server_controls
         | 
| 150 141 | 
             
            		controls = super
         | 
| 151 142 | 
             
            		if pagesize = self.paged_results_setsize && self.paged_results_setsize.nonzero?
         | 
    
        data/lib/treequel/directory.rb
    CHANGED
    
    | @@ -105,21 +105,20 @@ class Treequel::Directory | |
| 105 105 | 
             
            	### Create a new Treequel::Directory with the given +options+. Options is a hash with one
         | 
| 106 106 | 
             
            	### or more of the following key-value pairs:
         | 
| 107 107 | 
             
            	### 
         | 
| 108 | 
            -
            	###  | 
| 109 | 
            -
            	###  | 
| 110 | 
            -
            	### | 
| 111 | 
            -
            	###  | 
| 112 | 
            -
            	### | 
| 113 | 
            -
            	###  | 
| 114 | 
            -
            	### | 
| 115 | 
            -
            	### @option options [String] :base_dn (nil)
         | 
| 108 | 
            +
            	### [+:host+]
         | 
| 109 | 
            +
            	###    The LDAP host to connect to (default: 'localhost').
         | 
| 110 | 
            +
            	### [+:port+]
         | 
| 111 | 
            +
            	###    The port number to connect to (default: LDAP::LDAP_PORT).
         | 
| 112 | 
            +
            	### [+:connect_type+]
         | 
| 113 | 
            +
            	###    The type of connection to establish; :tls, :ssl, or :plain. Defaults to +:tls+.
         | 
| 114 | 
            +
            	### [+:base_dn+]
         | 
| 116 115 | 
             
            	###    The base DN of the directory; defaults to the first naming context of
         | 
| 117 116 | 
             
            	###    the directory's root DSE.
         | 
| 118 | 
            -
            	###  | 
| 117 | 
            +
            	### [+:bind_dn+]
         | 
| 119 118 | 
             
            	###    The DN of the user to bind as; if unset, binds anonymously.
         | 
| 120 | 
            -
            	###  | 
| 119 | 
            +
            	### [+:pass+]
         | 
| 121 120 | 
             
            	###    The password to use when binding.
         | 
| 122 | 
            -
            	###  | 
| 121 | 
            +
            	### [+:results_class+]
         | 
| 123 122 | 
             
            	###    The class to instantiate by default for entries fetched from the Directory.
         | 
| 124 123 | 
             
            	def initialize( options={} )
         | 
| 125 124 | 
             
            		options                = DEFAULT_OPTIONS.merge( options )
         | 
| @@ -171,31 +170,24 @@ class Treequel::Directory | |
| 171 170 |  | 
| 172 171 |  | 
| 173 172 | 
             
            	# The host to connect to.
         | 
| 174 | 
            -
            	# @return [String]
         | 
| 175 173 | 
             
            	attr_accessor :host
         | 
| 176 174 |  | 
| 177 175 | 
             
            	# The port to connect to.
         | 
| 178 | 
            -
            	# @return [Fixnum]
         | 
| 179 176 | 
             
            	attr_accessor :port
         | 
| 180 177 |  | 
| 181 178 | 
             
            	# The type of connection to establish
         | 
| 182 | 
            -
            	# @return [Symbol]
         | 
| 183 179 | 
             
            	attr_accessor :connect_type
         | 
| 184 180 |  | 
| 185 181 | 
             
            	# The Class to instantiate when wrapping results fetched from the Directory.
         | 
| 186 | 
            -
            	# @return [Class]
         | 
| 187 182 | 
             
            	attr_accessor :results_class
         | 
| 188 183 |  | 
| 189 184 | 
             
            	# The base DN of the directory
         | 
| 190 | 
            -
            	# @return [String]
         | 
| 191 185 | 
             
            	attr_accessor :base_dn
         | 
| 192 186 |  | 
| 193 187 | 
             
            	# The control modules that are registered with the directory
         | 
| 194 | 
            -
            	# @return [Array<Module>]
         | 
| 195 188 | 
             
            	attr_reader :registered_controls
         | 
| 196 189 |  | 
| 197 190 | 
             
            	# The DN of the user the directory is bound as
         | 
| 198 | 
            -
            	# @return [String]
         | 
| 199 191 | 
             
            	attr_reader :bound_user
         | 
| 200 192 |  | 
| 201 193 |  | 
| @@ -206,14 +198,12 @@ class Treequel::Directory | |
| 206 198 |  | 
| 207 199 |  | 
| 208 200 | 
             
            	### Fetch the Branch for the base node of the directory.
         | 
| 209 | 
            -
            	### @return [Treequel::Branch]
         | 
| 210 201 | 
             
            	def base
         | 
| 211 202 | 
             
            		return @base ||= self.results_class.new( self, self.base_dn )
         | 
| 212 203 | 
             
            	end
         | 
| 213 204 |  | 
| 214 205 |  | 
| 215 206 | 
             
            	### Returns a string that describes the directory
         | 
| 216 | 
            -
            	### @return [String]
         | 
| 217 207 | 
             
            	def to_s
         | 
| 218 208 | 
             
            		return "%s:%d (%s, %s, %s)" % [
         | 
| 219 209 | 
             
            			self.host,
         | 
| @@ -226,7 +216,6 @@ class Treequel::Directory | |
| 226 216 |  | 
| 227 217 |  | 
| 228 218 | 
             
            	### Return a human-readable representation of the object suitable for debugging
         | 
| 229 | 
            -
            	### @return [String]
         | 
| 230 219 | 
             
            	def inspect
         | 
| 231 220 | 
             
            		return %{#<%s:0x%0x %s:%d (%s) base_dn=%p, bound as=%s, schema=%s>} % [
         | 
| 232 221 | 
             
            			self.class.name,
         | 
| @@ -243,7 +232,6 @@ class Treequel::Directory | |
| 243 232 |  | 
| 244 233 | 
             
            	### Return the LDAP::Conn object associated with this directory, creating it with the
         | 
| 245 234 | 
             
            	### current options if necessary.
         | 
| 246 | 
            -
            	### @return [LDAP::Conn, LDAP::SSLConn]
         | 
| 247 235 | 
             
            	def conn
         | 
| 248 236 | 
             
            		return @conn ||= self.connect
         | 
| 249 237 | 
             
            	end
         | 
| @@ -252,15 +240,12 @@ class Treequel::Directory | |
| 252 240 | 
             
            	### Returns +true+ if a connection has been established. This does not necessarily mean
         | 
| 253 241 | 
             
            	### that the connection is still valid, it just means it successfully established one
         | 
| 254 242 | 
             
            	### at some point.
         | 
| 255 | 
            -
            	### @return [Boolean]
         | 
| 256 243 | 
             
            	def connected?
         | 
| 257 244 | 
             
            		return @conn ? true : false
         | 
| 258 245 | 
             
            	end
         | 
| 259 246 |  | 
| 260 247 |  | 
| 261 248 | 
             
            	### Drop the existing connection and establish a new one.
         | 
| 262 | 
            -
            	### @return [Boolean]  +true+ if the connection was re-established
         | 
| 263 | 
            -
            	### @raise [RuntimeError]  if the re-connection failed
         | 
| 264 249 | 
             
            	def reconnect
         | 
| 265 250 | 
             
            		self.log.info "Reconnecting to %s..." % [ self.uri ]
         | 
| 266 251 | 
             
            		@conn = self.connect
         | 
| @@ -276,7 +261,6 @@ class Treequel::Directory | |
| 276 261 |  | 
| 277 262 |  | 
| 278 263 | 
             
            	### Return the URI object that corresponds to the directory.
         | 
| 279 | 
            -
            	### @return [URI::LDAP]
         | 
| 280 264 | 
             
            	def uri
         | 
| 281 265 | 
             
            		uri_parts = {
         | 
| 282 266 | 
             
            			:scheme => self.connect_type == :ssl ? 'ldaps' : 'ldap',
         | 
| @@ -290,11 +274,6 @@ class Treequel::Directory | |
| 290 274 |  | 
| 291 275 |  | 
| 292 276 | 
             
            	### Bind as the specified +user_dn+ and +password+.
         | 
| 293 | 
            -
            	### 
         | 
| 294 | 
            -
            	### @param [String, #dn] user_dn  the DN of the user to bind as
         | 
| 295 | 
            -
            	### @param [String] password      the password to bind with
         | 
| 296 | 
            -
            	### 
         | 
| 297 | 
            -
            	### @return [void]
         | 
| 298 277 | 
             
            	def bind( user_dn, password )
         | 
| 299 278 | 
             
            		user_dn = user_dn.dn if user_dn.respond_to?( :dn )
         | 
| 300 279 |  | 
| @@ -307,10 +286,6 @@ class Treequel::Directory | |
| 307 286 |  | 
| 308 287 | 
             
            	### Execute the provided +block+ after binding as +user_dn+ with the given +password+. After
         | 
| 309 288 | 
             
            	### the block returns, the original binding (if any) will be restored.
         | 
| 310 | 
            -
            	### 
         | 
| 311 | 
            -
            	### @param (see #bind)
         | 
| 312 | 
            -
            	### 
         | 
| 313 | 
            -
            	### @return [void]
         | 
| 314 289 | 
             
            	def bound_as( user_dn, password )
         | 
| 315 290 | 
             
            		raise LocalJumpError, "no block given" unless block_given?
         | 
| 316 291 | 
             
            		previous_bind_dn = @bound_user
         | 
| @@ -324,7 +299,6 @@ class Treequel::Directory | |
| 324 299 |  | 
| 325 300 |  | 
| 326 301 | 
             
            	### Returns +true+ if the directory's connection is already bound to the directory.
         | 
| 327 | 
            -
            	### @return [Boolean]
         | 
| 328 302 | 
             
            	def bound?
         | 
| 329 303 | 
             
            		return self.conn.bound?
         | 
| 330 304 | 
             
            	end
         | 
| @@ -332,7 +306,6 @@ class Treequel::Directory | |
| 332 306 |  | 
| 333 307 |  | 
| 334 308 | 
             
            	### Ensure that the the receiver's connection is unbound.
         | 
| 335 | 
            -
            	### @return [void]
         | 
| 336 309 | 
             
            	def unbind
         | 
| 337 310 | 
             
            		if @conn.bound?
         | 
| 338 311 | 
             
            			old_conn = @conn
         | 
| @@ -343,7 +316,6 @@ class Treequel::Directory | |
| 343 316 |  | 
| 344 317 |  | 
| 345 318 | 
             
            	### Return the RDN string to the given +dn+ from the base of the directory.
         | 
| 346 | 
            -
            	### @param [#to_s] dn  the DN of the entry
         | 
| 347 319 | 
             
            	def rdn_to( dn )
         | 
| 348 320 | 
             
            		base_re = Regexp.new( ',' + Regexp.quote(self.base_dn) + '$' )
         | 
| 349 321 | 
             
            		return dn.to_s.sub( base_re, '' )
         | 
| @@ -352,8 +324,6 @@ class Treequel::Directory | |
| 352 324 |  | 
| 353 325 | 
             
            	### Given a Treequel::Branch object, find its corresponding LDAP::Entry and return
         | 
| 354 326 | 
             
            	### it.
         | 
| 355 | 
            -
            	### 
         | 
| 356 | 
            -
            	### @param [Treequel::Branch] branch  the branch to look up
         | 
| 357 327 | 
             
            	def get_entry( branch )
         | 
| 358 328 | 
             
            		self.log.debug "Looking up entry for %p" % [ branch.dn ]
         | 
| 359 329 | 
             
            		return self.conn.search_ext2( branch.dn, SCOPE[:base], '(objectClass=*)' ).first
         | 
| @@ -366,8 +336,6 @@ class Treequel::Directory | |
| 366 336 | 
             
            	### Given a Treequel::Branch object, find its corresponding LDAP::Entry and return
         | 
| 367 337 | 
             
            	### it with its operational attributes (http://tools.ietf.org/html/rfc4512#section-3.4)
         | 
| 368 338 | 
             
            	### included.
         | 
| 369 | 
            -
            	### 
         | 
| 370 | 
            -
            	### @param [Treequel::Branch] branch  the branch to look up
         | 
| 371 339 | 
             
            	def get_extended_entry( branch )
         | 
| 372 340 | 
             
            		self.log.debug "Looking up entry (with operational attributes) for %p" % [ branch.dn ]
         | 
| 373 341 | 
             
            		return self.conn.search_ext2( branch.dn, SCOPE[:base], '(objectClass=*)', %w[* +] ).first
         | 
| @@ -388,51 +356,46 @@ class Treequel::Directory | |
| 388 356 | 
             
            	end
         | 
| 389 357 |  | 
| 390 358 |  | 
| 391 | 
            -
            	### Perform a +scope+ search at +base+ using the specified +filter+.
         | 
| 392 | 
            -
            	### 
         | 
| 393 | 
            -
            	###  | 
| 394 | 
            -
            	###  | 
| 395 | 
            -
            	###                            +:onelevel+, +:base+, or +:subtree+. 
         | 
| 396 | 
            -
            	### @param [#to_s] filter      The search filter (RFC4515), either as a String 
         | 
| 397 | 
            -
            	###                            or something that stringifies to an filter string.
         | 
| 398 | 
            -
            	### @param [Hash] options      Search options.
         | 
| 359 | 
            +
            	### Perform a +scope+ search at +base+ using the specified +filter+. The scope can be one of 
         | 
| 360 | 
            +
            	### +:onelevel+, +:base+, or +:subtree+. The search filter should be a RFC4515-style filter 
         | 
| 361 | 
            +
            	### either as a String or something that stringifies to one (e.g., a Treequel::Filter). The
         | 
| 362 | 
            +
            	### available search options are:
         | 
| 399 363 | 
             
            	### 
         | 
| 400 | 
            -
            	###  | 
| 364 | 
            +
            	### [+:results_class+]
         | 
| 401 365 | 
             
            	###    The Class to use when wrapping results; if not specified, defaults to the class 
         | 
| 402 366 | 
             
            	###    of +base+ if it responds to #new_from_entry, or the directory object's 
         | 
| 403 367 | 
             
            	###    #results_class if it does not.
         | 
| 404 | 
            -
            	###  | 
| 368 | 
            +
            	### [+:selectattrs+]
         | 
| 405 369 | 
             
            	###    The attributes to return from the search; defaults to '*', which means to
         | 
| 406 370 | 
             
            	###    return all non-operational attributes. Specifying '+' will cause the search
         | 
| 407 371 | 
             
            	###    to include operational parameters as well.
         | 
| 408 | 
            -
            	###  | 
| 372 | 
            +
            	### [+:attrsonly+]
         | 
| 409 373 | 
             
            	###    If +true, the LDAP::Entry objects returned from the search won't have attribute values.
         | 
| 410 374 | 
             
            	###    This has no real effect on Treequel::Branches, but is provided in case other 
         | 
| 411 | 
            -
            	###    +results_class+ classes need it.
         | 
| 412 | 
            -
            	###  | 
| 413 | 
            -
            	###    Any server controls that should be sent with the search | 
| 414 | 
            -
            	### | 
| 415 | 
            -
            	### | 
| 416 | 
            -
            	###  | 
| 375 | 
            +
            	###    +results_class+ classes need it. Defaults to +false+.
         | 
| 376 | 
            +
            	### [+:server_controls+]
         | 
| 377 | 
            +
            	###    Any server controls that should be sent with the search as an Array of LDAP::Control
         | 
| 378 | 
            +
            	###    objects.
         | 
| 379 | 
            +
            	### [+:client_controls+]
         | 
| 380 | 
            +
            	###    Any client controls that should be applied to the search as an Array of LDAP::Control
         | 
| 381 | 
            +
            	###    objects.
         | 
| 382 | 
            +
            	### [+:timeout_s+]
         | 
| 417 383 | 
             
            	###    The number of seconds (in addition to :timeout_us) after which the search request should 
         | 
| 418 384 | 
             
            	###    be aborted.
         | 
| 419 | 
            -
            	###  | 
| 385 | 
            +
            	### [+:timeout_us+]
         | 
| 420 386 | 
             
            	###    The number of microseconds (in addition to :timeout_s) after which the search request 
         | 
| 421 387 | 
             
            	###    should be aborted.
         | 
| 422 | 
            -
            	###  | 
| 388 | 
            +
            	### [+:limit+]
         | 
| 423 389 | 
             
            	###    The maximum number of results to return from the server.
         | 
| 424 | 
            -
            	###  | 
| 390 | 
            +
            	### [+:sort_attribute+]
         | 
| 425 391 | 
             
            	###    An Array of String attribute names to sort by. 
         | 
| 426 | 
            -
            	###  | 
| 392 | 
            +
            	### [+:sort_func+]
         | 
| 427 393 | 
             
            	###    A function that will provide sorting.
         | 
| 428 394 | 
             
            	### 
         | 
| 429 | 
            -
            	###  | 
| 430 | 
            -
            	### | 
| 431 | 
            -
            	### | 
| 395 | 
            +
            	### Returns the array of results, each of which is wrapped in the options[:results_class]. 
         | 
| 396 | 
            +
            	### If a block is given, it acts like a filter: it's called once for each result, and the 
         | 
| 397 | 
            +
            	### array of return values from the block is returned instead.
         | 
| 432 398 | 
             
            	### 
         | 
| 433 | 
            -
            	### @yield [branch]  an optional block, which will receive the results one at a time
         | 
| 434 | 
            -
            	### @yieldparam [Treequel::Branch] branch  the resulting entry, wrapped in 
         | 
| 435 | 
            -
            	###    the options[:results_class].
         | 
| 436 399 | 
             
            	def search( base, scope=:subtree, filter='(objectClass=*)', options={} )
         | 
| 437 400 | 
             
            		collectclass = nil
         | 
| 438 401 |  | 
| @@ -451,13 +414,13 @@ class Treequel::Directory | |
| 451 414 | 
             
            			self.normalize_search_parameters( base, scope, filter, options )
         | 
| 452 415 |  | 
| 453 416 | 
             
            		# Unwrap the search options from the hash in the correct order
         | 
| 454 | 
            -
            		self.log.debug  | 
| 417 | 
            +
            		self.log.debug do
         | 
| 455 418 | 
             
            			attrlist = SEARCH_PARAMETER_ORDER.inject([]) do |list, param|
         | 
| 456 419 | 
             
            				list << "%s: %p" % [ param, searchopts[param] ]
         | 
| 457 420 | 
             
            			end
         | 
| 458 421 | 
             
            			"searching with base: %p, scope: %p, filter: %p, %s" %
         | 
| 459 422 | 
             
            				[ base_dn, scope, filter, attrlist.join(', ') ]
         | 
| 460 | 
            -
            		 | 
| 423 | 
            +
            		end
         | 
| 461 424 | 
             
            		parameters = searchopts.values_at( *SEARCH_PARAMETER_ORDER )
         | 
| 462 425 |  | 
| 463 426 | 
             
            		# Wrap each result in the class derived from the 'base' argument
         | 
| @@ -515,11 +478,8 @@ class Treequel::Directory | |
| 515 478 | 
             
            	end
         | 
| 516 479 |  | 
| 517 480 |  | 
| 518 | 
            -
            	### Create the entry for the given +branch+, setting its attributes to +newattrs | 
| 519 | 
            -
            	###  | 
| 520 | 
            -
            	### @param [Hash, Array<LDAP::Mod>] newattrs  the attributes to create the entry with. This
         | 
| 521 | 
            -
            	###                                   can be either a Hash of attributes, or an Array of
         | 
| 522 | 
            -
            	###                                   LDAP::Mod objects.
         | 
| 481 | 
            +
            	### Create the entry for the given +branch+, setting its attributes to +newattrs+, which
         | 
| 482 | 
            +
            	### can be either a Hash of attributes, or an Array of LDAP::Mod objects.
         | 
| 523 483 | 
             
            	def create( branch, newattrs={} )
         | 
| 524 484 | 
             
            		newattrs = normalize_attributes( newattrs ) if newattrs.is_a?( Hash )
         | 
| 525 485 | 
             
            		self.conn.add( branch.to_s, newattrs )
         | 
| @@ -556,7 +516,6 @@ class Treequel::Directory | |
| 556 516 | 
             
            	### argument(e.g., Proc, Method, Hash); the argument is the raw value String returned 
         | 
| 557 517 | 
             
            	### from the LDAP entry, and it should return the converted value. Adding a mapping 
         | 
| 558 518 | 
             
            	### with a nil +conversion+ effectively clears it.
         | 
| 559 | 
            -
            	### @see #convert_to_object
         | 
| 560 519 | 
             
            	def add_attribute_conversion( oid, conversion=nil )
         | 
| 561 520 | 
             
            		conversion = Proc.new if block_given?
         | 
| 562 521 | 
             
            		@attribute_conversions[ oid ] = conversion
         | 
| @@ -567,7 +526,6 @@ class Treequel::Directory | |
| 567 526 | 
             
            	### responds to #[] with an object argument(e.g., Proc, Method, Hash); the argument is 
         | 
| 568 527 | 
             
            	### the Ruby object that's being set as a value in an LDAP entry, and it should return the 
         | 
| 569 528 | 
             
            	### raw LDAP string. Adding a mapping with a nil +conversion+ effectively clears it.
         | 
| 570 | 
            -
            	### @see #convert_to_attribute
         | 
| 571 529 | 
             
            	def add_object_conversion( oid, conversion=nil )
         | 
| 572 530 | 
             
            		conversion = Proc.new if block_given?
         | 
| 573 531 | 
             
            		@object_conversions[ oid ] = conversion
         | 
    
        data/lib/treequel/exceptions.rb
    CHANGED
    
    | @@ -30,7 +30,6 @@ module Treequel | |
| 30 30 | 
             
            	class ValidationFailed < Treequel::ModelError
         | 
| 31 31 |  | 
| 32 32 | 
             
            		### Create a new Treequel::ValidationFailed exception with the given +errors+.
         | 
| 33 | 
            -
            		### @param [Treequel::Model::Errors, String] errors  the validaton errors
         | 
| 34 33 | 
             
            		def initialize( errors )
         | 
| 35 34 | 
             
            			if errors.respond_to?( :full_messages )
         | 
| 36 35 | 
             
            				@errors = errors
         | 
| @@ -44,7 +43,7 @@ module Treequel | |
| 44 43 | 
             
            		public
         | 
| 45 44 | 
             
            		######
         | 
| 46 45 |  | 
| 47 | 
            -
            		#  | 
| 46 | 
            +
            		# the validation errors
         | 
| 48 47 | 
             
            		attr_reader :errors
         | 
| 49 48 |  | 
| 50 49 | 
             
            	end # class ValidationFailed
         | 
    
        data/lib/treequel/filter.rb
    CHANGED
    
    | @@ -64,8 +64,6 @@ class Treequel::Filter | |
| 64 64 |  | 
| 65 65 |  | 
| 66 66 | 
             
            		### Append operator: add the +other+ filter to the list.
         | 
| 67 | 
            -
            		### @param [Treequel::Filter] other  the new filter to add
         | 
| 68 | 
            -
            		### @return [Treequel::Filter::FilterList]  self (for chaining)
         | 
| 69 67 | 
             
            		def <<( other )
         | 
| 70 68 | 
             
            			@filters << other
         | 
| 71 69 | 
             
            			return self
         | 
| @@ -75,7 +73,7 @@ class Treequel::Filter | |
| 75 73 |  | 
| 76 74 |  | 
| 77 75 | 
             
            	### An abstract class for filter components.
         | 
| 78 | 
            -
            	###  | 
| 76 | 
            +
            	### Subclass and override #to_s to implement a custom Component class.
         | 
| 79 77 | 
             
            	class Component
         | 
| 80 78 | 
             
            		include Treequel::Loggable
         | 
| 81 79 |  | 
| @@ -150,7 +148,6 @@ class Treequel::Filter | |
| 150 148 | 
             
            		end
         | 
| 151 149 |  | 
| 152 150 | 
             
            		### Add an additional filter to the list of requirements
         | 
| 153 | 
            -
            		### @param [Treequel::Filter] filter  the new requirement
         | 
| 154 151 | 
             
            		def add_requirement( filter )
         | 
| 155 152 | 
             
            			@filterlist << filter
         | 
| 156 153 | 
             
            		end
         | 
| @@ -176,7 +173,6 @@ class Treequel::Filter | |
| 176 173 | 
             
            		end
         | 
| 177 174 |  | 
| 178 175 | 
             
            		### Add an additional filter to the list of alternatives
         | 
| 179 | 
            -
            		### @param [Treequel::Filter] filter  the new alternative
         | 
| 180 176 | 
             
            		def add_alternation( filter )
         | 
| 181 177 | 
             
            			@filterlist << filter
         | 
| 182 178 | 
             
            		end
         | 
| @@ -712,7 +708,7 @@ class Treequel::Filter | |
| 712 708 | 
             
            	end
         | 
| 713 709 |  | 
| 714 710 |  | 
| 715 | 
            -
            	### AND  | 
| 711 | 
            +
            	### Return a new Filter that is the AND filter of the receiver with +other_filter+.
         | 
| 716 712 | 
             
            	def &( other_filter )
         | 
| 717 713 | 
             
            		return other_filter if self.promiscuous?
         | 
| 718 714 | 
             
            		return self.dup if other_filter.promiscuous?
         | 
| @@ -721,8 +717,7 @@ class Treequel::Filter | |
| 721 717 | 
             
            	alias_method :+, :&
         | 
| 722 718 |  | 
| 723 719 |  | 
| 724 | 
            -
            	### OR  | 
| 725 | 
            -
            	### @param [Treequel::Filter] other_filter
         | 
| 720 | 
            +
            	### Return a new Filter that is the OR filter of the receiver with +other_filter+.
         | 
| 726 721 | 
             
            	def |( other_filter )
         | 
| 727 722 | 
             
            		return other_filter if self.promiscuous?
         | 
| 728 723 | 
             
            		return self.dup if other_filter.promiscuous?
         | 
    
        data/lib/treequel/mixins.rb
    CHANGED
    
    | @@ -22,7 +22,6 @@ module Treequel | |
| 22 22 | 
             
            		### Define the given +delegated_methods+ as delegators to the like-named method
         | 
| 23 23 | 
             
            		### of the return value of the +delegate_method+.
         | 
| 24 24 | 
             
            		### 
         | 
| 25 | 
            -
            		### @example
         | 
| 26 25 | 
             
            		###    class MyClass
         | 
| 27 26 | 
             
            		###      extend Treequel::Delegation
         | 
| 28 27 | 
             
            		###      
         | 
| @@ -122,10 +121,8 @@ module Treequel | |
| 122 121 | 
             
            		module_function
         | 
| 123 122 | 
             
            		###############
         | 
| 124 123 |  | 
| 125 | 
            -
            		### Normalize the given key
         | 
| 126 | 
            -
            		###  | 
| 127 | 
            -
            		### @return a downcased Symbol stripped of any invalid characters, and 
         | 
| 128 | 
            -
            		###         with '-' characters converted to '_'.
         | 
| 124 | 
            +
            		### Normalize the given key, returning a downcased Symbol stripped of any invalid 
         | 
| 125 | 
            +
            		### characters, and with '-' characters converted to '_'.
         | 
| 129 126 | 
             
            		def normalize_key( key )
         | 
| 130 127 | 
             
            			return key if key.to_s =~ Treequel::Constants::Patterns::NUMERICOID
         | 
| 131 128 | 
             
            			return key.to_s.downcase.
         | 
| @@ -135,7 +132,6 @@ module Treequel | |
| 135 132 | 
             
            		end
         | 
| 136 133 |  | 
| 137 134 | 
             
            		### Return a copy of +hash+ with all of its keys normalized by #normalize_key.
         | 
| 138 | 
            -
            		### @param [Hash] hash  the Hash to normalize
         | 
| 139 135 | 
             
            		def normalize_hash( hash )
         | 
| 140 136 | 
             
            			hash = hash.dup
         | 
| 141 137 | 
             
            			hash.keys.each do |key|
         | 
| @@ -155,7 +151,6 @@ module Treequel | |
| 155 151 |  | 
| 156 152 | 
             
            		### A logging proxy class that wraps calls to the logger into calls that include
         | 
| 157 153 | 
             
            		### the name of the calling class.
         | 
| 158 | 
            -
            		### @private
         | 
| 159 154 | 
             
            		class ClassNameProxy
         | 
| 160 155 |  | 
| 161 156 | 
             
            			### Create a new proxy for the given +klass+.
         | 
| @@ -48,22 +48,19 @@ class Treequel::Model::Errors < ::Hash | |
| 48 48 |  | 
| 49 49 |  | 
| 50 50 | 
             
            	### Adds an error for the given +subject+.
         | 
| 51 | 
            -
            	### @param [Symbol, #to_sym] subject    the subject of the error
         | 
| 52 | 
            -
            	### @param [String] message             the description of the error condition
         | 
| 53 51 | 
             
            	def add( subject, message )
         | 
| 54 52 | 
             
            		self[ subject ] << message
         | 
| 55 53 | 
             
            	end
         | 
| 56 54 |  | 
| 57 55 |  | 
| 58 56 | 
             
            	### Get the number of errors that have been registered.
         | 
| 59 | 
            -
            	### @Return [Fixnum]  the number of errors
         | 
| 60 57 | 
             
            	def count
         | 
| 61 58 | 
             
            		return self.values.inject( 0 ) {|num, val| num + val.length }
         | 
| 62 59 | 
             
            	end
         | 
| 63 60 |  | 
| 64 61 |  | 
| 65 62 | 
             
                ### Get an Array of messages describing errors which have occurred.
         | 
| 66 | 
            -
                ###  | 
| 63 | 
            +
                ### 
         | 
| 67 64 | 
             
                ###   errors.full_messages
         | 
| 68 65 | 
             
                ###   # => ['cn is not valid',
         | 
| 69 66 | 
             
                ###   #     'uid is not at least 2 letters']
         |