PageRenderTime 104ms CodeModel.GetById 54ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/Ruby/lib/ruby/gems/1.8/gems/configatron-2.8.2/lib/configatron/store.rb

http://github.com/agross/netopenspace
Ruby | 332 lines | 235 code | 31 blank | 66 comment | 29 complexity | c419ae9908884c0fee1b632c0d707eab MD5 | raw file
  1class Configatron
  2  class Store
  3    if RUBY_VERSION.match(/^1\.9\.2/)
  4      require 'syck'
  5      ::YAML::ENGINE.yamler = 'syck'
  6    end
  7
  8    alias_method :send!, :send
  9
 10    # Takes an optional Hash of parameters
 11    def initialize(options = {}, name = nil, parent = nil)
 12      @_name = name
 13      @_parent = parent
 14      @_store = {}
 15      configure_from_hash(options)
 16      @_protected = []
 17      @_locked = false
 18    end
 19
 20    # Returns a Hash representing the configurations
 21    def to_hash
 22      h = Hash.new
 23      @_store.each { |k,v|
 24        # Descend the tree and hashify each node
 25        h[k] = v.is_a?(Store) ? v.to_hash : v
 26      }
 27      h
 28    end
 29
 30    def heirarchy
 31      path = [@_name]
 32      parent = @_parent
 33      until parent.nil?
 34        path << parent.instance_variable_get('@_name')
 35        parent = parent.instance_variable_get('@_parent')
 36      end
 37      path.compact!
 38      path.reverse!
 39      path.join('.')
 40    end
 41
 42    def configatron_keys
 43      return @_store.keys.collect{|k| k.to_s}.sort
 44    end
 45
 46    # Checks whether or not a parameter exists
 47    #
 48    # Examples:
 49    #   configatron.i.am.alive = 'alive!'
 50    #   configatron.i.am.exists?(:alive) # => true
 51    #   configatron.i.am.exists?(:dead) # => false
 52    def exists?(name)
 53      @_store.has_key?(name.to_sym) || @_store.has_key?(name.to_s)
 54    end
 55
 56    # respond_to to respond_to
 57    def respond_to?(name)
 58      exists?(name) || super
 59    end
 60
 61    def inspect
 62      path = [@_name]
 63      parent = @_parent
 64      until parent.nil?
 65        path << parent.instance_variable_get('@_name')
 66        parent = parent.instance_variable_get('@_parent')
 67      end
 68      path << 'configatron'
 69      path.compact!
 70      path.reverse!
 71      f_out = []
 72      @_store.each do |k, v|
 73        if v.is_a?(Configatron::Store)
 74          v.inspect.each_line do |line|
 75            if line.match(/\n/)
 76              line.each_line do |l|
 77                l.strip!
 78                f_out << l
 79              end
 80            else
 81              line.strip!
 82              f_out << line
 83            end
 84          end
 85        else
 86          f_out << "#{path.join('.')}.#{k} = #{v.inspect}"
 87        end
 88      end
 89      f_out.compact.sort.join("\n")
 90    end
 91
 92    # Allows for the configuration of the system via a Hash
 93    def configure_from_hash(options)
 94      parse_options(options)
 95    end
 96
 97    # Allows for the configuration of the system from a YAML file.
 98    # Takes the path to the YAML file.  Also takes an optional parameter,
 99    # <tt>:hash</tt>, that indicates a specific hash that should be
