Module: ThreadAttrAccessor

Defined in:
lib/thread_attr_accessor.rb,
lib/thread_attr_accessor/version.rb

Overview

‘extend` this module on your class/module to get per-thread class attribute accessors. Example:

class MyClass

extend ThreadAttrAccessor

thread_attr_accessor :setting

end

MyClass.setting = :original

threads = [

Thread.new { MyClass.setting = :foo; puts MyClass.setting },
Thread.new { MyClass.setting = :bar; puts MyClass.setting },

]

threads.each(&:join) MyClass.setting == :original # true

Constant Summary collapse

VERSION =
"0.3.1"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(base) ⇒ Object



37
38
39
40
41
42
43
44
# File 'lib/thread_attr_accessor.rb', line 37

def self.extended(base)
  mod = Module.new

  unless base.const_defined?(:ThreadAttributeAccessors, false)
    base.const_set(:ThreadAttributeAccessors, mod)
    base.extend(mod)
  end
end

.search_in_ancestor_threads(key) ⇒ Object



27
28
29
30
31
32
33
34
35
# File 'lib/thread_attr_accessor.rb', line 27

def self.search_in_ancestor_threads(key)
  ancestor = Thread.current.parent_thread

  until ancestor.nil? || (ancestor_value = ancestor.thread_variable_get(key))
    ancestor = ancestor.parent_thread
  end

  ancestor_value
end

.thread_accessor_key(base, name) ⇒ Object



23
24
25
# File 'lib/thread_attr_accessor.rb', line 23

def self.thread_accessor_key(base, name)
  "#{base.name}.#{name}"
end

Instance Method Details

#thread_attr_accessor(*names, private: false, **opts) ⇒ Object



105
106
107
108
109
110
111
# File 'lib/thread_attr_accessor.rb', line 105

def thread_attr_accessor(*names, private: false, **opts)
  private_reader = private.to_s == "reader" || private == true
  private_writer = private.to_s == "writer" || private == true

  thread_attr_reader(*names, private: private_reader, **opts)
  thread_attr_writer(*names, private: private_writer, **opts)
end

#thread_attr_reader(*names, default: nil, inherit: false, private: false, **opts) ⇒ Object



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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/thread_attr_accessor.rb', line 62

def thread_attr_reader(*names, default: nil, inherit: false, private: false, **opts)
  if default && inherit
    get_default = ->(thread_key) {
      ThreadAttrAccessor.search_in_ancestor_threads(thread_key) ||
      default.call
    }
  elsif inherit
    get_default = ThreadAttrAccessor.method(:search_in_ancestor_threads)
  elsif default
    get_default = ->(*) { default.call }
  end

  if get_default
    get_value = ->(thread_key) {
      if value = Thread.current.thread_variable_get(thread_key)
        value
      else
        default_value = get_default.call(thread_key)
        Thread.current.thread_variable_set(thread_key, default_value)
        default_value
      end
    }
  else
    get_value = ->(thread_key) {
      Thread.current.thread_variable_get(thread_key)
    }
  end

  mod = const_get(:ThreadAttributeAccessors)

  names.each do |name|
    thread_key = ThreadAttrAccessor.thread_accessor_key(self, name)

    mod.send(:define_method, name) do
      get_value.call(thread_key)
    end

    if private
      mod.send :private, name
    end
  end
end

#thread_attr_writer(*names, private: false, **opts) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/thread_attr_accessor.rb', line 46

def thread_attr_writer(*names, private: false, **opts)
  mod = const_get(:ThreadAttributeAccessors)

  names.each do |name|
    thread_key = ThreadAttrAccessor.thread_accessor_key(self, name)

    mod.send(:define_method, "#{name}=") do |value|
      Thread.current.thread_variable_set(thread_key, value)
    end

    if private
      mod.send :private, "#{name}="
    end
  end
end