ruby-activeldap 0.4.4 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -75,7 +75,7 @@ module ActiveLDAP
75
75
  key = options[:foreign_key] || association_id.to_s + "_id"
76
76
  local_key = options[:local_key] || ''
77
77
  class_eval <<-"end_eval"
78
- def #{association_id}(objects = false)
78
+ def #{association_id}(objects = true)
79
79
  local_key = "#{local_key}"
80
80
  local_key = dnattr() if local_key.empty?
81
81
  return #{klass}.find_all(:attribute => "#{key}", :value => attribute_method(local_key), :objects => objects)
@@ -100,7 +100,7 @@ module ActiveLDAP
100
100
  key = options[:local_key] || association_id.to_s + "_id"
101
101
  foreign_key = options[:foreign_key] || ''
102
102
  class_eval <<-"end_eval"
103
- def #{association_id}(objects = false)
103
+ def #{association_id}(objects = true)
104
104
  foreign_key = "#{foreign_key}"
105
105
  if foreign_key.empty?
106
106
  foreign_key = dnattr()
@@ -74,6 +74,12 @@ module ActiveLDAP
74
74
  class ConnectionError < RuntimeError
75
75
  end
76
76
 
77
+ # ObjectClassError
78
+ #
79
+ # An exception raised when an objectClass is not defined in the schema
80
+ class ObjectClassError < RuntimeError
81
+ end
82
+
77
83
 
78
84
  # Base
79
85
  #
@@ -189,7 +195,7 @@ module ActiveLDAP
189
195
  # Setup default logger to console
190
196
  if @@logger.nil?
191
197
  @@logger = Log4r::Logger.new('activeldap')
192
- @@logger.level = Log4r::FATAL
198
+ @@logger.level = Log4r::OFF
193
199
  Log4r::StderrOutputter.new 'console'
194
200
  @@logger.add('console')
195
201
  end
@@ -240,9 +246,8 @@ module ActiveLDAP
240
246
  raise ConnectionError, "#{detail.exception} - LDAP connection failure, or server does not support schema queries."
241
247
  end
242
248
 
243
-
244
249
  # Cleanly return
245
- return nil
250
+ return true
246
251
  end # Base.connect
247
252
 
248
253
  # Base.close
@@ -387,7 +392,6 @@ module ActiveLDAP
387
392
  end
388
393
 
389
394
  # Allow a single string argument
390
- attr = dnattr()
391
395
  objects = false
392
396
  val = config
393
397
  # Or a hash
@@ -487,9 +491,6 @@ module ActiveLDAP
487
491
  @ldap_data = {} # original ldap entry data
488
492
  @ldap_data.default = []
489
493
  @attr_methods = {} # list of valid method calls for attributes used for dereferencing
490
- @must = {} # list of schema required attributes
491
- @may = {} # list of schema optional attributes
492
- @sup = {} # list of schema supplemental attributes
493
494
 
494
495
  # Break val apart if it is a dn
