File: repository.rb

package info (click to toggle)
ruby-logging 2.2.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 660 kB
  • sloc: ruby: 6,139; sh: 11; makefile: 2
file content (216 lines) | stat: -rw-r--r-- 6,756 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216

require 'singleton'

module Logging

  # The Repository is a hash that stores references to all Loggers
  # that have been created. It provides methods to determine parent/child
  # relationships between Loggers and to retrieve Loggers from the hash.
  #
  class Repository
    include Singleton

    PATH_DELIMITER = '::'  # :nodoc:

    # nodoc:
    #
    # This is a singleton class -- use the +instance+ method to obtain the
    # +Repository+ instance.
    #
    def initialize
      @h = {:root => ::Logging::RootLogger.new}

      # configures the internal logger which is disabled by default
      logger = ::Logging::Logger.allocate
      logger._setup(
          to_key(::Logging),
          :parent   => @h[:root],
          :additive => false,
          :level    => ::Logging::LEVELS.length   # turns this logger off
      )
      @h[logger.name] = logger
    end

    # call-seq:
    #    instance[name]
    #
    # Returns the +Logger+ named _name_.
    #
    # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
    # retrieve the logger. When _name_ is a +Class+ the class name will be
    # used to retrieve the logger. When _name_ is an object the name of the
    # object's class will be used to retrieve the logger.
    #
    # Example:
    #
    #   repo = Repository.instance
    #   obj = MyClass.new
    #
    #   log1 = repo[obj]
    #   log2 = repo[MyClass]
    #   log3 = repo['MyClass']
    #
    #   log1.object_id == log2.object_id         # => true
    #   log2.object_id == log3.object_id         # => true
    #
    def []( key ) @h[to_key(key)] end

    # call-seq:
    #    instance[name] = logger
    #
    # Stores the _logger_ under the given _name_.
    #
    # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
    # store the logger. When _name_ is a +Class+ the class name will be
    # used to store the logger. When _name_ is an object the name of the
    # object's class will be used to store the logger.
    #
    def []=( key, val ) @h[to_key(key)] = val end

    # call-seq:
    #    fetch( name )
    #
    # Returns the +Logger+ named _name_. An +KeyError+ will be raised if
    # the logger does not exist.
    #
    # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
    # retrieve the logger. When _name_ is a +Class+ the class name will be
    # used to retrieve the logger. When _name_ is an object the name of the
    # object's class will be used to retrieve the logger.
    #
    def fetch( key ) @h.fetch(to_key(key)) end

    # call-seq:
    #    has_logger?( name )
    #
    # Returns +true+ if the given logger exists in the repository. Returns
    # +false+ if this is not the case.
    #
    # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
    # retrieve the logger. When _name_ is a +Class+ the class name will be
    # used to retrieve the logger. When _name_ is an object the name of the
    # object's class will be used to retrieve the logger.
    #
    def has_logger?( key ) @h.has_key?(to_key(key)) end

    # call-seq:
    #    delete( name )
    #
    # Deletes the named logger from the repository. All direct children of the
    # logger will have their parent reassigned. So the parent of the logger
    # being deleted becomes the new parent of the children.
    #
    # When _name_ is a +String+ or a +Symbol+ it will be used "as is" to
    # remove the logger. When _name_ is a +Class+ the class name will be
    # used to remove the logger. When _name_ is an object the name of the
    # object's class will be used to remove the logger.
    #
    # Raises a RuntimeError if you try to delete the root logger.
    # Raises an KeyError if the named logger is not found.
    def delete( key )
      key = to_key(key)
      raise 'the :root logger cannot be deleted' if :root == key

      parent = @h.fetch(key).parent
      children(key).each {|c| c.__send__(:parent=, parent)}
      @h.delete(key)
    end

    # call-seq:
    #    parent( key )
    #
    # Returns the parent logger for the logger identified by _key_ where
    # _key_ follows the same identification rules described in
    # <tt>Repository#[]</tt>. A parent is returned regardless of the
    # existence of the logger referenced by _key_.
    #
    # A note about parents -
    #
    # If you have a class A::B::C, then the parent of C is B, and the parent
    # of B is A. Parents are determined by namespace.
    #
    def parent( key )
      name = parent_name(to_key(key))
      return if name.nil?
      @h[name]
    end

    # call-seq:
    #    children( key )
    #
    # Returns an array of the children loggers for the logger identified by
    # _key_ where _key_ follows the same identification rules described in
    # +Repository#[]+. Children are returned regardless of the
    # existence of the logger referenced by _key_.
    #
    def children( parent )
      ary = []
      parent = to_key(parent)

      @h.each_pair do |child,logger|
        next if :root == child
        ary << logger if parent == parent_name(child)
      end
      return ary.sort
    end

    # call-seq:
    #    to_key( key )
    #
    # Takes the given _key_ and converts it into a form that can be used to
    # retrieve a logger from the +Repository+ hash.
    #
    # When _key_ is a +String+ or a +Symbol+ it will be returned "as is".
    # When _key_ is a +Class+ the class name will be returned. When _key_ is
    # an object the name of the object's class will be returned.
    #
    def to_key( key )
      case key
      when :root, 'root'; :root
      when String; key
      when Symbol; key.to_s
      when Module; key.logger_name
      when Object; key.class.logger_name
      end
    end

    # Returns the name of the parent for the logger identified by the given
    # _key_. If the _key_ is for the root logger, then +nil+ is returned.
    #
    def parent_name( key )
      return if :root == key

      a = key.split PATH_DELIMITER
      p = :root
      while a.slice!(-1) and !a.empty?
        k = a.join PATH_DELIMITER
        if @h.has_key? k then p = k; break end
      end
      p
    end

    # :stopdoc:
    def self.reset
      if defined?(@singleton__instance__)
        @singleton__mutex__.synchronize {
          @singleton__instance__ = nil
        }
      else
        @__instance__ = nil
        class << self
          nonce = class << Singleton; self; end
          if defined?(nonce::FirstInstanceCall)
            define_method(:instance, nonce::FirstInstanceCall)
          else
            remove_method(:instance)
            Singleton.__init__(::Logging::Repository)
          end
        end
      end
      return nil
    end
    # :startdoc:

  end  # class Repository
end  # module Logging