hyper-react 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +27 -0
  3. data/.gitignore +36 -0
  4. data/.rubocop.yml +1159 -0
  5. data/.travis.yml +29 -0
  6. data/Appraisals +20 -0
  7. data/CHANGELOG.md +93 -0
  8. data/Gemfile +6 -0
  9. data/LICENSE +19 -0
  10. data/README.md +121 -0
  11. data/Rakefile +33 -0
  12. data/UPGRADING.md +24 -0
  13. data/component-name-lookup.md +145 -0
  14. data/config.ru +25 -0
  15. data/gemfiles/opal_0.8_react_13.gemfile +13 -0
  16. data/gemfiles/opal_0.8_react_14.gemfile +13 -0
  17. data/gemfiles/opal_0.8_react_15.gemfile +13 -0
  18. data/gemfiles/opal_0.9_react_13.gemfile +13 -0
  19. data/gemfiles/opal_0.9_react_14.gemfile +13 -0
  20. data/gemfiles/opal_0.9_react_15.gemfile +13 -0
  21. data/hyper-react.gemspec +43 -0
  22. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +4 -0
  23. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
  24. data/lib/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
  25. data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
  26. data/lib/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
  27. data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
  28. data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
  29. data/lib/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
  30. data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +109 -0
  31. data/lib/hyper-react.rb +52 -0
  32. data/lib/rails-helpers/top_level_rails_component.rb +54 -0
  33. data/lib/react-sources/react-server.js +2 -0
  34. data/lib/react/api.rb +162 -0
  35. data/lib/react/callbacks.rb +42 -0
  36. data/lib/react/children.rb +30 -0
  37. data/lib/react/component.rb +139 -0
  38. data/lib/react/component/api.rb +50 -0
  39. data/lib/react/component/base.rb +9 -0
  40. data/lib/react/component/class_methods.rb +214 -0
  41. data/lib/react/component/dsl_instance_methods.rb +27 -0
  42. data/lib/react/component/params.rb +6 -0
  43. data/lib/react/component/props_wrapper.rb +83 -0
  44. data/lib/react/component/should_component_update.rb +98 -0
  45. data/lib/react/component/tags.rb +144 -0
  46. data/lib/react/element.rb +168 -0
  47. data/lib/react/event.rb +76 -0
  48. data/lib/react/ext/hash.rb +9 -0
  49. data/lib/react/ext/string.rb +8 -0
  50. data/lib/react/hash.rb +13 -0
  51. data/lib/react/native_library.rb +92 -0
  52. data/lib/react/object.rb +15 -0
  53. data/lib/react/observable.rb +29 -0
  54. data/lib/react/react-source.rb +9 -0
  55. data/lib/react/rendering_context.rb +142 -0
  56. data/lib/react/state.rb +190 -0
  57. data/lib/react/test.rb +16 -0
  58. data/lib/react/test/dsl.rb +17 -0
  59. data/lib/react/test/matchers/render_html_matcher.rb +49 -0
  60. data/lib/react/test/rspec.rb +15 -0
  61. data/lib/react/test/session.rb +46 -0
  62. data/lib/react/top_level.rb +132 -0
  63. data/lib/react/validator.rb +136 -0
  64. data/lib/reactive-ruby/component_loader.rb +49 -0
  65. data/lib/reactive-ruby/isomorphic_helpers.rb +197 -0
  66. data/lib/reactive-ruby/rails.rb +7 -0
  67. data/lib/reactive-ruby/rails/component_mount.rb +46 -0
  68. data/lib/reactive-ruby/rails/controller_helper.rb +15 -0
  69. data/lib/reactive-ruby/rails/railtie.rb +14 -0
  70. data/lib/reactive-ruby/serializers.rb +15 -0
  71. data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +42 -0
  72. data/lib/reactive-ruby/version.rb +3 -0
  73. data/lib/reactrb/auto-import.rb +32 -0
  74. data/lib/reactrb/deep-compare.rb +24 -0
  75. data/lib/reactrb/new-event-name-convention.rb +11 -0
  76. data/lib/sources/react-latest.js +21169 -0
  77. data/lib/sources/react-v13.js +21645 -0
  78. data/lib/sources/react-v14.js +20821 -0
  79. data/lib/sources/react-v15.js +21170 -0
  80. data/logo1.png +0 -0
  81. data/logo2.png +0 -0
  82. data/logo3.png +0 -0
  83. data/path_release_steps.md +9 -0
  84. data/spec/controller_helper_spec.rb +34 -0
  85. data/spec/index.html.erb +10 -0
  86. data/spec/react/callbacks_spec.rb +106 -0
  87. data/spec/react/children_spec.rb +76 -0
  88. data/spec/react/component/base_spec.rb +32 -0
  89. data/spec/react/component_spec.rb +872 -0
  90. data/spec/react/dsl_spec.rb +296 -0
  91. data/spec/react/element_spec.rb +136 -0
  92. data/spec/react/event_spec.rb +24 -0
  93. data/spec/react/native_library_spec.rb +344 -0
  94. data/spec/react/observable_spec.rb +7 -0
  95. data/spec/react/opal_jquery_extensions_spec.rb +66 -0
  96. data/spec/react/param_declaration_spec.rb +258 -0
  97. data/spec/react/react_spec.rb +209 -0
  98. data/spec/react/state_spec.rb +55 -0
  99. data/spec/react/test/dsl_spec.rb +43 -0
  100. data/spec/react/test/matchers/render_html_matcher_spec.rb +83 -0
  101. data/spec/react/test/rspec_spec.rb +62 -0
  102. data/spec/react/test/session_spec.rb +100 -0
  103. data/spec/react/test/utils_spec.rb +45 -0
  104. data/spec/react/top_level_component_spec.rb +96 -0
  105. data/spec/react/tutorial/tutorial_spec.rb +36 -0
  106. data/spec/react/validator_spec.rb +124 -0
  107. data/spec/reactive-ruby/component_loader_spec.rb +71 -0
  108. data/spec/reactive-ruby/isomorphic_helpers_spec.rb +155 -0
  109. data/spec/reactive-ruby/rails/asset_pipeline_spec.rb +10 -0
  110. data/spec/reactive-ruby/rails/component_mount_spec.rb +66 -0
  111. data/spec/reactive-ruby/server_rendering/contextual_renderer_spec.rb +35 -0
  112. data/spec/spec_helper.rb +115 -0
  113. data/spec/support/react/spec_helpers.rb +64 -0
  114. data/spec/vendor/es5-shim.min.js +6 -0
  115. data/spec/vendor/jquery-2.2.4.min.js +4 -0
  116. metadata +387 -0
