reactive-ruby 0.7.28 → 0.7.29

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +6 -0
  3. data/Gemfile.lock +4 -1
  4. data/README.md +132 -68
  5. data/Rakefile +5 -2
  6. data/example/examples/Gemfile +0 -2
  7. data/example/rails-tutorial/Gemfile +3 -2
  8. data/lib/generators/reactive_ruby/test_app/templates/application.rb +11 -0
  9. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/application.rb +2 -0
  10. data/lib/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +3 -0
  11. data/lib/generators/reactive_ruby/test_app/templates/boot.rb +6 -0
  12. data/lib/generators/reactive_ruby/test_app/templates/script/rails +5 -0
  13. data/lib/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
  14. data/lib/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
  15. data/lib/generators/reactive_ruby/test_app/test_app_generator.rb +105 -0
  16. data/lib/rails-helpers/top_level_rails_component.rb +9 -16
  17. data/lib/{reactive-ruby → react}/api.rb +8 -65
  18. data/lib/{reactive-ruby → react}/callbacks.rb +0 -0
  19. data/lib/react/component.rb +266 -0
  20. data/lib/react/component/api.rb +48 -0
  21. data/lib/react/component/class_methods.rb +183 -0
  22. data/lib/{reactive-ruby → react}/element.rb +10 -11
  23. data/lib/{reactive-ruby → react}/event.rb +0 -0
  24. data/lib/{reactive-ruby → react}/ext/hash.rb +0 -0
  25. data/lib/{reactive-ruby → react}/ext/string.rb +0 -0
  26. data/lib/react/native_library.rb +57 -0
  27. data/lib/{reactive-ruby → react}/observable.rb +0 -4
  28. data/lib/{reactive-ruby → react}/rendering_context.rb +0 -6
  29. data/lib/{reactive-ruby → react}/state.rb +3 -6
  30. data/lib/{reactive-ruby → react}/top_level.rb +2 -3
  31. data/lib/react/validator.rb +127 -0
  32. data/lib/reactive-ruby.rb +20 -20
  33. data/lib/reactive-ruby/version.rb +1 -1
  34. data/{opal-spec/reactjs → spec}/index.html.erb +1 -1
  35. data/{opal-spec → spec/react}/callbacks_spec.rb +8 -9
  36. data/{opal-spec → spec/react}/component_spec.rb +170 -120
  37. data/spec/react/dsl_spec.rb +16 -0
  38. data/{opal-spec → spec/react}/element_spec.rb +7 -20
  39. data/{opal-spec → spec/react}/event_spec.rb +3 -1
  40. data/spec/react/native_library_spec.rb +10 -0
  41. data/spec/react/param_declaration_spec.rb +18 -0
  42. data/{opal-spec → spec/react}/react_spec.rb +3 -2
  43. data/spec/react/react_state_spec.rb +22 -0
  44. data/spec/react/top_level_component_spec.rb +68 -0
  45. data/{opal-spec → spec/react}/tutorial/tutorial_spec.rb +11 -13
  46. data/{opal-spec → spec/react}/validator_spec.rb +50 -4
  47. data/spec/reactive-ruby/isomorphic_helpers_spec.rb +22 -4
  48. data/spec/spec_helper.rb +51 -0
  49. data/spec/support/react/spec_helpers.rb +57 -0
  50. data/spec/vendor/es5-shim.min.js +6 -0
  51. metadata +56 -24
  52. data/lib/reactive-ruby/component.rb +0 -502
  53. data/lib/reactive-ruby/validator.rb +0 -99
  54. data/old-readme +0 -220
  55. data/opal-spec/spec_helper.rb +0 -29
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ describe 'the React DSL' do
5
+ it "will treat the component class name as a first class component name" # Foo()
6
+ it "can add class names by the haml .class notation" # Foo.my_class
7
+ it "can use the 'class' keyword for classes" # Foo(class: "my-class")
8
+ it "will turn the last string in a block into a span" # Foo { "hello there" }
9
+ it "has a .span short hand String method" # "hello there".span
10
+ it "has a .br short hand String method"
11
+ it "has a .td short hand String method"
12
+ it "has a .para short hand String method"
13
+ it "can generate a unrendered node using the .as_node method" # div { "hello" }.as_node
14
+ it "can use the dangerously_set_inner_HTML param" # div { dangerously_set_inner_HTML: "<div>danger</div>" }
15
+ end
16
+ end
@@ -1,12 +1,13 @@
1
1
  require "spec_helper"
