treequel 1.0.1 → 1.0.4

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