Class: Treequel::Branch

Inherits:
Object
  • Object
show all
Extended by:
Loggability, AttributeDeclarations, Delegation
Includes:
Comparable, Constants, Constants::Patterns, HashUtilities
Defined in:
lib/treequel/branch.rb

Overview

The object in Treequel that wraps an entry. It knows how to construct other branches for the entries below itself, and how to search for those entries.

Direct Known Subclasses

Model

Constant Summary collapse

DEFAULT_LDIF_WIDTH =

The default width of LDIF output

70
LDIF_FOLD_SEPARATOR =

The characters to use to fold an LDIF line (newline + a space)

"\n "

Constants included from Constants

Constants::CONTROL_NAMES, Constants::CONTROL_OIDS, Constants::EXTENSION_NAMES, Constants::EXTENSION_OIDS, Constants::FEATURE_NAMES, Constants::FEATURE_OIDS, Constants::MINIMAL_OPERATIONAL_ATTRIBUTES, Constants::SCOPE, Constants::SCOPE_NAME

Constants included from Constants::Patterns

Constants::Patterns::ALPHA, Constants::Patterns::AMPERSAND, Constants::Patterns::ASSERTIONVALUE, Constants::Patterns::ASTERISK, Constants::Patterns::ATTRIBUTE_TYPE, Constants::Patterns::ATTRIBUTE_TYPE_AND_VALUE, Constants::Patterns::ATTRIBUTE_VALUE, Constants::Patterns::BASE64_CHAR, Constants::Patterns::BASE64_STRING, Constants::Patterns::COLON, Constants::Patterns::COMMA, Constants::Patterns::DESCR, Constants::Patterns::DIGIT, Constants::Patterns::DISTINGUISHED_NAME, Constants::Patterns::DN_ESCAPED, Constants::Patterns::DOLLAR, Constants::Patterns::DOT, Constants::Patterns::DQUOTE, Constants::Patterns::DSTRING, Constants::Patterns::EQUALS, Constants::Patterns::ESC, Constants::Patterns::ESCAPED, Constants::Patterns::EXCLAMATION, Constants::Patterns::EXTENSIONS, Constants::Patterns::FILL, Constants::Patterns::FOLD, Constants::Patterns::HEX, Constants::Patterns::HEXPAIR, Constants::Patterns::HEXSTRING, Constants::Patterns::HYPHEN, Constants::Patterns::KEYCHAR, Constants::Patterns::KEYSTRING, Constants::Patterns::KIND, Constants::Patterns::LANGLE, Constants::Patterns::LCURLY, Constants::Patterns::LDAP_ATTRIBUTE_DESCRIPTION, Constants::Patterns::LDAP_ATTRIBUTE_TYPE_DESCRIPTION, Constants::Patterns::LDAP_MATCHING_RULE_DESCRIPTION, Constants::Patterns::LDAP_MATCHING_RULE_USE_DESCRIPTION, Constants::Patterns::LDAP_MISORDERED_DESC_OBJECTCLASS_DESCRIPTION, Constants::Patterns::LDAP_MISORDERED_KIND_OBJECTCLASS_DESCRIPTION, Constants::Patterns::LDAP_MISORDERED_SYNTAX_ATTRIBUTE_TYPE_DESCRIPTION, Constants::Patterns::LDAP_OBJECTCLASS_DESCRIPTION, Constants::Patterns::LDAP_SUBSTRING_FILTER, Constants::Patterns::LDAP_SUBSTRING_FILTER_VALUE, Constants::Patterns::LDAP_SYNTAX_DESCRIPTION, Constants::Patterns::LDAP_TRAILING_KIND_OBJECTCLASS_DESCRIPTION, Constants::Patterns::LDAP_UNESCAPE_SQUOTE_ATTRIBUTE_TYPE_DESCRIPTION, Constants::Patterns::LDIF_ATTRIBUTE_DESCRIPTION, Constants::Patterns::LDIF_ATTRIBUTE_TYPE, Constants::Patterns::LDIF_ATTRTYPE_OPTION, Constants::Patterns::LDIF_ATTRTYPE_OPTIONS, Constants::Patterns::LDIF_ATTRVAL_SPEC, Constants::Patterns::LDIF_ATTR_TYPE_CHARS, Constants::Patterns::LDIF_OPT_CHAR, Constants::Patterns::LDIF_SAFE_CHAR, Constants::Patterns::LDIF_SAFE_INIT_CHAR, Constants::Patterns::LDIF_SAFE_STRING, Constants::Patterns::LDIF_VALUE_SPEC, Constants::Patterns::LDIGIT, Constants::Patterns::LEADCHAR, Constants::Patterns::LEADKEYCHAR, Constants::Patterns::LEN, Constants::Patterns::LPAREN, Constants::Patterns::LUTF1, Constants::Patterns::MALFORMED_DSTRING, Constants::Patterns::MALFORMED_QDSTRING, Constants::Patterns::NOIDLEN, Constants::Patterns::NORMAL, Constants::Patterns::NUL, Constants::Patterns::NUMBER, Constants::Patterns::NUMERICOID, Constants::Patterns::OCTET, Constants::Patterns::OID, Constants::Patterns::OIDLIST, Constants::Patterns::OIDS, Constants::Patterns::PAIR, Constants::Patterns::PLUS, Constants::Patterns::QDESCR, Constants::Patterns::QDESCRLIST, Constants::Patterns::QDESCRS, Constants::Patterns::QDSTRING, Constants::Patterns::QDSTRINGLIST, Constants::Patterns::QDSTRINGS, Constants::Patterns::QQ, Constants::Patterns::QS, Constants::Patterns::QUOTED_DESCR, Constants::Patterns::QUOTED_NUMERICOID, Constants::Patterns::QUTF1, Constants::Patterns::QUTF8, Constants::Patterns::RANGLE, Constants::Patterns::RCURLY, Constants::Patterns::RELATIVE_DISTINGUISHED_NAME, Constants::Patterns::RPAREN, Constants::Patterns::SEMI, Constants::Patterns::SEP, Constants::Patterns::SHARP, Constants::Patterns::SP, Constants::Patterns::SPACE, Constants::Patterns::SPECIAL, Constants::Patterns::SQUOTE, Constants::Patterns::STRING, Constants::Patterns::STRINGCHAR, Constants::Patterns::SUTF1, Constants::Patterns::TILDE, Constants::Patterns::TRAILCHAR, Constants::Patterns::TUTF1, Constants::Patterns::UNESCAPED, Constants::Patterns::URI_REF, Constants::Patterns::USAGE, Constants::Patterns::USCORE, Constants::Patterns::UTF0, Constants::Patterns::UTF1, Constants::Patterns::UTF1SUBSET, Constants::Patterns::UTF2, Constants::Patterns::UTF3, Constants::Patterns::UTF4, Constants::Patterns::UTF8, Constants::Patterns::UTFMB, Constants::Patterns::VALUEENCODING, Constants::Patterns::VERTBAR, Constants::Patterns::WSP, Constants::Patterns::XSTRING

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AttributeDeclarations