2
2
 
3
+ if opal?
3
4
  describe React::Element do
4
- it "should bridge `type` of native React.Element attributes" do
5
+ it 'bridges `type` of native React.Element attributes' do
5
6
  element = React.create_element('div')
6
7
  expect(element.element_type).to eq("div")
7
8
  end
8
9
 
9
- async "should be renderable" do
10
+ async 'is renderable' do
10
11
  element = React.create_element('span')
11
12
  div = `document.createElement("div")`
12
13
  React.render(element, div) do
@@ -16,8 +17,8 @@ describe React::Element do
16
17
  end
17
18
  end
18
19
 
19
- describe "Event subscription" do
20
- it "should be subscribable through `on(:event_name)` method" do
20
+ describe 'Event subscription' do
21
+ it 'is subscribable through `on(:event_name)` method' do
21
22
  expect { |b|
22
23
  element = React.create_element("div").on(:click, &b)
23
24
  instance = renderElementToDocument(element)
@@ -37,24 +38,10 @@ describe React::Element do
37
38
  }.to yield_control
38
39
  end
39
40
 
40
- it "should return self for `on` method" do
41
+ it 'returns self for `on` method' do
41
42
  element = React.create_element("div")
42
43
  expect(element.on(:click){}).to eq(element)
43
44
  end
44
45
  end
45
-
46
- describe "Children" do
47
- it "should return a Enumerable" do
48
- ele = React.create_element('div') { [React.create_element('a'), React.create_element('li')] }
49
- nodes = ele.children.map {|ele| ele.element_type }
50
- expect(nodes).to eq(["a", "li"])
51
- end
52
-
53
- it "should return a Enumerator when not providing a block" do
54
- ele = React.create_element('div') { [React.create_element('a'), React.create_element('li')] }
55
- nodes = ele.children.each
56
- expect(nodes).to be_a(Enumerator)
57
- expect(nodes.size).to eq(2)
58
- end
59
- end
46
+ end
60
47
  end
@@ -1,5 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
+ if opal?
3
4
  describe React::Event do
4
5
  it "should bridge attributes of native SyntheticEvent (see http://facebook.github.io/react/docs/events.html#syntheticevent)" do
5
6
  element = React.create_element('div').on(:click) do |event|
@@ -19,4 +20,5 @@ describe React::Event do
19
20
  instance = renderElementToDocument(element)
20
21
  simulateEvent(:click, instance)
21
22
  end
22
- end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ describe React::NativeLibrary do
5
+ it "will import a React.js library into the Ruby name space" # class BS < NativeLibrary; imports 'ReactBootstrap'; end
6
+ it "exclude specific components from a library" # exclude "Modal" # can't access BS.Modal
7
+ it "rename specific components from a library" # rename "Modal" => "FooBar" # BS.FooBar connects to ReactBootstrap.Modal
8
+ it "can importan multiple libraries into one class"
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+ describe 'the required_param macro' do
5
+ it "can be used to declare a required param" # required_param :foo
6
+ it "can have a simple type" # required_param :foo, type: String
7
+ it "can use the [] notation for arrays" # required_param :foo, type: []
8
+ it "can use the [] notation for arrays of a specific type" # required_param :foo, type: [String]
9
+ it "can convert a json hash to a type" # required_param :foo, type: BazWoggle # requires a BazWoggle conversion be provided
10
+ it "will alias a Proc type param" # required_param :foo, type: Proc # we can just say foo(...) to call the proc
11
+ it "will bind a two way linkage to an observable param" # required_param :foo, type: React::Observable # defines foo, and foo! bound to the observer
12
+ # you can create an observable simply by passing the value of some state!
13
+ end
14
+ describe 'the optional_param macro' do
15
+ # works just like a required_param, and
16
+ it "can have a default value" # optional_param :foo, type: String, default: ""
17
+ end
18
+ end
@@ -1,5 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
+ if opal?
3
4
  describe React do
