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,100 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ RSpec.describe React::Test::Session do
5
+ subject { described_class.new }
6
+ before do
7
+ stub_const 'Greeter', Class.new
8
+ Greeter.class_eval do
9
+ include React::Component
10
+
11
+ params do
12
+ optional :message
13
+ optional :from
14
+ end
15
+
16
+ def render
17
+ span { "Hello #{params.message}" }
18
+ end
19
+ end
20
+ end
21
+
22
+ describe '#mount' do
23
+ it 'returns an instance of the mounted component' do
24
+ expect(subject.mount(Greeter)).to be_a(Greeter)
25
+ end
26
+
27
+ it 'actualy mounts the component' do
28
+ expect(subject.mount(Greeter)).to be_mounted
29
+ end
30
+
31
+ it 'optionaly passes params to the component' do
32
+ instance = subject.mount(Greeter, message: 'world')
33
+ expect(instance.params.message).to eq('world')
34
+ end
35
+ end
36
+
37
+ describe '#instance' do
38
+ it 'returns the instance of the mounted component' do
39
+ instance = subject.mount(Greeter)
40
+ expect(subject.instance).to eq(instance)
41
+ end
42
+ end
43
+
44
+ describe '#element' do
45
+ it 'returns the React::Element for the mounted component' do
46
+ subject.mount(Greeter)
47
+ expect(subject.element).to be_a(React::Element)
48
+ end
49
+ end
50
+
51
+ describe '#native' do
52
+ it 'returns the React native instance of the component' do
53
+ instance = subject.mount(Greeter)
54
+ native = instance.instance_variable_get('@native')
55
+ expect(subject.native).to eq(native)
56
+ end
57
+ end
58
+
59
+ describe '#html' do
60
+ it 'returns the component rendered to static html' do
61
+ subject.mount(Greeter, message: 'world')
62
+ expect(subject.html).to eq('<span>Hello world</span>')
63
+ end
64
+
65
+ it 'returns the updated static html' do
66
+ subject.mount(Greeter)
67
+ subject.update_params(message: 'moon')
68
+ expect(subject.html).to eq('<span>Hello moon</span>')
69
+ end
70
+ end
71
+
72
+ describe '#update_params' do
73
+ it 'sends new params to the component' do
74
+ instance = subject.mount(Greeter, message: 'world')
75
+ subject.update_params(message: 'moon')
76
+ expect(instance.params.message).to eq('moon')
77
+ end
78
+
79
+ it 'leaves unspecified params in tact' do
80
+ instance = subject.mount(Greeter, message: 'world', from: 'outerspace')
81
+ subject.update_params(message: 'moon')
82
+ expect(instance.params.from).to eq('outerspace')
83
+ end
84
+
85
+ it 'causes the component to render' do
86
+ instance = subject.mount(Greeter, message: 'world')
87
+ expect(instance).to receive(:render)
88
+ subject.update_params(message: 'moon')
89
+ end
90
+ end
91
+
92
+ describe '#force_update' do
93
+ it 'causes the component to render' do
94
+ instance = subject.mount(Greeter)
95
+ expect(instance).to receive(:render)
96
+ subject.force_update!
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ module React
5
+ module Test
6
+ class Utils
7
+ def self.simulate(event, element)
8
+ Simulate.new.click(element)
9
+ end
10
+
11
+ class Simulate
12
+ include Native
13
+ def initialize
14
+ super(`React.addons.TestUtils.Simulate`)
15
+ end
16
+
17
+ def click(component_instance)
18
+ `#{@native}['click']`.call(component_instance.dom_node, {})
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ RSpec.describe React::Test::Utils do
25
+ it 'simulates' do
26
+ stub_const 'Foo', Class.new
27
+ Foo.class_eval do
28
+ include React::Component
29
+
30
+ def hello
31
+ @hello
32
+ end
33
+
34
+ def render
35
+ @hello = 'hello'
36
+ div { 'Click Me' }.on(:click) { |e| click(e) }
37
+ end
38
+ end
39
+
40
+ instance = renderToDocument(Foo)
41
+ expect_any_instance_of(Foo).to receive(:click)
42
+ described_class.simulate(:click, instance)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ module Components
5
+ module Controller
6
+ class Component1
7
+ include React::Component
8
+ def render
9
+ self.class.name.to_s
10
+ end
11
+ end
12
+ end
13
+
14
+ class Component1
15
+ include React::Component
16
+ def render
17
+ self.class.name.to_s
18
+ end
19
+ end
20
+
21
+ class Component2
22
+ include React::Component
23
+ def render
24
+ self.class.name.to_s
25
+ end
26
+ end
27
+ end
28
+
29
+ module Controller
30
+ class SomeOtherClass # see issue #80
31
+ end
32
+ end
33
+
34
+ class Component1
35
+ include React::Component
36
+ def render
37
+ self.class.name.to_s
38
+ end
39
+ end
40
+
41
+ def render_top_level(controller, component_name)
42
+ render_to_html(React::TopLevelRailsComponent, controller: controller,
43
+ component_name: component_name, render_params: {})
44
+ end
45
+
46
+ describe React::TopLevelRailsComponent do
47
+
48
+ it 'uses the controller name to lookup a component' do
49
+ expect(render_top_level("Controller", "Component1")).to eq('<span>Components::Controller::Component1</span>')
50
+ end
51
+
52
+ it 'can find the name without matching the controller' do
53
+ expect(render_top_level("Controller", "Component2")).to eq('<span>Components::Component2</span>')
54
+ end
55
+
56
+ it 'will find the outer most matching component' do
57
+ expect(render_top_level("OtherController", "Component1")).to eq('<span>Component1</span>')
58
+ end
59
+
60
+ it 'can find the correct component when the name is fully qualified' do
61
+ expect(render_top_level("Controller", "::Components::Component1")).to eq('<span>Components::Component1</span>')
62
+ end
63
+
64
+ describe '.html_tag?' do
65
+ it 'is truthy for valid html tags' do
66
+ expect(React.html_tag?('a')).to be_truthy
67
+ expect(React.html_tag?('div')).to be_truthy
68
+ end
69
+
70
+ it 'is truthy for valid svg tags' do
71
+ expect(React.html_tag?('svg')).to be_truthy
72
+ expect(React.html_tag?('circle')).to be_truthy
73
+ end
74
+
75
+ it 'is falsey for invalid tags' do
76
+ expect(React.html_tag?('tagizzle')).to be_falsey
77
+ end
78
+ end
79
+
80
+ describe '.html_attr?' do
81
+ it 'is truthy for valid html attributes' do
82
+ expect(React.html_attr?('id')).to be_truthy
83
+ expect(React.html_attr?('data')).to be_truthy
84
+ end
85
+
86
+ it 'is truthy for valid svg attributes' do
87
+ expect(React.html_attr?('cx')).to be_truthy
88
+ expect(React.html_attr?('strokeWidth')).to be_truthy
89
+ end
90
+
91
+ it 'is falsey for invalid attributes' do
92
+ expect(React.html_tag?('attrizzle')).to be_falsey
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ class HelloMessage
5
+ include React::Component
6
+ def render
7
+ div { "Hello World!" }
8
+ end
9
+ end
10
+
11
+ describe 'An Example from the react.rb doc', type: :component do
12
+ it 'produces the correct result' do
13
+ expect(HelloMessage).to render('<div>Hello World!</div>')
14
+ end
15
+ end
16
+
17
+ class HelloMessage2
18
+ include React::Component
19
+ define_state(:user_name) { '@catmando' }
20
+ def render
21
+ div { "Hello #{state.user_name}" }
22
+ end
23
+ end
24
+
25
+ describe 'Adding state to a component (second tutorial example)', type: :component do
26
+ it "produces the correct result" do
27
+ expect(HelloMessage2).to render('<div>Hello @catmando</div>')
28
+ end
29
+
30
+ it 'renders to the document' do
31
+ ele = `document.createElement('div')`
32
+ React.render(React.create_element(HelloMessage2), ele)
33
+ expect(`#{ele}.innerHTML`) =~ 'Hello @catmando'
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,124 @@
1
+ require "spec_helper"
2
+
3
+ if opal?
4
+ describe React::Validator do
5
+ describe '#validate' do
6
+ describe "Presence validation" do
7
+ it "should check if required props provided" do
8
+ validator = React::Validator.new.build do
9
+ requires :foo
10
+ requires :bar
11
+ end
12
+
13
+ expect(validator.validate({})).to eq(["Required prop `foo` was not specified", "Required prop `bar` was not specified"])
14
+ expect(validator.validate({foo: 1, bar: 3})).to eq([])
15
+ end
16
+
17
+ it "should check if passed non specified prop" do
18
+ validator = React::Validator.new.build do
19
+ optional :foo
20
+ end
21
+
22
+ expect(validator.validate({bar: 10})).to eq(["Provided prop `bar` not specified in spec"])
23
+ expect(validator.validate({foo: 10})).to eq([])
24
+ end
25
+ end
26
+
27
+ describe "Type validation" do
28
+ it "should check if passed value with wrong type" do
29
+ validator = React::Validator.new.build do
30
+ requires :foo, type: String
31
+ end
32
+
33
+ expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` could not be converted to String"])
34
+ expect(validator.validate({foo: "10"})).to eq([])
35
+ end
36
+
37
+ it "should check if passed value with wrong custom type" do
38
+ stub_const 'Bar', Class.new
39
+ validator = React::Validator.new.build do
40
+ requires :foo, type: Bar
41
+ end
42
+
43
+ expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` could not be converted to Bar"])
44
+ expect(validator.validate({foo: Bar.new})).to eq([])
45
+ end
46
+
47
+ it 'coerces native JS prop types to opal objects' do
48
+ validator = React::Validator.new.build do
49
+ requires :foo, type: `{ x: 1 }`
50
+ end
51
+
52
+ message = "Provided prop `foo` could not be converted to [object Object]"
53
+ expect(validator.validate({foo: `{ x: 1 }`})).to eq([message])
54
+ end
55
+
56
+ it 'coerces native JS values to opal objects' do
57
+ validator = React::Validator.new.build do
58
+ requires :foo, type: Array[Fixnum]
59
+ end
60
+ message = "Provided prop `foo`[0] could not be converted to #{Fixnum.name}"
61
+ expect(validator.validate({foo: `[ { x: 1 } ]`})).to eq([message])
62
+ end
63
+
64
+ it "should support Array[Class] validation" do
65
+ validator = React::Validator.new.build do
66
+ requires :foo, type: Array[Hash]
67
+ end
68
+
69
+ expect(validator.validate({foo: [1,'2',3]})).to eq(
70
+ [
71
+ "Provided prop `foo`[0] could not be converted to Hash",
72
+ "Provided prop `foo`[1] could not be converted to Hash",
73
+ "Provided prop `foo`[2] could not be converted to Hash"
74
+ ]
75
+ )
76
+ expect(validator.validate({foo: [{},{},{}]})).to eq([])
77
+ end
78
+ end
79
+
80
+ describe "Limited values" do
81
+ it "should check if passed value is not one of the specified values" do
82
+ validator = React::Validator.new.build do
83
+ requires :foo, values: [4,5,6]
84
+ end
85
+
86
+ expect(validator.validate({foo: 3})).to eq(["Value `3` for prop `foo` is not an allowed value"])
87
+ expect(validator.validate({foo: 4})).to eq([])
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#undefined_props' do
93
+ let(:props) { { foo: 'foo', bar: 'bar', biz: 'biz', baz: 'baz' } }
94
+ let(:validator) do
95
+ React::Validator.new.build do
96
+ requires :foo
97
+ optional :bar
98
+ end
99
+ end
100
+
101
+ it 'slurps up any extra params into a hash' do
102
+ others = validator.undefined_props(props)
103
+ expect(others).to eq({ biz: 'biz', baz: 'baz' })
104
+ end
105
+
106
+ it 'prevents validate non-specified params' do
107
+ validator.undefined_props(props)
108
+ expect(validator.validate(props)).to eq([])
109
+ end
110
+ end
111
+
112
+ describe "default_props" do
113
+ it "should return specified default values" do
114
+ validator = React::Validator.new.build do
115
+ requires :foo, default: 10
116
+ requires :bar
117
+ optional :lorem, default: 20
118
+ end
119
+
120
+ expect(validator.default_props).to eq({foo: 10, lorem: 20})
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ if ruby?
4
+ RSpec.describe ReactiveRuby::ComponentLoader do
5
+ GLOBAL_WRAPPER = <<-JS
6
+ var global = global || this;
7
+ var self = self || this;
8
+ var window = window || this;
9
+ var console = {
10
+ warn: function(s) { }
11
+ };
12
+ JS
13
+
14
+ let(:js) { ::Rails.application.assets['components'].to_s }
15
+ let(:context) { ExecJS.compile(GLOBAL_WRAPPER + js) }
16
+ let(:v8_context) { ReactiveRuby::ServerRendering.context_instance_for(context) }
17
+
18
+ describe '.new' do
19
+ it 'raises a meaningful exception when initialized without a context' do
20
+ expect {
21
+ described_class.new(nil)
22
+ }.to raise_error(/Could not obtain ExecJS runtime context/)
23
+ end
24
+ end
25
+
26
+ describe '#load' do
27
+ it 'loads given asset file into context' do
28
+ loader = described_class.new(v8_context)
29
+
30
+ expect {
31
+ loader.load
32
+ }.to change { !!v8_context.eval('Opal.React') }.from(false).to(true)
33
+ end
34
+
35
+ it 'is truthy upon successful load' do
36
+ loader = described_class.new(v8_context)
37
+ expect(loader.load).to be_truthy
38
+ end
39
+
40
+ it 'fails silently returning false' do
41
+ loader = described_class.new(v8_context)
42
+ expect(loader.load('foo')).to be_falsey
43
+ end
44
+ end
45
+
46
+ describe '#load!' do
47
+ it 'is truthy upon successful load' do
48
+ loader = described_class.new(v8_context)
49
+ expect(loader.load!).to be_truthy
50
+ end
51
+
52
+ it 'raises an expection if loading fails' do
53
+ loader = described_class.new(v8_context)
54
+ expect { loader.load!('foo') }.to raise_error(/No react\.rb components/)
55
+ end
56
+ end
57
+
58
+ describe '#loaded?' do
59
+ it 'is truthy if components file is already loaded' do
60
+ loader = described_class.new(v8_context)
61
+ loader.load
62
+ expect(loader).to be_loaded
63
+ end
64
+
65
+ it 'is false if components file is not loaded' do
66
+ loader = described_class.new(v8_context)
67
+ expect(loader).to_not be_loaded
68
+ end
69
+ end
70
+ end
71
+ end