react.rb 0.0.1 → 0.0.2

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.
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: []