Completed
Push — master ( ba50eb...301cca )
by Yoh
53s
created

ChildrenRenderer.method_missing()   A

Complexity

Conditions 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
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_update) do |&block|
52
          if block
53
            @before_update = block
54
          else
55
            @before_update
56
          end
57
        end
58
59
        define_singleton_method(:after_update) do |&block|
60
          if block
61
            @after_update = block
62
          else
63
            @after_update
64
          end
65
        end
66
      end
67
68
      TAGS.each do |tag|
69
        define_method(tag) do |props, *children, &block|
70
          children << ChildrenRenderer.new(self).instance_eval(&block) if block
71
          Hyalite.create_element(tag, props, *children)
72
        end
73
      end
74
75
      klass.extend ClassMethods
76
    end
77
78
    class ChildrenRenderer
79
      def initialize(component)
80
        @component = component
81
        @children = []
82
        TAGS.each do |tag|
83
          define_singleton_method(tag) do |props, *children, &block|
84
            @children << Hyalite.create_element(tag, props, *children)
85
            @children
86
          end
87
        end
88
      end
89
90
      def method_missing(method_name, *args, &block)
91
        if @component.respond_to?(method_name, true)
92
          @component.send(method_name, *args, &block)
93
        else
94
          super
95
        end
96
      end
97
98
      def respond_to_missing?(method_name, include_private = false)
99
        @component.respond_to?(method_name, include_private) || super
100
      end
101
    end
102
103
    module ClassMethods
104
      def el(props, *children)
105
        Hyalite.create_element(self, props, *children)
106
      end
107
    end
108
109
    def initial_state
110
      self.class.initial_state
111
    end
112
113
    def state
114
      @state.to_h
115
    end
116
117
    def state=(state)
118
      @state.set(state)
119
    end
120
121
    def child_context
122
      {}
123
    end
124
125
    def component_will_mount
126
      self.instance_eval(&self.class.before_mount) if self.class.before_mount
127
    end
128
129
    def component_did_mount
130
      self.instance_eval(&self.class.after_mount) if self.class.after_mount
131
    end
132
133
    def component_will_update(props, state, context)
134
      self.instance_eval(&self.class.before_update) if self.class.before_update
135
    end
136
137
    def component_did_update(props, state, context)
138
      self.instance_eval(&self.class.after_update) if self.class.after_update
139
    end
140
141
    def should_component_update(props, state, context)
142
      true
143
    end
144
145
    def force_update(&block)
146
      @updator.enqueue_force_update(self);
147
      if block_given?
148
        @updator.enqueue_callback(self, &block)
149
      end
150
    end
151
152
    def set_state(states, &block)
153
      @updator.enqueue_set_state(self, states)
154
      if block_given?
155
        @updator.enqueue_callback(self, &block)
156
      end
157
    end
158
    alias :update_state :set_state
159
160
    def method_missing(method_name, *args, &block)
161
      if @props.has_key?(method_name)
162
        @props[method_name]
163
      else
164
        super
165
      end
166
    end
167
168
    def respond_to_missing?(method_name, include_private = false)
169
      @props.has_key?(method_name) || super
170
    end
171
172
    def render
173
    end
174
175
    class State
176
      def initialize(component, updator, initial_state)
177
        @component = component
178
        @updator = updator
179
        @state = initial_state.clone
180
        initial_state.each do |key, value|
181
          define_singleton_method(key) do
182
            @state[key]
183
          end
184
          define_singleton_method(key + '=') do |value|
185
            @updator.enqueue_set_state(@component, key => value)
186
          end
187
        end
188
      end
189
190
      def [](key)
191
        @state[key]
192
      end
193
194
      def set(state)
195
        @state = state.clone
196
      end
197
198
      def to_h
199
        @state
200
      end
201
    end
202
  end
203
204
  class EmptyComponent
205
    include Component
206
207
    def self.empty_element
208
      @instance ||= ElementObject.new(EmptyComponent, nil, nil, nil, nil)
209
    end
210
211
    def render
212
      Hyalite.create_element("noscript", nil, nil)
213
    end
214
  end
215
216
  class TopLevelWrapper
217
    include Component
218
219
    def render
220
      @props
221
    end
222
  end
223
end
224