react.rb 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d41b80ffb70a0cfd51d99327653c12283fc4507c
4
- data.tar.gz: 7cf663a17b5c5ff75ada548badd48b47394a96b1
3
+ metadata.gz: 2dbadd7b8df4dbcfb57fd8b20da802307d913740
4
+ data.tar.gz: 649ec20f57caec86097ad8abdfd2075abf3d8997
5
5
  SHA512:
6
- metadata.gz: 0d1ecf283bed8249da9f488f5ceb37fdd398cc06ac7d83643be535b13df18a4e8bb69d000fc25e22b44189738e7170f7e2af9b2c6cc1827fd8410e6095cc9590
7
- data.tar.gz: a785b76558b4c9832aa8ba53db2fbf28a07a0993b5bf83e32a4042157293a9ba1c658296d0733c5855cc6d108ca1215cb9ec005392a8485893cd41fbf1a7e984
6
+ metadata.gz: 0ce9d3607ecca7d4891b0ba96dca4ebe5bcd950ff8092a3bd569cbd0da536a4c0f2bbc96faa6e17361875f07b0620bfd3aa13958edc96d7c51225af17d5ed053
7
+ data.tar.gz: a351a443594be61d7759cf02242a42424e2048a520aa2cac19208d533b358b50d33b9f09d37a1e3dbf32218f95d8d797b2ec19915dd9215d81b3a4be12820fec
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # React.rb
2
2
 
