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.
Files changed (53) hide show
  1. data/ChangeLog +130 -1
  2. data/Rakefile +8 -3
  3. data/Rakefile.local +2 -0
  4. data/bin/treeirb +6 -2
  5. data/bin/treequel +5 -4
  6. data/lib/treequel/branch.rb +133 -72
  7. data/lib/treequel/branchcollection.rb +16 -5
  8. data/lib/treequel/branchset.rb +37 -6
  9. data/lib/treequel/constants.rb +12 -0
  10. data/lib/treequel/directory.rb +96 -41
  11. data/lib/treequel/filter.rb +42 -1
  12. data/lib/treequel/model/objectclass.rb +111 -0
  13. data/lib/treequel/model.rb +363 -0
  14. data/lib/treequel/monkeypatches.rb +65 -0
  15. data/lib/treequel/schema/attributetype.rb +108 -18
  16. data/lib/treequel/schema/ldapsyntax.rb +15 -0
  17. data/lib/treequel/schema/matchingrule.rb +24 -0
  18. data/lib/treequel/schema/matchingruleuse.rb +24 -0
  19. data/lib/treequel/schema/objectclass.rb +70 -5
  20. data/lib/treequel/schema/table.rb +5 -15
  21. data/lib/treequel/schema.rb +64 -1
  22. data/lib/treequel.rb +5 -5
  23. data/rake/documentation.rb +27 -0
  24. data/rake/hg.rb +14 -2
  25. data/rake/manual.rb +1 -1
  26. data/spec/lib/constants.rb +9 -7
  27. data/spec/lib/control_behavior.rb +1 -0
  28. data/spec/lib/matchers.rb +1 -0
  29. data/spec/treequel/branch_spec.rb +229 -20
  30. data/spec/treequel/branchcollection_spec.rb +73 -39
  31. data/spec/treequel/branchset_spec.rb +59 -8
  32. data/spec/treequel/control_spec.rb +1 -0
  33. data/spec/treequel/controls/contentsync_spec.rb +1 -0
  34. data/spec/treequel/controls/pagedresults_spec.rb +1 -0
  35. data/spec/treequel/controls/sortedresults_spec.rb +1 -0
  36. data/spec/treequel/directory_spec.rb +46 -10
  37. data/spec/treequel/filter_spec.rb +28 -5
  38. data/spec/treequel/mixins_spec.rb +7 -14
  39. data/spec/treequel/model/objectclass_spec.rb +330 -0
  40. data/spec/treequel/model_spec.rb +433 -0
  41. data/spec/treequel/monkeypatches_spec.rb +118 -0
  42. data/spec/treequel/schema/attributetype_spec.rb +116 -0
  43. data/spec/treequel/schema/ldapsyntax_spec.rb +8 -0
  44. data/spec/treequel/schema/matchingrule_spec.rb +6 -1
  45. data/spec/treequel/schema/matchingruleuse_spec.rb +5 -0
  46. data/spec/treequel/schema/objectclass_spec.rb +41 -3
  47. data/spec/treequel/schema/table_spec.rb +31 -18
  48. data/spec/treequel/schema_spec.rb +13 -16
  49. data/spec/treequel_spec.rb +22 -0
  50. data.tar.gz.sig +1 -0
  51. metadata +40 -7
  52. metadata.gz.sig +0 -0
  53. data/spec/treequel/utils_spec.rb +0 -49
@@ -92,7 +92,7 @@ class Treequel::Schema
92
92
  @names = names
93
93
  @desc = desc
94
94
  @obsolete = obsolete ? true : false
95
- @sup_name = sup
95
+ @sup_oid = sup
96
96
  @must_oids = must_oids
97
97
  @may_oids = may_oids
98
98
  @extensions = extensions
@@ -120,8 +120,8 @@ class Treequel::Schema
120
120
  # Is the objectClass obsolete?
121
121
  predicate_attr :obsolete
122
122
 
123
- # The name of the objectClass's superior class (if specified)
124
- attr_accessor :sup_name
123
+ # The OID of the objectClass's superior class (if specified)
124
+ attr_accessor :sup_oid
125
125
 
