treequel 1.0.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 (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
+