predicate_attr

Methods included from Delegation

def_ivar_delegators, def_method_delegators

Methods included from HashUtilities

merge_recursively, normalize_attributes, stringify_keys, symbolify_keys

Constructor Details

#initialize(directory, dn, entry = nil) ⇒ Branch

Create a new Treequel::Branch with the given directory, dn, and an optional entry. If the optional entry object is given, it will be used to fetch values from the directory; if it isn’t provided, it will be fetched from the directory the first time it is needed.

Raises:

  • (ArgumentError)


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/treequel/branch.rb', line 80

def initialize( directory, dn, entry=nil )
  raise ArgumentError, "nil DN" unless dn
  raise ArgumentError, "invalid DN" unless
    dn.match( Patterns::DISTINGUISHED_NAME ) || dn.empty?
  raise ArgumentError, "can't cast a %s to an LDAP::Entry" % [entry.class.name] unless
    entry.nil? || entry.is_a?( Hash )

  @directory = directory
  @dn        = dn
  @entry     = entry ? stringify_keys( entry ) : nil
  @values    = {}

  @include_operational_attrs = self.class.include_operational_attrs?

  self.log.debug "New branch (%s): entry = %p, directory = %p" % [ @dn, @entry, @directory ]
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(attribute, value = nil, additional_attributes = {}) ⇒ Object (protected)

