File: adamantium.rb

package info (click to toggle)
ruby-unparser 0.6.13-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 936 kB
  • sloc: ruby: 7,691; sh: 6; makefile: 4
file content (150 lines) | stat: -rw-r--r-- 3,341 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
54
55
56
57
58
59
60
61
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# frozen_string_literal: true

module Unparser
  # Allows objects to be made immutable
  #
  # Original code before vendoring and reduction from: https://github.com/dkubb/adamantium.
  module Adamantium
    module InstanceMethods
      # A noop #dup for immutable objects
      #
      # @return [self]
      #
      # @api public
      def dup
        self
      end

      # Freeze the object
      #
      # @return [Object]
      #
      # @api public
      def freeze
        memoized_method_cache
        super()
      end

    private

      def memoized_method_cache
        @memoized_method_cache ||= Memory.new({})
      end

    end # InstanceMethods

    # Storage for memoized methods
    class Memory

      # Initialize the memory storage for memoized methods
      #
      # @return [undefined]
      #
      # @api private
      def initialize(values)
        @values  = values
        @monitor = Monitor.new
        freeze
      end

      # Fetch the value from memory, or evaluate if it does not exist
      #
      # @param [Symbol] name
      #
      # @yieldreturn [Object]
      #   the value to memoize
      #
      # @api public
      def fetch(name)
        @values.fetch(name) do      # check for the key
          @monitor.synchronize do   # acquire a lock if the key is not found
            @values.fetch(name) do  # recheck under lock
              @values[name] = yield # set the value
            end
          end
        end
      end
    end # Memory

    # Methods mixed in to adamantium classes
    module ClassMethods

      # Instantiate a new frozen object
      #
      # @return [Object]
      #
      # @api public
      def new(*)
        super.freeze
      end

    end # ClassMethods

    # Methods mixed in to adamantium modules
    module ModuleMethods

      # Memoize a list of methods
      #
      # @param [Array<#to_s>] methods
      #   a list of methods to memoize
      #
      # @return [self]
      #
      # @api public
      def memoize(*methods)
        methods.each(&method(:memoize_method))
        self
      end

      # Test if method is memoized
      #
      # @param [Symbol] name
      #
      # @return [Bool]
      def memoized?(method_name)
        memoized_methods.key?(method_name)
      end

      # Return unmemoized instance method
      #
      # @param [Symbol] name
      #
      # @return [UnboundMethod]
      #   the memoized method
      #
      # @raise [NameError]
      #   raised if the method is unknown
      #
      # @api public
      def unmemoized_instance_method(method_name)
        memoized_methods.fetch(method_name) do
          fail ArgumentError, "##{method_name} is not memoized"
        end
      end

    private

      def memoize_method(method_name)
        if memoized_methods.key?(method_name)
          fail ArgumentError, "##{method_name} is already memoized"
        end

        memoized_methods[method_name] = MethodBuilder.new(self, method_name).call
      end

      def memoized_methods
        @memoized_methods ||= {}
      end

    end # ModuleMethods

    def self.included(descendant)
      descendant.class_eval do
        include InstanceMethods
        extend ModuleMethods
        extend ClassMethods if instance_of?(Class)
      end
    end
    private_class_method :included
  end # Adamantium
end # Unparser