treequel 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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