1
1
module ActiveModel
2
2
class Serializer
3
3
module Attributes
4
+ # @api private
5
+ module AttrNames
6
+ def self . set_name_cache ( name , value )
7
+ const_name = "ATTR_#{ name } "
8
+ unless const_defined? const_name
9
+ const_set const_name , value . duplicable? ? value . dup . freeze : value
10
+ end
11
+ end
12
+ end
13
+
14
+ # @api private
15
+ class Cache
16
+ def initialize
17
+ @module = Module . new
18
+ @method_cache = ThreadSafe ::Cache . new
19
+ end
20
+
21
+ def []( name )
22
+ @method_cache . compute_if_absent ( name ) do
23
+ safe_name = name . to_s . unpack ( 'h*' ) . first
24
+ temp_method = "__temp__#{ safe_name } "
25
+ ActiveModel ::Serializer ::Attributes ::AttrNames . set_name_cache safe_name , name
26
+ @module . module_eval method_body ( temp_method , safe_name ) , __FILE__ , __LINE__
27
+ @module . instance_method temp_method
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def method_body ( method_name , const_name )
34
+ <<-EOMETHOD
35
+ def #{ method_name } (instance)
36
+ name = ::ActiveModel::Serializer::Attributes::AttrNames::ATTR_#{ const_name }
37
+ instance.read_attribute_for_serialization(name)
38
+ end
39
+ EOMETHOD
40
+ end
41
+ end
42
+ # @api private
43
+ MethodCache = Cache . new
4
44
# @api private
5
45
class Attribute
6
46
delegate :call , to : :reader
@@ -24,7 +64,7 @@ def self.build(name, block)
24
64
class AttributeReader < Attribute
25
65
def initialize ( name )
26
66
super ( name )
27
- @reader = -> ( instance ) { instance . read_attribute_for_serialization ( name ) }
67
+ define_method ( :call , MethodCache [ name ] )
28
68
end
29
69
end
30
70
# @api private
0 commit comments