treequel 1.0.4 → 1.1.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 +130 -1
- data/Rakefile +8 -3
- data/Rakefile.local +2 -0
- data/bin/treeirb +6 -2
- data/bin/treequel +5 -4
- data/lib/treequel/branch.rb +133 -72
- data/lib/treequel/branchcollection.rb +16 -5
- data/lib/treequel/branchset.rb +37 -6
- data/lib/treequel/constants.rb +12 -0
- data/lib/treequel/directory.rb +96 -41
- data/lib/treequel/filter.rb +42 -1
- data/lib/treequel/model/objectclass.rb +111 -0
- data/lib/treequel/model.rb +363 -0
- data/lib/treequel/monkeypatches.rb +65 -0
- data/lib/treequel/schema/attributetype.rb +108 -18
- data/lib/treequel/schema/ldapsyntax.rb +15 -0
- data/lib/treequel/schema/matchingrule.rb +24 -0
- data/lib/treequel/schema/matchingruleuse.rb +24 -0
- data/lib/treequel/schema/objectclass.rb +70 -5
- data/lib/treequel/schema/table.rb +5 -15
- data/lib/treequel/schema.rb +64 -1
- data/lib/treequel.rb +5 -5
- data/rake/documentation.rb +27 -0
- data/rake/hg.rb +14 -2
- data/rake/manual.rb +1 -1
- data/spec/lib/constants.rb +9 -7
- data/spec/lib/control_behavior.rb +1 -0
- data/spec/lib/matchers.rb +1 -0
- data/spec/treequel/branch_spec.rb +229 -20
- data/spec/treequel/branchcollection_spec.rb +73 -39
- data/spec/treequel/branchset_spec.rb +59 -8
- data/spec/treequel/control_spec.rb +1 -0
- data/spec/treequel/controls/contentsync_spec.rb +1 -0
- data/spec/treequel/controls/pagedresults_spec.rb +1 -0
- data/spec/treequel/controls/sortedresults_spec.rb +1 -0
- data/spec/treequel/directory_spec.rb +46 -10
- data/spec/treequel/filter_spec.rb +28 -5
- data/spec/treequel/mixins_spec.rb +7 -14
- data/spec/treequel/model/objectclass_spec.rb +330 -0
- data/spec/treequel/model_spec.rb +433 -0
- data/spec/treequel/monkeypatches_spec.rb +118 -0
- data/spec/treequel/schema/attributetype_spec.rb +116 -0
- data/spec/treequel/schema/ldapsyntax_spec.rb +8 -0
- data/spec/treequel/schema/matchingrule_spec.rb +6 -1
- data/spec/treequel/schema/matchingruleuse_spec.rb +5 -0
- data/spec/treequel/schema/objectclass_spec.rb +41 -3
- data/spec/treequel/schema/table_spec.rb +31 -18
- data/spec/treequel/schema_spec.rb +13 -16
- data/spec/treequel_spec.rb +22 -0
- data.tar.gz.sig +1 -0
- metadata +40 -7
- metadata.gz.sig +0 -0
- data/spec/treequel/utils_spec.rb +0 -49
data/ChangeLog
CHANGED
@@ -1,4 +1,133 @@
|
|
1
|
-
|
1
|
+
304[tip] 92c28b14730a 2010-09-20 13:51 -0700 ged
|
2
|
+
Added tag 1.1.0 for changeset b415e0fce774
|
3
|
+
|
4
|
+
303[1.1.0] b415e0fce774 2010-09-20 13:51 -0700 ged
|
5
|
+
Added signature for changeset 4ba782a3a7e4
|
6
|
+
|
7
|
+
302 4ba782a3a7e4 2010-09-17 09:09 -0700 ged
|
8
|
+
Include mixins for inherited objectClasses, too.
|
9
|
+
|
10
|
+
301 f075a27a35eb 2010-09-17 09:03 -0700 ged
|
11
|
+
Updated build system
|
12
|
+
|
13
|
+
300 c77bac0bf816 2010-09-17 09:02 -0700 ged
|
14
|
+
Manual updates for the Model section (paired with Mahlon)
|
15
|
+
|
16
|
+
299 1b375c5dc123 2010-09-15 16:46 -0700 ged
|
17
|
+
Use the #syntax method instead of the syntax_oid in #inspect output so inherited syntaxes are shown
|
18
|
+
|
19
|
+
298 0786411cd707 2010-09-15 16:43 -0700 ged
|
20
|
+
Use the system LDAP config if no URI is given
|
21
|
+
|
22
|
+
297 d3a6c89d8004 2010-09-15 16:42 -0700 ged
|
23
|
+
Un-spam debugging on entry lookup
|
24
|
+
|
25
|
+
296 2101482df41f 2010-09-15 16:41 -0700 ged
|
26
|
+
Overriding #inspect in Treequel::Model to show the list of extensions applied to the entry
|
27
|
+
|
28
|
+
295 a384412c0e6f 2010-08-25 16:56 -0700 ged
|
29
|
+
Rescue the right error in Treequel::Model#method_missing and add a spec for the negative case.
|
30
|
+
|
31
|
+
294 b220a83d31b5 2010-08-25 16:48 -0700 ged
|
32
|
+
Load the entry from Model's #method_missing to catch calls to methods that are added via
|
33
|
+
|
34
|
+
293 2753f8405caf 2010-08-23 17:12 -0700 ged
|
35
|
+
Fixing object/attribute mapping for attributes whose types that inherit their syntax from their superclass
|
36
|
+
|
37
|
+
292 2e2b035d3721 2010-08-23 15:19 -0700 ged
|
38
|
+
Coverage improvements, manual work
|
39
|
+
|
40
|
+
291 693a163bd068 2010-08-23 08:36 -0700 ged
|
41
|
+
Started catching the manual up to 1.1.0.
|
42
|
+
|
43
|
+
290 df0b0594cb62 2010-08-23 08:36 -0700 ged
|
44
|
+
Made Treequel::Branch#delete with no arguments delete the entry
|
45
|
+
|
46
|
+
289 31fc0ea1ea31 2010-08-19 16:35 -0700 ged
|
47
|
+
Fixes for Ruby 1.9.2.
|
48
|
+
|
49
|
+
288 7c7d3e2034b0 2010-08-19 07:21 -0700 ged
|
50
|
+
Build system update; fixed ruby-termios dependency
|
51
|
+
|
52
|
+
287 f9151315d37f 2010-08-18 17:35 -0700 ged
|
53
|
+
Implement Branchset operators
|
54
|
+
|
55
|
+
286 cd3ef7e3ffb0 2010-08-16 17:20 -0700 ged
|
56
|
+
Reworked operational attributes to use the 'USAGE' attribute at Mahlon's suggestion.
|
57
|
+
|
58
|
+
285 dfb032f5e5c1 2010-08-16 17:19 -0700 ged
|
59
|
+
Fixes for Treequel::Model instantiation and lookup.
|
60
|
+
|
61
|
+
284 844ee21c6916 2010-08-16 17:05 -0700 ged
|
62
|
+
Made Treequel::Schema::Table Enumerable
|
63
|
+
|
64
|
+
283 ff2629196b4e 2010-08-06 16:11 -0700 ged
|
65
|
+
Don't add the objectClass attribute when searching through Treequel::Model if
|
66
|
+
|
67
|
+
282 d4e58760ee34 2010-08-06 15:02 -0700 ged
|
68
|
+
Handle Sequel's Ruby1.9 Symbol-operator workaround in filter attributes
|
69
|
+
|
70
|
+
281 d60c6b83db01 2010-08-06 15:02 -0700 ged
|
71
|
+
Also output empty-string attributes as non-binary
|
72
|
+
|
73
|
+
280 bb182f705fe5 2010-08-05 14:07 -0700 ged
|
74
|
+
Unwrap base64ed LDIF lines before wrapping them to the new line length.
|
75
|
+
|
76
|
+
279 32084630894f 2010-08-05 11:14 -0700 ged
|
77
|
+
Fix LDIF-generation for really reals.
|
78
|
+
|
79
|
+
278 aabbab99b093 2010-08-05 10:40 -0700 ged
|
80
|
+
Optimizations, logging cleanup.
|
81
|
+
|
82
|
+
277 7a4f2e5bef0a 2010-08-02 08:45 -0700 ged
|
83
|
+
Bugfixes.
|
84
|
+
|
85
|
+
276 2f741e5294bf 2010-07-29 14:34 -0700 ged
|
86
|
+
Filter component symmetry, Model refactor
|
87
|
+
|
88
|
+
275 bc0bc3aea136 2010-07-28 09:06 -0700 ged
|
89
|
+
Added support for Sequel-style #or: branchset.filter( :something ).or( :somethingelse ).
|
90
|
+
|
91
|
+
274 30091794b910 2010-07-28 07:14 -0700 ged
|
92
|
+
Added Treequel::Model#respond_to?
|
93
|
+
|
94
|
+
273 e9c908b1f426 2010-07-27 08:05 -0700 ged
|
95
|
+
Bugfix, make object conversion work for setting attributes too.
|
96
|
+
|
97
|
+
272 30ba889041a8 2010-07-26 20:04 -0700 ged
|
98
|
+
Bugfixes, coverage of LDIF-generation.
|
99
|
+
|
100
|
+
271 a6dd7b685a6a 2010-07-16 18:32 -0700 ged
|
101
|
+
Fixing the "cd .." special case
|
102
|
+
|
103
|
+
270 2793fa802dad 2010-07-14 20:16 -0700 ged
|
104
|
+
Untaint objectClasses passed to Treequel::Model::mixins_for_objectclasses.
|
105
|
+
|
106
|
+
269 b76dd9ca1f3f 2010-07-13 19:14 -0700 ged
|
107
|
+
The workaround for two-param syntax mapping Procs didn't work after all. Modifying
|
108
|
+
|
109
|
+
268 70cc87a200ad 2010-07-13 19:08 -0700 ged
|
110
|
+
Added schema-object roundtripping, with a script/specs to test it.
|
111
|
+
|
112
|
+
267 47e865bfef9e 2010-07-13 12:31 -0700 ged
|
113
|
+
Added the ability to set the default results class on a per-directory basis.
|
114
|
+
|
115
|
+
266 c61373e3dc49 2010-07-13 08:03 -0700 ged
|
116
|
+
Fixes for Apache DS and bugfix in Treequel::Model.
|
117
|
+
|
118
|
+
265 601003ff3077 2010-07-10 17:16 -0700 ged
|
119
|
+
Treequel::Model bugfix
|
120
|
+
|
121
|
+
264 a76065cfeba0 2010-07-09 07:19 -0700 ged
|
122
|
+
Adding Treequel::Model, bumping version to 1.1.0.
|
123
|
+
|
124
|
+
263:262,261 6dd6cb37f5ce 2010-07-09 07:16 -0700 ged
|
125
|
+
Merged with 47bb9cd7af3b
|
126
|
+
|
127
|
+
262:258 3f4134d20d9d 2010-07-08 09:40 -0700 ged
|
128
|
+
Delegate the Treequel::Directory#root_dse method through its #conn
|
129
|
+
|
130
|
+
261 0188c2ba5b7e 2010-07-07 23:21 -0700 ged
|
2
131
|
Added tag 1.0.4 for changeset 0ec4ff0ce67f
|
3
132
|
|
4
133
|
260[1.0.4] 0ec4ff0ce67f 2010-07-07 23:21 -0700 ged
|
data/Rakefile
CHANGED
@@ -18,6 +18,7 @@ BEGIN {
|
|
18
18
|
libdir = basedir + "lib"
|
19
19
|
extdir = libdir + Config::CONFIG['sitearch']
|
20
20
|
|
21
|
+
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
21
22
|
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
22
23
|
$LOAD_PATH.unshift( extdir.to_s ) unless $LOAD_PATH.include?( extdir.to_s )
|
23
24
|
}
|
@@ -76,7 +77,7 @@ elsif VERSION_FILE.exist?
|
|
76
77
|
PKG_VERSION = VERSION_FILE.read[ /VERSION\s*=\s*['"](\d+\.\d+\.\d+)['"]/, 1 ]
|
77
78
|
end
|
78
79
|
|
79
|
-
PKG_VERSION = '0.0.0' unless defined?( PKG_VERSION )
|
80
|
+
PKG_VERSION = '0.0.0' unless defined?( PKG_VERSION ) && !PKG_VERSION.nil?
|
80
81
|
|
81
82
|
PKG_FILE_NAME = "#{PKG_NAME.downcase}-#{PKG_VERSION}"
|
82
83
|
GEM_FILE_NAME = "#{PKG_FILE_NAME}.gem"
|
@@ -169,7 +170,7 @@ include RakefileHelpers
|
|
169
170
|
|
170
171
|
# Set the build ID if the mercurial executable is available
|
171
172
|
if hg = which( 'hg' )
|
172
|
-
id =
|
173
|
+
id = `#{hg} id -n`.chomp
|
173
174
|
PKG_BUILD = "pre%03d" % [(id.chomp[ /^[[:xdigit:]]+/ ] || '1')]
|
174
175
|
else
|
175
176
|
PKG_BUILD = 'pre000'
|
@@ -226,9 +227,9 @@ DEVELOPMENT_DEPENDENCIES = {
|
|
226
227
|
'text-format' => '>= 1.0.0',
|
227
228
|
'tmail' => '>= 1.2.3.1',
|
228
229
|
'diff-lcs' => '>= 1.1.2',
|
229
|
-
'termios' => '>= 0.9.4',
|
230
230
|
'columnize' => '>= 0.3.1',
|
231
231
|
'diff-lcs' => '>= 1.1.2',
|
232
|
+
'ruby-termios' => '>= 0.9.6',
|
232
233
|
'ruby-terminfo' => '>= 0.1.1',
|
233
234
|
}
|
234
235
|
|
@@ -277,6 +278,10 @@ GEMSPEC = Gem::Specification.new do |gem|
|
|
277
278
|
gem.files = RELEASE_FILES
|
278
279
|
gem.test_files = SPEC_FILES
|
279
280
|
|
281
|
+
# signing key and certificate chain
|
282
|
+
gem.signing_key = '/Volumes/Keys/ged-private_gem_key.pem'
|
283
|
+
gem.cert_chain = [File.expand_path('~/.gem/ged-public_gem_cert.pem')]
|
284
|
+
|
280
285
|
DEPENDENCIES.each do |name, version|
|
281
286
|
version = '>= 0' if version.length.zero?
|
282
287
|
gem.add_runtime_dependency( name, version )
|
data/Rakefile.local
CHANGED
data/bin/treeirb
CHANGED
@@ -6,8 +6,12 @@ require 'irb/cmd/nop'
|
|
6
6
|
require 'treequel'
|
7
7
|
|
8
8
|
|
9
|
-
uri = ARGV.shift
|
10
|
-
$dir = Treequel.directory( uri )
|
9
|
+
if uri = ARGV.shift
|
10
|
+
$dir = Treequel.directory( uri )
|
11
|
+
else
|
12
|
+
$dir = Treequel.directory_from_config
|
13
|
+
end
|
14
|
+
|
11
15
|
$stderr.puts "Directory is in $dir:", ' ' + $dir.inspect
|
12
16
|
|
13
17
|
IRB.start( $0 )
|
data/bin/treequel
CHANGED
@@ -571,7 +571,7 @@ class Treequel::Shell
|
|
571
571
|
# Calcuate column widths
|
572
572
|
oclen = children.map do |subbranch|
|
573
573
|
subbranch.include_operational_attrs = true
|
574
|
-
subbranch[:structuralObjectClass].length
|
574
|
+
subbranch[:structuralObjectClass] ? subbranch[:structuralObjectClass].length : 0
|
575
575
|
end.max
|
576
576
|
|
577
577
|
# Set up sorting by collecting all the requested sort criteria as Proc objects which
|
@@ -610,7 +610,7 @@ class Treequel::Shell
|
|
610
610
|
return
|
611
611
|
end
|
612
612
|
|
613
|
-
return self.parent_command if rdn == '..'
|
613
|
+
return self.parent_command( options ) if rdn == '..'
|
614
614
|
|
615
615
|
raise "invalid RDN %p" % [ rdn ] unless RELATIVE_DISTINGUISHED_NAME.match( rdn )
|
616
616
|
|
@@ -868,9 +868,10 @@ class Treequel::Shell
|
|
868
868
|
metadatalen = oclen + 16 + 6 # oc + timestamp + whitespace
|
869
869
|
maxdesclen = self.columns - metadatalen - rdn.length - 5
|
870
870
|
|
871
|
+
modtime = branch[:modifyTimestamp] || branch[:createTimestamp]
|
871
872
|
return "%#{oclen}s %s %s%s %s" % [
|
872
|
-
branch[:structuralObjectClass],
|
873
|
-
|
873
|
+
branch[:structuralObjectClass] || '',
|
874
|
+
modtime.strftime('%Y-%m-%d %H:%M'),
|
874
875
|
rdn,
|
875
876
|
branch[:hasSubordinates] ? '/' : '',
|
876
877
|
single_line_description( branch, maxdesclen )
|
data/lib/treequel/branch.rb
CHANGED
@@ -69,7 +69,8 @@ class Treequel::Branch
|
|
69
69
|
### @param [String] dn The DN of the entry the Branch is wrapping.
|
70
70
|
### @param [LDAP::Entry, Hash] entry The entry object if it's already been fetched.
|
71
71
|
def initialize( directory, dn, entry=nil )
|
72
|
-
raise ArgumentError, "invalid DN" unless
|
72
|
+
raise ArgumentError, "invalid DN" unless
|
73
|
+
dn.match( Patterns::DISTINGUISHED_NAME ) || dn.empty?
|
73
74
|
raise ArgumentError, "can't cast a %s to an LDAP::Entry" % [entry.class.name] unless
|
74
75
|
entry.nil? || entry.is_a?( Hash )
|
75
76
|
|
@@ -104,7 +105,7 @@ class Treequel::Branch
|
|
104
105
|
|
105
106
|
# Whether or not to include operational attributes when fetching the Branch's entry
|
106
107
|
predicate_attr :include_operational_attrs
|
107
|
-
|
108
|
+
alias_method :include_operational_attributes?, :include_operational_attrs?
|
108
109
|
|
109
110
|
### Change the DN the Branch uses to look up its entry.
|
110
111
|
###
|
@@ -124,6 +125,7 @@ class Treequel::Branch
|
|
124
125
|
self.clear_caches
|
125
126
|
@include_operational_attrs = new_setting ? true : false
|
126
127
|
end
|
128
|
+
alias_method :include_operational_attributes=, :include_operational_attrs=
|
127
129
|
|
128
130
|
|
129
131
|
### Return the attribute/s which make up this Branch's RDN.
|
@@ -181,6 +183,7 @@ class Treequel::Branch
|
|
181
183
|
### @return [String]
|
182
184
|
def parent_dn
|
183
185
|
return nil if self.dn == self.directory.base_dn
|
186
|
+
return '' if self.dn.index( ',' ).nil?
|
184
187
|
return self.split_dn( 2 ).last
|
185
188
|
end
|
186
189
|
|
@@ -260,35 +263,21 @@ class Treequel::Branch
|
|
260
263
|
end
|
261
264
|
|
262
265
|
|
263
|
-
###
|
264
|
-
###
|
265
|
-
###
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
def ldif_for_attr( attribute, values, width )
|
270
|
-
ldif = ''
|
271
|
-
|
272
|
-
Array( values ).each do |val|
|
273
|
-
line = "#{attribute}:"
|
266
|
+
### Return the Branch as a Hash.
|
267
|
+
### @see Treequel::Branch#[]
|
268
|
+
### @return [Hash] the entry as a Hash with converted values
|
269
|
+
def to_hash
|
270
|
+
entry = self.entry || self.valid_attributes_hash
|
271
|
+
self.log.debug " making a Hash from an entry: %p" % [ entry ]
|
274
272
|
|
275
|
-
|
276
|
-
|
273
|
+
return entry.keys.inject({}) do |hash, attribute|
|
274
|
+
if attribute == 'dn'
|
275
|
+
hash[ attribute ] = self.dn
|
277
276
|
else
|
278
|
-
|
277
|
+
hash[ attribute ] = self[ attribute ]
|
279
278
|
end
|
280
|
-
|
281
|
-
# calculate how many times the line needs to be split, then add any
|
282
|
-
# additional splits that need to be added because of the additional
|
283
|
-
# fold characters
|
284
|
-
splits = ( line.length / width )
|
285
|
-
splits += ( splits * LDIF_FOLD_SEPARATOR.length ) / width
|
286
|
-
splits.times {|i| line[ width * (i+1), 0 ] = LDIF_FOLD_SEPARATOR }
|
287
|
-
|
288
|
-
ldif << line << "\n"
|
279
|
+
hash
|
289
280
|
end
|
290
|
-
|
291
|
-
return ldif
|
292
281
|
end
|
293
282
|
|
294
283
|
|
@@ -298,32 +287,9 @@ class Treequel::Branch
|
|
298
287
|
attrsym = attrname.to_sym
|
299
288
|
|
300
289
|
unless @values.key?( attrsym )
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
self.log.debug " value is not cached; checking its attributeType"
|
306
|
-
if attribute = directory.schema.attribute_types[ attrsym ]
|
307
|
-
self.log.debug " attribute exists; checking the entry for a value"
|
308
|
-
|
309
|
-
syntax_oid = attribute.syntax_oid
|
310
|
-
|
311
|
-
if attribute.single?
|
312
|
-
self.log.debug " attributeType is SINGLE; unwrapping the Array"
|
313
|
-
@values[ attrsym ] = directory.convert_syntax_value( syntax_oid, value.first )
|
314
|
-
else
|
315
|
-
self.log.debug " attributeType is not SINGLE; keeping the Array"
|
316
|
-
@values[ attrsym ] = value.collect do |raw|
|
317
|
-
directory.convert_syntax_value( syntax_oid, raw )
|
318
|
-
end
|
319
|
-
@values[ attrsym ].freeze if @values[ attrsym ].is_a?( Array )
|
320
|
-
end
|
321
|
-
|
322
|
-
else
|
323
|
-
self.log.info "no attributeType for %p" % [ attrsym ]
|
324
|
-
@values[ attrsym ] = value
|
325
|
-
@values[ attrsym ].freeze
|
326
|
-
end
|
290
|
+
value = self.get_converted_object( attrsym )
|
291
|
+
value.freeze if value.respond_to?( :freeze )
|
292
|
+
@values[ attrsym ] = value
|
327
293
|
else
|
328
294
|
self.log.debug " value is cached."
|
329
295
|
end
|
@@ -349,6 +315,7 @@ class Treequel::Branch
|
|
349
315
|
### @param [Object] value the attribute value
|
350
316
|
def []=( attrname, value )
|
351
317
|
value = [ value ] unless value.is_a?( Array )
|
318
|
+
value.collect! {|val| self.get_converted_attribute(attrname, val) }
|
352
319
|
self.log.debug "Modifying %s to %p" % [ attrname, value ]
|
353
320
|
self.directory.modify( self, attrname.to_s => value )
|
354
321
|
@values.delete( attrname.to_sym )
|
@@ -384,19 +351,25 @@ class Treequel::Branch
|
|
384
351
|
###
|
385
352
|
### @return [TrueClass] if the delete succeeded
|
386
353
|
def delete( *attributes )
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
354
|
+
if attributes.empty?
|
355
|
+
self.log.info "No attributes specified; deleting entire entry for %s" % [ self.dn ]
|
356
|
+
self.directory.delete( self )
|
357
|
+
else
|
358
|
+
self.log.debug "Deleting attributes: %p" % [ attributes ]
|
359
|
+
mods = attributes.flatten.collect do |attribute|
|
360
|
+
if attribute.is_a?( Hash )
|
361
|
+
attribute.collect do |key,vals|
|
362
|
+
vals = Array( vals ).collect {|val| val.to_s }
|
363
|
+
LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, key.to_s, vals )
|
364
|
+
end
|
365
|
+
else
|
366
|
+
LDAP::Mod.new( LDAP::LDAP_MOD_DELETE, attribute.to_s, [] )
|
393
367
|
end
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
end
|
368
|
+
end.flatten
|
369
|
+
|
370
|
+
self.directory.modify( self, mods )
|
371
|
+
end
|
398
372
|
|
399
|
-
self.directory.modify( self, mods )
|
400
373
|
self.clear_caches
|
401
374
|
|
402
375
|
return true
|
@@ -478,7 +451,8 @@ class Treequel::Branch
|
|
478
451
|
### @param [String] rdn The RDN of the child to fetch.
|
479
452
|
### @return [Treequel::Branch]
|
480
453
|
def get_child( rdn )
|
481
|
-
|
454
|
+
self.log.debug "Getting child %p from base = %p" % [ rdn, self.dn ]
|
455
|
+
newdn = [ rdn, self.dn ].reject {|part| part.empty? }.join( ',' )
|
482
456
|
return self.class.new( self.directory, newdn )
|
483
457
|
end
|
484
458
|
|
@@ -517,6 +491,21 @@ class Treequel::Branch
|
|
517
491
|
end
|
518
492
|
|
519
493
|
|
494
|
+
### Return the receiver's operational attributes as attributeType schema objects.
|
495
|
+
###
|
496
|
+
### @return [Array<Treequel::Schema::AttributeType>] the operational attributes
|
497
|
+
def operational_attribute_types
|
498
|
+
return self.directory.schema.operational_attribute_types
|
499
|
+
end
|
500
|
+
|
501
|
+
|
502
|
+
### Return OIDs (numeric OIDs as Strings, named OIDs as Symbols) for each of the
|
503
|
+
### receiver's operational attributes.
|
504
|
+
def operational_attribute_oids
|
505
|
+
return self.operational_attribute_types.map( &:oid )
|
506
|
+
end
|
507
|
+
|
508
|
+
|
520
509
|
### Return Treequel::Schema::AttributeType instances for each of the receiver's
|
521
510
|
### objectClass's MUST attributeTypes. If any +additional_object_classes+ are given,
|
522
511
|
### include the MUST attributeTypes for them as well. This can be used to predict what
|
@@ -626,22 +615,29 @@ class Treequel::Branch
|
|
626
615
|
end
|
627
616
|
end
|
628
617
|
|
629
|
-
|
618
|
+
# :FIXME: Does the resulting hash need the additional objectClasses? objectClass is
|
619
|
+
# MUST via 'top', so it should already exist in that hash when merged with
|
620
|
+
# this one...
|
621
|
+
# attrhash[ :objectClass ] |= additional_object_classes
|
622
|
+
|
630
623
|
return attrhash
|
631
624
|
end
|
632
625
|
|
633
626
|
|
634
627
|
### Return Treequel::Schema::AttributeType instances for the set of all of the receiver's
|
635
|
-
### MUST and MAY attributeTypes.
|
628
|
+
### MUST and MAY attributeTypes plus the operational attributes.
|
636
629
|
###
|
637
630
|
### @return [Array<Treequel::Schema::AttributeType>]
|
638
631
|
def valid_attribute_types
|
639
|
-
return self.must_attribute_types |
|
632
|
+
return self.must_attribute_types |
|
633
|
+
self.may_attribute_types |
|
634
|
+
self.operational_attribute_types
|
640
635
|
end
|
641
636
|
|
642
637
|
|
643
638
|
### Return a uniqified Array of OIDs (numeric OIDs as Strings, named OIDs as Symbols) for
|
644
|
-
### the set of all of the receiver's MUST and MAY attributeTypes
|
639
|
+
### the set of all of the receiver's MUST and MAY attributeTypes plus the operational
|
640
|
+
### attributes.
|
645
641
|
###
|
646
642
|
### @return [Array<String, Symbol>]
|
647
643
|
def valid_attribute_oids
|
@@ -649,8 +645,10 @@ class Treequel::Branch
|
|
649
645
|
end
|
650
646
|
|
651
647
|
|
652
|
-
### If the given +attroid+ is
|
648
|
+
### If the attribute associated with the given +attroid+ is in the list of valid
|
649
|
+
### attributeTypes for the receiver given its objectClasses, return the
|
653
650
|
### AttributeType object that corresponds with it. If it isn't valid, return nil.
|
651
|
+
### Includes operational attributes.
|
654
652
|
###
|
655
653
|
### @param [String,Symbol] attroid a numeric OID (as a String) or a named OID (as a Symbol)
|
656
654
|
### @return [Treequel::Schema::AttributeType] the validated attributeType
|
@@ -660,7 +658,7 @@ class Treequel::Branch
|
|
660
658
|
|
661
659
|
|
662
660
|
### Return +true+ if the specified +attrname+ is a valid attributeType given the
|
663
|
-
### receiver's current objectClasses.
|
661
|
+
### receiver's current objectClasses. Does not include operational attributes.
|
664
662
|
###
|
665
663
|
### @param [String, Symbol] the OID (numeric or name) of the attribute in question
|
666
664
|
### @return [Boolean]
|
@@ -736,7 +734,6 @@ class Treequel::Branch
|
|
736
734
|
|
737
735
|
### Fetch the entry from the Branch's directory.
|
738
736
|
def lookup_entry
|
739
|
-
self.log.debug "Looking up entry for %p" % [ self ]
|
740
737
|
if self.include_operational_attrs?
|
741
738
|
self.log.debug " including operational attributes."
|
742
739
|
return self.directory.get_extended_entry( self )
|
@@ -747,6 +744,42 @@ class Treequel::Branch
|
|
747
744
|
end
|
748
745
|
|
749
746
|
|
747
|
+
### Get the value associated with +attrsym+, convert it to a Ruby object if the Branch's
|
748
|
+
### directory has a conversion rule, and return it.
|
749
|
+
def get_converted_object( attrsym )
|
750
|
+
return nil unless self.entry
|
751
|
+
value = self.entry[ attrsym.to_s ] or return nil
|
752
|
+
|
753
|
+
if attribute = self.directory.schema.attribute_types[ attrsym ]
|
754
|
+
if attribute.single?
|
755
|
+
value = self.directory.convert_to_object( attribute.syntax.oid, value.first )
|
756
|
+
else
|
757
|
+
value = value.collect do |raw|
|
758
|
+
self.directory.convert_to_object( attribute.syntax.oid, raw )
|
759
|
+
end
|
760
|
+
end
|
761
|
+
else
|
762
|
+
self.log.info "no attributeType for %p" % [ attrsym ]
|
763
|
+
end
|
764
|
+
|
765
|
+
return value
|
766
|
+
end
|
767
|
+
|
768
|
+
|
769
|
+
### Convert the specified +object+ according to the Branch's directory's conversion rules,
|
770
|
+
### and return it.
|
771
|
+
def get_converted_attribute( attrsym, object )
|
772
|
+
if attribute = self.directory.schema.attribute_types[ attrsym ]
|
773
|
+
self.log.debug "converting %p object to a %p attribute" %
|
774
|
+
[ attrsym, attribute.syntax.oid ]
|
775
|
+
return self.directory.convert_to_attribute( attribute.syntax.oid, object )
|
776
|
+
else
|
777
|
+
self.log.info "no attributeType for %p" % [ attrsym ]
|
778
|
+
return object.to_s
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
|
750
783
|
### Clear any cached values when the structural state of the object changes.
|
751
784
|
### @return [void]
|
752
785
|
def clear_caches
|
@@ -793,6 +826,34 @@ class Treequel::Branch
|
|
793
826
|
end
|
794
827
|
end
|
795
828
|
|
829
|
+
|
830
|
+
### Make LDIF for the given +attribute+ and its +values+, wrapping at the given
|
831
|
+
### +width+.
|
832
|
+
###
|
833
|
+
### @param [String] attribute the attribute
|
834
|
+
### @param [Array<String>] values the values for the given +attribute+
|
835
|
+
### @param [Fixnum] width the maximum width of the lines to return
|
836
|
+
def ldif_for_attr( attribute, value, width )
|
837
|
+
unsplit_line = "#{attribute}:"
|
838
|
+
|
839
|
+
if value.empty? || value =~ /\A#{LDIF_SAFE_STRING}\Z/
|
840
|
+
unsplit_line << ' ' << value.to_s
|
841
|
+
else
|
842
|
+
unsplit_line << ': ' << [ value ].pack( 'm' ).chomp
|
843
|
+
end
|
844
|
+
unsplit_line.gsub!( /\n/, '' )
|
845
|
+
|
846
|
+
ldif = ''
|
847
|
+
ldif << unsplit_line.slice!( 0, width ) << LDIF_FOLD_SEPARATOR until
|
848
|
+
unsplit_line.empty?
|
849
|
+
|
850
|
+
ldif.rstrip!
|
851
|
+
ldif << "\n"
|
852
|
+
|
853
|
+
return ldif
|
854
|
+
end
|
855
|
+
|
856
|
+
|
796
857
|
end # class Treequel::Branch
|
797
858
|
|
798
859
|
|
@@ -178,19 +178,30 @@ class Treequel::BranchCollection
|
|
178
178
|
end
|
179
179
|
|
180
180
|
|
181
|
-
### Return a new Treequel::BranchCollection that includes both the receiver's
|
182
|
-
### those in +other_object+ (
|
181
|
+
### Return either a new Treequel::BranchCollection that includes both the receiver's
|
182
|
+
### Branchsets and those in +other_object+ (if it responds_to #branchsets), or the results
|
183
|
+
### from executing the BranchCollection's search with +other_object+ appended if it doesn't.
|
184
|
+
### @param [Object] other_object
|
183
185
|
def +( other_object )
|
184
186
|
if other_object.respond_to?( :branchsets )
|
185
187
|
return self.class.new( self.branchsets + other_object.branchsets )
|
186
|
-
elsif other_object.respond_to?( :
|
187
|
-
return self.class.new( self.branchsets + [other_object.branchset] )
|
188
|
-
else
|
188
|
+
elsif other_object.respond_to?( :collection )
|
189
189
|
return self.class.new( self.branchsets + [other_object] )
|
190
|
+
else
|
191
|
+
return self.all + Array( other_object )
|
190
192
|
end
|
191
193
|
end
|
192
194
|
|
193
195
|
|
196
|
+
### Return the results from each of the receiver's Branchsets without the +other_object+.
|
197
|
+
### @param [#dn] other_object the object to omit from the results. Must respond_to #dn.
|
198
|
+
### @return [Array<Treequel::Branch>]
|
199
|
+
def -( other_object )
|
200
|
+
other_dn = other_object.dn
|
201
|
+
return self.reject {|branch| branch.dn == other_dn }
|
202
|
+
end
|
203
|
+
|
204
|
+
|
194
205
|
### Return a new Treequel::BranchCollection that contains the union of the branchsets from both
|
195
206
|
### collections.
|
196
207
|
def &( other_collection )
|
data/lib/treequel/branchset.rb
CHANGED
@@ -176,12 +176,26 @@ class Treequel::Branchset
|
|
176
176
|
end
|
177
177
|
|
178
178
|
|
179
|
-
###
|
180
|
-
###
|
181
|
-
### @param [Treequel::Branchset]
|
182
|
-
###
|
183
|
-
|
184
|
-
|
179
|
+
### If given another Branchset or a BranchCollection, return a BranchCollection that includes
|
180
|
+
### them both. If given anything else, execute the search and return
|
181
|
+
### @param [Treequel::Branchset, Treequel::Branch] other the branchset or branch to combine
|
182
|
+
### with
|
183
|
+
### @return [Treequel::BranchCollection, Array<Treequel::Branch>]
|
184
|
+
def +( other )
|
185
|
+
if other.is_a?( Treequel::BranchCollection ) || other.is_a?( Treequel::Branchset )
|
186
|
+
return Treequel::BranchCollection.new( self, other )
|
187
|
+
else
|
188
|
+
return self.all + Array( other )
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
### Return the results of executing the search without the +other_object+.
|
194
|
+
### @param [#dn] other_object the object to omit from the results; must respond_to #dn.
|
195
|
+
### @return [Array<Treequel::Branch>]
|
196
|
+
def -( other_object )
|
197
|
+
other_dn = other_object.dn
|
198
|
+
return self.reject {|branch| branch.dn == other_dn }
|
185
199
|
end
|
186
200
|
|
187
201
|
|
@@ -276,6 +290,23 @@ class Treequel::Branchset
|
|
276
290
|
end
|
277
291
|
|
278
292
|
|
293
|
+
### Add an alternate filter to an existing filter by ORing them.
|
294
|
+
### @param filterspec the filter spec to OR with the existing filter
|
295
|
+
### @raises [Treequel::InvalidOperation] if there is no existing filter
|
296
|
+
### @see Treequel::Filter.new for specifics on what +filterspec+ can be
|
297
|
+
def or( *filterspec )
|
298
|
+
opts = self.options
|
299
|
+
existing_filter = self.filter
|
300
|
+
raise Treequel::ExpressionError, "no existing filter" if
|
301
|
+
existing_filter.promiscuous?
|
302
|
+
|
303
|
+
newfilter = Treequel::Filter.new( *filterspec )
|
304
|
+
|
305
|
+
self.log.debug "cloning %p with alternative filterspec: %p" % [ self, filterspec ]
|
306
|
+
return self.clone( :filter => (self.filter | newfilter) )
|
307
|
+
end
|
308
|
+
|
309
|
+
|
279
310
|
### If called with no argument, returns the current scope of the Branchset. If
|
280
311
|
### called with an argument (which should be one of the keys of
|
281
312
|
### Treequel::Constants::SCOPE), returns a clone of the receiving Branchset
|
data/lib/treequel/constants.rb
CHANGED
@@ -141,6 +141,18 @@ module Treequel::Constants
|
|
141
141
|
FEATURE_NAMES = FEATURE_OIDS.invert.freeze
|
142
142
|
|
143
143
|
|
144
|
+
### The list of RFC4512 operational attributes that "SHOULD" be maintained.
|
145
|
+
### (http://tools.ietf.org/html/rfc4512#section-3.4)
|
146
|
+
MINIMAL_OPERATIONAL_ATTRIBUTES = [
|
147
|
+
:creatorsName,
|
148
|
+
:createTimestamp,
|
149
|
+
:modifiersName,
|
150
|
+
:modifyTimestamp,
|
151
|
+
:structuralObjectClass,
|
152
|
+
:governingStructureRule,
|
153
|
+
]
|
154
|
+
|
155
|
+
|
144
156
|
### OIDs of RFC values
|
145
157
|
module OIDS
|
146
158
|
|