Class: Treequel::Branchset

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Constants, Control, Loggable
Defined in:
lib/treequel/branchset.rb

Overview

A branchset represents an abstract set of LDAP records returned by a search in a directory. It can be used to create, retrieve, update, and delete records.

Search results are fetched on demand, so a branchset can be kept around and reused indefinitely (branchsets never cache results):

  people = directory.ou( :people )
  davids = people.filter(:firstName => 'david') # no records are retrieved
  davids.all # records are retrieved
  davids.all # records are retrieved again

Most branchset methods return modified copies of the branchset (functional style), so you can reuse different branchsets to access data:

  # (employeeId < 2000)
  veteran_davids = davids.filter( :employeeId < 2000 )
  
  # (&(employeeId < 2000)(|(deactivated >= '2008-12-22')(!(deactivated=*))))
  active_veteran_davids = 
      veteran_davids.filter([:or, ['deactivated >= ?', Date.today], [:not, [:deactivated]] ])
  
  # (&(employeeId < 2000)(|(deactivated >= '2008-12-22')(!(deactivated=*)))(mobileNumber=*))
  active_veteran_davids_with_cellphones = 
      active_veteran_davids.filter( [:mobileNumber] )

Branchsets are Enumerable objects, so they can be manipulated using any of the Enumerable methods, such as map, inject, etc.

Constant Summary

DEFAULT_SCOPE =

The default scope to use when searching if none is specified

:subtree
DEFAULT_FILTER =

The default filter to use when searching if non is specified

:objectClass
DEFAULT_OPTIONS =

The default options hash for new Branchsets

{
  :filter  => DEFAULT_FILTER,
  :scope   => DEFAULT_SCOPE,
  :timeout => 0,                  # Floating-point timeout -> sec, usec
  :select  => [],                 # Attributes to return -> attrs
  :order   => '',                 # Sorting criteria -> s_attr/s_proc
  :limit   => 0,                  # Limit -> number of results
}.freeze

Constants included from Loggable

LEVEL

Constants included from Constants

CONTROL_NAMES, CONTROL_OIDS, EXTENSION_NAMES, EXTENSION_OIDS, FEATURE_NAMES, FEATURE_OIDS, SCOPE, SCOPE_NAME

Instance Attribute Summary

Instance Method Summary

Methods included from Loggable

#initialize_copy, #log, #log_debug

Methods included from Control

#get_client_controls, #get_server_controls

Constructor Details

- (Branchset) initialize(branch, options = {})

Create a new Branchset for a search from the DN of the specified branch (a Treequel::Branch), with the given options.



77
78
79
80
81
82
83
84
85
# File 'lib/treequel/branchset.rb', line 77

def initialize( branch, options={} )
  @branch = branch
  @options = DEFAULT_OPTIONS.merge( options )

  self.extend( *@branch.directory.registered_controls ) unless
    @branch.directory.registered_controls.empty?

  super()
end

Instance Attribute Details

- (Object) branch

The branchset’s base branch that will be used when searching as the basedn



98
99
100
# File 'lib/treequel/branchset.rb', line 98

def branch
  @branch
end

- (Object) options

The branchset’s search options hash



95
96
97
# File 'lib/treequel/branchset.rb', line 95

def options
  @options
end

Instance Method Details

- (Treequel::BranchCollection) +(other_branchset)

Create a BranchCollection from the receiver and the other_branchset and return it.

Parameters:

Returns:



183
184
185
# File 'lib/treequel/branchset.rb', line 183

def +( other_branchset )
  return Treequel::BranchCollection.new( self, other_branchset )
end

- (Object) all



92
# File 'lib/treequel/branchset.rb', line 92

alias_method :all, :entries

- (Object) as(branchclass)

Return a clone of the receiving Branchset that will return instances of the give branchclass instead of Treequel::Branch objects. This may be a subclass of Treequel::Branch, but it doesn’t need to be as long as they duck-type the same.



364
365
366
367
368
# File 'lib/treequel/branchset.rb', line 364

def as( branchclass )
  newset = self.clone
  newset.branch = branchclass.new( self.branch.directory, self.branch.dn )
  return newset
end

- (Object) base_dn

Returns the DN of the Branchset’s branch.



113
114
115
# File 'lib/treequel/branchset.rb', line 113

def base_dn
  return self.branch.dn
end