100    # loaded from the file.
101    def configure_from_yaml(path, opts = {})
102      Configatron.log.warn "DEPRECATED! (configure_from_yaml) Please stop using YAML and use Ruby instead. This method will be removed in 2.9."
103      begin
104        yml = ::Yamler.load(path)
105        yml = yml[opts[:hash]] unless opts[:hash].nil?
106        configure_from_hash(yml)
107      rescue Errno::ENOENT => e
108        puts e.message
109      end
110    end
111
112    # Returns true if there are no configuration parameters
113    def nil?
114      return @_store.empty?
115    end
116
117    def blank?
118      value = retrieve(@_name)
119      value.respond_to?(:empty?) ? value.empty? : !value
120    end
121
122    # Retrieves a certain parameter and if that parameter
123    # doesn't exist it will return the default_value specified.
124    def retrieve(name, default_value = nil)
125      val = method_missing(name.to_sym)
126      return val.is_a?(Configatron::Store) ? default_value : val
127    end
128
129    # Removes a parameter. In the case of a nested parameter
130    # it will remove all below it.
131    def remove(name)
132      @_store.delete(name.to_sym)
133    end
134
135    # Sets a 'default' value. If there is already a value specified
136    # it won't set the value.
137    def set_default(name, default_value)
138      unless @_store[name.to_sym]
139        # @_store[name.to_sym] = parse_options(default_value)
140        self.send("#{name}=", default_value)
141      end
142    end
143
144    def method_missing(sym, *args) # :nodoc:
145      if sym.to_s.match(/(.+)=$/)
146        name = sym.to_s.gsub("=", '').to_sym
147        raise Configatron::ProtectedParameter.new(name) if @_protected.include?(name) || methods_include?(name)
148        raise Configatron::LockedNamespace.new(@_name) if @_locked && !@_store.has_key?(name)
149        @_store[name] = parse_options(*args)
150      elsif sym.to_s.match(/(.+)\?/)
151        return !@_store[$1.to_sym].blank?
152      elsif block_given?
153        yield self.send(sym)
154      elsif @_store.has_key?(sym)
155        val = @_store[sym]
156        if val.is_a?(Configatron::Proc)
157          res = val.execute
158          if val.finalize?
159            @_store[sym] = res
160          end
161          return res
162        end
163        return val
164      else
165        store = Configatron::Store.new({}, sym, self)
166        @_store[sym] = store
167        return store
168      end
169    end
170
171    def ==(other) # :nodoc:
172      self.to_hash == other
173    end
174
175    # Prevents a parameter from being reassigned. If called on a 'namespace' then
176    # all parameters below it will be protected as well.
177    def protect(name)
178      @_protected << name.to_sym
179    end
180
181    # Prevents all parameters from being reassigned.
182    def protect_all!
183      @_protected.clear
184      @_store.keys.each do |k|
185        val = self.send(k)
186        val.protect_all! if val.class == Configatron::Store
187        @_protected << k
188      end
189    end
190
191    # Removes the protection of a parameter.
192    def unprotect(name)
193      @_protected.reject! { |e| e == name.to_sym }
194    end
195
196    def unprotect_all!
197      @_protected.clear
198      @_store.keys.each do |k|
199        val = self.send(k)
200        val.unprotect_all! if val.class == Configatron::Store
201      end
202    end
203
204    # Prevents a namespace from having new parameters set. The lock is applied
205    # recursively to any namespaces below it.
206    def lock(name)
207      namespace = @_store[name.to_sym]
208      raise ArgumentError, "Namespace #{name.inspect} does not exist" if namespace.nil?
209      namespace.lock!
210    end
211
212    def unlock(name)
213      namespace = @_store[name.to_sym]
214      raise ArgumentError, "Namespace #{name.inspect} does not exist" if namespace.nil?
215      namespace.unlock!
216    end
217
218    # = DeepClone
219    #
220    # == Version
221    #  1.2006.05.23 (change of the first number means Big Change)
222    #
223    # == Description
224    #  Adds deep_clone method to an object which produces deep copy of it. It means
225    #  if you clone a Hash, every nested items and their nested items will be cloned.
226    #  Moreover deep_clone checks if the object is already cloned to prevent endless recursion.
227    #
228    # == Usage
229    #
230    #  (see examples directory under the ruby gems root directory)
231    #
232    #   require 'rubygems'
233    #   require 'deep_clone'
234    #
235    #   include DeepClone
236    #
237    #   obj = []
238    #   a = [ true, false, obj ]
239    #   b = a.deep_clone
240    #   obj.push( 'foo' )
241    #   p obj   # >> [ 'foo' ]
242    #   p b[2]  # >> []
243    #
244    # == Source
245    # http://simplypowerful.1984.cz/goodlibs/1.2006.05.23
246    #
247    # == Author
248    #  jan molic (/mig/at_sign/1984/dot/cz/)
249    #
250    # == Licence
251    #  You can redistribute it and/or modify it under the same terms of Ruby's license;
252    #  either the dual license version in 2003, or any later version.
253    #
254    def deep_clone( obj=self, cloned={} )
255      if cloned.has_key?( obj.object_id )
256        return cloned[obj.object_id]
257      else
258        begin
259          cl = obj.clone
260        rescue Exception
261          # unclonnable (TrueClass, Fixnum, ...)
262          cloned[obj.object_id] = obj
263          return obj
264        else
265          cloned[obj.object_id] = cl
266          cloned[cl.object_id] = cl
267          if cl.is_a?( Hash )
268            cl.clone.each { |k,v|
269              cl[k] = deep_clone( v, cloned )
270            }
271          elsif cl.is_a?( Array )
272            cl.collect! { |v|
273              deep_clone( v, cloned )
274            }
275          end
276          cl.instance_variables.each do |var|
277            v = cl.instance_eval( var.to_s )
278            v_cl = deep_clone( v, cloned )
279            cl.instance_eval( "#{var} = v_cl" )
280          end
281          return cl
282        end
283      end
284    end
285
286    protected
287    def lock!
288      @_locked = true
289      @_store.values.each { |store| store.lock! if store.is_a?(Configatron::Store) }
290    end
291
292    def unlock!
293      @_locked = false
294      @_store.values.each { |store| store.unlock! if store.is_a?(Configatron::Store) }
295    end
296
297    private
298    def methods_include?(name)
299      self.methods.include?(RUBY_VERSION > '1.9.0' ? name.to_sym : name.to_s)
300    end
301
302    def parse_options(options)
303      if options.is_a?(Hash)
304        options.each do |k,v|
305          if v.is_a?(Hash)
306            if v.keys.length == 1 && v.keys.first.is_a?(SYCK_CONSTANT)
307              self.method_missing("#{k}=", v.values.first.flatten)
308            else
309              self.method_missing(k.to_sym).configure_from_hash(v)
310            end
311          else
312            self.method_missing("#{k}=", v)
313          end
314        end
315      else
316        return options
317      end
318    end
319
320    begin
321      undef :test # :nodoc:
322    rescue Exception => e
323    end
324   
325    if RUBY_PLATFORM == 'java'
326      SYCK_CONSTANT = YAML::Yecht::MergeKey
327    else
328      SYCK_CONSTANT = (RUBY_VERSION.match(/^1\.9/) ? Syck::MergeKey : YAML::Syck::MergeKey) 
329    end
330
331  end # Store
332end # Configatron