Module: Interjectable::ClassMethods
- Defined in:
- lib/interjectable.rb,
lib/interjectable/rspec.rb
Constant Summary collapse
- BLANK =
Object.new
Class Method Summary collapse
Instance Method Summary collapse
-
#inject(dependency, &default_block) ⇒ Object
Defines a helper methods on instances that memoize values per-instance.
-
#inject_static(dependency, &default_block) ⇒ Object
Defines helper methods on instances that memoize values per-class.
- #injected_methods(include_super = true) ⇒ Array<Symbol>
- #test_inject(dependency, &setter) ⇒ Object
Class Method Details
.test_inject(rspec_example_group, target, dependency, value, &setter) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/interjectable/rspec.rb', line 80 def self.test_inject(rspec_example_group, target, dependency, value, &setter) unless value || setter raise ArgumentError, "missing value or setter for #{target}'s #{dependency.inspect}" end unless rspec_example_group < RSpec::Core::ExampleGroup raise "#test_inject can only be called from an RSpec ExampleGroup (e.g.: it, before, after)" end injector = if target.singleton_methods(false).include?(dependency) # inject_static(dependency) on this class InjectStatic.new(target, dependency) elsif target.singleton_methods.include?(dependency) # inject_static(dependency) on a superclass of this class SuperclassInjectStatic.new(target, dependency) elsif target.instance_methods(false).include?(dependency) # inject(dependency) on this class Inject.new(target, dependency) elsif target.instance_methods.include?(dependency) # inject(dependency) on a superclass of this class SuperclassInject.new(target, dependency) else raise ArgumentError, "tried to override a non-existent dependency: #{dependency.inspect}" end injector.override(value, &setter) scope = rspec_example_group.currently_executing_a_context_hook? ? :context : :each key = [target, dependency, scope] # If we already have a restore after(:each) hook for this class + # dependency + scope, don't add another. To check if we already have an # after(:each) hook, we look at all previous after(:each) hooks we've # registered and see if we are currently in a subclass (i.e. we are # nested within) of any of them. # # We don't need to guard against multiple after(:context / :all) hooks # for the same #test_inject call since those before hooks only run once, # and therefore only setup a single after hook. return if scope == :each && RESTORE_HOOKS[key].any? { |group| rspec_example_group <= group } RESTORE_HOOKS[key] << rspec_example_group rspec_example_group.after(scope) do injector.restore end end |
Instance Method Details
#inject(dependency, &default_block) ⇒ Object
Defines a helper methods on instances that memoize values per-instance.
Calling a second time is an error. Use ‘#test_inject` for overriding in RSpec tests. You need to `require “interjectable/rspec”` to use `#test_inject`. See the README.md.
Similar to writing
attr_writer :dependency
def dependency
@dependency ||= instance_eval(&default_block)
end
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/interjectable.rb', line 54 def inject(dependency, &default_block) if instance_methods(false).include?(dependency) raise MethodAlreadyDefined, "#{dependency} is already defined" end attr_writer dependency define_method(dependency) do ivar_name = :"@#{dependency}" if instance_variable_defined?(ivar_name) instance_variable_get(ivar_name) else instance_variable_set(ivar_name, instance_eval(&default_block)) end end @injected_methods ||= [] @injected_methods += [dependency, :"#{dependency}="] end |
#inject_static(dependency, &default_block) ⇒ Object
Defines helper methods on instances that memoize values per-class. (shared across all instances of a class, including instances of subclasses).
Calling a second time is an error. Use ‘#test_inject` for overriding in RSpec tests. You need to `require “interjectable/rspec”` to use `#test_inject`. See the README.md.
Similar to writing
cattr_writer :dependency
def dependency
@@dependency ||= instance_eval(&default_block)
end
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/interjectable.rb', line 89 def inject_static(dependency, &default_block) if instance_methods(false).include?(dependency) || methods(false).include?(dependency) raise MethodAlreadyDefined, "#{dependency} is already defined" end injecting_class = self cvar_name = :"@@#{dependency}" setter = :"#{dependency}=" define_method(setter) do |value| injecting_class.send(setter, value) end define_singleton_method(setter) do |value| injecting_class.class_variable_set(cvar_name, value) end define_method(dependency) do injecting_class.send(dependency) end define_singleton_method(dependency) do if class_variable_defined?(cvar_name) injecting_class.class_variable_get(cvar_name) else injecting_class.class_variable_set(cvar_name, instance_eval(&default_block)) end end @static_injected_methods ||= [] @static_injected_methods += [dependency, :"#{dependency}="] end |
#injected_methods(include_super = true) ⇒ Array<Symbol>
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/interjectable.rb', line 124 def injected_methods(include_super = true) injected = @static_injected_methods.to_a if include_super super_injected = ancestors.flat_map do |klass| klass.instance_variable_get(:@static_injected_methods).to_a end [ :injected_methods, *super_injected, *injected, ].uniq else [:injected_methods, *injected] end end |
#test_inject(dependency, &setter) ⇒ Object
71 72 73 74 75 76 77 78 |
# File 'lib/interjectable/rspec.rb', line 71 def test_inject(dependency, &setter) unless setter raise ArgumentError, "missing setter #{dependency.inspect}, correct usage: #test_inject(#{dependency.inspect}) { FakeDependency.new }" end rspec_example_group = setter.binding.receiver.class ClassMethods.test_inject(rspec_example_group, self, dependency, BLANK, &setter) end |