495
496
  if val.match(/^#{dnattr()}=([^,=]+),#{base()}$/i)
@@ -504,7 +505,7 @@ module ActiveLDAP
504
505
  @exists = false
505
506
  # Setup what should eb authoritative
506
507
  @dn = "#{dnattr()}=#{val},#{base()}"
507
- send(:objectClass=, required_classes())
508
+ send(:apply_objectclass, required_classes())
508
509
  else # do a search then
509
510
  # Search for the existing entry
510
511
  begin
@@ -521,9 +522,9 @@ module ActiveLDAP
521
522
  @@logger.debug("finished make_subtypes for #{attr}")
522
523
  # Add subtype to any existing values
523
524
  if @ldap_data.has_key? safe_attr
524
- value.each do |v|
525
+ value.each do |v|
525
526
  @ldap_data[safe_attr].push(v)
526
- end
527
+ end
527
528
  else
528
529
  @ldap_data[safe_attr] = value
529
530
  end
@@ -531,7 +532,7 @@ module ActiveLDAP
531
532
  end
532
533
  @exists = true
533
534
  # Populate schema data
534
- send(:objectClass=, @ldap_data['objectClass'])
535
+ send(:apply_objectclass, @ldap_data['objectClass'])
535
536
 
536
537
  # Populate real data now that we have the schema with aliases
537
538
  @ldap_data.each do |pair|
@@ -542,10 +543,11 @@ module ActiveLDAP
542
543
  @exists = false
543
544
  # Create what should be the authoritative DN
544
545
  @dn = "#{dnattr()}=#{val},#{base()}"
545
- send(:objectClass=, required_classes())
546
+ send(:apply_objectclass, required_classes())
546
547
 
547
548
  # Setup dn attribute (later rdn too!)
548
549
  attr_sym = "#{dnattr()}=".to_sym
550
+ @@logger.debug("new: setting dnattr: #{dnattr()} = #{val}")
549
551
  send(attr_sym, val)
550
552
  end
551
553
  end
@@ -560,79 +562,10 @@ module ActiveLDAP
560
562
  # attributes dynamically without schema awareness
561
563
  def attributes
562
564
  @@logger.debug("stub: attributes called")
565
+ send(:apply_objectclass, @data['objectClass']) if @data['objectClass'] != @last_oc
563
566
  return @attr_methods.keys
564
567
  end
565
568
 
566
- # objectClass=
567
- #
568
- # objectClass= special case for updating appropriately
569
- # This updates the objectClass entry in @data. It also
570
- # updating all required and allowed attributes while
571
- # removing defined attributes that are no longer valid
572
- # given the new objectclasses.
573
- def objectClass=(val)
574
- @@logger.debug("stub: objectClass=(#{val.inspect}) called")
575
- if val.class != Array
576
- raise TypeError, 'objectClass must be an Array'
577
- end
578
-
579
- val.each do |klass|
580
- unless klass.class == String
581
- raise TypeError, "Value in array is not a String. (#{klass.class})"
582
- end
583
- unless Base.schema.names("objectClasses").member? klass
584
- # TODO MAKE OWN EXCEPTION
585
- raise RuntimeError, "objectClass '#{klass}' unknown to LDAP server"
586
- end
587
- end
588
-
589
- # make sure this doesn't drop any of the required objectclasses
590
- required_classes().each do |oc|
591
- unless val.member? oc
592
- raise "'#{oc}' must be a defined objectClass for class '#{self.class}'"
593
- end
594
- end
595
-
596
- # Set the actual objectClass data
597
- define_attribute_methods('objectClass')
598
- @data['objectClass'] = val.uniq
599
-
600
- # Build |data| from schema
601
- # clear attr_method mapping first
602
- @attr_methods = {}
603
- @must = {}
604
- @may = {}
605
- @sup = {}
606
- val.each do |objc|
607
- # Setup dependencies for validation pre-save
608
- @must[objc] = Base.schema.attr('objectClasses', objc, 'MUST')
609
- @may[objc] = Base.schema.attr('objectClasses', objc, 'MAY')
610
- @sup[objc] = Base.schema.attr('objectClasses', objc, 'SUP')
611
- @must[objc] = [] if @must[objc].nil?
612
- @may[objc] = [] if @may[objc].nil?
613
- @sup[objc] = [] if @sup[objc].nil?
614
-
615
- # setup the alias/attr method mapping for @must
616
- @must[objc].each do |attr|
617
- # Update attr_method with appropriate
618
- define_attribute_methods(attr)
619
- end
620
-
621
- # setup the alias/attr method mapping for @may
622
- @may[objc].each do |attr|
623
- define_attribute_methods(attr)
624
- end
625
- end
626
-
627
- # Delete all now invalid attributes given the new objectClasses
628
- @data.keys.each do |key|
629
- # If it's not a proper aliased attribute, drop it
630
- unless @attr_methods.has_key? key
631
- @data.delete(key)
632
- end
633
- end
634
- end
635
-
636
569
  # exists?
637
570
  #
638
571
  # Return whether the entry exists in LDAP or not
@@ -654,15 +587,38 @@ module ActiveLDAP
654
587
  # Basic validation:
655
588
  # - Verify that every 'MUST' specified in the schema has a value defined
656
589
  # - Enforcement of undefined attributes is handled in the objectClass= method
590
+ # Must call enforce_types() first before enforcement can be guaranteed
657
591
  def validate
658
592
  @@logger.debug("stub: validate called")
659
- @must.each do |oc|
660
- oc[1].each do |req_attr|
661
- # TODO: should I ever check if key exists? bug if it doesnt...
593
+ # Clean up attr values, etc
594
+ send(:enforce_types)
595
+
596
+ # Validate objectclass settings
597
+ @data['objectClass'].each do |klass|
598
+ unless klass.class == String
599
+ raise TypeError, "Value in objectClass array is not a String. (#{klass.class}:#{klass.inspect})"
600
+ end
601
+ unless Base.schema.names("objectClasses").member? klass
602
+ raise ObjectClassError, "objectClass '#{klass}' unknown to LDAP server."
603
+ end
604
+ end
605
+
606
+ # make sure this doesn't drop any of the required objectclasses
607
+ required_classes().each do |oc|
608
+ unless @data['objectClass'].member? oc.to_s
609
+ raise ObjectClassError, "'#{oc}' must be a defined objectClass for class '#{self.class}' as set in the ldap_mapping"
610
+ end
611
+ end
612
+
613
+ # Make sure all MUST attributes have a value
614
+ @data['objectClass'].each do |objc|
615
+ must = Base.schema.attr('objectClasses', objc, 'MUST')
616
+ may = Base.schema.attr('objectClasses', objc, 'MAY')
617
+ must.each do |req_attr|
662
618
  deref = @attr_methods[req_attr]
663
619
  if @data[deref] == []
664
620
  raise AttributeEmpty,
665
- "objectClass '#{oc[0]}' requires attribute '#{Base.schema.attribute_aliases(req_attr).join(', ')}'"
621
+ "objectClass '#{objc}' requires attribute '#{Base.schema.attribute_aliases(req_attr).join(', ')}'"
666
622
  end
667
623
  end
668
624
  end
@@ -836,7 +792,7 @@ module ActiveLDAP
836
792
  @@logger.debug("#write: add successful")
837
793
  @exists = true
838
794
  rescue LDAP::ResultError => detail
839
- raise WriteError, "Could not add LDAP entry[#{Base.conn.err2string(Base.conn.err)}]: #{detail}"
795
+ raise WriteError, "Could not add LDAP entry[#{Base.connection.err2string(Base.connection.err)}]: #{detail}"
840
796
  end
841
797
  end
842
798
  @@logger.debug("#write: resetting @ldap_data to a dup of @data")
@@ -855,15 +811,25 @@ module ActiveLDAP
855
811
  # give tab completion in irb.
856
812
  def method_missing(name, *args)
857
813
  @@logger.debug("stub: called method_missing(#{name.inspect}, #{args.inspect})")
814
+
815
+ # dynamically update the available attributes without requiring an
816
+ # explicit call. The cache 'last_oc' saves a lot of cpu time.
817
+ if @data['objectClass'] != @last_oc
818
+ @@logger.debug("method_missing(#{name.inspect}, #{args.inspect}): updating apply_objectclass(#{@data['objectClass'].inspect})")
819
+ send(:apply_objectclass, @data['objectClass'])
820
+ end
858
821
  key = name.to_s
859
822
  case key
860
823
  when /^(\S+)=$/
861
824
  real_key = $1
825
+ @@logger.debug("method_missing: attr_methods has_key? #{real_key}")
862
826
  if @attr_methods.has_key? real_key
863
827
  raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" if args.size != 1
828
+ @@logger.debug("method_missing: calling :attribute_method=(#{real_key}, #{args[0]})")
864
829
  return send(:attribute_method=, real_key, args[0])
865
830
  end
866
831
  else
832
+ @@logger.debug("method_missing: attr_methods has_key? #{key}")
867
833
  if @attr_methods.has_key? key
868
834
  raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" if args.size > 1
869
835
  return attribute_method(key, *args)
@@ -872,29 +838,97 @@ module ActiveLDAP
872
838
  raise NoMethodError, "undefined method `#{key}' for #{self}"
873
839
  end
874
840
 
841
+ # Add available attributes to the methods
842
+ alias_method :__methods, :methods
843
+ def methods
844
+ return __methods + attributes()
845
+ end
846
+
875
847
 
876
848
  private
877
849
 
850
+ # enforce_types
851
+ #
852
+ # enforce_types applies your changes without attempting to write to LDAP. This means that
853
+ # if you set userCertificate to somebinary value, it will wrap it up correctly.
854
+ def enforce_types
855
+ @@logger.debug("stub: enforce_types called")
856
+ send(:apply_objectclass, @data['objectClass']) if @data['objectClass'] != @last_oc
857
+ # Enforce attribute value formatting
858
+ @data.keys.each do |key|
859
+ @data[key] = attribute_input_handler(key, @data[key])
860
+ end
861
+ @@logger.debug("stub: enforce_types done")
862
+ return true
863
+ end
864
+
865
+
866
+
867
+ # apply_objectclass
868
+ #
869
+ # objectClass= special case for updating appropriately
870
+ # This updates the objectClass entry in @data. It also
871
+ # updating all required and allowed attributes while
872
+ # removing defined attributes that are no longer valid
873
+ # given the new objectclasses.
874
+ def apply_objectclass(val)
875
+ @@logger.debug("stub: objectClass=(#{val.inspect}) called")
876
+ new_oc = val
877
+ new_oc = [val] if new_oc.class != Array
878
+ return new_oc if @last_oc == new_oc
879
+
880
+ # Store for caching purposes
881
+ @last_oc = new_oc.dup
882
+
883
+ # Set the actual objectClass data
884
+ define_attribute_methods('objectClass')
885
+ @data['objectClass'] = new_oc.uniq
886
+
887
+ # Build |data| from schema
888
+ # clear attr_method mapping first
889
+ @attr_methods = {}
890
+ attributes = []
891
+ new_oc.each do |objc|
892
+ # get all attributes for the class
893
+ attributes += Base.schema.class_attributes(objc.to_s)
894
+ end
895
+ attributes.uniq
896
+ attributes.each do |attr|
897
+ # Update attr_method with appropriate
898
+ define_attribute_methods(attr)
899
+ end
900
+
901
+ # Delete all now innew_ocid attributes given the new objectClasses
902
+ @data.keys.each do |key|
903
+ # If it's not a proper aliased attribute, drop it
904
+ unless @attr_methods.has_key? key
905
+ @data.delete(key)
906
+ end
907
+ end
908
+ end
909
+
910
+
911
+
878
912
  # Enforce typing:
879
913
  # Hashes are for subtypes
880
914
  # Arrays are for multiple entries
881
915
  def attribute_input_handler(attr, value)
882
916
  @@logger.debug("stub: called attribute_input_handler(#{attr.inspect}, #{value.inspect})")
883
917
  if attr.nil?
884
- raise RuntimeError, 'attr argument must not be nil.'
918
+ raise RuntimeError, 'The first argument, attr, must not be nil. Please report this as a bug!'
885
919
  end
886
920
  binary = Base.schema.binary_required? attr
887
921
  single = Base.schema.single_value? attr
888
922
  case value.class.to_s
889
923
  when 'Array'
890
924
  if single and value.size > 1
891
- raise TypeError, "This attribute can only have a single value"
925
+ raise TypeError, "Attribute #{attr} can only have a single value"
892
926
  end
893
927
  value.map! do |entry|
894
- if entry.class != Hash
895
- @@logger.debug("coercing value for #{attr} into a string because nested values exceeds a useful depth: #{entry.inspect} -> #{entry.to_s}")
896
- entry = entry.to_s
897
- end
928
+ if entry.class != Hash
929
+ @@logger.debug("coercing value for #{attr} into a string because nested values exceeds a useful depth: #{entry.inspect} -> #{entry.to_s}")
930
+ entry = entry.to_s
931
+ end
898
932
  entry = attribute_input_handler(attr, entry)[0]
899
933
  end
900
934
  when 'Hash'
@@ -1073,38 +1107,31 @@ module ActiveLDAP
1073
1107
  # attribute_method
1074
1108
  #
1075
1109
  # Return the value of the attribute called by method_missing?
1076
- def attribute_method(method, arrays = false)
1077
- @@logger.debug("stub: called attribute_method(#{method.inspect}, #{arrays.inspect}")
1110
+ def attribute_method(method, not_array = false)
1111
+ @@logger.debug("stub: called attribute_method(#{method.inspect}, #{not_array.inspect}")
1078
1112
  attr = @attr_methods[method]
1079
1113
 
1080
1114
  # Return a copy of the stored data
1081
- return @data[attr].dup if arrays
1082
- return array_of(@data[attr].dup, false)
1115
+ return array_of(@data[attr].dup, false) if not_array
1116
+ return @data[attr]
1083
1117
  end
1084
1118
 
1085
1119
 
1086
1120
  # attribute_method=
1087
1121
  #
1088
1122
  # Set the value of the attribute called by method_missing?
1089
- def attribute_method=(method, arg)
1090
- @@logger.debug("stub: called attribute_method=(#{method.inspect}, #{arg.inspect}")
1091
- # Copy input
1092
- begin
1093
- value = arg.dup
1094
- rescue TypeError
1095
- value = arg.to_s
1096
- end
1097
-
1123
+ def attribute_method=(method, value)
1124
+ @@logger.debug("stub: called attribute_method=(#{method.inspect}, #{value.inspect})")
1098
1125
  # Get the attr and clean up the input
1099
1126
  attr = @attr_methods[method]
1100
- value = attribute_input_handler(attr, value)
1101
-
1127
+ @@logger.debug("attribute_method=(#{method.inspect}, #{value.inspect}): method maps to #{attr}")
1128
+ #value = attribute_input_handler(attr, value)
1102
1129
  # Assign the value
1103
1130
  @data[attr] = value
1104
1131
 
1105
1132
  # Return a copy of what got saved
1106
1133
  @@logger.debug("stub: exitting attribute_method=")
1107
- return @data[attr].dup
1134
+ return @data[attr]
1108
1135
  end
1109
1136
 
1110
1137
 
@@ -1119,8 +1146,10 @@ module ActiveLDAP
1119
1146
  end
1120
1147
  aliases = Base.schema.attribute_aliases(attr)
1121
1148
  aliases.each do |ali|
1149
+ @@logger.debug("associating #{ali} --> #{attr}")
1122
1150
  @attr_methods[ali] = attr
1123
1151
  end
1152
+ @@logger.debug("stub: leaving define_attribute_methods(#{attr.inspect})")
1124
1153
  end
1125
1154
 
1126
1155
  # array_of
@@ -3,8 +3,9 @@ require 'ldap/schema'
3
3
 
4
4
  module LDAP
5
5
  class Schema2 < Schema
6
- @@cache = {}
7
-
6
+ @@attr_cache = {}
7
+ @@class_cache = {}
8
+
8
9
  # attr
9
10
  #
10
11
  # This is just like LDAP::Schema#attr except that it allows
@@ -18,19 +19,19 @@ module LDAP
18
19
  return '' if at.empty?
19
20
 
20
21
  # Check already parsed options first
21
- if @@cache.has_key? sub \
22
- and @@cache[sub].has_key? type \
23
- and @@cache[sub][type].has_key? at
24
- return @@cache[sub][type][at].dup
22
+ if @@attr_cache.has_key? sub \
23
+ and @@attr_cache[sub].has_key? type \
24
+ and @@attr_cache[sub][type].has_key? at
25
+ return @@attr_cache[sub][type][at].dup
25
26
  end
26
27
 
27
28
  # Initialize anything that is required
28
- unless @@cache.has_key? sub
29
- @@cache[sub] = {}
29
+ unless @@attr_cache.has_key? sub
30
+ @@attr_cache[sub] = {}
30
31
  end
31
32
 
32
- unless @@cache[sub].has_key? type
33
- @@cache[sub][type] = {}
33
+ unless @@attr_cache[sub].has_key? type
34
+ @@attr_cache[sub][type] = {}
34
35
  end
35
36
 
36
37
  at = at.upcase
@@ -47,31 +48,31 @@ module LDAP
47
48
  multi = ''
48
49
  case line
49
50
  when /#{at}\s+[\)A-Z]/
50
- @@cache[sub][type][at] = ['TRUE']
51
+ @@attr_cache[sub][type][at] = ['TRUE']
51
52
  return ['TRUE']
52
53
  when /#{at}\s+'(.+?)'/
53
- @@cache[sub][type][at] = [$1]
54
+ @@attr_cache[sub][type][at] = [$1]
54
55
  return [$1]
55
56
  when /#{at}\s+\((.+?)\)/
56
57
  multi = $1
57
58
  when /#{at}\s+\(([\w\d\s\.]+)\)/
58
59
  multi = $1
59
60
  when /#{at}\s+([\w\d\.]+)/
60
- @@cache[sub][type][at] = [$1]
61
+ @@attr_cache[sub][type][at] = [$1]
61
62
  return [$1]
62
63
  end
63
64
  # Split up multiple matches
64
65
  # if oc then it is sep'd by $
65
66
  # if attr then bu spaces
66
67
  if multi.match(/\$/)
67
- @@cache[sub][type][at] = multi.split("$").collect{|attr| attr.strip}
68
- return @@cache[sub][type][at].dup
68
+ @@attr_cache[sub][type][at] = multi.split("$").collect{|attr| attr.strip}
69
+ return @@attr_cache[sub][type][at].dup
69
70
  elsif not multi.empty?
70
- @@cache[sub][type][at] = multi.gsub(/'/, '').split(' ').collect{|attr| attr.strip}
71
- return @@cache[sub][type][at].dup
71
+ @@attr_cache[sub][type][at] = multi.gsub(/'/, '').split(' ').collect{|attr| attr.strip}
72
+ return @@attr_cache[sub][type][at].dup
72
73
  end
73
74
  end
74
- @@cache[sub][type][at] = []
75
+ @@attr_cache[sub][type][at] = []
75
76
  return []
76
77
  end
77
78
 
@@ -140,24 +141,63 @@ module LDAP
140
141
 
141
142
  return false
142
143
  end # binary_required?
144
+
145
+ # class_attributes
146
+ #
147
+ # Returns an Array of all the valid attributes (but not with full aliases)
148
+ # for the given objectClass
149
+ def class_attributes(objc)
150
+ if @@class_cache.has_key? objc
151
+ return @@class_cache[objc]
152
+ end
153
+
154
+ # First get all the current level attributes
155
+ @@class_cache[objc] = attr('objectClasses', objc, 'MUST') + attr('objectClasses', objc, 'MAY')
156
+
157
+ # Now add all attributes from the parent object (SUPerclasses)
158
+ # Hopefully an iterative approach will be pretty speedy
159
+ # 1. build complete list of SUPs
160
+ # 2. Add attributes from each
161
+ sups = attr('objectClasses', objc, 'SUP')
162
+ loop do
163
+ start_size = sups.size
164
+ new_sups = []
165
+ sups.each do |sup|
166
+ new_sups += attr('objectClasses', sup, 'SUP')
167
+ end
168
+ sups += new_sups
169
+ sups = sups.uniq
170
+ break if sups.size == start_size
171
+ end
172
+ sups.each do |sup|
173
+ @@class_cache[objc] += attr('objectClasses', sup, 'MUST') + attr('objectClasses', sup, 'MAY')
174
+ end
175
+
176
+ # Clean out the dupes.
177
+ @@class_cache[objc] = @@class_cache[objc].uniq
178
+
179
+ # Return the cached value
180
+ return @@class_cache[objc].dup
181
+ end
182
+
143
183
  end # Schema2
144
184
 
145
185
  class Conn
146
186
  def schema(base = nil, attrs = nil, sec = 0, usec = 0)
147
187
  attrs ||= [
148
- 'objectClasses',
149
- 'attributeTypes',
150
- 'matchingRules',
151
- 'matchingRuleUse',
152
- 'dITStructureRules',
153
- 'dITContentRules',
154
- 'nameForms',
155
- 'ldapSyntaxes',
188
+ 'objectClasses',
189
+ 'attributeTypes',
190
+ 'matchingRules',
191
+ 'matchingRuleUse',
192
+ 'dITStructureRules',
193
+ 'dITContentRules',
194
+ 'nameForms',
195
+ 'ldapSyntaxes',
156
196
  ]
157
197
  base ||= root_dse(['subschemaSubentry'], sec, usec)[0]['subschemaSubentry'][0]
158
198
  base ||= 'cn=schema'
159
199
  ent = search2(base, LDAP_SCOPE_BASE, '(objectClass=subschema)',
160
- attrs, false, sec, usec)
200
+ attrs, false, sec, usec)
161
201
  return Schema2.new(ent[0])
162
202
  end
163
203
  end
data/lib/activeldap.rb CHANGED
@@ -212,7 +212,8 @@
212
212
  # what classes are required when creating a new object. Of course, you can leave
213
213
  # that field out to default to ['top'] only. Then you can let each application
214
214
  # choose what objectClasses their objects should have by calling the method e.g.
215
- # Group#objectClass=(value).
215
+ # Group#objectClass=(value) or by modifying the value returned by the accessor,
216
+ # e.g. Group#objectClass.
216
217
  #
217
218
  # Note that is can be very important to define the default :classes value. Due to
218
219
  # implementation choices with most LDAP servers, once an object is created, its
@@ -259,28 +260,26 @@
259
260
  # Group objects that a user is in.
260
261
  #
261
262
  # irb> me = User.new('drewry')
262
- # => ...
263
263
  # irb> me.groups
264
- # => ["cdrom", "audio", "develop"]
265
- #
266
- # Methods created with belongs_to also take an optional argument: objects. This
267
- # argument specifies whether it will return the value of the 'dnattr' of the
268
- # objects, or whether it will return Group objects.
269
- #
270
- # irb> me.groups(true)
271
264
  # => [#<Group:0x000001 ...>, #<Group:0x000002 ...>, ...]
272
265
  # irb> me.groups(true).each { |group| p group.cn };nil
273
266
  # "cdrom"
274
267
  # "audio"
275
268
  # "develop"
276
269
  # => nil
277
- #
278
270
  # (Note: nil is just there to make the output cleaner...)
279
271
  #
272
+ # Methods created with belongs_to also take an optional argument: objects. This
273
+ # argument specifies whether it will return the value of the 'dnattr' of the
274
+ # objects, or whether it will return Group objects.
275
+ #
276
+ # irb> me.groups(false)
277
+ # => ["cdrom", "audio", "develop"]
278
+ #
280
279
  # TIP: If you weren't sure what the distinguished name attribute was for Group,
281
280
  # you could also do the following:
282
281
  #
283
- # irb> me.groups(true).each { |group| p group.dnattr };nil
282
+ # irb> me.groups.each { |group| p group.dnattr };nil
284
283
  # "cdrom"
285
284
  # "audio"
286
285
  # "develop"
@@ -328,9 +327,9 @@
328
327
  # irb> develop = Group.new('develop')
329
328
  # => ...
330
329
  # irb> develop.members
331
- # => ["drewry", "builder"]
332
- # irb> develop.members(true)
333
330
  # => [#<User:0x000001 ...>, #<User:...>]
331
+ # irb> develop.members(false)
332
+ # => ["drewry", "builder"]
334
333
  #
335
334
  #
336
335
  # The arguments for has_many follow the exact same idea that belongs_to's
@@ -392,11 +391,13 @@
392
391
  # * :base defaults to the base of the class this is executed from (as set in ldap_mapping)
393
392
  # * :scope defaults to LDAP::LDAP_SCOPE_SUBTREE. Usually you won't need to change it
394
393
  # * :attrs defaults to [] and is the list of attrs you want back. Empty means all of them.
395
- #
394
+ #
396
395
  # ==== #validate
397
396
  #
398
397
  # validate is a method that verifies that all attributes that are required by the
399
- # objects current objectClasses are populated. This is called by #write prior to
398
+ # objects current objectClasses are populated. This also will call the
399
+ # private "#enforce_types" method. This will make sure that all values defined are
400
+ # valid to be written to LDAP. #validate is called by #write prior to
400
401
  # performing any action. Its explicit use in an application is unnecessary, and
401
402
  # it may become a private method in the future.
402
403
  #
@@ -536,6 +537,11 @@
536
537
  # LDAP server could be created. Check you configuration.rb, Base.connect
537
538
  # arguments, and network connectivity! Also check your LDAP server logs to see
538
539
  # if it ever saw the request.
540
+ #
541
+ # ==== ObjectClassError
542
+ #
543
+ # This exception is raised when an object class is used that is not defined
544
+ # in the schema.
539
545
  #
540
546
  # === Others
541
547
  #
@@ -752,26 +758,26 @@
752
758
  # and everything should work well.
753
759
  #
754
760
  #
755
- # ==== Array results for everything
761
+ # ==== Non-array results for single values
756
762
  #
757
- # Even though Ruby/ActiveLDAP tries to be convenient by returning Arrays only
758
- # when an LDAP object attribute has multiple values, sometimes this can be a
759
- # programmatic nightmare. If you would like to force all returned values to
760
- # come in Array form, just query like so:
763
+ # Even though Ruby/ActiveLDAP attempts to maintain programmatic ease by
764
+ # returning Array values only. By specifying 'false' as an argument to
765
+ # any attribute method you will get back a String if it is single value.
766
+ # This is useful when you are just dumping values for human reading.
767
+ # Here's an example:
761
768
  #
762
769
  # irb> user = User.new('drewry')
763
770
  # => ...
764
- # irb> user.cn(true)
765
- # => ["Will Drewry"]
771
+ # irb> user.cn(false)
772
+ # => "Will Drewry"
766
773
  #
767
- # That's it. Now you can ALWAYS get Arrays back without having to write your own
768
- # wrappers.
774
+ # That's it. Now you can make human-readable output faster.
769
775
  #
770
776
  # ==== Dynamic attribute crawling
771
777
  #
772
- # If you use tab completion in irb, you'll notice that you can't tab complete the
773
- # dynamic attributes available for each object. You can still see what's available with the method call
774
- # #attributes.
778
+ # If you use tab completion in irb, you'll notice that you /can/ tab complete the dynamic
779
+ # attribute methods. You can still see which methods are for attributes using
780
+ # Base#attributes:
775
781
  #
776
782
  # irb> d = Group.new('develop')
777
783
  # => ...
@@ -892,7 +898,7 @@ require 'activeldap/configuration'
892
898
  require 'activeldap/schema2'
893
899
 
894
900
  module ActiveLDAP
895
- VERSION = "0.4.4"
901
+ VERSION = "0.5.0"
896
902
  end
897
903
 
898
904
  ActiveLDAP::Base.class_eval do
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.1
3
3
  specification_version: 1
4
4
  name: ruby-activeldap
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.4.4
7
- date: 2004-10-10
6
+ version: 0.5.0
7
+ date: 2004-10-21
8
8
  summary: Ruby/ActiveLDAP is a object-oriented API to LDAP
9
9
  require_paths:
10
10
  - lib