Proxy method: call #traverse_branch if attribute is a valid attribute and value isn’t nil.



685
686
687
688
# File 'lib/treequel/branch.rb', line 685

def method_missing( attribute, value=nil, additional_attributes={} )
  return super( attribute ) if value.nil?
  return self.traverse_branch( attribute, value, additional_attributes )
end

Instance Attribute Details

#directoryObject (readonly)

The directory the branch’s entry lives in



110
111
112
# File 'lib/treequel/branch.rb', line 110

def directory
  @directory
end

#dnObject Also known as: to_s

The DN of the branch.



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

def dn
  @dn
end

Class Method Details

.new_from_entry(entry, directory) ⇒ Object

Create a new Treequel::Branch from the given entry hash from the specified directory.



61
62
63
64
65
66
67
68
69
# File 'lib/treequel/branch.rb', line 61

def self::new_from_entry( entry, directory )
  entry = Treequel::HashUtilities.stringify_keys( entry )
  dnvals = entry.delete( 'dn' ) or
    raise ArgumentError, "no 'dn' attribute for entry"

  Treequel.logger.debug "Creating Branch from entry: %p in directory: %s" %
    [ dnvals.first, directory ]
  return self.new( directory, dnvals.first, entry )
end

Instance Method Details

#+(other_branch) ⇒ Object

Addition operator: return a Treequel::BranchCollection that contains both the receiver and other_branch.



494
495
496
# File 'lib/treequel/branch.rb', line 494

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

#<=>(other_branch) ⇒ Object

Comparable interface: Returns -1 if other_branch is less than, 0 if other_branch is equal to, and +1 if other_branch is greater than the receiving Branch.



464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/treequel/branch.rb', line 464

def <=>( other_branch )
  # Try the easy cases first
  return nil unless other_branch.respond_to?( :dn ) &&
    other_branch.respond_to?( :split_dn )
  return 0 if other_branch.dn == self.dn

  # Try comparing reversed attribute pairs
  rval = nil
  pairseq = self.split_dn.reverse.zip( other_branch.split_dn.reverse )
  pairseq.each do |a,b|
    comparison = (a <=> b)
    return comparison if !comparison.nil? && comparison.nonzero?
  end

  # The branches are related, so directly comparing DN strings will work
  return self.dn <=> other_branch.dn
end

#[](attrname) ⇒ Object

Fetch the value/s associated with the given attrname from the underlying entry.



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/treequel/branch.rb', line 301

def []( attrname )
  attrsym = attrname.to_sym

  if @values.key?( attrsym )
    # self.log.debug "  value for %p is cached (%p)." % [ attrname, @values[attrsym] ]
  else
    self.log.debug "  value for %p is NOT cached." % [ attrsym ]
    value = self.get_converted_object( attrsym )
    self.log.debug "  converted value is: %p" % [ value ]
    value.freeze if
      self.class.freeze_converted_values? &&
      value.respond_to?( :freeze )
    @values[ attrsym ] = value if value
  end

  return @values[ attrsym ]
end

#[]=(attrname, value) ⇒ Object

Set attribute attrname to a new value.



332
333
334
335
336
337
338
339
# File 'lib/treequel/branch.rb', line 332