4
5
  after(:each) do
5
6
  React::API.clear_component_class_cache
@@ -46,6 +47,7 @@ describe React do
46
47
  expect(instance.getDOMNode.childNodes.length).to eq(3)
47
48
  end
48
49
  end
50
+
49
51
  describe "custom element" do
50
52
  before do
51
53
  stub_const 'Foo', Class.new
@@ -155,7 +157,6 @@ describe React do
155
157
  end
156
158
  end
157
159
 
158
-
159
160
  describe "render" do
160
161
  async "should render element to DOM" do
161
162
  div = `document.createElement("div")`
@@ -205,5 +206,5 @@ describe React do
205
206
  end
206
207
  end
207
208
  end
208
-
209
+ end
209
210
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+
5
+ describe 'React::State' do
6
+ # class Foo; export_state :foo; end # accessible as Foo.foo outside
7
+ it "can created static exported states" do
8
+ stub_const 'Foo', Class.new
9
+ Foo.class_eval do
10
+ include React::Component
11
+ export_state(:foo) { 'bar' }
12
+ end
13
+
14
+ expect(Foo.foo).to eq('bar')
15
+ end
16
+
17
+ # these will all require async operations and testing to see if things get re-rendered see spec_helper the "render" test method
18
+ it "sets up observers when exported states are read" # if Foo.foo is used during rendering then when Foo.foo changes we will rerender
19
+ it "can be accessed outside of react using get/set_state" # React::State.set_state(object, attribute, value) + React::State.get_state(object, attribute)
20
+ end
21
+
22
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ if opal?
4
+
5
+ module Components
6
+
7
+ module Controller
8
+ class Component1
9
+ include React::Component
10
+ def render
11
+ self.class.name.to_s
12
+ end
13
+ end
14
+ end
15
+
16
+ class Component1
17
+ include React::Component
18
+ def render
19
+ self.class.name.to_s
20
+ end
21
+ end
22
+
23
+ class Component2
24
+ include React::Component
25
+ def render
26
+ self.class.name.to_s
27
+ end
28
+ end
29
+ end
30
+
31
+ module Controller
32
+ class SomeOtherClass # see issue #80
33
+ end
34
+ end
35
+
36
+ class Component1
37
+ include React::Component
38
+ def render
39
+ self.class.name.to_s
40
+ end
41
+ end
42
+
43
+
44
+ def render_top_level(controller, component_name)
45
+ React.render_to_static_markup(React.create_element(
46
+ React::TopLevelRailsComponent, {controller: controller, component_name: component_name, render_params: {}}))
47
+ end
48
+
49
+ describe React::TopLevelRailsComponent do
50
+
51
+ it 'uses the controller name to lookup a component' do
52
+ expect(render_top_level("Controller", "Component1")).to eq('<span>Components::Controller::Component1</span>')
53
+ end
54
+
55
+ it 'can find the name without matching the controller' do
56
+ expect(render_top_level("Controller", "Component2")).to eq('<span>Components::Component2</span>')
57
+ end
58
+
59
+ it 'will find the outer most matching component' do
60
+ expect(render_top_level("OtherController", "Component1")).to eq('<span>Component1</span>')
61
+ end
62
+
63
+ it 'can find the correct component when the name is fully qualified' do
64
+ expect(render_top_level("Controller", "::Components::Component1")).to eq('<span>Components::Component1</span>')
65
+ end
66
+
67
+ end
68
+ end
@@ -1,18 +1,17 @@
1
- require "spec_helper"
2
-
1
+ require 'spec_helper'
2
+
3
+ if opal?
3
4
  class HelloMessage
4
5
  include React::Component
5
6
  def render
6
7
  div { "Hello World!" }
7
8
  end
8
9
  end