- (Object) clone(options = {})

Override the default clone method to support cloning with different options.



119
120
121
122
123
124
# File 'lib/treequel/branchset.rb', line 119

def clone( options={} )
  self.log.debug "cloning %p with options = %p" % [ self, options ]
  newset = super()
  newset.options = @options.merge( options )
  return newset
end

- (Object) collection

Create a BranchCollection from the results of the Branchset and return it.



174
175
176
# File 'lib/treequel/branchset.rb', line 174

def collection
  return Treequel::BranchCollection.new( self.all )
end

- (Object) each(&block)

Iterate over the entries which match the current criteria and yield each of them as Treequel::Branch objects to the supplied block.

Raises:

  • (LocalJumpError)


190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/treequel/branchset.rb', line 190

def each( &block )
  raise LocalJumpError, "no block given" unless block

  self.branch.search( self.scope, self.filter,
    :selectattrs => self.select,
    :timeout => self.timeout,
    # :sortby => self.order,
    :limit => self.limit,
    :client_controls => self.get_client_controls,
    :server_controls => self.get_server_controls,
    &block
    )
end

- (Boolean) empty?

Return true if no entries match the Branchset’s current criteria.

Returns:

  • (Boolean)


220
221
222
# File 'lib/treequel/branchset.rb', line 220

def empty?
  return self.first.nil? ? true : false
end

- (Object) extend(*modules)

Extend the Branchset with one or more modules. Overridden to also call the modules’ initializers if they have them.



103
104
105
106
107
108
109
# File 'lib/treequel/branchset.rb', line 103

def extend( *modules )
  super
  modules.each do |mod|
    mod.instance_method( :initialize ).bind( self ).call if
      mod.private_instance_methods.map( &:to_sym ).include?( :initialize )
  end
end

- (Object) filter(*filterspec)

Returns a clone of the receiving Branchset with the given filterspec added to it.



265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/treequel/branchset.rb', line 265

def filter( *filterspec )
  if filterspec.empty?
    opts = self.options
    opts[:filter] = Treequel::Filter.new(opts[:filter]) unless
      opts[:filter].is_a?( Treequel::Filter )
    return opts[:filter]
  else
    self.log.debug "cloning %p with filterspec: %p" % [ self, filterspec ]
    newfilter = Treequel::Filter.new( *filterspec )
    return self.clone( :filter => self.filter + newfilter )
  end
end

- (Object) filter_string

Return an LDAP filter string made up of the current filter components.



168
169
170
# File 'lib/treequel/branchset.rb', line 168

def filter_string
  return self.filter.to_s
end

- (Object) first

Fetch the first entry which matches the current criteria and return it as an instance of the object that is set as the branch (e.g., Treequel::Branch).



207
208
209
210
211
212
213
214
215
216
# File 'lib/treequel/branchset.rb', line 207

def first
  self.branch.search( self.scope, self.filter,
    :selectattrs => self.select,
    :timeout => self.timeout,
    # :sortby => self.order,
    :client_controls => self.get_client_controls,
    :server_controls => self.get_server_controls,
    :limit => 1
    ).first
end

- (Object) inspect

Return a human-readable string representation of the object suitable for debugging.



153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/treequel/branchset.rb', line 153

def inspect
  "#<%s:0x%0x base_dn='%s', filter=%s, scope=%s, select=%s, limit=%d, timeout=%0.3f>" % [
    self.class.name,
    self.object_id * 2,
    self.base_dn,
    self.filter_string,
    self.scope,
    self.select.empty? ? '*' : self.select.join(','),
    self.limit,
    self.timeout,
  ]
end

- (Object) limit(new_limit = nil)

If called with a new_limit, returns a clone of the receiving Branchset that will fetch (at most) new_limit Branches. If no new_limit argument is specified, returns the Branchset’s current limit. A limit of ‘0’ means that all Branches will be fetched.



325
326
327
328
329
330
331
332
# File 'lib/treequel/branchset.rb', line 325

def limit( new_limit=nil )
  if new_limit.nil?
    return self.options[:limit]
  else
    self.log.debug "cloning %p with new limit: %p" % [ self, new_limit ]
    return self.clone( :limit => Integer(new_limit) )
  end
end

- (Object) map(attribute = nil, &block)

