PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_Main/External.LCA_RESTRICTED/Languages/Ruby/redist-libs/ruby/1.9.1/singleton.rb

#
Ruby | 313 lines | 187 code | 46 blank | 80 comment | 7 complexity | b9e3aa2b64235f69f12ddc63575a756d MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. # The Singleton module implements the Singleton pattern.
  2. #
  3. # Usage:
  4. # class Klass
  5. # include Singleton
  6. # # ...
  7. # end
  8. #
  9. # * this ensures that only one instance of Klass lets call it
  10. # ``the instance'' can be created.
  11. #
  12. # a,b = Klass.instance, Klass.instance
  13. # a == b # => true
  14. # Klass.new # NoMethodError - new is private ...
  15. #
  16. # * ``The instance'' is created at instantiation time, in other
  17. # words the first call of Klass.instance(), thus
  18. #
  19. # class OtherKlass
  20. # include Singleton
  21. # # ...
  22. # end
  23. # ObjectSpace.each_object(OtherKlass){} # => 0.
  24. #
  25. # * This behavior is preserved under inheritance and cloning.
  26. #
  27. #
  28. #
  29. # This is achieved by marking
  30. # * Klass.new and Klass.allocate - as private
  31. #
  32. # Providing (or modifying) the class methods
  33. # * Klass.inherited(sub_klass) and Klass.clone() -
  34. # to ensure that the Singleton pattern is properly
  35. # inherited and cloned.
  36. #
  37. # * Klass.instance() - returning ``the instance''. After a
  38. # successful self modifying (normally the first) call the
  39. # method body is a simple:
  40. #
  41. # def Klass.instance()
  42. # return @singleton__instance__
  43. # end
  44. #
  45. # * Klass._load(str) - calling Klass.instance()
  46. #
  47. # * Klass._instantiate?() - returning ``the instance'' or
  48. # nil. This hook method puts a second (or nth) thread calling
  49. # Klass.instance() on a waiting loop. The return value
  50. # signifies the successful completion or premature termination
  51. # of the first, or more generally, current "instantiation thread".
  52. #
  53. #
  54. # The instance method of Singleton are
  55. # * clone and dup - raising TypeErrors to prevent cloning or duping
  56. #
  57. # * _dump(depth) - returning the empty string. Marshalling strips
  58. # by default all state information, e.g. instance variables and
  59. # taint state, from ``the instance''. Providing custom _load(str)
  60. # and _dump(depth) hooks allows the (partially) resurrections of
  61. # a previous state of ``the instance''.
  62. require 'thread'
  63. module Singleton
  64. # disable build-in copying methods
  65. def clone
  66. raise TypeError, "can't clone instance of singleton #{self.class}"
  67. end
  68. def dup
  69. raise TypeError, "can't dup instance of singleton #{self.class}"
  70. end
  71. # default marshalling strategy
  72. def _dump(depth = -1)
  73. ''
  74. end
  75. module SingletonClassMethods
  76. # properly clone the Singleton pattern - did you know
  77. # that duping doesn't copy class methods?
  78. def clone
  79. Singleton.__init__(super)
  80. end
  81. def _load(str)
  82. instance
  83. end
  84. private
  85. # ensure that the Singleton pattern is properly inherited
  86. def inherited(sub_klass)
  87. super
  88. Singleton.__init__(sub_klass)
  89. end
  90. end
  91. class << Singleton
  92. def __init__(klass)
  93. klass.instance_eval {
  94. @singleton__instance__ = nil
  95. @singleton__mutex__ = Mutex.new
  96. }
  97. def klass.instance
  98. return @singleton__instance__ if @singleton__instance__
  99. @singleton__mutex__.synchronize {
  100. return @singleton__instance__ if @singleton__instance__
  101. @singleton__instance__ = new()
  102. }
  103. @singleton__instance__
  104. end
  105. klass
  106. end
  107. private
  108. # extending an object with Singleton is a bad idea
  109. undef_method :extend_object
  110. def append_features(mod)
  111. # help out people counting on transitive mixins
  112. unless mod.instance_of?(Class)
  113. raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}"
  114. end
  115. super
  116. end
  117. def included(klass)
  118. super
  119. klass.private_class_method :new, :allocate
  120. klass.extend SingletonClassMethods
  121. Singleton.__init__(klass)
  122. end
  123. end
  124. end
  125. if __FILE__ == $0
  126. def num_of_instances(klass)
  127. "#{ObjectSpace.each_object(klass){}} #{klass} instance(s)"
  128. end
  129. # The basic and most important example.
  130. class SomeSingletonClass
  131. include Singleton
  132. end
  133. puts "There are #{num_of_instances(SomeSingletonClass)}"
  134. a = SomeSingletonClass.instance
  135. b = SomeSingletonClass.instance # a and b are same object
  136. puts "basic test is #{a == b}"
  137. begin
  138. SomeSingletonClass.new
  139. rescue NoMethodError => mes
  140. puts mes
  141. end
  142. puts "\nThreaded example with exception and customized #_instantiate?() hook"; p
  143. Thread.abort_on_exception = false
  144. class Ups < SomeSingletonClass
  145. def initialize
  146. self.class.__sleep
  147. puts "initialize called by thread ##{Thread.current[:i]}"
  148. end
  149. end
  150. class << Ups
  151. def _instantiate?
  152. @enter.push Thread.current[:i]
  153. while false.equal?(@singleton__instance__)
  154. @singleton__mutex__.unlock
  155. sleep 0.08
  156. @singleton__mutex__.lock
  157. end
  158. @leave.push Thread.current[:i]
  159. @singleton__instance__
  160. end
  161. def __sleep
  162. sleep(rand(0.08))
  163. end
  164. def new
  165. begin
  166. __sleep
  167. raise "boom - thread ##{Thread.current[:i]} failed to create instance"
  168. ensure
  169. # simple flip-flop
  170. class << self
  171. remove_method :new
  172. end
  173. end
  174. end
  175. def instantiate_all
  176. @enter = []
  177. @leave = []
  178. 1.upto(9) {|i|
  179. Thread.new {
  180. begin
  181. Thread.current[:i] = i
  182. __sleep
  183. instance
  184. rescue RuntimeError => mes
  185. puts mes
  186. end
  187. }
  188. }
  189. puts "Before there were #{num_of_instances(self)}"
  190. sleep 3
  191. puts "Now there is #{num_of_instances(self)}"
  192. puts "#{@enter.join '; '} was the order of threads entering the waiting loop"
  193. puts "#{@leave.join '; '} was the order of threads leaving the waiting loop"
  194. end
  195. end
  196. Ups.instantiate_all
  197. # results in message like
  198. # Before there were 0 Ups instance(s)
  199. # boom - thread #6 failed to create instance
  200. # initialize called by thread #3
  201. # Now there is 1 Ups instance(s)
  202. # 3; 2; 1; 8; 4; 7; 5 was the order of threads entering the waiting loop
  203. # 3; 2; 1; 7; 4; 8; 5 was the order of threads leaving the waiting loop
  204. puts "\nLets see if class level cloning really works"
  205. Yup = Ups.clone
  206. def Yup.new
  207. begin
  208. __sleep
  209. raise "boom - thread ##{Thread.current[:i]} failed to create instance"
  210. ensure
  211. # simple flip-flop
  212. class << self
  213. remove_method :new
  214. end
  215. end
  216. end
  217. Yup.instantiate_all
  218. puts "\n\n","Customized marshalling"
  219. class A
  220. include Singleton
  221. attr_accessor :persist, :die
  222. def _dump(depth)
  223. # this strips the @die information from the instance
  224. Marshal.dump(@persist,depth)
  225. end
  226. end
  227. def A._load(str)
  228. instance.persist = Marshal.load(str)
  229. instance
  230. end
  231. a = A.instance
  232. a.persist = ["persist"]
  233. a.die = "die"
  234. a.taint
  235. stored_state = Marshal.dump(a)
  236. # change state
  237. a.persist = nil
  238. a.die = nil
  239. b = Marshal.load(stored_state)
  240. p a == b # => true
  241. p a.persist # => ["persist"]
  242. p a.die # => nil
  243. puts "\n\nSingleton with overridden default #inherited() hook"
  244. class Up
  245. end
  246. def Up.inherited(sub_klass)
  247. puts "#{sub_klass} subclasses #{self}"
  248. end
  249. class Middle < Up
  250. include Singleton
  251. end
  252. class Down < Middle; end
  253. puts "and basic \"Down test\" is #{Down.instance == Down.instance}\n
  254. Various exceptions"
  255. begin
  256. module AModule
  257. include Singleton
  258. end
  259. rescue TypeError => mes
  260. puts mes #=> Inclusion of the OO-Singleton module in module AModule
  261. end
  262. begin
  263. 'aString'.extend Singleton
  264. rescue NoMethodError => mes
  265. puts mes #=> undefined method `extend_object' for Singleton:Module
  266. end
  267. end