Guest User

Untitled

a guest
Feb 20th, 2018
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.49 KB | None | 0 0
  1. # Subclass of Module, used for storing methods copied from other
  2. # modules and classes. This lets classes shuffle their methods off
  3. # into a module to we can place other modules in front of the
  4. # class's own methods
  5. class StashModule < Module
  6. class << self
  7. def [](id)
  8. @modules[id]
  9. end
  10.  
  11. def save(mod)
  12. @modules ||= {}
  13. @modules[mod.__id__] = mod
  14. end
  15. end
  16.  
  17. def initialize
  18. super
  19. @stash = {}
  20. self.class.save(self)
  21. end
  22.  
  23. def [](name)
  24. @stash[name]
  25. end
  26.  
  27. def define(source, name)
  28. mod_id = __id__
  29. @stash[name] = source.instance_method(name)
  30. module_eval <<-DEF
  31. def #{name}(*args, &block)
  32. m = StashModule[#{mod_id}][#{name.inspect}]
  33. m.bind(self).call(*args[0...m.arity], &block)
  34. end
  35. DEF
  36. end
  37. end
  38.  
  39.  
  40. class Module
  41. private
  42.  
  43. # Stash all current methods in a module and add that module to
  44. # the hierarchy. Permits insertion of new modules "in front" of
  45. # the module itself so we can override methods using 'include'
  46. def inherit_from_self!
  47. stash = StashModule.new
  48. instance_methods(false).each do |name|
  49. stash.define(self, name)
  50. remove_method(name)
  51. end
  52. include stash
  53. end
  54.  
  55. # Includes a module but places it in front of this module's
  56. # own methods. The mixin can use 'super' to refer to this module
  57. def include_in_front(mixin)
  58. inherit_from_self!
  59. include mixin
  60. end
  61.  
  62. # A more fine-grained approach: overrides a single method and
  63. # allows you to refer to the old one using 'super'
  64. def override(name, &block)
  65. current = StashModule.new
  66. current.define(self, name)
  67. include current
  68. define_method(name, &block)
  69. end
  70. end
  71.  
  72.  
  73. # Example: make a class and a module, mix the module into the
  74. # class and use 'super' to refer to the class's method from the
  75. # mixin. Ordinarily, the class's methods would take precedence
  76. # over those from the module
  77.  
  78. class Foo
  79. def initialize(name)
  80. @name = name
  81. end
  82.  
  83. def foo
  84. @name.upcase
  85. end
  86. end
  87.  
  88. puts Foo.new('Mike').foo
  89. #=> "MIKE"
  90.  
  91. module Helper
  92. def foo(thing)
  93. "My name is #{super}! I like #{thing}"
  94. end
  95. end
  96.  
  97. class Foo
  98. include_in_front Helper
  99. end
  100.  
  101. puts Foo.new('Mike').foo('Ruby!')
  102. #=> "My name is MIKE! I like Ruby!"
  103.  
  104.  
  105. # Second example, using override
  106.  
  107. class Bar
  108. def talk(item)
  109. "It's some #{item}"
  110. end
  111.  
  112. override :talk do
  113. super.upcase
  114. end
  115. end
  116.  
  117. puts Bar.new.talk('stuff')
  118. #=> "IT'S SOME STUFF"
Add Comment
Please, Sign In to add comment