def []=( attrname, value )
  value = [ value ] unless value.is_a?( Array )
  value.collect! {|val| self.get_converted_attribute(attrname, val) }
  self.log.debug "Modifying %s to %p" % [ attrname, value ]
  self.directory.modify( self, attrname.to_s => value )
  @values.delete( attrname.to_sym )
  self.entry[ attrname.to_s ] = value
end

#branchsetObject

Return a Treequel::Branchset that will use the receiver as its base.



216
217
218
# File 'lib/treequel/branch.rb', line 216

def branchset
  return Treequel::Branchset.new( self )
end

#childrenObject

Return the Branch’s immediate children as Treeque::Branch objects.



210
211
212
# File 'lib/treequel/branch.rb', line 210

def children
  return self.search( :one, '(objectClass=*)' )
end

#copy(newdn, attributes = {}) ⇒ Object

Copy the entry for this Branch to a new entry with the given newdn and merge in the specified attributes.



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/treequel/branch.rb', line 419

def copy( newdn, attributes={} )

  # Fully-qualify RDNs
  newdn = newdn + ',' + self.parent_dn unless newdn.index(',')

  self.log.debug "Creating a copy of %p at %p" % [ self.dn, newdn ]
  newbranch = self.class.new( self.directory, newdn )

  attributes = self.entry.merge( stringify_keys(attributes) )

  self.log.debug "  merged attributes: %p" % [ attributes ]
  self.directory.create( newbranch, attributes )

  return newbranch
end

#create(attributes = {}) ⇒ Object

