treequel 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/ChangeLog +354 -0
  2. data/LICENSE +27 -0
  3. data/README +66 -0
  4. data/Rakefile +345 -0
  5. data/Rakefile.local +43 -0
  6. data/bin/treeirb +14 -0
  7. data/bin/treequel +229 -0
  8. data/examples/company-directory.rb +112 -0
  9. data/examples/ldap-monitor.rb +143 -0
  10. data/examples/ldap-monitor/public/css/master.css +328 -0
  11. data/examples/ldap-monitor/public/images/card_small.png +0 -0
  12. data/examples/ldap-monitor/public/images/chain_small.png +0 -0
  13. data/examples/ldap-monitor/public/images/globe_small.png +0 -0
  14. data/examples/ldap-monitor/public/images/globe_small_green.png +0 -0
  15. data/examples/ldap-monitor/public/images/plug.png +0 -0
  16. data/examples/ldap-monitor/public/images/shadows/large-30-down.png +0 -0
  17. data/examples/ldap-monitor/public/images/tick.png +0 -0
  18. data/examples/ldap-monitor/public/images/tick_circle.png +0 -0
  19. data/examples/ldap-monitor/public/images/treequel-favicon.png +0 -0
  20. data/examples/ldap-monitor/views/backends.erb +41 -0
  21. data/examples/ldap-monitor/views/connections.erb +74 -0
  22. data/examples/ldap-monitor/views/databases.erb +39 -0
  23. data/examples/ldap-monitor/views/dump_subsystem.erb +14 -0
  24. data/examples/ldap-monitor/views/index.erb +14 -0
  25. data/examples/ldap-monitor/views/layout.erb +35 -0
  26. data/examples/ldap-monitor/views/listeners.erb +30 -0
  27. data/examples/ldap_state.rb +62 -0
  28. data/lib/treequel.rb +145 -0
  29. data/lib/treequel/branch.rb +589 -0
  30. data/lib/treequel/branchcollection.rb +204 -0
  31. data/lib/treequel/branchset.rb +360 -0
  32. data/lib/treequel/constants.rb +604 -0
  33. data/lib/treequel/directory.rb +541 -0
  34. data/lib/treequel/exceptions.rb +32 -0
  35. data/lib/treequel/filter.rb +704 -0
  36. data/lib/treequel/mixins.rb +325 -0
  37. data/lib/treequel/schema.rb +245 -0
  38. data/lib/treequel/schema/attributetype.rb +252 -0
  39. data/lib/treequel/schema/ldapsyntax.rb +96 -0
  40. data/lib/treequel/schema/matchingrule.rb +124 -0
  41. data/lib/treequel/schema/matchingruleuse.rb +124 -0
  42. data/lib/treequel/schema/objectclass.rb +289 -0
  43. data/lib/treequel/sequel_integration.rb +26 -0
  44. data/lib/treequel/utils.rb +169 -0
  45. data/rake/191_compat.rb +26 -0
  46. data/rake/dependencies.rb +76 -0
  47. data/rake/helpers.rb +434 -0
  48. data/rake/hg.rb +261 -0
  49. data/rake/manual.rb +782 -0
  50. data/rake/packaging.rb +135 -0
  51. data/rake/publishing.rb +318 -0
  52. data/rake/rdoc.rb +30 -0
  53. data/rake/style.rb +62 -0
  54. data/rake/svn.rb +668 -0
  55. data/rake/testing.rb +187 -0
  56. data/rake/verifytask.rb +64 -0
  57. data/rake/win32.rb +190 -0
  58. data/spec/lib/constants.rb +93 -0
  59. data/spec/lib/helpers.rb +100 -0
  60. data/spec/treequel/branch_spec.rb +569 -0
  61. data/spec/treequel/branchcollection_spec.rb +213 -0
  62. data/spec/treequel/branchset_spec.rb +376 -0
  63. data/spec/treequel/directory_spec.rb +487 -0
  64. data/spec/treequel/filter_spec.rb +482 -0
  65. data/spec/treequel/mixins_spec.rb +330 -0
  66. data/spec/treequel/schema/attributetype_spec.rb +237 -0
  67. data/spec/treequel/schema/ldapsyntax_spec.rb +83 -0
  68. data/spec/treequel/schema/matchingrule_spec.rb +158 -0
  69. data/spec/treequel/schema/matchingruleuse_spec.rb +137 -0
  70. data/spec/treequel/schema/objectclass_spec.rb +262 -0
  71. data/spec/treequel/schema_spec.rb +118 -0
  72. data/spec/treequel/utils_spec.rb +49 -0
  73. data/spec/treequel_spec.rb +179 -0
  74. metadata +169 -0
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'English'
4
+
5
+ require 'treequel'
6
+ require 'treequel/mixins'
7
+ require 'treequel/schema'
8
+ require 'treequel/exceptions'
9
+
10
+
11
+ # This is a class for representing matchingRuleUse declarations in a Treequel::Schema.
12
+ #
13
+ # == Authors
14
+ #
15
+ # * Michael Granger <ged@FaerieMUD.org>
16
+ #
17
+ # :include: LICENSE
18
+ #
19
+ #--
20
+ #
21
+ # Please see the file LICENSE in the base directory for licensing details.
22
+ #
23
+ class Treequel::Schema::MatchingRuleUse
24
+ include Treequel::Loggable,
25
+ Treequel::Constants::Patterns
26
+
27
+ extend Treequel::AttributeDeclarations
28
+
29
+
30
+ #############################################################
31
+ ### C L A S S M E T H O D S
32
+ #############################################################
33
+
34
+ ### Parse an MatchingRuleUse entry from a matchingRuleUse description from a schema.
35
+ def self::parse( schema, description )
36
+ unless match = ( LDAP_MATCHING_RULE_USE_DESCRIPTION.match(description) )
37
+ raise Treequel::ParseError, "failed to parse matchingRuleUse from %p" % [ description ]
38
+ end
39
+
40
+ oid, names, desc, obsolete, attr_oids, extensions = match.captures
41
+ # Treequel.logger.debug " parsed matchingRuleUse: %p" % [ match.captures ]
42
+
43
+ # Normalize the attributes
44
+ names = Treequel::Schema.parse_names( names )
45
+ desc = Treequel::Schema.unquote_desc( desc )
46
+ attr_oids = Treequel::Schema.parse_oids( attr_oids )
47
+
48
+ return self.new( schema, oid, attr_oids, names, desc, obsolete, extensions )
49
+ end
50
+
51
+
52
+ #############################################################
53
+ ### I N S T A N C E M E T H O D S
54
+ #############################################################
55
+
56
+ ### Create a new MatchingRuleUse
57
+ def initialize( schema, oid, attr_oids, names=nil, desc=nil, obsolete=false, extensions=nil )
58
+ @schema = schema
59
+
60
+ @oid = oid
61
+ @names = names
62
+ @desc = desc
63
+ @obsolete = obsolete ? true : false
64
+ @attr_oids = attr_oids
65
+
66
+ @extensions = extensions
67
+
68
+ super()
69
+ end
70
+
71
+
72
+ ######
73
+ public
74
+ ######
75
+
76
+ # The schema the matchingRuleUse belongs to
77
+ attr_reader :schema
78
+
79
+ # The matchingRuleUse's oid
80
+ attr_reader :oid
81
+
82
+ # The Array of the matchingRuleUse's names
83
+ attr_reader :names
84
+
85
+ # The matchingRuleUse's description
86
+ attr_accessor :desc
87
+
88
+ # Is the matchingRuleUse obsolete?
89
+ predicate_attr :obsolete
90
+
91
+ # The OIDs of the attributes the matchingRuleUse applies to
92
+ attr_reader :attr_oids
93
+
94
+ # The matchingRuleUse's extensions (as a String)
95
+ attr_accessor :extensions
96
+
97
+
98
+ ### Return the first of the matchingRuleUse's names, if it has any, or +nil+.
99
+ def name
100
+ return self.names.first
101
+ end
102
+
103
+
104
+ ### Return a human-readable representation of the object suitable for debugging
105
+ def inspect
106
+ return "#<%s:0x%0x %s(%s) %p -> %p >" % [
107
+ self.class.name,
108
+ self.object_id / 2,
109
+ self.name,
110
+ self.oid,
111
+ self.desc,
112
+ self.attr_oids,
113
+ ]
114
+ end
115
+
116
+
117
+ ### Return Treequel::Schema::AttributeType objects for each of the types this MatchingRuleUse
118
+ ### applies to.
119
+ def attribute_types
120
+ return self.attr_oids.collect {|oid| self.schema.attribute_types[oid] }
121
+ end
122
+
123
+ end # class Treequel::Schema::MatchingRuleUse
124
+
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'English'
4
+
5
+ require 'treequel'
6
+ require 'treequel/schema'
7
+ require 'treequel/exceptions'
8
+
9
+
10
+ # This is a collection of classes for representing objectClasses in a Treequel::Schema.
11
+ #
12
+ # == Authors
13
+ #
14
+ # * Michael Granger <ged@FaerieMUD.org>
15
+ # * Mahlon E. Smith <mahlon@martini.nu>
16
+ #
17
+ # :include: LICENSE
18
+ #
19
+ #--
20
+ #
21
+ # Please see the file LICENSE in the base directory for licensing details.
22
+ #
23
+ class Treequel::Schema
24
+
25
+ # The types of objectClass as specified in the schema, along with which Ruby class
26
+ # corresponds to it. Each class registers itself as it's defined.
27
+ OBJECTCLASS_TYPES = {}
28
+
29
+
30
+ ### objectClass entries in a Treequel::Schema.
31
+ class ObjectClass
32
+ include Treequel::Loggable,
33
+ Treequel::Constants::Patterns
34
+
35
+ extend Treequel::AttributeDeclarations
36
+
37
+
38
+ private_class_method :new
39
+
40
+ # The 'kind' of objectClasses which don't specify a 'kind' explicitly
41
+ DEFAULT_OBJECTCLASS_KIND = 'STRUCTURAL'
42
+
43
+
44
+ #############################################################
45
+ ### C L A S S M E T H O D S
46
+ #############################################################
47
+
48
+ ### Inheritance callback: Make the constructor method of all inheriting classes
49
+ ### public.
50
+ def self::inherited( subclass )
51
+ subclass.instance_eval { public_class_method :new }
52
+ end
53
+
54
+
55
+ ### Parse an ObjectClass entry from a objectClass description from a schema.
56
+ def self::parse( schema, description )
57
+ unless match = ( LDAP_OBJECTCLASS_DESCRIPTION.match(description) )
58
+ raise Treequel::ParseError, "failed to parse objectClass from %p" % [ description ]
59
+ end
60
+
61
+ oid, names, desc, obsolete, sup, kind, must, may, extensions = match.captures
62
+
63
+ # Normalize the attributes
64
+ must_oids = Treequel::Schema.parse_oids( must )
65
+ may_oids = Treequel::Schema.parse_oids( may )
66
+ names = Treequel::Schema.parse_names( names )
67
+ desc = Treequel::Schema.unquote_desc( desc )
68
+
69
+ # Default the 'kind' attribute
70
+ kind ||= DEFAULT_OBJECTCLASS_KIND
71
+
72
+ # Find the appropriate concrete class to instantiate
73
+ concrete_class = Treequel::Schema::OBJECTCLASS_TYPES[ kind ] or
74
+ raise Treequel::Error, "no such objectClass type %p: expected one of: %p" %
75
+ [ kind, Treequel::Schema::OBJECTCLASS_TYPES.keys ]
76
+
77
+ return concrete_class.new( schema, oid, names, desc, obsolete, sup,
78
+ must_oids, may_oids, extensions )
79
+ end
80
+
81
+
82
+ #############################################################
83
+ ### I N S T A N C E M E T H O D S
84
+ #############################################################
85
+
86
+ ### Create a new ObjectClass
87
+ def initialize( schema, oid, names=nil, desc=nil, obsolete=false, sup=nil, must_oids=[],
88
+ may_oids=[], extensions=nil )
89
+ @schema = schema
90
+
91
+ @oid = oid
92
+ @names = names
93
+ @desc = desc
94
+ @obsolete = obsolete ? true : false
95
+ @sup_name = sup
96
+ @must_oids = must_oids
97
+ @may_oids = may_oids
98
+ @extensions = extensions
99
+
100
+ super()
101
+ end
102
+
103
+
104
+ ######
105
+ public
106
+ ######
107
+
108
+ # The schema the objectClass belongs to
109
+ attr_reader :schema
110
+
111
+ # The objectClass's oid
112
+ attr_reader :oid
113
+
114
+ # The Array of the objectClass's names
115
+ attr_reader :names
116
+
117
+ # The objectClass's description
118
+ attr_accessor :desc
119
+
120
+ # Is the objectClass obsolete?
121
+ predicate_attr :obsolete
122
+
123
+ # The name of the objectClass's superior class (if specified)
124
+ attr_accessor :sup_name
125
+
126
+ # The Array of the objectClass's MUST OIDs
127
+ attr_reader :must_oids
128
+
129
+ # The Array of the objectClass's MAY OIDs
130
+ attr_reader :may_oids
131
+
132
+ # The objectClass's extensions (as a String)
133
+ attr_accessor :extensions
134
+
135
+
136
+ ### Return the first of the objectClass's names, if it has any, or +nil+.
137
+ def name
138
+ return self.names.first
139
+ end
140
+
141
+
142
+ ### Return Treequel::Schema::AttributeType objects for each of the objectClass's
143
+ ### MUST attributes.
144
+ def must
145
+ self.must_oids.collect do |oid|
146
+ self.log.warn "No attribute type for OID %p (case bug?)" % [ oid ] unless
147
+ self.schema.attribute_types.key?( oid )
148
+ self.schema.attribute_types[oid]
149
+ end.compact
150
+ end
151
+
152
+
153
+ ### Return Treequel::Schema::AttributeType objects for each of the objectClass's
154
+ ### MAY attributes.
155
+ def may
156
+ self.may_oids.collect do |oid|
157
+ self.log.warn "No attribute type for OID %p (case bug?)" % [ oid ] unless
158
+ self.schema.attribute_types.key?( oid )
159
+ self.schema.attribute_types[oid]
160
+ end.compact
161
+ end
162
+
163
+
164
+ ### Returns +true+ if this objectClass is STRUCTURAL. Defaults to +false+ and then
165
+ ### overridden in StructuralObjectClass.
166
+ def structural?
167
+ return false
168
+ end
169
+
170
+
171
+ ### Return a human-readable representation of the object suitable for debugging
172
+ def inspect
173
+ return %{#<%s:0x%0x %s(%s) < %s "%s" MUST: %p, MAY: %p>} % [
174
+ self.class.name,
175
+ self.object_id / 2,
176
+ self.name,
177
+ self.oid,
178
+ self.sup_name,
179
+ self.desc,
180
+ self.must_oids,
181
+ self.may_oids,
182
+ ]
183
+ end
184
+
185
+
186
+ ### Return the ObjectClass for the receiver's SUP. If this is called on
187
+ ### 'top', returns nil.
188
+ def sup
189
+ unless name = self.sup_name
190
+ return nil if self.oid == Treequel::Constants::OIDS::TOP_OBJECTCLASS
191
+ return self.schema.object_classes[ :top ]
192
+ end
193
+ return self.schema.object_classes[ name.to_sym ]
194
+ end
195
+
196
+ end # class ObjectClass
197
+
198
+
199
+ ### An LDAP objectClass of type 'ABSTRACT'. From RFC 4512:
200
+ ###
201
+ ### An abstract object class, as the name implies, provides a base of
202
+ ### characteristics from which other object classes can be defined to
203
+ ### inherit from. An entry cannot belong to an abstract object class
204
+ ### unless it belongs to a structural or auxiliary class that inherits
205
+ ### from that abstract class.
206
+ ###
207
+ ### Abstract object classes cannot derive from structural or auxiliary
208
+ ### object classes.
209
+ ###
210
+ ### All structural object classes derive (directly or indirectly) from
211
+ ### the 'top' abstract object class. Auxiliary object classes do not
212
+ ### necessarily derive from 'top'.
213
+ ###
214
+ class AbstractObjectClass < Treequel::Schema::ObjectClass
215
+ Treequel::Schema::OBJECTCLASS_TYPES[ 'ABSTRACT' ] = self
216
+ end # class AbstractObjectClass
217
+
218
+
219
+ ### An LDAP objectClass of type 'AUXILIARY'. From FC4512:
220
+ ###
221
+ ### Auxiliary object classes are used to augment the characteristics of
222
+ ### entries. They are commonly used to augment the sets of attributes
223
+ ### required and allowed to be present in an entry. They can be used to
224
+ ### describe entries or classes of entries.
225
+ ###
226
+ ### Auxiliary object classes cannot subclass structural object classes.
227
+ ###
228
+ ### An entry can belong to any subset of the set of auxiliary object
229
+ ### classes allowed by the DIT content rule associated with the
230
+ ### structural object class of the entry. If no DIT content rule is
231
+ ### associated with the structural object class of the entry, the entry
232
+ ### cannot belong to any auxiliary object class.
233
+ ###
234
+ ### The set of auxiliary object classes that an entry belongs to can
235
+ ### change over time.
236
+ class AuxiliaryObjectClass < Treequel::Schema::ObjectClass
237
+ Treequel::Schema::OBJECTCLASS_TYPES[ 'AUXILIARY' ] = self
238
+ end # class AuxiliaryObjectClass
239
+
240
+
241
+ ### An LDAP objectClass of type 'STRUCTURAL'. From RFC4512:
242
+ ###
243
+ ### An object class defined for use in the structural specification of
244
+ ### the DIT is termed a structural object class. Structural object
245
+ ### classes are used in the definition of the structure of the names
246
+ ### of the objects for compliant entries.
247
+ ###
248
+ ### An object or alias entry is characterized by precisely one
249
+ ### structural object class superclass chain which has a single
250
+ ### structural object class as the most subordinate object class.
251
+ ### This structural object class is referred to as the structural
252
+ ### object class of the entry.
253
+ ###
254
+ ### Structural object classes are related to associated entries:
255
+ ###
256
+ ### - an entry conforming to a structural object class shall
257
+ ### represent the real-world object constrained by the object
258
+ ### class;
259
+ ###
260
+ ### - DIT structure rules only refer to structural object classes;
261
+ ### the structural object class of an entry is used to specify the
262
+ ### position of the entry in the DIT;
263
+ ###
264
+ ### - the structural object class of an entry is used, along with an
265
+ ### associated DIT content rule, to control the content of an
266
+ ### entry.
267
+ ###
268
+ ### The structural object class of an entry shall not be changed.
269
+ ###
270
+ ### Each structural object class is a (direct or indirect) subclass of
271
+ ### the 'top' abstract object class.
272
+ ###
273
+ ### Structural object classes cannot subclass auxiliary object classes.
274
+ ###
275
+ ### Each entry is said to belong to its structural object class as well
276
+ ### as all classes in its structural object class's superclass chain.
277
+ ###
278
+ class StructuralObjectClass < Treequel::Schema::ObjectClass
279
+ Treequel::Schema::OBJECTCLASS_TYPES[ 'STRUCTURAL' ] = self
280
+
281
+ ### Returns +true+, indicating that instances of this class are STRUCTURAL.
282
+ def structural?
283
+ return true
284
+ end
285
+
286
+ end # class StructuralObjectClass
287
+
288
+ end # class Treequel::Schema
289
+
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'treequel'
4
+ require 'treequel/filter'
5
+
6
+ begin
7
+ require 'sequel'
8
+ rescue LoadError => err
9
+ Treequel.logger.info "Sequel library didn't load: %s: %s" % [ err.class.name, err.message ]
10
+ Treequel.logger.debug " " + err.backtrace.join( "\n " )
11
+ end
12
+
13
+
14
+ # Provide a dummy Sequel::SQL::Expression class for when the Sequel library
15
+ # isn't installed.
16
+ unless defined?( Sequel ) &&
17
+ Sequel.const_defined?( :SQL ) &&
18
+ Sequel::SQL.const_defined?( :Expression )
19
+
20
+ module Sequel # :nodoc: all
21
+ module SQL
22
+ class Expression; end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'logger'
4
+ require 'erb'
5
+ require 'bigdecimal'
6
+ require 'date'
7
+
8
+ require 'treequel'
9
+ # require 'treequel/constants'
10
+
11
+
12
+ module Treequel # :nodoc:
13
+
14
+ #
15
+ # A alternate formatter for Logger instances.
16
+ #
17
+ # == Usage
18
+ #
19
+ # require 'treequel/utils'
20
+ # Treequel.logger.formatter = Treequel::LogFormatter.new( Treequel.logger )
21
+ #
22
+ # == Version
23
+ #
24
+ # $Id$
25
+ #
26
+ # == Authors
27
+ #
28
+ # * Michael Granger <ged@FaerieMUD.org>
29
+ #
30
+ # :include: LICENSE
31
+ #
32
+ #--
33
+ #
34
+ # Please see the file LICENSE in the 'docs' directory for licensing details.
35
+ #
36
+ class LogFormatter < Logger::Formatter
37
+
38
+ # The format to output unless debugging is turned on
39
+ DEFAULT_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s -- %7$s\n"
40
+
41
+ # The format to output if debugging is turned on
42
+ DEFAULT_DEBUG_FORMAT = "[%1$s.%2$06d %3$d/%4$s] %5$5s {%6$s} -- %7$s\n"
43
+
44
+
45
+ ### Initialize the formatter with a reference to the logger so it can check for log level.
46
+ def initialize( logger, format=DEFAULT_FORMAT, debug=DEFAULT_DEBUG_FORMAT ) # :notnew:
47
+ @logger = logger
48
+ @format = format
49
+ @debug_format = debug
50
+
51
+ super()
52
+ end
53
+
54
+ ######
55
+ public
56
+ ######
57
+
58
+ # The Logger object associated with the formatter
59
+ attr_accessor :logger
60
+
61
+ # The logging format string
62
+ attr_accessor :format
63
+
64
+ # The logging format string that's used when outputting in debug mode
65
+ attr_accessor :debug_format
66
+
67
+
68
+ ### Log using either the DEBUG_FORMAT if the associated logger is at ::DEBUG level or
69
+ ### using FORMAT if it's anything less verbose.
70
+ def call( severity, time, progname, msg )
71
+ args = [
72
+ time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
73
+ time.usec, # %2$d
74
+ Process.pid, # %3$d
75
+ Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
76
+ severity, # %5$s
77
+ progname, # %6$s
78
+ msg # %7$s
79
+ ]
80
+
81
+ if @logger.level == Logger::DEBUG
82
+ return self.debug_format % args
83
+ else
84
+ return self.format % args
85
+ end
86
+ end
87
+ end # class LogFormatter
88
+
89
+
90
+ #
91
+ # An alternate formatter for Logger instances that outputs +div+ HTML
92
+ # fragments.
93
+ #
94
+ # == Usage
95
+ #
96
+ # require 'treequel/utils'
97
+ # Treequel.logger.formatter = Treequel::HtmlLogFormatter.new( Treequel.logger )
98
+ #
99
+ # == Version
100
+ #
101
+ # $Id$
102
+ #
103
+ # == Authors
104
+ #
105
+ # * Michael Granger <ged@FaerieMUD.org>
106
+ #
107
+ # :include: LICENSE
108
+ #
109
+ #--
110
+ #
111
+ # Please see the file LICENSE in the 'docs' directory for licensing details.
112
+ #
113
+ class HtmlLogFormatter < Logger::Formatter
114
+ include ERB::Util # for html_escape()
115
+
116
+ # The default HTML fragment that'll be used as the template for each log message.
117
+ HTML_LOG_FORMAT = %q{
118
+ <div class="log-message %5$s">
119
+ <span class="log-time">%1$s.%2$06d</span>
120
+ [
121
+ <span class="log-pid">%3$d</span>
122
+ /
123
+ <span class="log-tid">%4$s</span>
124
+ ]
125
+ <span class="log-level">%5$s</span>
126
+ :
127
+ <span class="log-name">%6$s</span>
128
+ <span class="log-message-text">%7$s</span>
129
+ </div>
130
+ }
131
+
132
+ ### Override the logging formats with ones that generate HTML fragments
133
+ def initialize( logger, format=HTML_LOG_FORMAT ) # :notnew:
134
+ @logger = logger
135
+ @format = format
136
+ super()
137
+ end
138
+
139
+
140
+ ######
141
+ public
142
+ ######
143
+
144
+ # The HTML fragment that will be used as a format() string for the log
145
+ attr_accessor :format
146
+
147
+
148
+ ### Return a log message composed out of the arguments formatted using the
149
+ ### formatter's format string
150
+ def call( severity, time, progname, msg )
151
+ args = [
152
+ time.strftime( '%Y-%m-%d %H:%M:%S' ), # %1$s
153
+ time.usec, # %2$d
154
+ Process.pid, # %3$d
155
+ Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
156
+ severity.downcase, # %5$s
157
+ progname, # %6$s
158
+ html_escape( msg ).gsub(/\n/, '<br />') # %7$s
159
+ ]
160
+
161
+ return self.format % args
162
+ end
163
+
164
+ end # class HtmlLogFormatter
165
+
166
+ end # module Treequel
167
+
168
+ # vim: set nosta noet ts=4 sw=4:
169
+