Innate::StateAccessor

Simplify accessing Thread.current variables.

Example:

class Foo
  include Innate::StateAccessor
  state_accessor :session

  def calculate
    session[:num1] + session[:num2]
  end
end

Foo#calculate can now be called from anywhere in your application and it will have direct access to the session in the current request/response cycle in a thread-safe way without the need to explicitly pass the session along.

Public Class Methods

each(*names) click to toggle source

Iterate over the names and yield accordingly. names are either objects responding to to_sym or hashes.

It's only used within this module to make the code readable.

Used below.

# File lib/innate/state/accessor.rb, line 29
def self.each(*names)
  names.each do |name|
    if name.respond_to?(:to_hash)
      name.to_hash.each do |key, meth|
        yield(key.to_sym, meth.to_sym)
      end
    else
      key = meth = name.to_sym
      yield(key, meth)
    end
  end
end

Public Instance Methods

state_accessor(*names, &initializer) click to toggle source

Combined state_writer and state_reader. initializer is a block that may be given and its result will be the new value in case the method created by state_reader was never called before and the value wasn't set before.

Example:

state_accessor(:session)
state_accessor(:user){ session[:user] }
# File lib/innate/state/accessor.rb, line 52
def state_accessor(*names, &initializer)
  state_writer(*names)
  state_reader(*names, &initializer)
end
state_reader(*names, &initializer) click to toggle source

Reader accessor for Thread.current

Example:

class Foo
  include Innate::StateAccessor
  state_reader(:session)
  state_reader(:random){ rand(100_000) }

  def calculate
    val1 = session[:num1] + session[:num2] + random
    val2 = session[:num1] + session[:num2] + random
    val1 == val2 # => true
  end
end

NOTE:

If given +initializer+, there will be some performance impact since we
cannot use class_eval and have to use define_method instead, we also
have to check every time whether the initializer was executed already.

In 1.8.x the overhead of define_method is 3x that of class_eval/def
In 1.9.1 the overhead of define_method is 1.5x that of class_eval/def

This may only be an issue for readers that are called a lot of times.
# File lib/innate/state/accessor.rb, line 114
def state_reader(*names, &initializer)
  StateAccessor.each(*names) do |key, meth|
    if initializer
      define_method(meth) do
        unless Thread.current.key?(key)
          Thread.current[key] = instance_eval(&initializer)
        else
          Thread.current[key]
        end
      end
    else
      class_eval("def %s; Thread.current[%p]; end" % [meth, key])
    end
  end
end
state_writer(*names) click to toggle source

Writer accessor to Thread.current=

Example:

class Foo
  include Innate::StateAccessor
  state_writer(:result)

  def calculate
    self.result = 42
  end
end

class Bar
  include Innate::StateAccessor
  state_reader(:result)

  def calculcate
    result * result
  end
end

Foo.new.calculate # => 42
Bar.new.calculate # => 1764
# File lib/innate/state/accessor.rb, line 82
def state_writer(*names)
  StateAccessor.each(*names) do |key, meth|
    class_eval("def %s=(obj) Thread.current[%p] = obj; end" % [meth, key])
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.