Create the entry for this Branch with the specified attributes. The attributes should, at a minimum, contain the pair ‘:objectClass => [:someStructuralObjectClass]`.

groups = dir.ou( :groups )
newgroup = groups.cn( :staff )
newgroup.create( :objectClass => ['posixGroup'], :gidNumber => 2100 )
# => #<Treequel::Branch:0x1086a0ac8 cn=staff,ou=groups,dc=example,dc=com>


410
411
412
413
414
# File 'lib/treequel/branch.rb', line 410

def create( attributes={} )
  self.directory.create( self, attributes )
  self.clear_caches
  return self
end

#delete(*attributes) ⇒ Object

Delete the specified attributes, which are the attributes to delete either as attribute names (in which case all values of the attribute are deleted), or Hashes of attributes and the Array of value/s which should be deleted.

# Delete all 'description' attributes
branch.delete( :description )

# Delete the 'inetOrgPerson' and 'posixAccount' objectClasses from the entry
branch.delete( :objectClass => [:inetOrgPerson, :posixAccount] )

# Delete any blank 'description' or 'cn' attributes:
branch.delete( :description => '', :cn => '' )


367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/treequel/branch.rb', line 367

def delete( *attributes )

  # If no attributes are given, delete the whole entry
  if attributes.empty?
    self.log.info "No attributes specified; deleting entire entry for %s" % [ self.dn ]
    self.directory.delete( self )

  # Otherwise, gather up the LDAP::Mod objects that will delete the given attributes
  else
    self.log.debug "Deleting attributes: %p" % [ attributes ]
    mods = attributes.flatten.collect do |attribute|

      # Delete particular values of the attribute
      if attribute.is_a?( Hash )
        attribute.collect do |key,vals|
          vals = [ vals ] unless vals.is_a?( Array )
          vals.collect! {|val| self.get_converted_attribute(key, val) }
          LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, key.to_s, vals )
        end

      # Delete all values of the attribute
      else
        LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, attribute.to_s, [] )
      end

    end

    self.directory.modify( self, mods.flatten )
  end

  self.clear_caches

  return true
end

#entryObject

Return the LDAP::Entry associated with the receiver, fetching it from the directory if necessary. Returns nil if the entry doesn’t exist in the directory.



146
147
148
# File 'lib/treequel/branch.rb', line 146

def entry
  @entry ||= self.lookup_entry
end

#eql?(other) ⇒ Boolean

Comparison-by-value method – returns true if the receiver has the same DN as other.



450
451
452
453
# File 'lib/treequel/branch.rb', line 450

def eql?( other )
  return false unless other.class.eql?( self.class )
  return self.hash == other.hash
end

#exists?Boolean

Returns true if there is an entry currently in the directory with the branch’s DN.



153
154
155
# File 'lib/treequel/branch.rb', line 153

def exists?
  return self.entry ? true : false
end

#get_child(rdn) ⇒ Object

Fetch a new Treequel::Branch object for the child of the receiver with the specified rdn.



485
486
487
488
489
# File 'lib/treequel/branch.rb', line 485

def get_child( rdn )
  self.log.debug "Getting child %p from base = %p" % [ rdn, self.dn ]
  newdn = [ rdn, self.dn ].reject {|part| part.empty? }.join( ',' )
  return self.class.new( self.directory, newdn )
end

#hashObject

Generates a Fixnum hash for the receiver.



457
458
459
# File 'lib/treequel/branch.rb', line 457

def hash
  return [ self.class, self.dn ].hash
end

#include_operational_attrs=(new_setting) ⇒ Object Also known as: include_operational_attributes=

Enable (if new_setting is true) or disable fetching of operational attributes (RC4512, section 3.4).



130
131
132
133
# File 'lib/treequel/branch.rb', line 130

def include_operational_attrs=( new_setting )
  self.clear_caches
  @include_operational_attrs = new_setting ? true : false
end

#inspectObject

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



223
224
225
226
227
228
229
230
231
# File 'lib/treequel/branch.rb', line 223

def inspect
  return "#<%s:0x%0x %s @ %s entry=%p>" % [
    self.class.name,
    self.object_id * 2,
    self.dn,
    self.directory,
    @entry,
    ]
end

#loaded?Boolean

Returns true if the Branch’s entry has been fetched from the directory.



159
160
161
# File 'lib/treequel/branch.rb', line 159

def loaded?
  return @entry ? true : false
end

#may_attribute_types(*additional_object_classes) ⇒ Object

Return Treequel::Schema::AttributeType instances for each of the receiver’s objectClass’s MAY attributeTypes. If any additional_object_classes are given, include the MAY attributeTypes for them as well. This can be used to predict what optional attributes could be added to the entry if the additional_object_classes were added to it.



589
590
591
592
# File 'lib/treequel/branch.rb', line 589

def may_attribute_types( *additional_object_classes )
  return self.object_classes( *additional_object_classes ).
    collect {|oc| oc.may }.flatten.uniq
end

#may_attributes_hash(*additional_object_classes) ⇒ Object

Return a Hash of the optional attributes allowed by the Branch’s objectClasses. If any additional_object_classes are given, include the attributes that would be available for the entry if it had them.



609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/treequel/branch.rb', line 609

def may_attributes_hash( *additional_object_classes )
  entry = self.entry
  attrhash = {}

  self.may_attribute_types( *additional_object_classes ).each do |attrtype|
    # self.log.debug "  adding attrtype %p to the MAY attributes hash" % [ attrtype.named ]

    if attrtype.single?
      attrhash[ attrtype.name ] = nil
    else
      attrhash[ attrtype.name ] = []
    end
  end

  # :FIXME: Does the resulting hash need the additional objectClasses? objectClass is
  #         MUST via 'top', so it should already exist in that hash when merged with
  #         this one...
  # attrhash[ :objectClass ] |= additional_object_classes

  return attrhash
end

#may_oids(*additional_object_classes) ⇒ Object

Return OIDs (numeric OIDs as Strings, named OIDs as Symbols) for each of the receiver’s objectClass’s MAY attributeTypes. If any additional_object_classes are given, include the OIDs of the MAY attributes for them as well. This can be used to predict what optional attributes could be added to the entry if the additional_object_classes were added to it.



600
601
602
603
# File 'lib/treequel/branch.rb', line 600

def may_oids( *additional_object_classes )
  return self.object_classes( *additional_object_classes ).
    collect {|oc| oc.may_oids }.flatten.uniq
end

#merge(attributes) ⇒ Object Also known as: modify

Make the changes to the entry specified by the given attributes.

branch.merge( :description => ['The syadmin group'], :cn => ['sysadmin'] )


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

def merge( attributes )
  self.directory.modify( self, attributes )
  self.clear_caches

  return true
end

#move(rdn) ⇒ Object

Move the entry associated with this branch to a new entry indicated by rdn. If any attributes are given, also replace the corresponding attributes on the new entry with them.



439
440
441
442
443
444
445
# File 'lib/treequel/branch.rb', line 439

def move( rdn )
  self.log.debug "Asking the directory to move me to an entry called %p" % [ rdn ]
  self.directory.move( self, rdn )
  self.clear_caches

  return self
end

#must_attribute_types(*additional_object_classes) ⇒ Object

Return Treequel::Schema::AttributeType instances for each of the receiver’s objectClass’s MUST attributeTypes. If any additional_object_classes are given, include the MUST attributeTypes for them as well. This can be used to predict what attributes would need to be present for the entry to be saved if it added the additional_object_classes to its own.



543
544
545
546
547
548
# File 'lib/treequel/branch.rb', line 543

def must_attribute_types( *additional_object_classes )
  oclasses = self.object_classes( *additional_object_classes )
  types = oclasses.map( &:must ).flatten.uniq

  return types
end

#must_attributes_hash(*additional_object_classes) ⇒ Object

Return a Hash of the attributes required by the Branch’s objectClasses. If any additional_object_classes are given, include the attributes that would be necessary for the entry to be saved with them.



565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/treequel/branch.rb', line 565

def must_attributes_hash( *additional_object_classes )
  attrhash = {}

  self.must_attribute_types( *additional_object_classes ).each do |attrtype|
    # self.log.debug "  adding attrtype %p to the MUST attributes hash" % [ attrtype.name ]

    if attrtype.name == :objectClass
      attrhash[ :objectClass ] = ['top'] | additional_object_classes
    elsif attrtype.single?
      attrhash[ attrtype.name ] = ''
    else
      attrhash[ attrtype.name ] = ['']
    end
  end

  return attrhash
end

#must_oids(*additional_object_classes) ⇒ Object

Return OIDs (numeric OIDs as Strings, named OIDs as Symbols) for each of the receiver’s objectClass’s MUST attributeTypes. If any additional_object_classes are given, include the OIDs of the MUST attributes for them as well. This can be used to predict what attributes would need to be present for the entry to be saved if it added the additional_object_classes to its own.



556
557
558
559
# File 'lib/treequel/branch.rb', line 556

def must_oids( *additional_object_classes )
  return self.object_classes( *additional_object_classes ).
    collect {|oc| oc.must_oids }.flatten.uniq.reject {|val| val == '' }
end

#object_classes(*additional_classes) ⇒ Object

Return Treequel::Schema::ObjectClass instances for each of the receiver’s objectClass attributes. If any additional_classes are given, merge them with the current list of the current objectClasses for the lookup.



502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
# File 'lib/treequel/branch.rb', line 502

def object_classes( *additional_classes )
  # self.log.debug "Fetching object classes for %s" % [ self.dn ]
  schema = self.directory.schema

  oc_oids = self[:objectClass] || []
  oc_oids |= additional_classes.collect {|str| str.to_sym }
  oc_oids << 'top' if oc_oids.empty?

  oclasses = []
  oc_oids.each do |oid|
    oc = schema.object_classes[ oid.to_sym ] or
      raise Treequel::Error, "schema doesn't have a %p objectClass" % [ oid ]
    oclasses << oc
  end

  # self.log.debug "  found %d objectClasses: %p" % [  oclasses.length, oclasses.map(&:name) ]
  return oclasses.uniq
end

#operational_attribute_oidsObject

Return OIDs (numeric OIDs as Strings, named OIDs as Symbols) for each of the receiver’s operational attributes.



530
531
532
533
534
535
# File 'lib/treequel/branch.rb', line 530

def operational_attribute_oids
  return self.operational_attribute_types.inject([]) do |oids, attrtype|
    oids.push( *attrtype.names )
    oids << attrtype.oid
  end
end

#operational_attribute_typesObject

Return the receiver’s operational attributes as attributeType schema objects.



523
524
525
# File 'lib/treequel/branch.rb', line 523

def operational_attribute_types
  return self.directory.schema.operational_attribute_types
end

#parentObject

Return the Branch’s immediate parent node.



195
196
197
198
# File 'lib/treequel/branch.rb', line 195

def parent
  pardn = self.parent_dn or return nil
  return self.class.new( self.directory, pardn )
end

#parent_dnObject

Return the DN of this entry’s parent, or nil if it doesn’t have one.



187
188
189
190
191
# File 'lib/treequel/branch.rb', line 187

def parent_dn
  return nil if self.dn == self.directory.base_dn
  return '' if self.dn.index( ',' ).nil?
  return self.split_dn( 2 ).last
end

#rdnObject

Return the RDN of the branch.



165
166
167
# File 'lib/treequel/branch.rb', line 165

def rdn
  return self.split_dn( 2 ).first
end

#rdn_attributesObject

Return the attribute/s which make up this Branch’s RDN as a Hash.



138
139
140
# File 'lib/treequel/branch.rb', line 138

def rdn_attributes
  return make_rdn_hash( self.rdn )
end

#search(scope = :subtree, filter = '(objectClass=*)', parameters = {}, &block) ⇒ Object

Perform a search with the specified scope, filter, and parameters using the receiver as the base. See Trequel::Directory#search for details. Returns an Array of Treequel::Branch objects.



204
205
206
# File 'lib/treequel/branch.rb', line 204

def search( scope=:subtree, filter='(objectClass=*)', parameters={}, &block )
  return self.directory.search( self, scope, filter, parameters, &block )
end

#split_dn(limit = 0) ⇒ Object

Return the receiver’s DN as an Array of attribute=value pairs. If the optional limit is non-zero, only the limit-1 first pairs are split from the DN, and the remainder will be returned as the last element.



173
174
175
# File 'lib/treequel/branch.rb', line 173

def split_dn( limit=0 )
  return self.dn.split( /\s*,\s*/, limit )
end

#to_hashObject

Return the Branch as a Hash.



285
286
287
288
289
290
291
292
293
294
295
296
297
# File 'lib/treequel/branch.rb', line 285

def to_hash
  entry = self.entry || self.valid_attributes_hash
  self.log.debug "  making a Hash from an entry: %p" % [ entry ]

  return entry.keys.inject({}) do |hash, attribute|
    if attribute == 'dn'
      hash[ attribute ] = self.dn
    else
      hash[ attribute ] = self[ attribute ]
    end
    hash
  end
end

#to_ldif(width = DEFAULT_LDIF_WIDTH) ⇒ Object

Return the Branch as an LDAP::LDIF::Entry.



268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/treequel/branch.rb', line 268

def to_ldif( width=DEFAULT_LDIF_WIDTH )
  ldif = "dn: %s\n" % [ self.dn ]

  entry = self.entry || self.valid_attributes_hash
  self.log.debug "  making LDIF from an entry: %p" % [ entry ]

  entry.keys.reject {|k| k == 'dn' }.each do |attribute|
    Array( entry[attribute] ).each do |val|
      ldif << ldif_for_attr( attribute, val, width )
    end
  end

  return LDAP::LDIF::Entry.new( ldif )
end

#to_ufnObject

Return the entry’s DN as an RFC1781-style UFN (User-Friendly Name).



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/treequel/branch.rb', line 235

def to_ufn
  if LDAP.respond_to?( :dn2ufn )
    return LDAP.dn2ufn( self.dn )

  # An implementation for LDAP libraries with no
  # dn2ufn
  else
    ufn = ''
    tuples = self.split_dn

    # Separate the trailing domainComponents
    dcs = []
    dcs << tuples.pop while tuples.last =~ /^dc\s*=/i

    # Append the non-dc tuples with their attributes stripped first
    ufn << tuples.collect do |rdn|
      rdn.
        gsub(/\b#{ATTRIBUTE_TYPE}\s*=/, '').
        gsub(/\s*\+\s*/, ' + ')
    end.join( ', ' )

    # Now append the DCs joined with dots
    unless dcs.empty?
      ufn << ', '
      ufn << dcs.reverse.map {|rdn| rdn.sub(/dc\s*=\s*/i, '') }.join( '.' )
    end

    return ufn
  end
end

#uriObject

Return the LDAP URI for this branch



179
180
181
182
183
# File 'lib/treequel/branch.rb', line 179

def uri
  uri = self.directory.uri
  uri.dn = self.dn
  return uri
end

#valid_attribute?(attroid) ⇒ Boolean

Return true if the specified attrname is a valid attributeType given the receiver’s current objectClasses. Does not include operational attributes.



660
661
662
# File 'lib/treequel/branch.rb', line 660

def valid_attribute?( attroid )
  return !self.valid_attribute_type( attroid ).nil?
end

#valid_attribute_oidsObject

Return a uniqified Array of OIDs (numeric OIDs as Strings, named OIDs as Symbols) for the set of all of the receiver’s MUST and MAY attributeTypes plus the operational attributes.



644
645
646
# File 'lib/treequel/branch.rb', line 644

def valid_attribute_oids
  return self.must_oids | self.may_oids
end

#valid_attribute_type(attroid) ⇒ Object

If the attribute associated with the given attroid is in the list of valid attributeTypes for the receiver given its objectClasses, return the AttributeType object that corresponds with it. If it isn’t valid, return nil. Includes operational attributes.



653
654
655
# File 'lib/treequel/branch.rb', line 653

def valid_attribute_type( attroid )
  return self.valid_attribute_types.find {|attr_type| attr_type.valid_name?(attroid) }
end

#valid_attribute_typesObject

Return Treequel::Schema::AttributeType instances for the set of all of the receiver’s MUST and MAY attributeTypes plus the operational attributes.



634
635
636
637
638
# File 'lib/treequel/branch.rb', line 634

def valid_attribute_types
  return self.must_attribute_types |
         self.may_attribute_types  |
         self.operational_attribute_types
end

#valid_attributes_hash(*additional_object_classes) ⇒ Object

Return a Hash of all the attributes allowed by the Branch’s objectClasses. If any additional_object_classes are given, include the attributes that would be available for the entry if it had them.



668
669
670
671
672
673
674
675
676
# File 'lib/treequel/branch.rb', line 668

def valid_attributes_hash( *additional_object_classes )
  self.log.debug "Gathering a hash of all valid attributes:"
  must = self.must_attributes_hash( *additional_object_classes )
  self.log.debug "  MUST attributes: %p" % [ must ]
  may  = self.may_attributes_hash( *additional_object_classes )
  self.log.debug "  MAY attributes: %p" % [ may ]

  return may.merge( must )
end

#values_at(*attributes) ⇒ Object

Fetch one or more values for the specified attributes from the entry.

branch.values_at( :cn, :objectClass )
=> [["sysadmin"], ["top", "posixGroup", "apple-group"]]


324
325
326
327
328
# File 'lib/treequel/branch.rb', line 324

def values_at( *attributes )
  return attributes.collect do |attribute|
    self[ attribute ]
  end
end