/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

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