Module: Interjectable::ClassMethods
- Defined in:
- lib/interjectable.rb,
lib/interjectable/rspec.rb
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.
- #test_inject(dependency, &setter) ⇒ Object
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
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/interjectable.rb', line 30 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 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
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/interjectable.rb', line 62 def inject_static(dependency, &default_block) if instance_methods(false).include?(dependency) || methods(false).include?(dependency) raise MethodAlreadyDefined, "#{dependency} is already defined" end cvar_name = :"@@#{dependency}" setter = :"#{dependency}=" define_method(setter) do |value| self.class.send(setter, value) end define_singleton_method(setter) do |value| class_variable_set(cvar_name, value) end define_method(dependency) do self.class.send(dependency) end define_singleton_method(dependency) do if class_variable_defined?(cvar_name) class_variable_get(cvar_name) else class_variable_set(cvar_name, instance_eval(&default_block)) end end end |
#test_inject(dependency, &setter) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 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 124 125 |
# File 'lib/interjectable/rspec.rb', line 69 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 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 singleton_methods(false).include?(dependency) # inject_static(dependency) on this class InjectStatic.new(self, dependency) elsif singleton_methods.include?(dependency) # inject_static(dependency) on a superclass of this class SuperclassInjectStatic.new(self, dependency) elsif instance_methods(false).include?(dependency) # inject(dependency) on this class Inject.new(self, dependency) elsif instance_methods.include?(dependency) # inject(dependency) on a superclass of this class SuperclassInject.new(self, dependency) else raise ArgumentError, "tried to override a non-existent dependency: #{dependency.inspect}" end injector.override(setter) scope = rspec_example_group.currently_executing_a_context_hook? ? :context : :each key = [self, dependency, scope] # if dependency == :dependency && scope == :each # puts "override: #{key.inspect} #{rspec_example_group}" # end # 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 } # if dependency == :dependency && scope == :each # puts "adding new after=#{key.inspect} hooks=#{RESTORE_HOOKS[key]} group=#{rspec_example_group}" # end RESTORE_HOOKS[key] << rspec_example_group # if dependency == :dependency && scope == :each # puts RESTORE_HOOKS.select { |(_, d, s)| d == :dependency && s == :each } # end rspec_example_group.after(scope) do # if dependency == :dependency && scope == :each # puts "restore: #{key.inspect} #{rspec_example_group}" # end injector.restore end end |