Class: Farce::Extension
- Inherits:
-
Module
- Object
- Module
- Farce::Extension
- Defined in:
- lib/farce/extension.rb
Overview
Defines a reusable extension for adding methods to target classes. These methods can either be activated as refinements, or installed globally to extend the target classes.
DoubleSize = Farce::Extension.define(String) do
def double_size = size * 2
end
module Namespace
using DoubleSize
"hello".double_size # => 10
end
"hello".respond_to?(:double_size) # => false
DoubleSize.install
"hello".respond_to?(:double_size) # => true
Extending multiple classes
An extension can also modify multiple target classes simultaneously:
DoubleSize = Farce::Extension.new do
define(String) { def double_size = size * 2 }
define(Array) { def double_size = sum(&:double_size) }
end
using DoubleSize
["hello", "foo"].double_size # => 16
Class Method Summary collapse
-
.define(*targets) { ... } ⇒ Extension
Defines an extension for the given target classes.
Instance Method Summary collapse
-
#define(*targets) { ... } ⇒ self
Defines additional methods for a given target class.
-
#freeze ⇒ self
Freezes the extension.
-
#initialize { ... } ⇒ Extension
constructor
Creates a new extension.
-
#install
Installs the extension globally.
-
#installed? ⇒ Boolean
Whether the extension has been installed.
Constructor Details
Class Method Details
.define(*targets) { ... } ⇒ Extension
65 |
# File 'lib/farce/extension.rb', line 65 def self.define(...) = new { define(...) } |
Instance Method Details
#define(*targets) { ... } ⇒ self
Defines additional methods for a given target class.
The given block will be invoked at least twice. Once in the context of a refinement for the target class, and once in the context of the mixin module that will be prepended to the target class.
rubocop:disable-next Naming/BlockForwarding, Style/ArgumentsForwarding
104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/farce/extension.rb', line 104 def define(*targets, &block) # JRuby rejects repeated anonymous block forwarding inside a block. @lock.synchronize do check_state! targets.each do |target| refine(target, &block) mixin = @definitions.store_if_absent(target) { Mixin.new(self, target) } mixin.module_eval(&block) mixin.install if installed? end end self end |
#freeze ⇒ self
Freezes the extension.
No definitions can be added after freezing the extension.
137 138 139 140 141 142 143 |
# File 'lib/farce/extension.rb', line 137 def freeze return self if frozen? @lock.synchronize do @definitions.freeze super end end |
#install
This method returns an undefined value.
Installs the extension globally.
120 121 122 123 124 125 126 127 128 |
# File 'lib/farce/extension.rb', line 120 def install @lock.synchronize do return false if installed? check_state!(allow_frozen: true) @definitions.each_value(&:install) yield if block_given? @installed.set end end |
#installed? ⇒ Boolean
Returns whether the extension has been installed.
131 |
# File 'lib/farce/extension.rb', line 131 def installed? = @installed.set? |