Either maps entries which match the current criteria into an Array of the given attribute, or falls back to the block form if no attribute is specified. If both an attribute and a block are given, the block is called once for each attribute value instead of with each Branch.



229
230
231
232
233
234
235
236
237
238
239
# File 'lib/treequel/branchset.rb', line 229

def map( attribute=nil, &block ) # :yields: branch or attribute
  if attribute
    if block
      super() {|branch| block.call(branch[attribute]) }
    else
      super() {|branch| branch[attribute] }
    end
  else
    super( &block )
  end
end

- (Object) scope(new_scope = nil)

If called with no argument, returns the current scope of the Branchset. If called with an argument (which should be one of the keys of Treequel::Constants::SCOPE), returns a clone of the receiving Branchset with the new_scope.



283
284
285
286
287
288
289
290
# File 'lib/treequel/branchset.rb', line 283

def scope( new_scope=nil )
  if new_scope
    self.log.debug "cloning %p with new scope: %p" % [ self, new_scope ]
    return self.clone( :scope => new_scope.to_sym )
  else
    return @options[:scope]
  end
end

- (Object) select(*attributes)

If called with one or more attributes, returns a clone of the receiving Branchset that will only fetch the attributes specified. If no attributes are specified, return the list of attributes that will be fetched by the receiving Branchset. An empty Array means that it should fetch all attributes, which is the default.



298
299
300
301
302
303
304
305
# File 'lib/treequel/branchset.rb', line 298

def select( *attributes )
  if attributes.empty?
    return self.options[:select].collect {|attribute| attribute.to_s }
  else
    self.log.debug "cloning %p with new selection: %p" % [ self, attributes ]
    return self.clone( :select => attributes )
  end
end

- (Object) select_all

Returns a clone of the receiving Branchset that will fetch all attributes.



309
310
311
# File 'lib/treequel/branchset.rb', line 309

def select_all
  return self.clone( :select => [] )
end

- (Object) select_more(*attributes)

Return a clone of the receiving Branchset that will fetch the specified attributes in addition to its own.



316
317
318
# File 'lib/treequel/branchset.rb', line 316

def select_more( *attributes )
  return self.select( *(Array(@options[:select]) | attributes) )
end

- (Object) timeout(seconds = nil)

Return a clone of the receiving Branchset that will search with its timeout set to seconds, which is in floating-point seconds.



344
345
346
347
348
349
350
# File 'lib/treequel/branchset.rb', line 344

def timeout( seconds=nil )
  if seconds
    return self.clone( :timeout => seconds )
  else
    return @options[:timeout]
  end
end

- (Object) to_hash(keyattr, valueattr = nil)

Map the results returned by the search into a hash keyed by the first value of keyattr in the entry. If the optional valueattr argument is given, the values will be the first corresponding attribute, else the value will be the whole entry.



245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/treequel/branchset.rb', line 245

def to_hash( keyattr, valueattr=nil )
  return self.inject({}) do |hash, branch|
    key = branch[ keyattr ]
    key = key.first if key.respond_to?( :first )

    value = valueattr ? branch[ valueattr ] : branch.entry
    value = value.first if value.respond_to?( :first )

    hash[ key ] = value
    hash
  end
end

- (Object) to_s

Return the Branchset as a stringified URI.



147
148
149
# File 'lib/treequel/branchset.rb', line 147

def to_s
  return "%s/%s" % [ self.branch.dn, self.filter_string ]
end

- (Object) uri

Return a string representation of the Branchset’s filter



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/treequel/branchset.rb', line 128

def uri
  # :scheme,
  # :host, :port,
  # :dn,
  # :attributes,
  # :scope,
  # :filter,
  # :extensions,
  uri = self.branch.uri
  uri.attributes = self.select.join(',')
  uri.scope = SCOPE_NAME[ self.scope ]
  uri.filter = self.filter_string
  # :TODO: Add extensions? Support extensions in Branchset?

  return uri
end

- (Object) without_limit

Return a clone of the receiving Branchset that has no restriction on the number of Branches that will be fetched.



337
338
339
# File 'lib/treequel/branchset.rb', line 337

def without_limit
  return self.clone( :limit => 0 )
end

- (Object) without_timeout

Return a clone of the receiving Branchset that will not use a timeout when searching.



355
356
357
# File 'lib/treequel/branchset.rb', line 355

def without_timeout
  return self.clone( :timeout => 0 )
end