How to Implement Injection in Ruby

Technique to inject dependencies in Ruby without using DI frameworks

Looks fine to me. Classes are objects in Ruby, so dependency injection is just setting a variable at runtime. In your case, you are setting the @http_client instance variable of the AppClient class. Once that variable is accessed by the code that needs the implementation, the class you configured the application with will be returned and it will do the job as long as it responds to the correct messages.

Be careful, though. Remember that classes are singleton objects that are shared within a single Ruby process. Other code could call that accessor method and change that variable as well. This could happen at any point, not just at start up, and will affect all code that uses the implementation. The potential for conflict exists.

This makes this pattern specially unsuitable for use in libraries. Passing the implementation class as a parameter on the call site should be a more robust solution in that case.

Need a simple explanation of the inject method

You can think of the first block argument as an accumulator: the result of each run of the block is stored in the accumulator and then passed to the next execution of the block. In the case of the code shown above, you are defaulting the accumulator, result, to 0. Each run of the block adds the given number to the current total and then stores the result back into the accumulator. The next block call has this new value, adds to it, stores it again, and repeats.

At the end of the process, inject returns the accumulator, which in this case is the sum of all the values in the array, or 10.

Here's another simple example to create a hash from an array of objects, keyed by their string representation:

[1,"a",Object.new,:hi].inject({}) do |hash, item|
hash[item.to_s] = item
hash
end

In this case, we are defaulting our accumulator to an empty hash, then populating it each time the block executes. Notice we must return the hash as the last line of the block, because the result of the block will be stored back in the accumulator.

Ruby/Rails Dependency Injection

Move initialization of Saw to the default argument.

class Builder   
def saw(saw = Saw.new(4))
@saw = saw
end

def cut_wood
Saw.saw
end
end

Builder#saw supports dependency injection now.

Remember to remove attr_reader :saw from your code because it's being overridden by your custom reader.

What's the best practice to achieve dependency injection with ruby-graphql?

As you've mentioned, injection through the initializer might not be super straight forward, so if you want to go fully into dependency injection and inversion of control, you could leverage an IOC Container library like Dry Auto Inject. I know it might be a full blown solution, and it could possibly be too heavy handed for your use case (not sure), but since you're already using repositories in Ruby, it might not be.

Does dependency injection exist in Rails?

Dependency injection is usually unnecessary with Ruby. Jamis Buck blogged extensively about the reasons why. Well worth a read.

Inject a line of code into an existing method at runtime

The reason I need this is so that I can use the Ruby Tracepoint Class to extract some run time information about the method signature.

Specifically the default parameter values in b = 1 and d: 1

TracePoint allows you to fetch information without patching the method. You just have to set up a :call hook and then call the method:

TracePoint.trace(:call) do |tp|
tp.parameters.each do |type, name|
value = tp.binding.local_variable_get(name)
puts format('%8s: %s = %s', type, name, value.inspect)
end
end

A.new.some_method(123)

Output: (omitting the method's output)

     req: a = 123
opt: b = 1
rest: c = []
key: d = 1
keyrest: e = {}


Related Topics



Leave a reply



Submit