treequel 1.0.1 → 1.0.4

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 (73) hide show
  1. data/ChangeLog +176 -14
  2. data/LICENSE +1 -1
  3. data/Rakefile +61 -45
  4. data/Rakefile.local +20 -0
  5. data/bin/treequel +502 -269
  6. data/examples/ldap-rack-auth.rb +2 -0
  7. data/lib/treequel.rb +221 -18
  8. data/lib/treequel/branch.rb +410 -201
  9. data/lib/treequel/branchcollection.rb +25 -13
  10. data/lib/treequel/branchset.rb +42 -40
  11. data/lib/treequel/constants.rb +233 -3
  12. data/lib/treequel/control.rb +95 -0
  13. data/lib/treequel/controls/contentsync.rb +138 -0
  14. data/lib/treequel/controls/pagedresults.rb +162 -0
  15. data/lib/treequel/controls/sortedresults.rb +216 -0
  16. data/lib/treequel/directory.rb +212 -65
  17. data/lib/treequel/exceptions.rb +11 -12
  18. data/lib/treequel/filter.rb +1 -12
  19. data/lib/treequel/mixins.rb +83 -47
  20. data/lib/treequel/monkeypatches.rb +29 -0
  21. data/lib/treequel/schema.rb +23 -19
  22. data/lib/treequel/schema/attributetype.rb +33 -3
  23. data/lib/treequel/schema/ldapsyntax.rb +0 -11
  24. data/lib/treequel/schema/matchingrule.rb +0 -11
  25. data/lib/treequel/schema/matchingruleuse.rb +0 -11
  26. data/lib/treequel/schema/objectclass.rb +36 -10
  27. data/lib/treequel/schema/table.rb +159 -0
  28. data/lib/treequel/sequel_integration.rb +7 -7
  29. data/lib/treequel/utils.rb +4 -66
  30. data/rake/documentation.rb +89 -0
  31. data/rake/helpers.rb +375 -307
  32. data/rake/hg.rb +16 -2
  33. data/rake/manual.rb +11 -6
  34. data/rake/packaging.rb +20 -35
  35. data/rake/publishing.rb +22 -62
  36. data/spec/lib/constants.rb +20 -0
  37. data/spec/lib/control_behavior.rb +44 -0
  38. data/spec/lib/matchers.rb +51 -0
  39. data/spec/treequel/branch_spec.rb +88 -29
  40. data/spec/treequel/branchcollection_spec.rb +24 -1
  41. data/spec/treequel/branchset_spec.rb +123 -51
  42. data/spec/treequel/control_spec.rb +48 -0
  43. data/spec/treequel/controls/contentsync_spec.rb +38 -0
  44. data/spec/treequel/controls/pagedresults_spec.rb +138 -0
  45. data/spec/treequel/controls/sortedresults_spec.rb +171 -0
  46. data/spec/treequel/directory_spec.rb +186 -16
  47. data/spec/treequel/mixins_spec.rb +42 -3
  48. data/spec/treequel/schema/attributetype_spec.rb +22 -20
  49. data/spec/treequel/schema/objectclass_spec.rb +67 -46
  50. data/spec/treequel/schema/table_spec.rb +134 -0
  51. data/spec/treequel_spec.rb +277 -15
  52. metadata +89 -108
  53. data/bin/treequel.orig +0 -963
  54. data/examples/ldap-monitor.rb +0 -143
  55. data/examples/ldap-monitor/public/css/master.css +0 -328
  56. data/examples/ldap-monitor/public/images/card_small.png +0 -0
  57. data/examples/ldap-monitor/public/images/chain_small.png +0 -0
  58. data/examples/ldap-monitor/public/images/globe_small.png +0 -0
  59. data/examples/ldap-monitor/public/images/globe_small_green.png +0 -0
  60. data/examples/ldap-monitor/public/images/plug.png +0 -0
  61. data/examples/ldap-monitor/public/images/shadows/large-30-down.png +0 -0
  62. data/examples/ldap-monitor/public/images/tick.png +0 -0
  63. data/examples/ldap-monitor/public/images/tick_circle.png +0 -0
  64. data/examples/ldap-monitor/public/images/treequel-favicon.png +0 -0
  65. data/examples/ldap-monitor/views/backends.erb +0 -41
  66. data/examples/ldap-monitor/views/connections.erb +0 -74
  67. data/examples/ldap-monitor/views/databases.erb +0 -39
  68. data/examples/ldap-monitor/views/dump_subsystem.erb +0 -14
  69. data/examples/ldap-monitor/views/index.erb +0 -14
  70. data/examples/ldap-monitor/views/layout.erb +0 -35
  71. data/examples/ldap-monitor/views/listeners.erb +0 -30
  72. data/rake/rdoc.rb +0 -30
  73. data/rake/win32.rb +0 -190
