Jared Rader
Jared Rader

Reputation: 880

What is Thread.current for in the DCI in Ruby example?

What is Thread.current for in this code? I'm looking at this example of using DCI in a Rails application. In lib/context.rb, there's this:

module Context
  include ContextAccessor

  def context=(ctx)
    Thread.current[:context] = ctx
  end

  def in_context
    old_context = self.context
    self.context = self
    res = yield
    self.context = old_context
    res
  end
end

which is used in the various contexts in app/contexts, e.g.:

def bid
  in_context do
    validator.validate
    biddable.create_bid
  end
  #...
end

What is the benefit of running the code in the in_context block and setting a key-value pair on the current thread?

Upvotes: 0

Views: 149

Answers (2)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Generally, inside block you do not have an access to the caller’s context (besides closure variables.)

▶ class A
▷   attr_accessor :a
▷   def test
▷     yield if block_given?
▷   end  
▷ end  
#⇒ :test
▶ inst = A.new
#⇒ #<A:0x00000006f41e28>
▶ inst.a = 'Test'
#⇒ "Test"
▶ inst.test do 
▷   puts self
▷   # here you do not have an access to inst at all
▷   # this would raise an exception: puts self.a
▷ end
#⇒ main

But with context you still might have an access to inst from inside block:

▶ in_context do 
▷   puts self.context.a
▷ end
#⇒ 'Test'

So, one might introduce the proc (consider both A and B have Context included):

▶ pr = ->() { puts self.context }
▶ A.new.in_context &pr
#⇒ #<A:0x00000006f41e28>
▶ B.new.in_context &pr
#⇒ #<B:0x00000006f41eff>

Now external proc pr has virtually full access to its caller.

Upvotes: 3

dimakura
dimakura

Reputation: 7655

Thread.current is required to support multiple threading application, where each thread has its own context.

There is also ContextAccessor module included, where one gets context. Putting them together just gives more clear picture:

# context.rb
def context=(ctx)
  Thread.current[:context] = ctx
end

# context_accessor.rb
def context
  Thread.current[:context]
end

The in_context method is designed to safely change context inside its block. Whatever the changes were, the old context is restored when the block ends execution.

Upvotes: 2

Related Questions