Completed
Push — master ( 0214c0...4b005a )
by Yoh
45s
created

Component.component_will_unmount()   A

Complexity

Conditions 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 3
rs 10
cc 2
1
require 'hyalite/short_hand'
2
3
module Hyalite
4
  module Component
5
    TAGS = %w(
6
      a abbr address area article aside audio b base bdi bdo blockquote body br button button button button canvas caption
7
      cite code col colgroup command datalist dd del details dfn div dl dt em embed fieldset figcaption figure footer form
8
      h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins kbd keygen label legend li link map mark menu meta
9
      meter nav noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small
10
      source span strong style sub summary sup table tbody td textarea tfoot th thead time title tr track u ul var video wbr
11
    )
12
13
    def pp(obj)
14
      puts obj.inspect
15
    end
16
17
    attr_accessor :props, :context, :refs
18
19
    def init_component(props, context, updator)
20
      @props = props
21
      @context = context
22
      @updator = updator
23
      @state = State.new(self, updator, initial_state)
24
      @refs = nil
25
    end
26
27
    def self.included(klass)
28
      klass.instance_eval do
29
        define_singleton_method(:state) do |key, initial_value|
30
          (@initial_state ||= {})[key] = initial_value
31
        end
32
33
        define_singleton_method(:initial_state) { @initial_state || {} }
34
35
        define_singleton_method(:before_mount) do |&block|
36
          if block
37
            @before_mount = block
38
          else
39
            @before_mount
40
          end
41
        end
42
43
        define_singleton_method(:after_mount) do |&block|
44
          if block
45
            @after_mount = block
46
          else
47
            @after_mount
48
          end
49
        end
50
51
        define_singleton_method(:before_unmount) do |&block|
52
          if block
53
            @before_unmount = block
54
          else
55
            @before_unmount
56
          end
57
        end
58
59
        define_singleton_method(:after_unmount) do |&block|
60
          if block
61
            @after_unmount = block
62
          else
63
            @after_unmount
64
          end
65
        end
66
67
        define_singleton_method(:before_update) do |&block|
68
          if block
69
            @before_update = block
70
          else
71
            @before_update
72
          end
73
        end
74
75
        define_singleton_method(:after_update) do |&block|
76
          if block
77
            @after_update = block
78
          else
79
            @after_update
80
          end
81
        end
82
      end
83
84
      TAGS.each do |tag|
85
        define_method(tag) do |props, *children, &block|
86
          if block
87
            Hyalite.create_element_hook do |hook_setter|
88
              renderer = ChildrenRenderer.new(self, hook_setter)
89
              renderer.instance_eval(&block)
90
              children << renderer.children
91
            end
92
          end
93
          Hyalite.create_element(tag, props, *children)
94
        end
95
      end
96
97
      klass.extend ClassMethods
98
    end
99
100
    class ChildrenRenderer
101
      attr_reader :children
102
103
      def initialize(component, hook_setter)
104
        @component = component
105
        @children = []
106
        hook_setter.hook do |el|
107
          @children << el
108
        end
109
      end
110
111
      def method_missing(method_name, *args, &block)
112
        if @component.respond_to?(method_name, true)
113
          @component.send(method_name, *args, &block)
114
        else
115
          super
116
        end
117
      end
118
119
      def respond_to_missing?(method_name, include_private = false)
120
        @component.respond_to?(method_name, include_private) || super
121
      end
122
    end
123
124
    module ClassMethods
125
      def el(props, *children, &block)
126
        children << ChildrenRenderer.new(self).instance_eval(&block) if block
127
        Hyalite.create_element(self, props, *children)
128
      end
129
    end
130
131
    def initial_state
132
      self.class.initial_state
133
    end
134
135
    def state
136
      @state.to_h
137
    end
138
139
    def state=(state)
140
      @state.set(state)
141
    end
142
143
    def child_context
144
      {}
145
    end
146
147
    def component_will_mount
148
      self.instance_eval(&self.class.before_mount) if self.class.before_mount
149
    end
150
151
    def component_did_mount
152
      self.instance_eval(&self.class.after_mount) if self.class.after_mount
153
    end
154
155
    def component_will_unmount
156
      self.instance_eval(&self.class.before_unmount) if self.class.before_unmount
157
    end
158
159
    def component_did_unmount
160
      self.instance_eval(&self.class.after_unmount) if self.class.after_unmount
161
    end
162
163
    def component_will_update(props, state, context)
164
      self.instance_eval(&self.class.before_update) if self.class.before_update
165
    end
166
167
    def component_did_update(props, state, context)
168
      self.instance_eval(&self.class.after_update) if self.class.after_update
169
    end
170
171
    def should_component_update(props, state, context)
172
      true
173
    end
174
175
    def force_update(&block)
176
      @updator.enqueue_force_update(self);
177
      if block_given?
178
        @updator.enqueue_callback(self, &block)
179
      end
180
    end
181
182
    def set_state(states, &block)
183
      @updator.enqueue_set_state(self, states)
184
      if block_given?
185
        @updator.enqueue_callback(self, &block)
186
      end
187
    end
188
    alias :update_state :set_state
189
190
    def method_missing(method_name, *args, &block)
191
      if @props.has_key?(method_name)
192
        @props[method_name]
193
      else
194
        super
195
      end
196
    end
197
198
    def respond_to_missing?(method_name, include_private = false)
199
      @props.has_key?(method_name) || super
200
    end
201
202
    def render
203
    end
204
205
    class State
206
      def initialize(component, updator, initial_state)
207
        @component = component
208
        @updator = updator
209
        @state = initial_state.clone
210
        initial_state.each do |key, value|
211
          define_singleton_method(key) do
212
            @state[key]
213
          end
214
          define_singleton_method(key + '=') do |value|
215
            @updator.enqueue_set_state(@component, key => value)
216
          end
217
        end
218
      end
219
220
      def [](key)
221
        @state[key]
222
      end
223
224
      def set(state)
225
        @state = state.clone
226
      end
227
228
      def to_h
229
        @state
230
      end
231
    end
232
  end
233
234
  class EmptyComponent
235
    include Component
236
237
    def self.empty_element
238
      @instance ||= ElementObject.new(EmptyComponent, nil, nil, nil, nil)
239
    end
240
241
    def render
242
      Hyalite.create_element("noscript", nil, nil)
243
    end
244
  end
245
246
  class TopLevelWrapper
247
    include Component
248
249
    def render
250
      @props
251
    end
252
  end
253
end
254