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 # or hashes.

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

Used below.

    # File lib/innate/state/accessor.rb, line 29
29:     def self.each(*names)
30:       names.each do |name|
31:         if name.respond_to?(:to_hash)
32:           name.to_hash.each do |key, meth|
33:             yield(key.to_sym, meth.to_sym)
34:           end
35:         else
36:           key = meth = name.to_sym
37:           yield(key, meth)
38:         end
39:       end
40:     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
52:     def state_accessor(*names, &initializer)
53:       state_writer(*names)
54:       state_reader(*names, &initializer)
55:     end
state_reader(*names, &initializer) click to toggle source

Reader accessor for Thread.current[key]

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
114:     def state_reader(*names, &initializer)
115:       StateAccessor.each(*names) do |key, meth|
116:         if initializer
117:           define_method(meth) do
118:             unless Thread.current.key?(key)
119:               Thread.current[key] = instance_eval(&initializer)
120:             else
121:               Thread.current[key]
122:             end
123:           end
124:         else
125:           class_eval("def %s; Thread.current[%p]; end" % [meth, key])
126:         end
127:       end
128:     end
state_writer(*names) click to toggle source

Writer accessor to Thread.current[key]=

  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
82:     def state_writer(*names)
83:       StateAccessor.each(*names) do |key, meth|
84:         class_eval("def %s=(obj) Thread.current[%p] = obj; end" % [meth, key])
85:       end
86:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.