126
126
  # The objectClass's extensions (as a String)
127
127
  attr_accessor :extensions
@@ -194,6 +194,48 @@ class Treequel::Schema
194
194
  end
195
195
 
196
196
 
197
+ ### Returns the objectClass as a String, which is the RFC4512-style schema
198
+ ### description.
199
+ def to_s
200
+ # ObjectClassDescription = LPAREN WSP
201
+ # numericoid ; object identifier
202
+ # [ SP "NAME" SP qdescrs ] ; short names (descriptors)
203
+ # [ SP "DESC" SP qdstring ] ; description
204
+ # [ SP "OBSOLETE" ] ; not active
205
+ # [ SP "SUP" SP oids ] ; superior object classes
206
+ # [ SP kind ] ; kind of class
207
+ # [ SP "MUST" SP oids ] ; attribute types
208
+ # [ SP "MAY" SP oids ] ; attribute types
209
+ # extensions WSP RPAREN
210
+ #
211
+ # kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"
212
+
213
+ parts = [ self.oid ]
214
+
215
+ parts << "NAME %s" % Treequel::Schema.qdescrs( self.names ) unless self.names.empty?
216
+ parts << "DESC %s" % [ Treequel::Schema.qdstring(self.desc) ] if self.desc
217
+ parts << "OBSOLETE" if self.obsolete?
218
+ parts << "SUP %s" % [ Treequel::Schema.oids(self.sup_oid) ] if self.sup_oid
219
+ parts << self.kind
220
+ parts << "MUST %s" % [ Treequel::Schema.oids(self.must_oids(false)) ] unless
221
+ self.must_oids(false).empty?
222
+ parts << "MAY %s" % [ Treequel::Schema.oids(self.may_oids(false)) ] unless
223
+ self.may_oids(false).empty?
224
+ parts << self.extensions.strip unless self.extensions.empty?
225
+
226
+ return "( %s )" % [ parts.join(' ') ]
227
+ end
228
+
229
+ # @oid = oid
230
+ # @names = names
231
+ # @desc = desc
232
+ # @obsolete = obsolete ? true : false
233
+ # @sup_oid = sup
234
+ # @must_oids = must_oids
235
+ # @may_oids = may_oids
236
+ # @extensions = extensions
237
+
238
+
197
239
  ### Return a human-readable representation of the object suitable for debugging
198
240
  def inspect