@@ -0,0 +1,209 @@
1
+ require "spec_helper"
2
+
3
+ if opal?
4
+ RSpec.describe React, type: :component do
5
+ after(:each) do
6
+ React::API.clear_component_class_cache
7
+ end
8
+
9
+ describe "is_valid_element" do
10
+ it "should return true if passed a valid element" do
11
+ element = React::Element.new(`React.createElement('div')`)
12
+ expect(React.is_valid_element(element)).to eq(true)
13
+ end
14
+
15
+ it "should return false is passed a non React element" do
16
+ element = React::Element.new(`{}`)
17
+ expect(React.is_valid_element(element)).to eq(false)
18
+ end
19
+ end
20
+
21
+ describe "create_element" do
22
+ it "should create a valid element with only tag" do
23
+ element = React.create_element('div')
24
+ expect(React.is_valid_element(element)).to eq(true)
25
+ end
26
+
27
+ context "with block" do
28
+ it "should create a valid element with text as only child when block yield String" do
29
+ element = React.create_element('div') { "lorem ipsum" }
30
+ expect(React.is_valid_element(element)).to eq(true)
31
+ expect(element.props.children).to eq("lorem ipsum")
32
+ end
33
+
34
+ it "should create a valid element with children as array when block yield Array of element" do
35
+ element = React.create_element('div') do
36
+ [React.create_element('span'), React.create_element('span'), React.create_element('span')]
37
+ end
38
+ expect(React.is_valid_element(element)).to eq(true)
39
+ expect(element.props.children.length).to eq(3)
40
+ end
41
+
42
+ it "should render element with children as array when block yield Array of element" do
43
+ element = React.create_element('div') do
44
+ [React.create_element('span'), React.create_element('span'), React.create_element('span')]
45
+ end
46
+ instance = renderElementToDocument(element)
47
+ expect(Element[instance].children.length).to eq(3)
48
+ end
49
+ end
50
+
51
+ describe "custom element" do
52
+ before do
53
+ stub_const 'Foo', Class.new
54
+ Foo.class_eval do
55
+ def render
56
+ React.create_element("div") { "lorem" }
57
+ end
58
+ end
59
+ end
60
+
61
+ it "should render element with only one children correctly" do
62
+ element = React.create_element(Foo) { React.create_element('span') }
63
+ instance = renderElementToDocument(element)
64
+ expect(instance.props.children).not_to be_a(Array)
65
+ expect(instance.props.children.type).to eq("span")
66
+ end
67
+
68
+ it "should render element with more than one children correctly" do
69
+ element = React.create_element(Foo) { [React.create_element('span'), React.create_element('span')] }
70
+ instance = renderElementToDocument(element)
71
+ expect(instance.props.children).to be_a(Array)
72
+ expect(instance.props.children.length).to eq(2)
73
+ end
74
+
75
+ it "should create a valid element provided class defined `render`" do
76
+ element = React.create_element(Foo)
77
+ expect(React.is_valid_element(element)).to eq(true)
78
+ end
79
+
80
+ it "should allow creating with properties" do
81
+ element = React.create_element(Foo, foo: "bar")
82
+ expect(element.props.foo).to eq("bar")
83
+ end
84
+
85
+ it "should raise error if provided class doesn't defined `render`" do
86
+ expect { React.create_element(Array) }.to raise_error
87
+ end
88
+
89
+ it "should use the same instance for the same ReactComponent" do
90
+ Foo.class_eval do
91
+ attr_accessor :a
92
+ def initialize(n)
93
+ self.a = 10
94
+ end
95
+
96
+ def component_will_mount
97
+ self.a = 20
98
+ end
99
+
100
+ def render
101
+ React.create_element("div") { self.a.to_s }
102
+ end
103
+ end
104
+
105
+ expect(Foo).to render("<div>20</div>")
106
+ end
107
+
108
+ it "should match the instance cycle to ReactComponent life cycle" do
109
+ `var count = 0;`
110
+
111
+ Foo.class_eval do
112
+ def initialize
113
+ `count = count + 1;`
114
+ end
115
+ def render
116
+ React.create_element("div")
117
+ end
118
+ end
119
+
120
+ renderToDocument(Foo)
121
+ renderToDocument(Foo)
122
+
123
+ expect(`count`).to eq(2)
124
+ end
125
+ end
126
+
127
+ describe "create element with properties" do
128
+ it "should enforce snake-cased property name" do
129
+ element = React.create_element("div", class_name: "foo")
130
+ expect(element.props.className).to eq("foo")
131
+ end
132
+
133
+ it "should allow custom property" do
134
+ element = React.create_element("div", foo: "bar")
135
+ expect(element.props.foo).to eq("bar")
136
+ end
137
+
138
+ it "should not camel-case custom property" do
139
+ element = React.create_element("div", foo_bar: "foo")
140
+ expect(element.props.foo_bar).to eq("foo")
141
+ end
142
+ end
143
+
144
+ describe "class_name helpers (React.addons.classSet)" do
145
+ it "should transform Hash provided to `class_name` props as string", v13_only: true do
146
+ classes = {foo: true, bar: false, lorem: true}
147
+ element = React.create_element("div", class_name: classes)
148
+ expect(element.props.className).to eq("foo lorem")
149
+ end
150
+
151
+ it "should not alter behavior when passing a string" do
152
+ element = React.create_element("div", class_name: "foo bar")
153
+
154
+ expect(element.props.className).to eq("foo bar")
155
+ end
156
+ end
157
+ end
158
+
159
+ describe "render" do
160
+ async "should render element to DOM" do
161
+ div = `document.createElement("div")`
162
+ React.render(React.create_element('span') { "lorem" }, div) do
163
+ run_async {
164
+ expect(`div.children[0].tagName`).to eq("SPAN")
165
+ expect(`div.textContent`).to eq("lorem")
166
+ }
167
+ end
168
+ end
169
+
170
+ it "should work without providing a block" do
171
+ div = `document.createElement("div")`
172
+ React.render(React.create_element('span') { "lorem" }, div)
173
+ end
174
+
175
+ it "should return a React::Component::API compatible object" do
176
+ div = `document.createElement("div")`
177
+ component = React.render(React.create_element('span') { "lorem" }, div)
178
+ React::Component::API.public_instance_methods(true).each do |method_name|
179
+ expect(component).to respond_to(method_name)
180
+ end
181
+ end
182
+
183
+ pending "should return nil to prevent abstraction leakage" do
184
+ div = `document.createElement("div")`
185
+ expect {
186
+ React.render(React.create_element('span') { "lorem" }, div)
187
+ }.to be_nil
188
+ end
189
+ end
190
+
191
+ describe "render_to_string" do
192
+ it "should render a React.Element to string" do
193
+ ele = React.create_element('span') { "lorem" }
194
+ expect(React.render_to_string(ele)).to be_kind_of(String)
195
+ end
196
+ end
197
+
198
+ describe "unmount_component_at_node" do
199
+ async "should unmount component at node" do
200
+ div = `document.createElement("div")`
201
+ React.render(React.create_element('span') { "lorem" }, div ) do
202
+ run_async {
203
+ expect(React.unmount_component_at_node(div)).to eq(true)
204
+ }
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ describe 'React::State' do
5
+ it "can created static exported states" do
6
+ stub_const 'Foo', Class.new
7
+ Foo.class_eval do
8
+ include React::Component
9
+ export_state(:foo) { 'bar' }
10
+ end
11
+
12
+ expect(Foo.foo).to eq('bar')
13
+ end
14
+
15
+ # these will all require async operations and testing to see if things get
16
+ # re-rendered see spec_helper the "render" test method
17
+
18
+ # if Foo.foo is used during rendering then when Foo.foo changes we will
19
+ # rerender
20
+ it "sets up observers when exported states are read"
21
+
22
+ # React::State.set_state(object, attribute, value) +
23
+ # React::State.get_state(object, attribute)
24
+ it "can be accessed outside of react using get/set_state"
25
+
26
+ it 'ignores state updates during rendering' do
27
+ stub_const 'StateTest', Class.new(React::Component::Base)
28
+ StateTest.class_eval do
29
+ export_state :boom
30
+ before_mount do
31
+ # force boom to be on the observing list during the current rendering cycle
32
+ StateTest.boom! !StateTest.boom
33
+ # this is automatically called by after_mount / after_update, but we don't want
34
+ # to have to setup a complicated async test, so we just force it now.
35
+ # if we don't do this, then updating boom will have no effect on the first render
36
+ React::State.update_states_to_observe
37
+ end
38
+ def render
39
+ (StateTest.boom ? "Boom" : "No Boom").tap { StateTest.boom! !StateTest.boom }
40
+ end
41
+ end
42
+ %x{
43
+ var log = [];
44
+ var org_warn_console = window.console.warn;
45
+ var org_error_console = window.console.error;
46
+ window.console.warn = window.console.error = function(str){log.push(str)}
47
+ }
48
+ markup = React.render_to_static_markup(React.create_element(StateTest))
49
+ `window.console.warn = org_warn_console; window.console.error = org_error_console;`
50
+ expect(markup).to eq('<span>Boom</span>')
51
+ expect(StateTest.boom).to be_falsy
52
+ expect(`log`).to eq([])
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ RSpec.describe React::Test::DSL do
5
+ describe 'the DSL' do
6
+ let(:session) { Class.new { include React::Test::DSL }.new }
7
+
8
+ before do
9
+ React::Test.reset_session!
10
+
11
+ stub_const 'Greeter', Class.new
12
+ Greeter.class_eval do
13
+ include React::Component
14
+
15
+ params do
16
+ optional :message
17
+ optional :from
18
+ end
19
+
20
+ def render
21
+ span { "Hello #{params.message}" }
22
+ end
23
+ end
24
+ end
25
+
26
+ it 'is possible to include it in another class' do
27
+ session.mount(Greeter)
28
+ expect(session.instance).to be_a(Greeter)
29
+ end
30
+
31
+ it "should provide a 'component' shortcut for more expressive tests" do
32
+ session.component.mount(Greeter)
33
+ expect(session.component.instance).to be_a(Greeter)
34
+ end
35
+
36
+ React::Test::Session::DSL_METHODS.each do |method|
37
+ it "responds to all DSL method: #{method}" do
38
+ expect(session).to respond_to(method)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ describe React::Test::Matchers::RenderHTMLMatcher do
5
+ let(:component) {
6
+ Class.new do
7
+ include React::Component
8
+ params do
9
+ optional :string
10
+ end
11
+ def render
12
+ div do
13
+ span { params.string } if params.string
14
+ 'lorem'
15
+ end
16
+ end
17
+ end
18
+ }
19
+ let(:expected) { '<div>lorem</div>' }
20
+ let(:matcher) { described_class.new(expected) }
21
+
22
+ describe '#matches?' do
23
+ it 'is truthy when rendered component html equals expected html' do
24
+ expect(matcher.matches?(component)).to be_truthy
25
+ end
26
+
27
+ it 'is falsey when rendered component html does not equal expected html' do
28
+ matcher = described_class.new('foo')
29
+ expect(matcher.matches?(component)).to be_falsey
30
+ end
31
+ end
32
+
33
+ describe '#with_params' do
34
+ let(:expected) { '<div><span>str</span>lorem</div>' }
35
+
36
+ it 'renders the component with the given params' do
37
+ matcher.with_params(string: 'str')
38
+ expect(matcher.matches?(component)).to be_truthy
39
+ end
40
+ end
41
+
42
+ describe '#failure_message' do
43
+ let(:expected) { '<div><span>str</span>lorem</div>' }
44
+
45
+ it 'includes the name of the component' do
46
+ stub_const 'Foo', component
47
+ matcher.matches?(Foo)
48
+ expect(matcher.failure_message).to match(/expected 'Foo'/)
49
+ end
50
+
51
+ it 'includes the params hash' do
52
+ matcher.with_params(string: 'bar')
53
+ matcher.matches?(component)
54
+ expect(matcher.failure_message).to match(/with params '{"string"=>"bar"}'/)
55
+ end
56
+
57
+ it 'includes the expected html value' do
58
+ matcher.matches?(component)
59
+ expect(matcher.failure_message).to match(/to render '#{expected}'/)
60
+ end
61
+
62
+ it 'includes the actual html value' do
63
+ actual = '<div>lorem<\/div>'
64
+ matcher.matches?(component)
65
+ expect(matcher.failure_message).to match(/, but '#{actual}' was rendered/)
66
+ end
67
+
68
+ it 'does not include "to not render"' do
69
+ matcher.matches?(component)
70
+ expect(matcher.failure_message).to_not match(/to not render/)
71
+ end
72
+ end
73
+
74
+ describe '#negative_failure_message' do
75
+ let(:expected) { '<div><span>str</span>lorem</div>' }
76
+
77
+ it 'includes "to not render"' do
78
+ matcher.matches?(component)
79
+ expect(matcher.negative_failure_message).to match(/to not render/)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ RSpec.describe 'react/test/rspec', type: :component do
5
+ before do
6
+ stub_const 'Greeter', Class.new
7
+ Greeter.class_eval do
8
+ include React::Component
9
+ params do
10
+ optional :message
11
+ optional :from
12
+ end
13
+
14
+ def render
15
+ span { "Hello #{params.message}" }
16
+ end
17
+ end
18
+ end
19
+
20
+ it 'should include react/test in rspec' do
21
+ comp = mount(Greeter)
22
+ expect(component.instance).to eq(comp)
23
+ end
24
+
25
+ it 'includes rspec matchers' do
26
+ expect(Greeter).to render(
27
+ '<span>Hello world</span>'
28
+ ).with_params(message: 'world')
29
+ end
30
+
31
+ describe 'resetting the session' do
32
+ it 'creates an instance of the mounted component in one example' do
33
+ mount(Greeter)
34
+ end
35
+
36
+ it '...then is not availalbe in the next' do
37
+ expect { component.instance }.to raise_error
38
+ end
39
+ end
40
+ end
41
+
42
+ RSpec.describe 'react/test/rspec', type: :other do
43
+ before do
44
+ stub_const 'Greeter', Class.new
45
+ Greeter.class_eval do
46
+ include React::Component
47
+ params do
48
+ optional :message
49
+ optional :from
50
+ end
51
+
52
+ def render
53
+ span { "Hello #{params.message}" }
54
+ end
55
+ end
56
+ end
57
+
58
+ it 'should not include react/test in rspec' do
59
+ expect { mount(Greeter) }.to raise_error
60
+ end
61
+ end
62
+ end