9
-
10
- describe "An Example from the react.rb doc" do
11
-
12
- it "produces the correct result" do
10
+
11
+ describe 'An Example from the react.rb doc' do
12
+ it 'produces the correct result' do
13
13
  expect(React.render_to_static_markup(React.create_element(HelloMessage))).to eq('<div>Hello World!</div>')
14
14
  end
15
-
16
15
  end
17
16
 
18
17
  class HelloMessage2
@@ -23,15 +22,14 @@ class HelloMessage2
23
22
  end
24
23
  end
25
24
 
26
- describe "Adding state to a component (second tutorial example)" do
27
-
25
+ describe 'Adding state to a component (second tutorial example)' do
28
26
  it "produces the correct result" do
29
27
  expect(React.render_to_static_markup(React.create_element(HelloMessage2))).to eq('<div>Hello @catmando</div>')
30
28
  end
31
-
32
- it "renders to the document" do
29
+
30
+ it 'renders to the document' do
33
31
  React.render(React.create_element(HelloMessage2), `document.getElementById('render_here')`)
34
32
  expect(`document.getElementById('render_here').innerHTML`) =~ 'Hello @catmando'
35
33
  end
36
-
37
- end
34
+ end
35
+ end
@@ -1,7 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
+ if opal?
3
4
  describe React::Validator do
4
- describe "validate" do
5
+ describe '#validate' do
5
6
  describe "Presence validation" do
6
7
  it "should check if required props provided" do
7
8
  validator = React::Validator.build do
@@ -29,7 +30,7 @@ describe React::Validator do
29
30
  requires :foo, type: String
30
31
  end
31
32
 
32
- expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` was not the specified type `String`"])
33
+ expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` could not be converted to String"])
33
34
  expect(validator.validate({foo: "10"})).to eq([])
34
35
  end
35
36
 
@@ -39,16 +40,40 @@ describe React::Validator do
39
40
  requires :foo, type: Bar
40
41
  end
41
42
 
