-
Notifications
You must be signed in to change notification settings - Fork 21.4k
/
code_generator.rb
65 lines (57 loc) · 1.56 KB
/
code_generator.rb
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
# frozen_string_literal: true
module ActiveSupport
class CodeGenerator # :nodoc:
class MethodSet
METHOD_CACHES = Hash.new { |h, k| h[k] = Module.new }
def initialize(namespace)
@cache = METHOD_CACHES[namespace]
@sources = []
@methods = {}
end
def define_cached_method(name, as: name)
name = name.to_sym
as = as.to_sym
@methods.fetch(name) do
unless @cache.method_defined?(as)
yield @sources
end
@methods[name] = as
end
end
def apply(owner, path, line)
unless @sources.empty?
@cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
end
@methods.each do |name, as|
owner.define_method(name, @cache.instance_method(as))
end
end
end
class << self
def batch(owner, path, line)
if owner.is_a?(CodeGenerator)
yield owner
else
instance = new(owner, path, line)
result = yield instance
instance.execute
result
end
end
end
def initialize(owner, path, line)
@owner = owner
@path = path
@line = line
@namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
end
def define_cached_method(name, namespace:, as: name, &block)
@namespaces[namespace].define_cached_method(name, as: as, &block)
end
def execute
@namespaces.each_value do |method_set|
method_set.apply(@owner, @path, @line - 1)
end
end
end
end