3
- **React.rb is a [Opal Ruby](http://opalrb.org) wrapper of [React.js library](http://facebook.github.io/react/)**.
3
+ **React.rb is an [Opal Ruby](http://opalrb.org) wrapper of [React.js library](http://facebook.github.io/react/)**.
4
4
 
5
5
  It let you write reactive UI component with Ruby's elegancy and compiled to run in Javascript. :heart:
6
6
 
@@ -16,6 +16,7 @@ and in your Opal application,
16
16
  ```ruby
17
17
  require "opal"
18
18
  require "react"
19
+
19
20
  React.render(React.create_element('h1'){ "Hello World!" }, `document.body`)
20
21
  ```
21
22
 
@@ -34,12 +35,14 @@ class HelloMessage
34
35
  end
35
36
  end
36
37
 
37
- React.render_static_markup(React.create_element(HelloMessage)) # => '<div>Hello World!</div>'
38
+ puts React.render_to_static_markup(React.create_element(HelloMessage))
39
+
40
+ # => '<div>Hello World!</div>'
38
41
  ```
39
42
 
40
43
  ### More complicated one
41
44
 
42
- To hook into native ReactComponent life cycle, the native `this` will be passed to the class's initializer. And all corresponding life cycle methods (`componentDidMount`, etc) will be invoked on the instance using the corresponding snake-case method name.
45
+ To hook into native ReactComponent life cycle, the native `this` will be passed to the class's initializer. And all corresponding life cycle methods (`componentDidMount`, etc) will be invoked on the instance using the snake-case method name.
43
46
 
44
47
  ```ruby
45
48
  class HelloMessage
@@ -64,7 +67,7 @@ puts React.render_to_static_markup(React.create_element(HelloMessage, name: 'Joh
64
67
 
65
68
  ### React::Component
66
69
 
67
- Hey, we are using Ruby, simply include `React::Component` to save your typing and have some handy method defined.
70
+ Hey, we are using Ruby, simply include `React::Component` to save your typing and have some handy methods defined.
68
71
 
69
72
  ```ruby
70
73
  class HelloMessage
@@ -99,8 +102,11 @@ class App
99
102
  end
100
103
 
101
104
  puts React.render_to_static_markup(React.create_element(App))
105
+
102
106
  # => '<div><span>Default greeting: Cool! John!</span></div>'
107
+
103
108
  React.render(React.create_element(App), `document.body`)
109
+
104
110
  # mounted!
105
111
  ```
106
112
 
@@ -111,7 +117,7 @@ React.render(React.create_element(App), `document.body`)
111
117
 
112
118
  ### Props validation
113
119
 
114
- How about props validation? Inspired from [Grape API](https://github.com/intridea/grape), props validation rule could be created easily through `params` class method as below,
120
+ How about props validation? Inspired by [Grape API](https://github.com/intridea/grape), props validation rule could be created easily through `params` class method as below,
115
121
 
116
122
  ```ruby
117
123
  class App
@@ -131,6 +137,55 @@ class App
131
137
  end
132
138
  ```
133
139
 
140
+ ### Mixins
141
+
142
+ Simply create a Ruby module to encapsulate the behavior. Example below is modified from the original [React.js Exmaple on Mixin](http://facebook.github.io/react/docs/reusable-components.html#mixins). [Opal Browser](https://github.com/opal/opal-browser) syntax are used here to make it cleaner.
143
+
144
+ ```ruby
145
+ module SetInterval
146
+ def self.included(base)
147
+ base.class_eval do
148
+ before_mount { @interval = [] }
149
+ before_unmount do
150
+ # abort associated timer of a component right before unmount
151
+ @interval.each { |i| i.abort }
152
+ end
153
+ end
154
+ end
155
+
156
+ def set_interval(seconds, &block)
157
+ @interval << $window.every(seconds, &block)
158
+ end
159
+ end
160
+
161
+ class TickTock
162
+ include React::Component
163
+ include SetInterval
164
+
165
+ define_state(:seconds) { 0 }
166
+
167
+ before_mount do
168
+ set_interval(1) { self.seconds = self.seconds + 1 }
169
+ set_interval(1) { puts "Tick!" }
170
+ end
171
+
172
+ def render
173
+ span do
174
+ "React has been running for: #{self.seconds}"
175
+ end
176
+ end
177
+ end
178
+
179
+ React.render(React.create_element(TickTock), $document.body.to_n)
180
+
181
+ $window.after(5) do
182
+ React.unmount_component_at_node($document.body.to_n)
183
+ end
184
+
185
+ # => Tick!
186
+ # => ... for 5 times then stop ticking after 5 seconds
187
+ ```
188
+
134
189
  ## Example
135
190
 
136
191
  * React Tutorial: see [example/react-tutorial](example/react-tutorial), the original CommentBox example.
@@ -138,7 +193,6 @@ end
138
193
 
139
194
  ## TODOS
140
195
 
141
- * Mixins examples
142
196
  * Documentation
143
197
  * API wrapping coverage of the original js library (pretty close though)
144
198
  * React Native?
@@ -18,35 +18,44 @@ module React
18
18
  return #{type.respond_to?(:initial_state) ? type.initial_state.to_n : `{}`};
19
19
  },
20
20
  componentWillMount: function() {
21
- instance = #{type.new(`this`)};
21
+ var instance = this._getOpalInstance.apply(this);
22
22
  return #{`instance`.component_will_mount if type.method_defined? :component_will_mount};
23
23
  },
24
24
  componentDidMount: function() {
25
- instance = #{type.new(`this`)};
25
+ var instance = this._getOpalInstance.apply(this);
26
26
  return #{`instance`.component_did_mount if type.method_defined? :component_did_mount};
27
27
  },
28
28
  componentWillReceiveProps: function(next_props) {
29
- instance = #{type.new(`this`)};
29
+ var instance = this._getOpalInstance.apply(this);
30
30
  return #{`instance`.component_will_receive_props(`next_props`) if type.method_defined? :component_will_receive_props};
31
31
  },
32
32
  shouldComponentUpdate: function(next_props, next_state) {
33
- instance = #{type.new(`this`)};
33
+ var instance = this._getOpalInstance.apply(this);
34
34
  return #{`instance`.should_component_update?(`next_props`, `next_state`) if type.method_defined? :should_component_update?};
35
35
  },
36
36
  componentWillUpdate: function(next_props, next_state) {
37
- instance = #{type.new(`this`)};
37
+ var instance = this._getOpalInstance.apply(this);
38
38
  return #{`instance`.component_will_update(`next_props`, `next_state`) if type.method_defined? :component_will_update};
39
39
  },
40
40
  componentDidUpdate: function(prev_props, prev_state) {
41
- instance = #{type.new(`this`)};
41
+ var instance = this._getOpalInstance.apply(this);
42
42
  return #{`instance`.component_did_update(`prev_props`, `prev_state`) if type.method_defined? :component_did_update};
43
43
  },
44
44
  componentWillUnmount: function() {
45
- instance = #{type.new(`this`)};
45
+ var instance = this._getOpalInstance.apply(this);
46
46
  return #{`instance`.component_will_unmount if type.method_defined? :component_will_unmount};
47
47
  },
48
+ _getOpalInstance: function() {
49
+ if (this.__opalInstance == undefined) {
50
+ var instance = #{type.new(`this`)};
51
+ } else {
52
+ var instance = this.__opalInstance;
53
+ }
54
+ this.__opalInstance = instance;
55
+ return instance;
56
+ },
48
57
  render: function() {
49
- instance = #{type.new(`this`)};
58
+ var instance = this._getOpalInstance.apply(this);
50
59
  return #{`instance`.render.to_n};
51
60
  }
52
61
  })
@@ -69,8 +69,16 @@ module React
69
69
  self.run_callback(:before_unmount)
70
70
  end
71
71
 
72
+ def p(*args, &block)
73
+ if block || args.count == 0 || (args.count == 1 && args.first.is_a?(Hash))
74
+ _p_tag(*args, &block)
75
+ else
76
+ Kernel.p(*args)
77
+ end
78
+ end
79
+
72
80
  def method_missing(name, *args, &block)
73
- unless (React::HTML_TAGS.include?(name) || name == 'present')
81
+ unless (React::HTML_TAGS.include?(name) || name == 'present' || name == '_p_tag')
74
82
  return super
75
83
  end
76
84
 
@@ -78,6 +86,10 @@ module React
78
86
  name = args.shift
79
87
  end
80
88
 
89
+ if name == "_p_tag"
90
+ name = "p"
91
+ end
92
+
81
93
  @buffer = [] unless @buffer
82
94
  if block
83
95
  current = @buffer
@@ -1,3 +1,3 @@
1
1
  module React
2
- VERSION = "0.0.1"
3
- end
2
+ VERSION = "0.0.2"
3
+ end
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.email = 'zeta11235813@gmail.com'
9
9
  s.homepage = 'https://github.com/zetachang/react.rb'
10
10
  s.summary = 'Opal Ruby wrapper of React.js library.'
11
+ s.license = 'MIT'
11
12
  s.description = "Write reactive UI component with Ruby's elegancy and compiled to run in Javascript."
12
13
 
13
14
  s.files = `git ls-files`.split("\n")
@@ -536,6 +536,47 @@ describe React::Component do
536
536
  element = React.create_element(Foo)
537
537
  expect(React.render_to_static_markup(element)).to eq("<div></div>")
538
538
  end
539
+
540
+ it "should redefine `p` to make method missing work" do
541
+ stub_const 'Foo', Class.new
542
+ Foo.class_eval do
543
+ include React::Component
544
+
545
+ def render
546
+ p(class_name: "foo") do
547
+ p
548
+ div { "lorem ipsum" }
549
+ p(id: "10")
550
+ end
551
+ end
552
+ end
553
+
554
+ element = React.create_element(Foo)
555
+ expect(React.render_to_static_markup(element)).to eq("<p class=\"foo\"><p></p><div>lorem ipsum</div><p id=\"10\"></p></p>")
556
+ end
557
+
558
+ it "should only override `p` in render context" do
559
+ stub_const 'Foo', Class.new
560
+ Foo.class_eval do
561
+ include React::Component
562
+
563
+ before_mount do
564
+ p "first"
565
+ end
566
+
567
+ after_mount do
568
+ p "second"
569
+ end
570
+
571
+ def render
572
+ div
573
+ end
574
+ end
575
+
576
+ expect(Kernel).to receive(:p).with("first")
577
+ expect(Kernel).to receive(:p).with("second")
578
+ renderToDocument(Foo)
579
+ end
539
580
  end
540
581
 
541
582
  describe "isMounted()" do
@@ -1,6 +1,10 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe React do
4
+ after(:each) do
5
+ React::API.clear_component_class_cache
6
+ end
7
+
4
8
  describe "is_valid_element" do
5
9
  it "should return true if passed a valid element" do
6
10
  element = React::Element.new(`React.createElement('div')`)
@@ -79,6 +83,43 @@ describe React do
79
83
  it "should raise error if provided class doesn't defined `render`" do
80
84
  expect { React.create_element(Array) }.to raise_error
81
85
  end
86
+
87
+ it "should use the same instance for the same ReactComponent" do
88
+ Foo.class_eval do
89
+ attr_accessor :a
90
+ def initialize(n)
91
+ self.a = 10
92
+ end
93
+
94
+ def component_will_mount
95
+ self.a = 20
96
+ end
97
+
98
+ def render
99
+ React.create_element("div") { self.a.to_s }
100
+ end
101
+ end
102
+
103
+ expect(React.render_to_static_markup(React.create_element(Foo))).to eq("<div>20</div>")
104
+ end
105
+
106
+ it "should match the instance cycle to ReactComponent life cycle" do
107
+ `var count = 0;`
108
+
109
+ Foo.class_eval do
110
+ def initialize
111
+ `count = count + 1;`
112
+ end
113
+ def render
114
+ React.create_element("div")
115
+ end
116
+ end
117
+
118
+ renderToDocument(Foo)
119
+ renderToDocument(Foo)
120
+
121
+ expect(`count`).to eq(2)
122
+ end
82
123
  end
83
124
 
84
125
  describe "create element with properties" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Chang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-22 00:00:00.000000000 Z
11
+ date: 2015-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -155,7 +155,8 @@ files:
155
155
  - vendor/active_support/core_ext/kernel/singleton_class.rb
156
156
  - vendor/active_support/core_ext/module/remove_method.rb
157
157
  homepage: https://github.com/zetachang/react.rb
158
- licenses: []
158
+ licenses:
159
+ - MIT
159
160
  metadata: {}
160
161
  post_install_message:
161
162
  rdoc_options: []