42
- expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` was not the specified type `Bar`"])
43
+ expect(validator.validate({foo: 10})).to eq(["Provided prop `foo` could not be converted to Bar"])
43
44
  expect(validator.validate({foo: Bar.new})).to eq([])
44
45
  end
45
46
 
47
+ it 'coerces native JS prop types to opal objects' do
48
+ validator = React::Validator.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.build do
58
+ requires :foo, type: Array[Fixnum]
59
+ end
60
+
61
+ message = "Provided prop `foo`[0] could not be converted to Numeric"
62
+ expect(validator.validate({foo: `[ { x: 1 } ]`})).to eq([message])
63
+ end
64
+
46
65
  it "should support Array[Class] validation" do
47
66
  validator = React::Validator.build do
48
67
  requires :foo, type: Array[Hash]
49
68
  end
50
69
 
51
- expect(validator.validate({foo: [1,'2',3]})).to eq(["Provided prop `foo` was not an Array of the specified type `Hash`"])
70
+ expect(validator.validate({foo: [1,'2',3]})).to eq(
71
+ [
72
+ "Provided prop `foo`[0] could not be converted to Hash",
73
+ "Provided prop `foo`[1] could not be converted to Hash",
74
+ "Provided prop `foo`[2] could not be converted to Hash"
75
+ ]
76
+ )
52
77
  expect(validator.validate({foo: [{},{},{}]})).to eq([])
53
78
  end
54
79
  end
@@ -65,6 +90,26 @@ describe React::Validator do
65
90
  end
66
91
  end
67
92
 
93
+ describe '#undefined_props' do
94
+ let(:props) { { foo: 'foo', bar: 'bar', biz: 'biz', baz: 'baz' } }
95
+ let(:validator) do
96
+ React::Validator.build do
97
+ requires :foo
98
+ optional :bar
99
+ end
100
+ end
101
+
102
+ it 'slurps up any extra params into a hash' do
103
+ others = validator.undefined_props(props)
104
+ expect(others).to eq({ biz: 'biz', baz: 'baz' })
105
+ end
106
+
107
+ it 'prevents validate non-specified params' do
108
+ validator.undefined_props(props)
109
+ expect(validator.validate(props)).to eq([])
110
+ end
111
+ end
112
+
68
113
  describe "default_props" do
69
114
  it "should return specified default values" do
70
115
  validator = React::Validator.build do
@@ -77,3 +122,4 @@ describe React::Validator do
77
122
  end
78
123
  end
79
124
  end
125
+ end
@@ -1,26 +1,43 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe React::IsomorphicHelpers do
4
- describe 'code execution context', :ruby do
4
+ describe 'code execution context' do
5
5
  let(:klass) { Class.send(:include, described_class) }
6
- describe 'module class methods' do
6
+
7
+ describe 'module class methods', :opal do
8
+ it { expect(described_class).to_not be_on_opal_server }
9
+ it { expect(described_class).to be_on_opal_client }
10
+ end
11
+
12
+ describe 'included class methods', :opal do
13
+ it { expect(klass).to_not be_on_opal_server }
14
+ it { expect(klass).to be_on_opal_client }
15
+ end
16
+
17
+ describe 'included instance methods', :opal do
18
+ it { expect(klass.new).to_not be_on_opal_server }
19
+ it { expect(klass.new).to be_on_opal_client }
20
+ end
21
+
22
+ describe 'module class methods', :ruby do
7
23
  it { is_expected.to_not be_on_opal_server }
8
24
  it { is_expected.to_not be_on_opal_client }
9
25
  end
10
26
 
11
- describe 'included class methods' do
27
+ describe 'included class methods', :ruby do
12
28
  subject { klass }
13
29
  it { is_expected.to_not be_on_opal_server }
14
30
  it { is_expected.to_not be_on_opal_client }
15
31
  end
16
32
 
17
- describe 'included instance methods' do
33
+ describe 'included instance methods', :ruby do
18
34
  subject { klass.new }
19
35
  it { is_expected.to_not be_on_opal_server }
20
36
  it { is_expected.to_not be_on_opal_client }
21
37
  end
22
38
  end
23
39
 
40
+ if ruby?
24
41
  describe 'load_context', :ruby do
25
42
  let(:v8_context) { TestV8Context.new }
26
43
  let(:controller) { double('controller') }
@@ -135,3 +152,4 @@ RSpec.describe React::IsomorphicHelpers do
135
152
  end
136
153
  end
137
154
  end
155
+ end
data/spec/spec_helper.rb CHANGED
@@ -13,7 +13,58 @@ end
13
13
 
14
14
  if RUBY_ENGINE == 'opal'
15
15
  require 'reactive-ruby'
16
+ require File.expand_path('../support/react/spec_helpers', __FILE__)
17
+
18
+ module Opal
19
+ module RSpec
20
+ module AsyncHelpers
21
+ module ClassMethods
22
+ def rendering(title, &block)
23
+ klass = Class.new do
24
+ include React::Component
25
+
26
+ def self.block
27
+ @block
28
+ end
29
+
30
+ def self.name
31
+ "dummy class"
32
+ end
33
+
34
+ def render
35
+ instance_eval &self.class.block
36
+ end
37
+
38
+ def self.should_generate(opts={}, &block)
39
+ sself = self
40
+ @self.async(@title, opts) do
41
+ expect_component_to_eventually(sself, &block)
42
+ end
43
+ end
44
+
45
+ def self.should_immediately_generate(opts={}, &block)
46
+ sself = self
47
+ @self.it(@title, opts) do
48
+ element = build_element sself, {}
49
+ context = block.arity > 0 ? self : element
50
+ expect((element and context.instance_exec(element, &block))).to be(true)
51
+ end
52
+ end
53
+
54
+ end
55
+ klass.instance_variable_set("@block", block)
56
+ klass.instance_variable_set("@self", self)
57
+ klass.instance_variable_set("@title", "it can render #{title}")
58
+ klass
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+
16
66
  RSpec.configure do |config|
67
+ config.include React::SpecHelpers
17
68
  config.filter_run_excluding :ruby
18
69
  end
19
70
  end