199
241
  return %{#<%s:0x%0x %s(%s) < %s "%s" MUST: %p, MAY: %p>} % [
@@ -201,7 +243,7 @@ class Treequel::Schema
201
243
  self.object_id / 2,
202
244
  self.name,
203
245
  self.oid,
204
- self.sup_name,
246
+ self.sup_oid,
205
247
  self.desc,
206
248
  self.must_oids,
207
249
  self.may_oids,
@@ -212,13 +254,36 @@ class Treequel::Schema
212
254
  ### Return the ObjectClass for the receiver's SUP. If this is called on
213
255
  ### 'top', returns nil.
214
256
  def sup
215
- unless name = self.sup_name
257
+ unless name = self.sup_oid
216
258
  return nil if self.oid == Treequel::Constants::OIDS::TOP_OBJECTCLASS
217
259
  return self.schema.object_classes[ :top ]
218
260
  end
219
261
  return self.schema.object_classes[ name.to_sym ]
220
262
  end
221
263
 
264
+
265
+ ### Return the SUP chain for the receiver up to 'top', including the receiver
266
+ ### itself.
267
+ ### @return [Array<Treequel::Schema::ObjectClass>] the array of ObjectClass objects
268
+ ### the receiver inherits from.
269
+ def ancestors
270
+ rval = [ self ]
271
+
272
+ if parent = self.sup
273
+ rval += parent.ancestors
274
+ end
275
+
276
+ return rval
277
+ end
278
+
279
+
280
+ ### Return the string that represents the kind of objectClass
281
+ ### the receiver represents.
282
+ ### @return [String] one of: 'ABSTRACT', 'STRUCTURAL', 'AUXILIARY'
283
+ def kind
284
+ return Treequel::Schema::OBJECTCLASS_TYPES.invert[ self.class ]
285
+ end
286
+
222
287
  end # class ObjectClass
223
288
 
224
289
 
@@ -11,27 +11,16 @@ require 'treequel/mixins'
11
11
 
12
12
  # This is an object that is used to store LDAP schema information in a
13
13
  # case-insensitive table.
14
- #
15
- # == Authors
16
- #
17
- # * Michael Granger <ged@FaerieMUD.org>
18
- # * Mahlon E. Smith <mahlon@martini.nu>
19
- #
20
- # :include: LICENSE
21
- #
22
- #--
23
- #
24
- # Please see the file LICENSE in the base directory for licensing details.
25
- #
26
14
  class Treequel::Schema::Table
27
15
  extend Forwardable
28
- include Treequel::Loggable,
16
+ include Enumerable,
17
+ Treequel::Loggable,
29
18
  Treequel::Normalization,
30
19
  Treequel::Constants::Patterns
31
20
 
32
21
  # The list of methods that should be delegated through the key-normalization
33
22
  # method.
34
- KEYED_METHODS = [ :"[]", :"[]=", :delete, :fetch, :key?, :has_key?, :include?,
23
+ KEYED_METHODS = [ :"[]", :"[]=", :delete, :fetch, :key?, :has_key?, :include?,
35
24
  :member?, :store ]
36
25
 
37
26
 
@@ -73,7 +62,8 @@ class Treequel::Schema::Table
73
62
 
74
63
  # Delegate some methods to the underlying Hash
75
64
  begin
76
- unoverridden_methods = Hash.instance_methods(false).collect {|mname| mname.to_sym }
65
+ unoverridden_methods = Hash.
66
+ instance_methods(false).collect {|mname| mname.to_sym }
77
67
  def_delegators :@hash, *( unoverridden_methods - KEYED_METHODS )
78
68
  end
79
69
 
@@ -105,6 +105,54 @@ class Treequel::Schema
105
105
  end
106
106
 
107
107
 
108
+ ### Return a description of the given +descriptors+ suitable for inclusion in
109
+ ### an RFC4512-style schema description entry.
110
+ ### @param [Array<String>] descriptors an Array of descriptors
111
+ ### @return [String] the 'qdescrs' text
112
+ def self::qdescrs( *descriptors )
113
+ descriptors.flatten!
114
+ if descriptors.length > 1
115
+ return "( %s )" % [ descriptors.collect {|str| self.qdstring(str) }.join(" ") ]
116
+ else
117
+ return self.qdstring( descriptors.first )
118
+ end
119
+ end
120
+
121
+
122
+ # qdstring = SQUOTE dstring SQUOTE
123
+ # dstring = 1*( QS / QQ / QUTF8 ) ; escaped UTF-8 string
124
+ #
125
+ # QQ = ESC %x32 %x37 ; "\27"
126
+ # QS = ESC %x35 ( %x43 / %x63 ) ; "\5C" / "\5c"
127
+ #
128
+ # ; Any UTF-8 encoded Unicode character
129
+ # ; except %x27 ("\'") and %x5C ("\")
130
+ # QUTF8 = QUTF1 / UTFMB
131
+
132
+ ### Escape and quote the specified +string+ according to the rules in
133
+ ### RFC4512/2252.
134
+ ### @param [String] string the unescaped UTF8 string
135
+ ### @return [String] the string after quoting and escaping
136
+ def self::qdstring( string )
137
+ return "'%s'" % [ string.to_s.gsub(/\\/, '\\\\5c').gsub(/'/, '\\\\27') ]
138
+ end
139
+
140
+
141
+ ### Return a description of the given +oids+ suitable for inclusion in
142
+ ### an RFC4512-style schema description entry.
143
+ ### @param [Array<String>] oids an Array of numeric or symbolic OIDs
144
+ ### @return [String] the oid list text
145
+ def self::oids( *oids )
146
+ oids.flatten!
147
+ if oids.length > 1
148
+ return "( %s )" % [ oids.join(" $ ") ]
149
+ else
150
+ return oids.first
151
+ end
152
+ end
153
+
154
+
155
+
108
156
  #################################################################
109
157
  ### I N S T A N C E M E T H O D S
110
158
  #################################################################
@@ -126,28 +174,43 @@ class Treequel::Schema
126
174
  public
127
175
  ######
128
176
 
129
- # The Hash of Treequel::Schema::ObjectClass objects, keyed by OID and any associated NAME
177
+ # The table of Treequel::Schema::ObjectClass objects, keyed by OID and any associated NAME
130
178
  # attributes (as Symbols), that describes the objectClasses in the directory's schema.
179
+ # @return [Treequel::Schema::Table]
131
180
  attr_reader :object_classes
132
181
 
133
182
  # The hash of Treequel::Schema::AttributeType objects, keyed by OID and any associated NAME
134
183
  # attributes (as Symbols), that describe the attributeTypes in the directory's schema.
184
+ # @return [Treequel::Schema::Table]
135
185
  attr_reader :attribute_types
136
186
 
137
187
  # The hash of Treequel::Schema::LDAPSyntax objects, keyed by OID, that describe the
138
188
  # syntaxes in the directory's schema.
189
+ # @return [Treequel::Schema::Table]
139
190
  attr_reader :ldap_syntaxes
140
191
 
141
192
  # The hash of Treequel::Schema::MatchingRule objects, keyed by OID and any associated NAME
142
193
  # attributes (as Symbols), that describe the matchingRules int he directory's schema.
194
+ # @return [Treequel::Schema::Table]
143
195
  attr_reader :matching_rules
144
196
 
145
197
  # The hash of Treequel::Schema::MatchingRuleUse objects, keyed by OID and any associated NAME
146
198
  # attributes (as Symbols), that describe the attributes to which a matchingRule can be applied.
199
+ # @return [Treequel::Schema::Table]
147
200
  attr_reader :matching_rule_uses
201
+ alias_method :matching_rule_use, :matching_rule_uses
202
+
203
+
204
+ ### Return the Treequel::Schema::AttributeType objects that correspond to the
205
+ ### operational attributes that are supported by the directory.
206
+ ### @return [Array<Treequel::Schema::AttributeType>] the operational attributes
207
+ def operational_attribute_types
208
+ return self.attribute_types.values.find_all {|attrtype| attrtype.operational? }.uniq
209
+ end
148
210
 
149
211
 
150
212
  ### Return a human-readable representation of the object suitable for debugging.
213
+ ### @return [String]
151
214
  def inspect
152
215
  ivar_descs = self.instance_variables.sort.collect do |ivar|
153
216
  len = self.instance_variable_get( ivar ).length
data/lib/treequel.rb CHANGED
@@ -25,7 +25,7 @@ end
25
25
 
26
26
  # A library for interacting with LDAP modelled after Sequel.
27
27
  #
28
- # @version 1.0.4
28
+ # @version 1.1.0
29
29
  #
30
30
  # @example
31
31
  # # Connect to the directory at the specified URL
@@ -53,10 +53,10 @@ end
53
53
  module Treequel
54
54
 
55
55
  # Library version
56
- VERSION = '1.0.4'
56
+ VERSION = '1.1.0'
57
57
 
58
58
  # VCS revision
59
- REVISION = %q$Revision: c8534439a5bc $
59
+ REVISION = %q$Revision: 2e2b035d3721 $
60
60
 
61
61
  # Common paths for ldap.conf
62
62
  COMMON_LDAP_CONF_PATHS = %w[
@@ -250,7 +250,7 @@ module Treequel
250
250
  ### @return [Hash] The hash of configuration values read from the file, in a form suitable for
251
251
  ### passing to {Treequel::Directory#initialize}.
252
252
  def self::read_opts_from_config( configfile )
253
- Treequel.log.debug "Reading config options from %s..." % [ configfile ]
253
+ Treequel.log.info "Reading config options from %s..." % [ configfile ]
254
254
  opts = {}
255
255
 
256
256
  linecount = 0
@@ -292,7 +292,7 @@ module Treequel
292
292
  opts[:port] = $1.to_i
293
293
 
294
294
  # SSL <on|off|start_tls>
295
- when /^\s*SSL\s+(on|off|start_tls)/i
295
+ when /^\s*SSL\s+(\S+)/i
296
296
  mode = $1.downcase
297
297
  case mode
298
298
  when 'on'
@@ -44,6 +44,7 @@ begin
44
44
  end
45
45
 
46
46
  class YARD::CLI::Base; include YardGlobals; end
47
+ class YARD::CLI::Command; include YardGlobals; end
47
48
  class YARD::Parser::SourceParser; extend YardGlobals; include YardGlobals; end
48
49
  class YARD::Parser::CParser; include YardGlobals; end
49
50
  class YARD::CodeObjects::Base; include YardGlobals; end
@@ -53,6 +54,32 @@ begin
53
54
  class YARD::RegistryStore; include YardGlobals; end
54
55
  class YARD::Docstring; include YardGlobals; end
55
56
  module YARD::Templates::Helpers::ModuleHelper; include YardGlobals; end
57
+ module YARD::Tags::RefTaglist; include YardGlobals; end
58
+
59
+ if vvec(RUBY_VERSION) >= vvec("1.9.1")
60
+ # Monkeypatched to allow more than two '#' characters at the beginning
61
+ # of the comment line.
62
+ # Patched from yard-0.5.8
63
+ require 'yard/parser/ruby/ruby_parser'
64
+ class YARD::Parser::Ruby::RipperParser < Ripper
65
+ def on_comment(comment)
66
+ $stderr.puts "Adding comment: %p" % [ comment ]
67
+ visit_ns_token(:comment, comment)
68
+
69
+ comment = comment.gsub(/^\#+\s{0,1}/, '').chomp
70
+ append_comment = @comments[lineno - 1]
71
+
72
+ if append_comment && @comments_last_column == column
73
+ @comments.delete(lineno - 1)
74
+ comment = append_comment + "\n" + comment
75
+ end
76
+
77
+ @comments[lineno] = comment
78
+ @comments_last_column = column
79
+ end
80
+ end # class YARD::Parser::Ruby::RipperParser
81
+ end
82
+
56
83
  # </metamonkeypatch>
57
84
 
58
85
  YARD_OPTIONS = [] unless defined?( YARD_OPTIONS )
data/rake/hg.rb CHANGED
@@ -215,13 +215,20 @@ unless defined?( HG_DOTDIR )
215
215
  paths = get_repo_paths()
216
216
  if origin_url = paths['default']
217
217
  ask_for_confirmation( "Pull and update from '#{origin_url}'?", false ) do
218
- run 'hg', 'pull', '-u'
218
+ Rake::Task['hg:pull_without_confirmation'].invoke
219
219
  end
220
220
  else
221
221
  trace "Skipping pull: No 'default' path."
222
222
  end
223
223
  end
224
224
 
225
+
226
+ desc "Pull and update without confirmation"
227
+ task :pull_without_confirmation do
228
+ run 'hg', 'pull', '-u'
229
+ end
230
+
231
+
225
232
  desc "Check the current code in if tests pass"
226
233
  task :checkin => ['hg:pull', 'hg:newfiles', 'test', COMMIT_MSG_FILE] do
227
234
  targets = get_target_args()
@@ -242,13 +249,18 @@ unless defined?( HG_DOTDIR )
242
249
  paths = get_repo_paths()
243
250
  if origin_url = paths['default']
244
251
  ask_for_confirmation( "Push to '#{origin_url}'?", false ) do
245
- run 'hg', 'push'
252
+ Rake::Task['hg:push_without_confirmation'].invoke
246
253
  end
247
254
  else
248
255
  trace "Skipping push: No 'default' path."
249
256
  end
250
257
  end
251
258
 
259
+ desc "Push to the default repo without confirmation"
260
+ task :push_without_confirmation do
261
+ run 'hg', 'push'
262
+ end
263
+
252
264
  end
253
265
 
254
266
  if HG_DOTDIR.exist?
data/rake/manual.rb CHANGED
@@ -269,7 +269,7 @@ module Manual
269
269
 
270
270
  ### Create a new PageCatalog that will load Manual::Page objects for .page files
271
271
  ### in the specified +sourcedir+.
272
- def initialize( sourcedir, layoutsdir )
272
+ def initialize( sourcedir, layoutsdir )
273
273
  @sourcedir = sourcedir
274
274
  @layoutsdir = layoutsdir
275
275
 
@@ -21,32 +21,34 @@ module Treequel::TestConstants # :nodoc:all
21
21
 
22
22
  TEST_DSE = [{
23
23
  "supportedSASLMechanisms" => [
24
- "SRP", "SRP", "SRP", "PLAIN", "PLAIN",
25
- "PLAIN", "OTP", "OTP", "OTP", "NTLM", "NTLM", "NTLM", "LOGIN",
26
- "LOGIN", "LOGIN", "GSSAPI", "GSSAPI", "GSSAPI", "DIGEST-MD5",
24
+ "SRP", "SRP", "SRP", "PLAIN", "PLAIN",
25
+ "PLAIN", "OTP", "OTP", "OTP", "NTLM", "NTLM", "NTLM", "LOGIN",
26
+ "LOGIN", "LOGIN", "GSSAPI", "GSSAPI", "GSSAPI", "DIGEST-MD5",
27
27
  "DIGEST-MD5", "DIGEST-MD5", "CRAM-MD5", "CRAM-MD5", "CRAM-MD5"
28
28
  ],
29
29
  "supportedFeatures" => [
30
30
  "1.3.6.1.1.14", "1.3.6.1.4.1.4203.1.5.1", "1.3.6.1.4.1.4203.1.5.2",
31
- "1.3.6.1.4.1.4203.1.5.3", "1.3.6.1.4.1.4203.1.5.4",
31
+ "1.3.6.1.4.1.4203.1.5.3", "1.3.6.1.4.1.4203.1.5.4",
32
32
  "1.3.6.1.4.1.4203.1.5.5"
33
33
  ],
34
34
  "namingContexts" => [TEST_BASE_DN],
35
35
  "supportedLDAPVersion" => ["3"],
36
36
  "subschemaSubentry" => ["cn=Subschema"],
37
37
  "supportedControl" => [
38
- "1.3.6.1.4.1.4203.1.9.1.1", "2.16.840.1.113730.3.4.18",
38
+ "1.3.6.1.4.1.4203.1.9.1.1", "2.16.840.1.113730.3.4.18",
39
39
  "2.16.840.1.113730.3.4.2", "1.3.6.1.4.1.4203.1.10.1",
40
- "1.2.840.113556.1.4.319", "1.2.826.0.1.334810.2.3",
40
+ "1.2.840.113556.1.4.319", "1.2.826.0.1.334810.2.3",
41
41
  "1.2.826.0.1.3344810.2.3", "1.3.6.1.1.13.2",
42
42
  "1.3.6.1.1.13.1", "1.3.6.1.1.12"
43
43
  ],
44
44
  "supportedExtension" => [
45
- "1.3.6.1.4.1.1466.20037", "1.3.6.1.4.1.4203.1.11.1",
45
+ "1.3.6.1.4.1.1466.20037", "1.3.6.1.4.1.4203.1.11.1",
46
46
  "1.3.6.1.4.1.4203.1.11.3"
47
47
  ],
48
48
  "dn"=>[""]
49
49
  }]
50
+ TEST_DSE.first.keys.each {|key| TEST_DSE.first[key].freeze }
51
+
50
52
 
51
53
  TEST_HOSTS_DN_ATTR = 'ou'
52
54
  TEST_HOSTS_DN_VALUE = 'Hosts'
@@ -6,6 +6,7 @@ BEGIN {
6
6
 
7
7
  libdir = basedir + "lib"
8
8
 
9
+ $LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
9
10
  $LOAD_PATH.unshift( libdir ) unless $LOAD_PATH.include?( libdir )
10
11
  }
11
12
 
data/spec/lib/matchers.rb CHANGED
@@ -47,5 +47,6 @@ module Treequel::Matchers
47
47
  ArrayIncludingMatcher.new( objects )
48
48
  end
49
49
 
50
+
50
51
  end # module Treequel::Matchers
51
52