File: thread_local.rb

package info (click to toggle)
ruby-tins 1.32.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,248 kB
  • sloc: ruby: 6,659; makefile: 3
file content (53 lines) | stat: -rw-r--r-- 1,513 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
module Tins
  module ThreadLocal
    @@cleanup = lambda do |my_object_id|
      my_id = "__thread_local_#{my_object_id}__"
      for t in Thread.list
        t[my_id] = nil if t[my_id]
      end
    end

    # Define a thread local variable named _name_ in this module/class. If the
    # value _value_ is given, it is used to initialize the variable.
    def thread_local(name, default_value = nil, &default)
      is_a?(Module) or raise TypeError, "receiver has to be a Module"

      default_value && default and raise ArgumentError,
        "require either default_falue or default block"

      if default_value
        default = -> * { default_value }
      end

      name = name.to_s
      my_id = "__thread_local_#{__id__}__"

      ObjectSpace.define_finalizer(self, @@cleanup)

      define_method(name) do
        values = Thread.current[my_id] ||= {}
        if default && !values.key?(name)
          values[name] = default.call
        end
        values[name]
      end

      define_method("#{name}=") do |value|
        Thread.current[my_id] ||= {}
        Thread.current[my_id][name] = value
      end

      self
    end

    # Define a thread local variable for the current instance with name _name_.
    # If the value _value_ is given, it is used to initialize the variable.
    def instance_thread_local(name, default_value = nil, &default)
      class << self
        extend Tins::ThreadLocal
        self
      end.thread_local name, default_value, &default
      self
    end
  end
end