reactive-ruby 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +30 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +53 -0
- data/LICENSE +19 -0
- data/README.md +303 -0
- data/config.ru +15 -0
- data/example/examples/Gemfile +7 -0
- data/example/examples/Gemfile.lock +45 -0
- data/example/examples/config.ru +44 -0
- data/example/examples/hello.js.rb +43 -0
- data/example/react-tutorial/Gemfile +7 -0
- data/example/react-tutorial/Gemfile.lock +49 -0
- data/example/react-tutorial/README.md +8 -0
- data/example/react-tutorial/_comments.json +14 -0
- data/example/react-tutorial/config.ru +63 -0
- data/example/react-tutorial/example.js.rb +290 -0
- data/example/react-tutorial/public/base.css +62 -0
- data/example/todos/Gemfile +11 -0
- data/example/todos/Gemfile.lock +84 -0
- data/example/todos/README.md +37 -0
- data/example/todos/Rakefile +8 -0
- data/example/todos/app/application.rb +22 -0
- data/example/todos/app/components/app.react.rb +61 -0
- data/example/todos/app/components/footer.react.rb +31 -0
- data/example/todos/app/components/todo_item.react.rb +46 -0
- data/example/todos/app/components/todo_list.react.rb +25 -0
- data/example/todos/app/models/todo.rb +19 -0
- data/example/todos/config.ru +14 -0
- data/example/todos/index.html.haml +16 -0
- data/example/todos/spec/todo_spec.rb +28 -0
- data/example/todos/vendor/base.css +410 -0
- data/example/todos/vendor/bg.png +0 -0
- data/example/todos/vendor/jquery.js +4 -0
- data/lib/rails-helpers/react_component.rb +32 -0
- data/lib/reactive-ruby.rb +23 -0
- data/lib/reactive-ruby/api.rb +177 -0
- data/lib/reactive-ruby/callbacks.rb +35 -0
- data/lib/reactive-ruby/component.rb +411 -0
- data/lib/reactive-ruby/element.rb +87 -0
- data/lib/reactive-ruby/event.rb +76 -0
- data/lib/reactive-ruby/ext/hash.rb +9 -0
- data/lib/reactive-ruby/ext/string.rb +8 -0
- data/lib/reactive-ruby/isomorphic_helpers.rb +223 -0
- data/lib/reactive-ruby/observable.rb +33 -0
- data/lib/reactive-ruby/rendering_context.rb +91 -0
- data/lib/reactive-ruby/serializers.rb +15 -0
- data/lib/reactive-ruby/state.rb +90 -0
- data/lib/reactive-ruby/top_level.rb +53 -0
- data/lib/reactive-ruby/validator.rb +83 -0
- data/lib/reactive-ruby/version.rb +3 -0
- data/logo1.png +0 -0
- data/logo2.png +0 -0
- data/logo3.png +0 -0
- data/reactive-ruby.gemspec +25 -0
- data/spec/callbacks_spec.rb +107 -0
- data/spec/component_spec.rb +597 -0
- data/spec/element_spec.rb +60 -0
- data/spec/event_spec.rb +22 -0
- data/spec/react_spec.rb +209 -0
- data/spec/reactjs/index.html.erb +11 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/tutorial/tutorial_spec.rb +37 -0
- data/spec/validator_spec.rb +79 -0
- data/vendor/active_support/core_ext/array/extract_options.rb +29 -0
- data/vendor/active_support/core_ext/class/attribute.rb +127 -0
- data/vendor/active_support/core_ext/kernel/singleton_class.rb +13 -0
- data/vendor/active_support/core_ext/module/remove_method.rb +11 -0
- metadata +205 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
require "reactive-ruby/ext/string"
|
2
|
+
|
3
|
+
module React
|
4
|
+
class Element
|
5
|
+
include Native
|
6
|
+
|
7
|
+
alias_native :element_type, :type
|
8
|
+
alias_native :props, :props
|
9
|
+
|
10
|
+
attr_reader :type
|
11
|
+
attr_reader :properties
|
12
|
+
attr_reader :block
|
13
|
+
|
14
|
+
attr_accessor :waiting_on_resources
|
15
|
+
|
16
|
+
def initialize(native_element, type, properties, block)
|
17
|
+
@type = type
|
18
|
+
@properties = properties
|
19
|
+
@block = block
|
20
|
+
@native = native_element
|
21
|
+
end
|
22
|
+
|
23
|
+
def on(event_name)
|
24
|
+
name = event_name.to_s.event_camelize
|
25
|
+
if React::Event::BUILT_IN_EVENTS.include?("on#{name}")
|
26
|
+
self.props["on#{name}"] = %x{
|
27
|
+
function(event){
|
28
|
+
#{yield React::Event.new(`event`)}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
else
|
32
|
+
self.props["_on#{name}"] = %x{
|
33
|
+
function(){
|
34
|
+
#{yield *Array(`arguments`)}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(class_name, args = {}, &new_block)
|
42
|
+
class_name = class_name.split("__").collect { |s| s.gsub("_", "-") }.join("_")
|
43
|
+
new_props = properties.dup
|
44
|
+
new_props["class"] = "#{new_props['class']} #{class_name} #{args.delete("class")} #{args.delete('className')}".split(" ").uniq.join(" ")
|
45
|
+
new_props.merge! args
|
46
|
+
RenderingContext.replace(
|
47
|
+
self,
|
48
|
+
React::RenderingContext.build { React::RenderingContext.render(type, new_props, &new_block) }
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete
|
53
|
+
RenderingContext.delete(self)
|
54
|
+
end
|
55
|
+
|
56
|
+
def children
|
57
|
+
nodes = self.props.children
|
58
|
+
class << nodes
|
59
|
+
include Enumerable
|
60
|
+
|
61
|
+
def to_n
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def each(&block)
|
66
|
+
if block_given?
|
67
|
+
%x{
|
68
|
+
React.Children.forEach(#{self.to_n}, function(context){
|
69
|
+
#{block.call(React::Element.new(`context`))}
|
70
|
+
})
|
71
|
+
}
|
72
|
+
else
|
73
|
+
Enumerator.new(`React.Children.count(#{self.to_n})`) do |y|
|
74
|
+
%x{
|
75
|
+
React.Children.forEach(#{self.to_n}, function(context){
|
76
|
+
#{y << React::Element.new(`context`)}
|
77
|
+
})
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
nodes
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module React
|
2
|
+
class Event
|
3
|
+
include Native
|
4
|
+
alias_native :bubbles, :bubbles
|
5
|
+
alias_native :cancelable, :cancelable
|
6
|
+
alias_native :current_target, :currentTarget
|
7
|
+
alias_native :default_prevented, :defaultPrevented
|
8
|
+
alias_native :event_phase, :eventPhase
|
9
|
+
alias_native :is_trusted?, :isTrusted
|
10
|
+
alias_native :native_event, :nativeEvent
|
11
|
+
alias_native :target, :target
|
12
|
+
alias_native :timestamp, :timeStamp
|
13
|
+
alias_native :event_type, :type
|
14
|
+
alias_native :prevent_default, :preventDefault
|
15
|
+
alias_native :stop_propagation, :stopPropagation
|
16
|
+
# Clipboard
|
17
|
+
alias_native :clipboard_data, :clipboardData
|
18
|
+
# Keyboard
|
19
|
+
alias_native :alt_key, :altKey
|
20
|
+
alias_native :char_code, :charCode
|
21
|
+
alias_native :ctrl_key, :ctrlKey
|
22
|
+
alias_native :get_modifier_state, :getModifierState
|
23
|
+
alias_native :key, :key
|
24
|
+
alias_native :key_code, :keyCode
|
25
|
+
alias_native :locale, :locale
|
26
|
+
alias_native :location, :location
|
27
|
+
alias_native :meta_key, :metaKey
|
28
|
+
alias_native :repeat, :repeat
|
29
|
+
alias_native :shift_key, :shiftKey
|
30
|
+
alias_native :which, :which
|
31
|
+
# Focus
|
32
|
+
alias_native :related_target, :relatedTarget
|
33
|
+
# Mouse
|
34
|
+
alias_native :alt_key, :altKey
|
35
|
+
alias_native :button, :button
|
36
|
+
alias_native :buttons, :buttons
|
37
|
+
alias_native :client_x, :clientX
|
38
|
+
alias_native :client_y, :clientY
|
39
|
+
alias_native :ctrl_key, :ctrlKey
|
40
|
+
alias_native :get_modifier_state, :getModifierState
|
41
|
+
alias_native :meta_key, :metaKey
|
42
|
+
alias_native :page_x, :pageX
|
43
|
+
alias_native :page_y, :pageY
|
44
|
+
alias_native :related_target, :relatedTarget
|
45
|
+
alias_native :screen_x, :screen_x
|
46
|
+
alias_native :screen_y, :screen_y
|
47
|
+
alias_native :shift_key, :shift_key
|
48
|
+
# Touch
|
49
|
+
alias_native :alt_key, :altKey
|
50
|
+
alias_native :changed_touches, :changedTouches
|
51
|
+
alias_native :ctrl_key, :ctrlKey
|
52
|
+
alias_native :get_modifier_state, :getModifierState
|
53
|
+
alias_native :meta_key, :metaKey
|
54
|
+
alias_native :shift_key, :shiftKey
|
55
|
+
alias_native :target_touches, :targetTouches
|
56
|
+
alias_native :touches, :touches
|
57
|
+
# UI
|
58
|
+
alias_native :detail, :detail
|
59
|
+
alias_native :view, :view
|
60
|
+
# Wheel
|
61
|
+
alias_native :delta_mode, :deltaMode
|
62
|
+
alias_native :delta_x, :deltaX
|
63
|
+
alias_native :delta_y, :deltaY
|
64
|
+
alias_native :delta_z, :deltaZ
|
65
|
+
|
66
|
+
BUILT_IN_EVENTS = %w{onCopy onCut onPaste onKeyDown onKeyPress onKeyUp
|
67
|
+
onFocus onBlur onChange onInput onSubmit onClick onDoubleClick onDrag
|
68
|
+
onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop
|
69
|
+
onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver
|
70
|
+
onMouseUp onTouchCancel onTouchEnd onTouchMove onTouchStart onScroll}
|
71
|
+
|
72
|
+
def initialize(native_element)
|
73
|
+
@native = native_element
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
module React
|
2
|
+
|
3
|
+
module IsomorphicHelpers
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
if RUBY_ENGINE != 'opal'
|
10
|
+
|
11
|
+
def self.load_context(ctx, controller)
|
12
|
+
puts "************************** React Server Context Initialized *********************************************"
|
13
|
+
@context = Context.new("#{controller.object_id}-#{Time.now.to_i}", ctx, controller)
|
14
|
+
end
|
15
|
+
|
16
|
+
else
|
17
|
+
|
18
|
+
def self.load_context(unique_id = nil) # can be called on the client to force re-initialization for testing purposes
|
19
|
+
if !unique_id or !@context or @context.unique_id != unique_id
|
20
|
+
if on_opal_server?
|
21
|
+
message = "************************ React Prerendering Context Initialized ***********************"
|
22
|
+
else
|
23
|
+
message = "************************ React Browser Context Initialized ****************************"
|
24
|
+
end
|
25
|
+
log(message)
|
26
|
+
@context = Context.new(unique_id)
|
27
|
+
end
|
28
|
+
@context
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.log(message, message_type = :info)
|
34
|
+
message = [message] unless message.is_a? Array
|
35
|
+
if message_type == :info
|
36
|
+
if on_opal_server?
|
37
|
+
style = 'background: #00FFFF; color: red'
|
38
|
+
else
|
39
|
+
style = 'background: #222; color: #bada55'
|
40
|
+
end
|
41
|
+
message = ["%c" + message[0], style]+message[1..-1]
|
42
|
+
`console.log.apply(console, message)`
|
43
|
+
elsif message_type == :warning
|
44
|
+
`console.warn.apply(console, message)`
|
45
|
+
else
|
46
|
+
`console.error.apply(console, message)`
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if RUBY_ENGINE != 'opal'
|
51
|
+
|
52
|
+
def self.on_opal_server?
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.on_opal_client?
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
else
|
61
|
+
|
62
|
+
def self.on_opal_server?
|
63
|
+
`typeof window.document === 'undefined'`
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.on_opal_client?
|
67
|
+
!on_opal_server?
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
def log(*args)
|
73
|
+
IsomorphicHelpers.log(*args)
|
74
|
+
end
|
75
|
+
|
76
|
+
def on_opal_server?
|
77
|
+
IsomorphicHelpers.on_opal_server?
|
78
|
+
end
|
79
|
+
|
80
|
+
def on_opal_client?
|
81
|
+
IsomorphicHelpers.on_opal_client?
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.prerender_footers
|
85
|
+
footer = Context.prerender_footer_blocks.collect { |block| block.call }.join("\n")
|
86
|
+
if RUBY_ENGINE != 'opal'
|
87
|
+
footer = (footer + "#{@context.send_to_opal(:prerender_footers)}") if @context
|
88
|
+
footer = footer.html_safe
|
89
|
+
end
|
90
|
+
footer
|
91
|
+
end
|
92
|
+
|
93
|
+
class Context
|
94
|
+
|
95
|
+
attr_reader :controller
|
96
|
+
attr_reader :unique_id
|
97
|
+
|
98
|
+
def self.before_first_mount_blocks
|
99
|
+
@before_first_mount_blocks ||= []
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.prerender_footer_blocks
|
103
|
+
@prerender_footer_blocks ||= []
|
104
|
+
end
|
105
|
+
|
106
|
+
def initialize(unique_id, ctx = nil, controller = nil)
|
107
|
+
@unique_id = unique_id
|
108
|
+
if RUBY_ENGINE != 'opal'
|
109
|
+
@controller = controller
|
110
|
+
@ctx = ctx
|
111
|
+
ctx["ServerSideIsomorphicMethods"] = self
|
112
|
+
send_to_opal(:load_context, @unique_id)
|
113
|
+
end
|
114
|
+
self.class.before_first_mount_blocks.each { |block| block.call(self) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def eval(js)
|
118
|
+
@ctx.eval(js) if @ctx
|
119
|
+
end
|
120
|
+
|
121
|
+
def send_to_opal(method, *args)
|
122
|
+
args = [1] if args.length == 0
|
123
|
+
if @ctx
|
124
|
+
unless @ctx.eval('Opal.React')
|
125
|
+
@ctx.eval(Opal::Processor.load_asset_code(::Rails.application.assets, 'components')) rescue nil
|
126
|
+
raise "No opal-react components found in the components.rb file" unless @ctx.eval('Opal.React')
|
127
|
+
end
|
128
|
+
@ctx.eval("Opal.React.IsomorphicHelpers.$#{method}(#{args.join(', ')})")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.register_before_first_mount_block(&block)
|
133
|
+
before_first_mount_blocks << block
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.register_prerender_footer_block(&block)
|
137
|
+
prerender_footer_blocks << block
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
class IsomorphicProcCall
|
143
|
+
|
144
|
+
def result
|
145
|
+
@result.first if @result
|
146
|
+
end
|
147
|
+
|
148
|
+
def initialize(name, block, *args)
|
149
|
+
@name = name
|
150
|
+
block.call(self, *args)
|
151
|
+
@result ||= send_to_server(*args) if IsomorphicHelpers.on_opal_server?
|
152
|
+
end
|
153
|
+
|
154
|
+
def when_on_client(&block)
|
155
|
+
@result = [block.call] if IsomorphicHelpers.on_opal_client?
|
156
|
+
end
|
157
|
+
|
158
|
+
def send_to_server(*args)
|
159
|
+
if IsomorphicHelpers.on_opal_server?
|
160
|
+
args_as_json = args.to_json
|
161
|
+
@result = [JSON.parse(`window.ServerSideIsomorphicMethods[#{@name}](#{args_as_json})`)]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def when_on_server(&block)
|
166
|
+
@result = [block.call.to_json] unless IsomorphicHelpers.on_opal_client? or IsomorphicHelpers.on_opal_server?
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
module ClassMethods
|
173
|
+
|
174
|
+
def on_opal_server?
|
175
|
+
IsomorphicHelpers.on_opal_server?
|
176
|
+
end
|
177
|
+
|
178
|
+
def on_opal_client?
|
179
|
+
IsomorphicHelpers.on_opal_client?
|
180
|
+
end
|
181
|
+
|
182
|
+
def log(*args)
|
183
|
+
IsomorphicHelpers.log(*args)
|
184
|
+
end
|
185
|
+
|
186
|
+
def controller
|
187
|
+
IsomorphicHelpers.context.controller
|
188
|
+
end
|
189
|
+
|
190
|
+
def before_first_mount(&block)
|
191
|
+
React::IsomorphicHelpers::Context.register_before_first_mount_block &block
|
192
|
+
end
|
193
|
+
|
194
|
+
def prerender_footer(&block)
|
195
|
+
React::IsomorphicHelpers::Context.register_prerender_footer_block &block
|
196
|
+
end
|
197
|
+
|
198
|
+
if RUBY_ENGINE != 'opal'
|
199
|
+
|
200
|
+
def isomorphic_method(name, &block)
|
201
|
+
React::IsomorphicHelpers::Context.send(:define_method, name) do |args_as_json|
|
202
|
+
React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, *JSON.parse(args_as_json)).result
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
else
|
207
|
+
|
208
|
+
require 'json'
|
209
|
+
|
210
|
+
def isomorphic_method(name, &block)
|
211
|
+
self.class.send(:define_method, name) do | *args |
|
212
|
+
React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, *args).result
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module React
|
2
|
+
|
3
|
+
class Observable
|
4
|
+
|
5
|
+
def initialize(value, on_change = nil, &block)
|
6
|
+
@value = value
|
7
|
+
@on_change = on_change || block
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method_sym, *args, &block)
|
11
|
+
@value.send(method_sym, *args, &block).tap { |result| @on_change.call result }
|
12
|
+
end
|
13
|
+
|
14
|
+
def respond_to?(method, *args)
|
15
|
+
if [:call, :to_proc].include? method
|
16
|
+
true
|
17
|
+
else
|
18
|
+
@value.respond_to? method, *args
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(new_value)
|
23
|
+
@on_change.call new_value
|
24
|
+
@value = new_value
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_proc
|
28
|
+
lambda { |arg = @value| @on_change.call arg }
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module React
|
2
|
+
|
3
|
+
class RenderingContext
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :waiting_on_resources
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.render(name, *args, &block)
|
10
|
+
@buffer = [] unless @buffer
|
11
|
+
if block
|
12
|
+
element = build do
|
13
|
+
saved_waiting_on_resources = waiting_on_resources
|
14
|
+
self.waiting_on_resources = nil
|
15
|
+
result = block.call
|
16
|
+
# Todo figure out how children rendering should happen, probably should have special method that pushes children into the buffer
|
17
|
+
# i.e. render_child/render_children that takes Element/Array[Element] and does the push into the buffer
|
18
|
+
if !name and ( # !name means called from outer render so we check that it has rendered correctly
|
19
|
+
(@buffer.count > 1) or # should only render one element
|
20
|
+
(@buffer.count == 1 and @buffer.last != result) or # it should return that element
|
21
|
+
(@buffer.count == 0 and !(result.is_a? String or (result.respond_to? :acts_as_string? and result.acts_as_string?) or result.is_a? Element)) #for convience we will also convert the return value to a span if its a string
|
22
|
+
)
|
23
|
+
raise "a components render method must generate and return exactly 1 element or a string"
|
24
|
+
end
|
25
|
+
|
26
|
+
@buffer << result.to_s if result.is_a? String or (result.respond_to? :acts_as_string? and result.acts_as_string?) # For convience we push the last return value on if its a string
|
27
|
+
@buffer << result if result.is_a? Element and @buffer.count == 0
|
28
|
+
if name
|
29
|
+
buffer = @buffer.dup
|
30
|
+
React.create_element(name, *args) { buffer }.tap do |element|
|
31
|
+
element.waiting_on_resources = saved_waiting_on_resources || !!buffer.detect { |e| e.waiting_on_resources if e.respond_to? :waiting_on_resources }
|
32
|
+
end
|
33
|
+
elsif @buffer.last.is_a? React::Element
|
34
|
+
@buffer.last.tap { |element| element.waiting_on_resources ||= saved_waiting_on_resources }
|
35
|
+
else
|
36
|
+
@buffer.last.to_s.span.tap { |element| element.waiting_on_resources = saved_waiting_on_resources }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
else
|
40
|
+
element = React.create_element(name, *args)
|
41
|
+
element.waiting_on_resources = waiting_on_resources
|
42
|
+
end
|
43
|
+
@buffer << element
|
44
|
+
self.waiting_on_resources = nil
|
45
|
+
element
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.build(&block)
|
49
|
+
current = @buffer
|
50
|
+
@buffer = []
|
51
|
+
return_val = yield @buffer
|
52
|
+
@buffer = current
|
53
|
+
return_val
|
54
|
+
#ensure
|
55
|
+
# @buffer = current
|
56
|
+
# return_val
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.as_node(element)
|
60
|
+
@buffer.delete(element)
|
61
|
+
element
|
62
|
+
end
|
63
|
+
|
64
|
+
class << self; alias_method :delete, :as_node; end
|
65
|
+
|
66
|
+
def self.replace(e1, e2)
|
67
|
+
@buffer[@buffer.index(e1)] = e2
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class ::Object
|
73
|
+
|
74
|
+
alias_method :old_method_missing, :method_missing
|
75
|
+
|
76
|
+
["span", "para", "td", "th", "while_loading"].each do |tag|
|
77
|
+
define_method(tag) do | *args, &block |
|
78
|
+
args.unshift(tag)
|
79
|
+
return self.method_missing(*args, &block) if self.is_a? React::Component
|
80
|
+
React::RenderingContext.render(*args) { self.to_s }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def br
|
85
|
+
return self.method_missing(*["br"]) if self.is_a? React::Component
|
86
|
+
React::RenderingContext.render("span") { React::RenderingContext.render(self.to_s); React::RenderingContext.render("br") }
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|