react-opal 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bbee40ce70c05f1c8be8904a0516736a898e0965
4
+ data.tar.gz: 3cb8fa21df7d35d38041b72ba48354e4f0bdf183
5
+ SHA512:
6
+ metadata.gz: 9a8506067fcb72df4a5c1b1160229a209bec151a37c3b36e932a1ea27ad27d02d08aafc88d7b8f5ece44e2a8e34cecdc4629500930ed20e2179c58e392206719
7
+ data.tar.gz: c88db5dc1b1a919992ed9d5aafae113b5ca62c75b00e36687aff4ae72172e2137e4765129263f2a8daf46894cee33292700e5a51afbe9bac1ba1c7a6fea41c3b
data/lib/react-opal.rb ADDED
@@ -0,0 +1,15 @@
1
+ if RUBY_ENGINE == 'opal'
2
+ require 'react/opal/top_level'
3
+ require 'react/opal/props_children'
4
+ require 'react/opal/component'
5
+ require 'react/opal/native_element'
6
+ require 'react/opal/event'
7
+ require 'react/opal/component_factory'
8
+ require 'react/opal/validator'
9
+ else
10
+ require 'opal'
11
+ require 'react/opal/version'
12
+ require 'opal-activesupport'
13
+
14
+ Opal.append_path File.expand_path('../', __FILE__).untaint
15
+ end
@@ -0,0 +1,35 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+
3
+ module React
4
+ module Callbacks
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ def run_callback(name, *args)
10
+ attribute_name = "_#{name}_callbacks"
11
+ callbacks = self.class.send(attribute_name)
12
+ callbacks.each do |callback|
13
+ if callback.is_a?(Proc)
14
+ instance_exec(*args, &callback)
15
+ else
16
+ send(callback, *args)
17
+ end
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ def define_callback(callback_name)
23
+ attribute_name = "_#{callback_name}_callbacks"
24
+ class_attribute(attribute_name)
25
+ self.send("#{attribute_name}=", [])
26
+ define_singleton_method(callback_name) do |*args, &block|
27
+ callbacks = self.send(attribute_name)
28
+ callbacks.concat(args)
29
+ callbacks.push(block) if block_given?
30
+ self.send("#{attribute_name}=", callbacks)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,221 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+ require 'react/opal/callbacks'
3
+ require 'react/opal/ext/hash'
4
+ require 'react/opal/component/api'
5
+
6
+ module React
7
+ module Component
8
+ def self.included(base)
9
+ base.include(API)
10
+ base.include(React::Callbacks)
11
+ base.class_eval do
12
+ class_attribute :init_state, :validator, :context_types, :child_context_types, :child_context_get
13
+ define_callback :before_mount
14
+ define_callback :after_mount
15
+ define_callback :before_receive_props
16
+ define_callback :before_update
17
+ define_callback :after_update
18
+ define_callback :before_unmount
19
+ end
20
+ base.extend(ClassMethods)
21
+ end
22
+
23
+ def params
24
+ Hash.new(`#{self}.props`).inject({}) do |memo, (k, v)|
25
+ memo[k.underscore] = v
26
+ memo
27
+ end
28
+ end
29
+
30
+ def refs
31
+ Hash.new(`#{self}.refs`)
32
+ end
33
+
34
+ def context
35
+ Hash.new(`#{self}.context`)
36
+ end
37
+
38
+ def emit(event_name, *args)
39
+ self.params["on_#{event_name.to_s}"].call(*args)
40
+ end
41
+
42
+ def component_will_mount
43
+ self.run_callback(:before_mount)
44
+ end
45
+
46
+ def component_did_mount
47
+ self.run_callback(:after_mount)
48
+ end
49
+
50
+ def component_will_receive_props(next_props)
51
+ self.run_callback(:before_receive_props, Hash.new(next_props))
52
+ end
53
+
54
+ def should_component_update?(next_props, next_state)
55
+ self.respond_to?(:needs_update?) ? self.needs_update?(Hash.new(next_props), Hash.new(next_state)) : true
56
+ end
57
+
58
+ def component_will_update(next_props, next_state)
59
+ self.run_callback(:before_update, Hash.new(next_props), Hash.new(next_state))
60
+ end
61
+
62
+ def component_did_update(prev_props, prev_state)
63
+ self.run_callback(:after_update, Hash.new(prev_props), Hash.new(prev_state))
64
+ end
65
+
66
+ def component_will_unmount
67
+ self.run_callback(:before_unmount)
68
+ end
69
+
70
+ def p(*args, &block)
71
+ if block || args.count == 0 || (args.count == 1 && args.first.is_a?(Hash))
72
+ _p_tag(*args, &block)
73
+ else
74
+ Kernel.p(*args)
75
+ end
76
+ end
77
+
78
+ def method_missing(name, *args, &block)
79
+ unless (React::HTML_TAGS.include?(name) || name == 'present' || name == '_p_tag')
80
+ return super
81
+ end
82
+
83
+ if name == "present"
84
+ name = args.shift
85
+ end
86
+
87
+ if name == "_p_tag"
88
+ name = "p"
89
+ end
90
+
91
+ @buffer = [] unless @buffer
92
+ if block
93
+ current = @buffer
94
+ @buffer = []
95
+ result = block.call
96
+ element = React.create_element(name, *args) { @buffer.count == 0 ? result : @buffer }
97
+ @buffer = current
98
+ else
99
+ element = React.create_element(name, *args)
100
+ end
101
+
102
+ @buffer << element
103
+ element
104
+ end
105
+
106
+ def to_n
107
+ self
108
+ end
109
+
110
+ module ClassMethods
111
+ def prop_types
112
+ if self.validator
113
+ {
114
+ _componentValidator: %x{
115
+ function(props, propName, componentName) {
116
+ var errors = #{validator.validate(Hash.new(`props`))};
117
+ var error = new Error(#{"In component `" + self.name + "`\n" + `errors`.join("\n")});
118
+ return #{`errors`.count > 0 ? `error` : `undefined`};
119
+ }
120
+ }
121
+ }
122
+ else
123
+ {}
124
+ end
125
+ end
126
+
127
+ def initial_state
128
+ self.init_state || {}
129
+ end
130
+
131
+ def default_props
132
+ self.validator ? self.validator.default_props : {}
133
+ end
134
+
135
+ def params(&block)
136
+ if self.validator
137
+ self.validator.evaluate_more_rules(&block)
138
+ else
139
+ self.validator = React::Validator.build(&block)
140
+ end
141
+ end
142
+
143
+ def define_state_prop(prop, &block)
144
+ define_state prop
145
+ update_value = lambda do |new_value|
146
+ new_value = instance_exec(new_value, &block) if block
147
+ self.send("#{prop}=", new_value)
148
+ end
149
+ before_mount do
150
+ # need to execute in context of each object
151
+ instance_exec params[prop], &update_value
152
+ end
153
+ before_receive_props do |new_props|
154
+ # need to execute in context of each object
155
+ instance_exec new_props[prop], &update_value
156
+ end
157
+ end
158
+
159
+ def get_prop_type(klass)
160
+ if klass == Proc
161
+ `React.PropTypes.func`
162
+ elsif klass.is_a?(Proc)
163
+ `React.PropTypes.object`
164
+ elsif klass == Boolean
165
+ `React.PropTypes.bool`
166
+ elsif klass.ancestors.include?(Numeric)
167
+ `React.PropTypes.number`
168
+ elsif klass == String
169
+ `React.PropTypes.string`
170
+ elsif klass == Array
171
+ `React.PropTypes.array`
172
+ else
173
+ `React.PropTypes.object`
174
+ end
175
+ end
176
+
177
+ def consume_context(item, klass)
178
+ self.context_types ||= {}
179
+ self.context_types[item] = get_prop_type(klass)
180
+ end
181
+
182
+ def provide_context(item, klass, &block)
183
+ self.child_context_types ||= {}
184
+ self.child_context_types[item] = get_prop_type(klass)
185
+ self.child_context_get ||= {}
186
+ self.child_context_get[item] = block
187
+ unless method_defined?(:get_child_context)
188
+ define_method(:get_child_context) do
189
+ Hash[self.child_context_get.map do |item, blk|
190
+ [item, instance_eval(&blk)]
191
+ end].to_n
192
+ end
193
+ end
194
+ end
195
+
196
+ def define_state(*states)
197
+ raise "Block could be only given when define exactly one state" if block_given? && states.count > 1
198
+
199
+ self.init_state = {} unless self.init_state
200
+
201
+ if block_given?
202
+ self.init_state[states[0]] = yield
203
+ end
204
+ states.each do |name|
205
+ # getter
206
+ define_method("#{name}") do
207
+ self.state[name]
208
+ end
209
+ # setter
210
+ define_method("#{name}=") do |new_state|
211
+ hash = {}
212
+ hash[name] = new_state
213
+ self.set_state(hash)
214
+
215
+ new_state
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,29 @@
1
+ module React
2
+ module Component
3
+ module API
4
+ def self.included(base)
5
+ base.include(::React::PropsChildren)
6
+ end
7
+
8
+ def state
9
+ Hash.new(`#{self}.state`)
10
+ end
11
+
12
+ def force_update!
13
+ `#{self}.forceUpdate()`
14
+ end
15
+
16
+ def set_state(state, &block)
17
+ %x{
18
+ #{self}.setState(#{state.shallow_to_n}, function(){
19
+ #{block.call if block}
20
+ });
21
+ }
22
+ end
23
+
24
+ def dom_node
25
+ raise "`dom_node` is deprecated in favor of `React.find_dom_node`"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,78 @@
1
+ module React
2
+ class ComponentFactory
3
+ @@component_classes = {}
4
+
5
+ def self.clear_component_class_cache
6
+ @@component_classes = {}
7
+ end
8
+
9
+ def self.native_component_class(klass)
10
+ @@component_classes[klass.to_s] ||= begin
11
+ klass.class_eval do
12
+ include(React::Component::API)
13
+ # In Opal 0.8, native_alias fails if the method isn't there but we don't want to force all of these to be implemented
14
+ optional_native_alias = lambda do |js, ruby|
15
+ not_there = `!(#{self}.$$proto['$' + #{ruby}])`
16
+ native_alias js, ruby unless not_there
17
+ end
18
+ optional_native_alias[:componentWillMount, :component_will_mount]
19
+ optional_native_alias[:componentDidMount, :component_did_mount]
20
+ optional_native_alias[:componentWillReceiveProps, :component_will_receive_props]
21
+ optional_native_alias[:shouldComponentUpdate, :should_component_update?]
22
+ optional_native_alias[:componentWillUpdate, :component_will_update]
23
+ optional_native_alias[:componentDidUpdate, :component_did_update]
24
+ optional_native_alias[:componentWillUnmount, :component_will_unmount]
25
+ optional_native_alias[:getChildContext, :get_child_context]
26
+ native_alias :render, :render
27
+ end
28
+ %x{
29
+ if (!Object.assign) {
30
+ Object.defineProperty(Object, 'assign', {
31
+ enumerable: false,
32
+ configurable: true,
33
+ writable: true,
34
+ value: function(target, firstSource) {
35
+ 'use strict';
36
+ if (target === undefined || target === null) {
37
+ throw new TypeError('Cannot convert first argument to object');
38
+ }
39
+
40
+ var to = Object(target);
41
+ for (var i = 1; i < arguments.length; i++) {
42
+ var nextSource = arguments[i];
43
+ if (nextSource === undefined || nextSource === null) {
44
+ continue;
45
+ }
46
+
47
+ var keysArray = Object.keys(Object(nextSource));
48
+ for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
49
+ var nextKey = keysArray[nextIndex];
50
+ var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
51
+ if (desc !== undefined && desc.enumerable) {
52
+ to[nextKey] = nextSource[nextKey];
53
+ }
54
+ }
55
+ }
56
+ return to;
57
+ }
58
+ });
59
+ }
60
+ function ctor(props){
61
+ this.constructor = ctor;
62
+ this.state = #{klass.respond_to?(:initial_state) ? klass.initial_state.to_n : `{}`};
63
+ React.Component.apply(this, arguments);
64
+ #{klass}.$$alloc.prototype.$initialize.call(this, Opal.Hash.$new(props));
65
+ };
66
+ ctor.prototype = klass.$$proto;
67
+ Object.assign(ctor.prototype, React.Component.prototype);
68
+ ctor.propTypes = #{klass.respond_to?(:prop_types) ? klass.prop_types.to_n : `{}`};
69
+ ctor.contextTypes = #{klass.respond_to?(:context_types) ? klass.context_types.to_n : `{}`};
70
+ ctor.childContextTypes = #{klass.respond_to?(:child_context_types) ? klass.child_context_types.to_n : `{}`};
71
+ ctor.defaultProps = #{klass.respond_to?(:default_props) ? klass.default_props.to_n : `{}`};
72
+ ctor.displayName = #{klass.to_s};
73
+ }
74
+ `ctor`
75
+ end
76
+ end
77
+ end
78
+ 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,9 @@
1
+ class Hash
2
+ def shallow_to_n
3
+ hash = `{}`
4
+ self.map do |key, value|
5
+ `hash[#{key}] = #{value}`
6
+ end
7
+ hash
8
+ end
9
+ end
@@ -0,0 +1,52 @@
1
+ module React
2
+ class NativeElement
3
+ include PropsChildren
4
+
5
+ # As of React 0.14, elements are now just plain object literals, so we can't inherit anymore
6
+ # We can just set each of the properties on our object though
7
+ # See var ReactElement = function (type, key, ref, self, source, owner, props) in the React source
8
+ def initialize(native)
9
+ %x{
10
+ self.$$typeof = #{native}.$$typeof;
11
+ self.type = #{native}.type;
12
+ self.key = #{native}.key;
13
+ self.ref = #{native}.ref;
14
+ self.props = #{native}.props;
15
+ self._owner = #{native}._owner;
16
+ self._store = #{native}._store;
17
+ self._self = #{native}._self;
18
+ self._source = #{native}._source;
19
+ }
20
+ end
21
+
22
+ def element_type
23
+ self.JS[:type]
24
+ end
25
+
26
+ def on(event_name)
27
+ name = event_name.to_s.camelize
28
+
29
+ prop_key = "on#{name}"
30
+
31
+ if React::Event::BUILT_IN_EVENTS.include?(prop_key)
32
+ callback = %x{
33
+ function(event){
34
+ #{yield React::Event.new(`event`)}
35
+ }
36
+ }
37
+ else
38
+ callback = %x{
39
+ function(){
40
+ #{yield *Array(`arguments`)}
41
+ }
42
+ }
43
+ end
44
+
45
+ new_prop = `{}`
46
+ `new_prop[prop_key] = #{callback}`
47
+
48
+ cloned = `React.cloneElement(#{self}, #{new_prop})`
49
+ React::NativeElement.new cloned
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,50 @@
1
+ module React
2
+ module PropsChildren
3
+ def props
4
+ Hash.new(`#{self}.props`)
5
+ end
6
+
7
+ def children
8
+ nodes = `#{self}.props.children`
9
+
10
+ if `React.Children.count(nodes)` == 0
11
+ `[]`
12
+ elsif `React.Children.count(nodes)` == 1
13
+ if `(typeof nodes === 'string') || (typeof nodes === 'number')`
14
+ [nodes]
15
+ else
16
+ `[React.Children.only(nodes)]`
17
+ end
18
+ else
19
+ # Not sure the overhead of doing this..
20
+ class << nodes
21
+ include Enumerable
22
+
23
+ def to_n
24
+ self
25
+ end
26
+
27
+ def each(&block)
28
+ if block_given?
29
+ %x{
30
+ React.Children.forEach(#{self.to_n}, function(context){
31
+ #{block.call(`context`)}
32
+ })
33
+ }
34
+ else
35
+ Enumerator.new(`React.Children.count(#{self.to_n})`) do |y|
36
+ %x{
37
+ React.Children.forEach(#{self.to_n}, function(context){
38
+ #{y << `context`}
39
+ })
40
+ }
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ nodes
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,14 @@
1
+ module React
2
+ module Testing
3
+ `var ReactTestUtils = React.addons.TestUtils`
4
+
5
+ def simulate_event(event_name, dom_element, event_data = {})
6
+ simulator = Native(`ReactTestUtils.Simulate`)
7
+ simulator[event_name].call(dom_element, event_data)
8
+ end
9
+
10
+ def render_to_document(element)
11
+ `ReactTestUtils.renderIntoDocument(#{element})`
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,101 @@
1
+ require 'native'
2
+ require 'active_support'
3
+
4
+ module React
5
+ HTML_TAGS = %w(a abbr address area article aside audio b base bdi bdo big blockquote body br
6
+ button canvas caption cite code col colgroup data datalist dd del details dfn
7
+ dialog div dl dt em embed fieldset figcaption figure footer form h1 h2 h3 h4 h5
8
+ h6 head header hr html i iframe img input ins kbd keygen label legend li link
9
+ main map mark menu menuitem meta meter nav noscript object ol optgroup option
10
+ output p param picture pre progress q rp rt ruby s samp script section select
11
+ small source span strong style sub summary sup table tbody td textarea tfoot th
12
+ thead time title tr track u ul var video wbr)
13
+
14
+ def self.create_element(type, properties = {})
15
+ params = []
16
+
17
+ # Component Spec or Normal DOM
18
+ native = `(typeof type === 'function')` || HTML_TAGS.include?(type)
19
+ params << if native
20
+ type
21
+ elsif type.kind_of?(Class)
22
+ raise "Provided class should define `render` method" if !(type.method_defined? :render)
23
+ React::ComponentFactory.native_component_class(type)
24
+ else
25
+ raise "#{type} not implemented"
26
+ end
27
+
28
+ # Passed in properties
29
+ props = camel_case_hash_keys(properties) do |key, value|
30
+ if key == "class_name" && value.is_a?(Hash)
31
+ value.inject([]) { |ary, (k, v)| v ? ary.push(k) : ary }.join(" ")
32
+ elsif key == 'value_link'
33
+ process_value_link value
34
+ else
35
+ value
36
+ end
37
+ end
38
+
39
+ params << props.shallow_to_n
40
+
41
+ # Children Nodes
42
+ if block_given?
43
+ [yield].flatten.each do |ele|
44
+ params << ele
45
+ end
46
+ end
47
+
48
+ element = `React.createElement.apply(null, #{params})`
49
+ React::NativeElement.new(element)
50
+ end
51
+
52
+ def self.lower_camelize(str)
53
+ camelized = str.camelize
54
+ camelized[0].downcase + camelized[1..-1]
55
+ end
56
+
57
+ def self.camel_case_hash_keys(input)
58
+ as_array = input.map do |key, value|
59
+ new_value = block_given? ? yield(key, value) : value
60
+ [lower_camelize(key), new_value]
61
+ end
62
+ Hash[as_array]
63
+ end
64
+
65
+ def self.process_value_link(arguments)
66
+ arguments = arguments.call if arguments.is_a? Proc
67
+ camel_case_hash_keys(arguments).to_n
68
+ end
69
+
70
+ def self.render(element, container)
71
+ component = Native(`ReactDOM.render(#{element}, container, function(){#{yield if block_given?}})`)
72
+ component.class.include(React::Component::API)
73
+ component
74
+ end
75
+
76
+ def self.is_valid_element(element)
77
+ `React.isValidElement(#{element})`
78
+ end
79
+
80
+ def self.render_to_string(element)
81
+ `ReactDOMServer.renderToString(#{element})`
82
+ end
83
+
84
+ def self.render_to_static_markup(element)
85
+ `ReactDOMServer.renderToStaticMarkup(#{element})`
86
+ end
87
+
88
+ def self.unmount_component_at_node(node)
89
+ `ReactDOM.unmountComponentAtNode(node)`
90
+ end
91
+
92
+ def self.expose_native_class(*args)
93
+ args.each do |klass|
94
+ `window[#{klass.to_s}] = #{React::ComponentFactory.native_component_class(klass)}`
95
+ end
96
+ end
97
+
98
+ def self.find_dom_node(component)
99
+ `ReactDOM.findDOMNode(#{component})`
100
+ end
101
+ end
@@ -0,0 +1,69 @@
1
+ module React
2
+ class Validator
3
+ def self.build(&block)
4
+ validator = self.new
5
+ validator.instance_eval(&block)
6
+ validator
7
+ end
8
+
9
+ def initialize
10
+ @rules = {}
11
+ end
12
+
13
+ def evaluate_more_rules(&block)
14
+ self.instance_eval(&block)
15
+ end
16
+
17
+ def requires(prop_name, options = {})
18
+ rule = options
19
+ options[:required] = true
20
+ @rules[prop_name] = options
21
+ end
22
+
23
+ def optional(prop_name, options = {})
24
+ rule = options
25
+ options[:required] = false
26
+ @rules[prop_name] = options
27
+ end
28
+
29
+ def validate(props)
30
+ errors = []
31
+ props.keys.each do |prop_name|
32
+ errors << "Provided prop `#{prop_name}` not specified in spec" if @rules[prop_name] == nil
33
+ end
34
+
35
+ props = props.select {|key| @rules.keys.include?(key) }
36
+
37
+ # requires or not
38
+ (@rules.keys - props.keys).each do |prop_name|
39
+ errors << "Required prop `#{prop_name}` was not specified" if @rules[prop_name][:required]
40
+ end
41
+
42
+ # type
43
+ props.each do |prop_name, value|
44
+ if klass = @rules[prop_name][:type]
45
+ if klass.is_a?(Array)
46
+ errors << "Provided prop `#{prop_name}` was not an Array of the specified type `#{klass[0]}`" unless value.all?{ |ele| ele.is_a?(klass[0]) }
47
+ else
48
+ errors << "Provided prop `#{prop_name}` was not the specified type `#{klass}`" unless value.is_a?(klass)
49
+ end
50
+ end
51
+ end
52
+
53
+ # values
54
+ props.each do |prop_name, value|
55
+ if values = @rules[prop_name][:values]
56
+ errors << "Value `#{value}` for prop `#{prop_name}` is not an allowed value" unless values.include?(value)
57
+ end
58
+ end
59
+
60
+ errors
61
+ end
62
+
63
+ def default_props
64
+ @rules
65
+ .select {|key, value| value.keys.include?("default") }
66
+ .inject({}) {|memo, (k,v)| memo[k] = v[:default]; memo}
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module React
2
+ VERSION = '0.14.1'
3
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: react-opal
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.14.1
5
+ platform: ruby
6
+ authors:
7
+ - Brady Wied
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: opal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: opal-activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.0
41
+ description: Write reactive UI component with Ruby's elegancy and compiled to run
42
+ in Javascript.
43
+ email: brady@bswtechconsulting.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/react-opal.rb
49
+ - lib/react/opal/callbacks.rb
50
+ - lib/react/opal/component.rb
51
+ - lib/react/opal/component/api.rb
52
+ - lib/react/opal/component_factory.rb
53
+ - lib/react/opal/event.rb
54
+ - lib/react/opal/ext/hash.rb
55
+ - lib/react/opal/native_element.rb
56
+ - lib/react/opal/props_children.rb
57
+ - lib/react/opal/testing.rb
58
+ - lib/react/opal/top_level.rb
59
+ - lib/react/opal/validator.rb
60
+ - lib/react/opal/version.rb
61
+ homepage: https://github.com/wied03/react-opal
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.6.1
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Opal Ruby wrapper of React.js library.
85
+ test_files: []