@@ -29,17 +29,6 @@ require 'treequel/branch'
29
29
  #
30
30
  # Note that you could accomplish most of what BranchCollection does
31
31
  # using filters, but some people might find this a bit more readable.
32
- #
33
- # == Authors
34
- #
35
- # * Michael Granger <ged@FaerieMUD.org>
36
- #
37
- # :include: LICENSE
38
- #
39
- #--
40
- #
41
- # Please see the file LICENSE in the base directory for licensing details.
42
- #
43
32
  class Treequel::BranchCollection
44
33
  include Enumerable,
45
34
  Treequel::Loggable,
@@ -52,12 +41,21 @@ class Treequel::BranchCollection
52
41
  ### C L A S S M E T H O D S
53
42
  #################################################################
54
43
 
55
- ### Create a delegator that will return an instance of the receiver created with the results of
56
- ### iterating over the branchsets and calling the delegated method.
44
+ ### Create a delegator that will return an instance of the receiver
45
+ ### created with the results of iterating over the branchsets and calling
46
+ ### the delegated method.
47
+ ### @param [Array<Symbol>] symbols The methods to define
57
48
  def self::def_cloning_delegators( *symbols )
58
49
  symbols.each do |methname|
59
50
  # Create the method body
60
51
  methodbody = Proc.new {|*args|
52
+
53
+ # Check to be sure the mutator version of the method is being called
54
+ arity = self.branchsets.first.method( methname ).arity
55
+ if arity.nonzero? && args.empty?
56
+ raise ArgumentError, "wrong number of arguments: (0 for %d)" % [ arity.abs ]
57
+ end
58
+
61
59
  mutated_branchsets = self.branchsets.
62
60
  collect {|bs| bs.send(methname, *args) }.flatten
63
61
  self.class.new( *mutated_branchsets )
@@ -75,6 +73,8 @@ class Treequel::BranchCollection
75
73
  #################################################################
76
74
 
77
75
  ### Create a new Treequel::BranchCollection that will operate on the given +branchsets+.
76
+ ### @param [Array<Treequel::Branchset, #each>] branchsets the objects that will be
77
+ ### combined in the BranchCollection.
78
78
  def initialize( *branchsets )
79
79
  @branchsets = branchsets.flatten.collect do |obj|
80
80
  if obj.respond_to?( :each )
@@ -107,6 +107,7 @@ class Treequel::BranchCollection
107
107
 
108
108
 
109
109
  ### Return a human-readable string representation of the object suitable for debugging.
110
+ ### @return [String]
110
111
  def inspect
111
112
  "#<%s:0x%0x %d branchsets: %p>" % [
112
113
  self.class.name,
@@ -119,6 +120,7 @@ class Treequel::BranchCollection
119
120
 
120
121
  ### Iterate over the Treequel::Branches found by each member branchset, yielding each
121
122
  ### one in turn.
123
+ ### @yield [Treequel::Branch]
122
124
  def each( &block )
123
125
  raise LocalJumpError, "no block given" unless block
124
126
  self.branchsets.each do |bs|
@@ -128,6 +130,7 @@ class Treequel::BranchCollection
128
130
 
129
131
 
130
132
  ### Return the first Treequel::Branch that is returned from the collection's branchsets.
133
+ ### @return [Treequel::Branch]
131
134
  def first
132
135
  branch = nil
133
136
 
@@ -138,7 +141,16 @@ class Treequel::BranchCollection
138
141
  return branch
139
142
  end
140
143
 
144
+
145
+ ### Return +true+ if none of the collection's branches match any entries.
146
+ ### @return [Boolean]
147
+ def empty?
148
+ return self.branchsets.all? {|bs| bs.empty? } ? true : false
149
+ end
150
+
151
+
141
152
  ### Overridden to support Branchset#map
153
+ ### @param (see Treequel::Branchset#map)
142
154
  def map( attribute=nil, &block )
143
155
  if attribute
144
156
  if block
@@ -10,6 +10,7 @@ require 'treequel/constants'
10
10
  require 'treequel/branch'
11
11
  require 'treequel/filter'
12
12
  require 'treequel/sequel_integration'
13
+ require 'treequel/control'
13
14
 
14
15
 
15
16
  # A branchset represents an abstract set of LDAP records returned by
@@ -41,21 +42,11 @@ require 'treequel/sequel_integration'
41
42
  #
42
43
  # Branchsets are Enumerable objects, so they can be manipulated using any of the
43
44
  # Enumerable methods, such as map, inject, etc.
44
- #
45
- # == Authors
46
- #
47
- # * Michael Granger <ged@FaerieMUD.org>
48
- #
49
- # :include: LICENSE
50
- #
51
- #--
52
- #
53
- # Please see the file LICENSE in the base directory for licensing details.
54
- #
55
45
  class Treequel::Branchset
56
46
  include Enumerable,
57
47
  Treequel::Loggable,
58
- Treequel::Constants
48
+ Treequel::Constants,
49
+ Treequel::Control
59
50
 
60
51
  # The default scope to use when searching if none is specified
61
52
  DEFAULT_SCOPE = :subtree
@@ -84,9 +75,13 @@ class Treequel::Branchset
84
75
  ### Create a new Branchset for a search from the DN of the specified +branch+ (a
85
76
  ### Treequel::Branch), with the given +options+.
86
77
  def initialize( branch, options={} )
87
- super()
88
78
  @branch = branch
89
79
  @options = DEFAULT_OPTIONS.merge( options )
80
+
81
+ self.extend( *@branch.directory.registered_controls ) unless
82
+ @branch.directory.registered_controls.empty?
83
+
84
+ super()
90
85
  end
91
86
 
92
87
 
@@ -103,6 +98,17 @@ class Treequel::Branchset
103
98
  attr_accessor :branch
104
99
 
105
100
 
101
+ ### Extend the Branchset with one or more modules. Overridden to also call the modules'
102
+ ### initializers if they have them.
103
+ def extend( *modules )
104
+ super
105
+ modules.each do |mod|
106
+ mod.instance_method( :initialize ).bind( self ).call if
107
+ mod.private_instance_methods.map( &:to_sym ).include?( :initialize )
108
+ end
109
+ end
110
+
111
+
106
112
  ### Returns the DN of the Branchset's branch.
107
113
  def base_dn
108
114
  return self.branch.dn
@@ -166,7 +172,16 @@ class Treequel::Branchset
166
172
 
167
173
  ### Create a BranchCollection from the results of the Branchset and return it.
168
174
  def collection
169
- Treequel::BranchCollection.new( self.all )
175
+ return Treequel::BranchCollection.new( self.all )
176
+ end
177
+
178
+
179
+ ### Create a BranchCollection from the receiver and the +other_branchset+ and return
180
+ ### it.
181
+ ### @param [Treequel::Branchset] other_branchset the branchset to combine with
182
+ ### @return [Treequel::BranchCollection] the resulting collection object
183
+ def +( other_branchset )
184
+ return Treequel::BranchCollection.new( self, other_branchset )
170
185
  end
171
186
 
172
187
 
@@ -174,29 +189,39 @@ class Treequel::Branchset
174
189
  ### as Treequel::Branch objects to the supplied block.
175
190
  def each( &block )
176
191
  raise LocalJumpError, "no block given" unless block
177
- directory = self.branch.directory
178
192
 
179
- directory.search( self.branch, self.scope, self.filter,
193
+ self.branch.search( self.scope, self.filter,
180
194
  :selectattrs => self.select,
181
195
  :timeout => self.timeout,
182
196
  # :sortby => self.order,
183
197
  :limit => self.limit,
198
+ :client_controls => self.get_client_controls,
199
+ :server_controls => self.get_server_controls,
184
200
  &block
185
201
  )
186
202
  end
187
203
 
204
+
188
205
  ### Fetch the first entry which matches the current criteria and return it as an instance of
189
206
  ### the object that is set as the +branch+ (e.g., Treequel::Branch).
190
207
  def first
191
- self.branch.directory.search( self.branch, self.scope, self.filter,
208
+ self.branch.search( self.scope, self.filter,
192
209
  :selectattrs => self.select,
193
210
  :timeout => self.timeout,
194
211
  # :sortby => self.order,
212
+ :client_controls => self.get_client_controls,
213
+ :server_controls => self.get_server_controls,
195
214
  :limit => 1
196
215
  ).first
197
216
  end
198
217
 
199
218
 
219
+ ### Return +true+ if no entries match the Branchset's current criteria.
220
+ def empty?
221
+ return self.first.nil? ? true : false
222
+ end
223
+
224
+
200
225
  ### Either maps entries which match the current criteria into an Array of the given
201
226
  ### +attribute+, or falls back to the block form if no +attribute+ is specified. If both an
202
227
  ### +attribute+ and a +block+ are given, the +block+ is called once for each +attribute+ value
@@ -341,29 +366,6 @@ class Treequel::Branchset
341
366
  newset.branch = branchclass.new( self.branch.directory, self.branch.dn )
342
367
  return newset
343
368
  end
344
-
345
-
346
- # Hiding this until we figure out how to do server-side ordering (i.e.,
347
- # http://tools.ietf.org/html/rfc2891)
348
-
349
- ### Return a clone of the receiving Branchsest that will order its results by the
350
- ### +attributes+ specified.
351
- def __order( attribute=:__default__ ) # :nodoc:
352
- if attribute == :__default__
353
- if block_given?
354
- sort_func = Proc.new
355
- return self.clone( :order => sort_func )
356
- else
357
- return self.options[:order]
358
- end
359
- elsif attribute.nil?
360
- self.log.debug "cloning %p with no order" % [ self ]
361
- return self.clone( :order => nil )
362
- else
363
- self.log.debug "cloning %p with new order: %p" % [ self, attribute ]
364
- return self.clone( :order => attribute.to_sym )
365
- end
366
- end
367
369
 
368
370
 
369
371
  end # class Treequel::Branchset
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
+ require 'uri'
3
4
  require 'ldap'
4
5
  require 'treequel'
5
6
 
@@ -27,6 +28,118 @@ module Treequel::Constants
27
28
  LDAP::LDAP_SCOPE_SUBTREE => 'subtree',
28
29
  }
29
30
 
31
+ ### Names and OIDs of various controls, in OID order
32
+ CONTROL_OIDS = {
33
+ :valuesreturnfilter => '1.2.826.0.1.334810.2.3',
34
+ :matchedvals => '1.2.826.0.1.3344810.2.2',
35
+ :matchedvalues => '1.2.826.0.1.3344810.2.3',
36
+
37
+ # MS Active Directory controls, from various MSDN references, most
38
+ # notably:
39
+ # http://msdn.microsoft.com/en-us/library/cc223320%28PROT.10%29.aspx
40
+ :paged => '1.2.840.113556.1.4.319',
41
+ :server_show_deleted => '1.2.840.113556.1.4.417',
42
+ :sortrequest => '1.2.840.113556.1.4.473',
43
+ :sortresult => '1.2.840.113556.1.4.474',
44
+ :crossdom_move_target => '1.2.840.113556.1.4.521',
45
+ :server_notification => '1.2.840.113556.1.4.528',
46
+ :extended_dn => '1.2.840.113556.1.4.529',
47
+ :referrals => '1.2.840.113556.1.4.616',
48
+ :server_lazy_commit => '1.2.840.113556.1.4.619',
49
+ :server_sd_flags => '1.2.840.113556.1.4.801',
50
+ :incremental_values => '1.2.840.113556.1.4.802',
51
+ :tree_delete => '1.2.840.113556.1.4.805',
52
+ :server_dirsync => '1.2.840.113556.1.4.841',
53
+ :get_stats => '1.2.840.113556.1.4.970',
54
+ :verify_name => '1.2.840.113556.1.4.1338',
55
+ :domain_scope => '1.2.840.113556.1.4.1339',
56
+ :search_options => '1.2.840.113556.1.4.1340',
57
+ :rodc_dcpromo => '1.2.840.113556.1.4.1341',
58
+ :permissive_modify => '1.2.840.113556.1.4.1413',
59
+ :asq => '1.2.840.113556.1.4.1504',
60
+ :fast_bind => '1.2.840.113556.1.4.1781',
61
+ :quota_control => '1.2.840.113556.1.4.1852',
62
+ :shutdown_notify => '1.2.840.113556.1.4.1907',
63
+ :range_retrieval_noerr => '1.2.840.113556.1.4.1948',
64
+ :force_update => '1.2.840.113556.1.4.1974',
65
+ :input_dn => '1.2.840.113556.1.4.2026',
66
+
67
+ # RFC 4527
68
+ :preread => '1.3.6.1.1.13.1',
69
+ :postread => '1.3.6.1.1.13.2',
70
+
71
+ :assertion => '1.3.6.1.1.12',
72
+
73
+ :passwordpolicy => '1.3.6.1.4.1.42.2.27.8.5.1',
74
+
75
+ :ttl_refresh => '1.3.6.1.4.1.1466.101.119.1',
76
+ :start_tls => '1.3.6.1.4.1.1466.20037',
77
+
78
+ :sync => '1.3.6.1.4.1.4203.1.9.1.1',
79
+ :sync_state => '1.3.6.1.4.1.4203.1.9.1.2',
80
+ :sync_done => '1.3.6.1.4.1.4203.1.9.1.3',
81
+ :subentries => '1.3.6.1.4.1.4203.1.10.1',
82
+
83
+ # OpenLDAP "devil made me do it" OID arc
84
+ :noop => "1.3.6.1.4.1.4203.666.5.2",
85
+ :no_subordinates => "1.3.6.1.4.1.4203.666.5.11",
86
+ :relax => "1.3.6.1.4.1.4203.666.5.12",
87
+ :managedit => "1.3.6.1.4.1.4203.666.5.12",
88
+ :slurp => "1.3.6.1.4.1.4203.666.5.13",
89
+ :valsort => "1.3.6.1.4.1.4203.666.5.14",
90
+ :dontusecopy => "1.3.6.1.4.1.4203.666.5.15",
91
+ :x_deref => "1.3.6.1.4.1.4203.666.5.16",
92
+ :x_whatfailed => "1.3.6.1.4.1.4203.666.5.17",
93
+ :x_chaining_behavior => "1.3.6.1.4.1.4203.666.11.3",
94
+
95
+ # LDAP Duplicated Entry Control Extension
96
+ :dupent_request => '2.16.840.1.113719.1.27.101.1',
97
+ :dupent_response => '2.16.840.1.113719.1.27.101.2',
98
+ :dupent_entry => '2.16.840.1.113719.1.27.101.3',
99
+
100
+ :managedsait => '2.16.840.1.113730.3.4.2',
101
+ :persistentsearch => '2.16.840.1.113730.3.4.3',
102
+ :pwexpired => '2.16.840.1.113730.3.4.4',
103
+ :pwexpiring => '2.16.840.1.113730.3.4.5',
104
+ :entrychange => '2.16.840.1.113730.3.4.7',
105
+ :vlvrequest => '2.16.840.1.113730.3.4.9',
106
+ :vlvresponse => '2.16.840.1.113730.3.4.10',
107
+ :proxyauthentication => '2.16.840.1.113730.3.4.18',
108
+
109
+ }.freeze
110
+ CONTROL_NAMES = CONTROL_OIDS.invert.freeze
111
+
112
+
113
+ ### Names and OIDs of LDAP extensions, in OID order
114
+ EXTENSION_OIDS = {
115
+ # Borrowed from OpenLDAP's ldap.h
116
+ :cancel => '1.3.6.1.1.8', # RFC 3909
117
+ :turn => '1.3.6.1.1.19', # RFC 4531
118
+
119
+ :refresh => '1.3.6.1.4.1.1466.101.119.1', # RFC 2589
120
+ :start_tls => '1.3.6.1.4.1.1466.20037', # RFC 4511
121
+
122
+ :modify_passwd => '1.3.6.1.4.1.4203.1.11.1', # RFC 3062
123
+ :who_am_i => '1.3.6.1.4.1.4203.1.11.3', # RFC 4532
124
+ }.freeze
125
+ EXTENSION_NAMES = EXTENSION_OIDS.invert.freeze
126
+
127
+
128
+ ### Names and OIDs of LDAP features, in OID order
129
+ FEATURE_OIDS = {
130
+ # Borrowed from OpenLDAP's ldap.h
131
+ :modify_increment => '1.3.6.1.1.14',
132
+
133
+ :all_op_attrs => '1.3.6.1.4.1.4203.1.5.1', # RFC 3673
134
+ :objectclass_attrs => '1.3.6.1.4.1.4203.1.5.2',
135
+ :absolute_filters => '1.3.6.1.4.1.4203.1.5.3',
136
+ :language_tag_options => '1.3.6.1.4.1.4203.1.5.4',
137
+ :language_range_options => '1.3.6.1.4.1.4203.1.5.5',
138
+
139
+ :subordinate_scope => '1.3.6.1.4.1.4203.666.8.1',
140
+ }.freeze
141
+ FEATURE_NAMES = FEATURE_OIDS.invert.freeze
142
+
30
143
 
31
144
  ### OIDs of RFC values
32
145
  module OIDS
@@ -80,6 +193,16 @@ module Treequel::Constants
80
193
  ### A collection of Regexps to match various LDAP values
81
194
  module Patterns
82
195
 
196
+ # Steal the URIREF regexp from the URI library. We have to look in
197
+ # both places to support both 1.9.1 and 1.8.x.
198
+ URI_REF = if URI::REGEXP.const_defined?( :PATTERN )
199
+ /#{URI::REGEXP::PATTERN::URI_REF}/
200
+ elsif URI::REGEXP.const_defined?( :URI_REF )
201
+ /#{URI::REGEXP::URI_REF}/
202
+ else
203
+ raise "Couldn't find the URI_REF constant in the URI library!"
204
+ end
205
+
83
206
  # :stopdoc:
84
207
 
85
208
  # Schema-parsing patterns based on the BNF in
@@ -228,26 +351,34 @@ module Treequel::Constants
228
351
  # numericoid = number 1*( DOT number )
229
352
  NUMERICOID = /#{NUMBER}(?: #{DOT} #{NUMBER} )+/x
230
353
 
354
+ # ActiveDirectory quotes its numeric OIDs (sometimes)
355
+ QUOTED_NUMERICOID = /#{SQUOTE} #{NUMERICOID} #{SQUOTE}/x
231
356
 
232
- # Short names, also known as ¨iptors, are used as more readable
357
+ # Short names, also known as descriptors, are used as more readable
233
358
  # aliases for object identifiers. Short names are case insensitive and
234
359
  # conform to the ABNF:
235
360
 
236
361
  # descr = keystring
237
362
  DESCR = KEYSTRING
238
363
 
364
+ # ActiveDirectory quotes its descriptors (sometimes)
365
+ QUOTED_DESCR = / #{SQUOTE} #{DESCR} #{SQUOTE} /x
366
+
239
367
  # Where either an object identifier or a short name may be specified,
240
368
  # the following production is used:
241
369
 
242
370
  # oid = descr / numericoid
243
- OID = / #{DESCR} | #{NUMERICOID} /x
371
+ # NOTE: Added QUOTED_NUMERICOID and QUOTED_DESCR to support ActiveDirectory
372
+ OID = / #{DESCR} | #{QUOTED_DESCR} | #{NUMERICOID} | #{QUOTED_NUMERICOID} /x
244
373
 
245
374
 
246
375
  # len = number
247
376
  LEN = NUMBER
248
377
 
249
378
  # noidlen = numericoid [ LCURLY len RCURLY ]
250
- NOIDLEN = /#{NUMERICOID} (?:#{LCURLY} #{LEN} #{RCURLY})?/x
379
+ # NOTE: I changed this from NUMERICOID to OID to support ActiveDirectory schema
380
+ # entries
381
+ NOIDLEN = /#{OID} (?:#{LCURLY} #{LEN} #{RCURLY})?/x
251
382
 
252
383
  # oidlist = oid *( WSP DOLLAR WSP oid )
253
384
  OIDLIST = /#{OID} (?: #{WSP} #{DOLLAR} #{WSP} #{OID} )*/x
@@ -595,6 +726,105 @@ module Treequel::Constants
595
726
  }x
596
727
 
597
728
 
729
+ #
730
+ # LDIF (RFC 2849)
731
+ #
732
+
733
+ # attr-type-chars = ALPHA / DIGIT / "-"
734
+ # opt-char = attr-type-chars
735
+ # same as KEYCHAR
736
+ LDIF_ATTR_TYPE_CHARS = KEYCHAR
737
+ LDIF_OPT_CHAR = KEYCHAR
738
+
739
+ # option = 1*opt-char
740
+ LDIF_ATTRTYPE_OPTION = %r{ #{LDIF_OPT_CHAR}+ }x
741
+
742
+ # options = option / (option ";" options)
743
+ LDIF_ATTRTYPE_OPTIONS = %r{
744
+ #{LDIF_ATTRTYPE_OPTION}
745
+ (?: ; #{LDIF_ATTRTYPE_OPTION} )*
746
+ }x
747
+
748
+ # AttributeType = ldap-oid / (ALPHA *(attr-type-chars))
749
+ LDIF_ATTRIBUTE_TYPE = %r{
750
+ #{NUMERICOID}
751
+ |
752
+ [#{ALPHA}] #{LDIF_ATTR_TYPE_CHARS}*
753
+ }x
754
+
755
+ # AttributeDescription = AttributeType [";" options]
756
+ # ; Definition taken from [4]
757
+ LDIF_ATTRIBUTE_DESCRIPTION = %r{
758
+ #{LDIF_ATTRIBUTE_TYPE}
759
+ (?: ; #{LDIF_ATTRTYPE_OPTIONS} )?
760
+ }x
761
+
762
+ # SPACE = %x20 ; ASCII SP, space
763
+ # FILL = *SPACE
764
+ FILL = '\x20+'
765
+
766
+ # SAFE-CHAR = %x01-09 / %x0B-0C / %x0E-7F
767
+ # ; any value <= 127 decimal except NUL, LF,
768
+ # ; and CR
769
+ LDIF_SAFE_CHAR = %r{[\x01-\x09\x0b-\x0c\x0e-\x7f]}
770
+
771
+ # SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F /
772
+ # %x21-39 / %x3B / %x3D-7F
773
+ # ; any value <= 127 except NUL, LF, CR,
774
+ # ; SPACE, colon (":", ASCII 58 decimal)
775
+ # ; and less-than ("<" , ASCII 60 decimal)
776
+ LDIF_SAFE_INIT_CHAR = %r{[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B\x3D-\x7F]}
777
+
778
+ # SAFE-STRING = [SAFE-INIT-CHAR *SAFE-CHAR]
779
+ LDIF_SAFE_STRING = %r{
780
+ #{LDIF_SAFE_INIT_CHAR}
781
+ #{LDIF_SAFE_CHAR}*
782
+ }x
783
+
784
+
785
+ # BASE64-CHAR = %x2B / %x2F / %x30-39 / %x3D / %x41-5A /
786
+ # %x61-7A
787
+ # ; +, /, 0-9, =, A-Z, and a-z
788
+ # ; as specified in [5]
789
+ BASE64_CHAR = %r{[\x2B\x2F\x30-\x39\x3D\x41-\x5A\x61-\x7A]}
790
+
791
+ # BASE64-STRING = [*(BASE64-CHAR)]
792
+ BASE64_STRING = %r{ #{BASE64_CHAR}* }x
793
+
794
+ # SEP = (CR LF / LF)
795
+ SEP = %r{\r?\n}
796
+
797
+ # Any non-empty line, including comment lines, in an LDIF file
798
+ # MAY be folded by inserting a line separator (SEP) and a SPACE.
799
+ FOLD = %r{ #{SEP} #{SPACE} }x
800
+
801
+ # value-spec = ":" ( FILL 0*1(SAFE-STRING) /
802
+ # ":" FILL (BASE64-STRING) /
803
+ # "<" FILL url)
804
+ LDIF_VALUE_SPEC = %r{
805
+ :
806
+ (
807
+ #{FILL} #{LDIF_SAFE_STRING}+ (?: #{FOLD} #{LDIF_SAFE_CHAR}* )*
808
+ |
809
+ : #{FILL} #{BASE64_STRING} (?: #{FOLD} #{BASE64_STRING} )*
810
+ |
811
+ < #{FILL} #{URI_REF}
812
+ )
813
+ }x
814
+
815
+ # attrval-spec = AttributeDescription value-spec SEP
816
+ LDIF_ATTRVAL_SPEC = %r{
817
+ (#{LDIF_ATTRIBUTE_DESCRIPTION})
818
+ #{LDIF_VALUE_SPEC}
819
+ #{SEP}
820
+ }xm
821
+
822
+
823
+ # Freeze all the pattern constants so they don't get clobbered
824
+ constants.each do |const|
825
+ const_get( const ).freeze
826
+ end
827
+
598
828
  end # module Patterns
599
829
 
600
830
  end # module Treequel::Constants