-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslotable.rb
112 lines (93 loc) · 3 KB
/
slotable.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
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
# frozen_string_literal: true
require "phlex"
require_relative "slotable/version"
module Phlex
module Slotable
module DeferredRender
def before_template(&)
vanish(&)
super
end
end
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def slot(slot_name, callable = nil, types: nil, collection: false)
include DeferredRender
if types
types.each do |type, callable|
define_setter_method(slot_name, callable, collection: collection, type: type)
end
else
define_setter_method(slot_name, callable, collection: collection)
end
define_predicate_method(slot_name, collection: collection)
define_getter_method(slot_name, collection: collection)
end
private
def define_setter_method(slot_name, callable, collection:, type: nil)
slot_name_with_type = type ? "#{type}_#{slot_name}" : slot_name
signature = callable.nil? ? "(&block)" : "(*args, **kwargs, &block)"
setter_method = if collection
<<-RUBY
def with_#{slot_name_with_type}#{signature}
@#{slot_name}_slots ||= []
@#{slot_name}_slots << #{callable_value(slot_name_with_type, callable)}
end
RUBY
else
<<-RUBY
def with_#{slot_name_with_type}#{signature}
@#{slot_name}_slot = #{callable_value(slot_name_with_type, callable)}
end
RUBY
end
class_eval(setter_method, __FILE__, __LINE__)
define_lambda_method(slot_name_with_type, callable) if callable.is_a?(Proc)
end
def define_lambda_method(slot_name, callable)
define_method :"__call_#{slot_name}__", &callable
private :"__call_#{slot_name}__"
end
def define_getter_method(slot_name, collection:)
getter_method = if collection
<<-RUBY
def #{slot_name}_slots = @#{slot_name}_slots ||= []
private :#{slot_name}_slots
RUBY
else
<<-RUBY
def #{slot_name}_slot = @#{slot_name}_slot
private :#{slot_name}_slot
RUBY
end
class_eval(getter_method, __FILE__, __LINE__)
end
def define_predicate_method(slot_name, collection:)
predicate_method = if collection
<<-RUBY
def #{slot_name}_slots? = #{slot_name}_slots.any?
private :#{slot_name}_slots?
RUBY
else
<<-RUBY
def #{slot_name}_slot? = !#{slot_name}_slot.nil?
private :#{slot_name}_slot?
RUBY
end
class_eval(predicate_method, __FILE__, __LINE__)
end
def callable_value(slot_name, callable)
case callable
when nil
%(block)
when Proc
%(-> { __call_#{slot_name}__(*args, **kwargs, &block) })
else
%(#{callable}.new(*args, **kwargs, &block))
end
end
end
end
end