reactive-ruby 0.7.3

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 (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +53 -0
  5. data/LICENSE +19 -0
  6. data/README.md +303 -0
  7. data/config.ru +15 -0
  8. data/example/examples/Gemfile +7 -0
  9. data/example/examples/Gemfile.lock +45 -0
  10. data/example/examples/config.ru +44 -0
  11. data/example/examples/hello.js.rb +43 -0
  12. data/example/react-tutorial/Gemfile +7 -0
  13. data/example/react-tutorial/Gemfile.lock +49 -0
  14. data/example/react-tutorial/README.md +8 -0
  15. data/example/react-tutorial/_comments.json +14 -0
  16. data/example/react-tutorial/config.ru +63 -0
  17. data/example/react-tutorial/example.js.rb +290 -0
  18. data/example/react-tutorial/public/base.css +62 -0
  19. data/example/todos/Gemfile +11 -0
  20. data/example/todos/Gemfile.lock +84 -0
  21. data/example/todos/README.md +37 -0
  22. data/example/todos/Rakefile +8 -0
  23. data/example/todos/app/application.rb +22 -0
  24. data/example/todos/app/components/app.react.rb +61 -0
  25. data/example/todos/app/components/footer.react.rb +31 -0
  26. data/example/todos/app/components/todo_item.react.rb +46 -0
  27. data/example/todos/app/components/todo_list.react.rb +25 -0
  28. data/example/todos/app/models/todo.rb +19 -0
  29. data/example/todos/config.ru +14 -0
  30. data/example/todos/index.html.haml +16 -0
  31. data/example/todos/spec/todo_spec.rb +28 -0
  32. data/example/todos/vendor/base.css +410 -0
  33. data/example/todos/vendor/bg.png +0 -0
  34. data/example/todos/vendor/jquery.js +4 -0
  35. data/lib/rails-helpers/react_component.rb +32 -0
  36. data/lib/reactive-ruby.rb +23 -0
  37. data/lib/reactive-ruby/api.rb +177 -0
  38. data/lib/reactive-ruby/callbacks.rb +35 -0
  39. data/lib/reactive-ruby/component.rb +411 -0
  40. data/lib/reactive-ruby/element.rb +87 -0
  41. data/lib/reactive-ruby/event.rb +76 -0
  42. data/lib/reactive-ruby/ext/hash.rb +9 -0
  43. data/lib/reactive-ruby/ext/string.rb +8 -0
  44. data/lib/reactive-ruby/isomorphic_helpers.rb +223 -0
  45. data/lib/reactive-ruby/observable.rb +33 -0
  46. data/lib/reactive-ruby/rendering_context.rb +91 -0
  47. data/lib/reactive-ruby/serializers.rb +15 -0
  48. data/lib/reactive-ruby/state.rb +90 -0
  49. data/lib/reactive-ruby/top_level.rb +53 -0
  50. data/lib/reactive-ruby/validator.rb +83 -0
  51. data/lib/reactive-ruby/version.rb +3 -0
  52. data/logo1.png +0 -0
  53. data/logo2.png +0 -0
  54. data/logo3.png +0 -0
  55. data/reactive-ruby.gemspec +25 -0
  56. data/spec/callbacks_spec.rb +107 -0
  57. data/spec/component_spec.rb +597 -0
  58. data/spec/element_spec.rb +60 -0
  59. data/spec/event_spec.rb +22 -0
  60. data/spec/react_spec.rb +209 -0
  61. data/spec/reactjs/index.html.erb +11 -0
  62. data/spec/spec_helper.rb +29 -0
  63. data/spec/tutorial/tutorial_spec.rb +37 -0
  64. data/spec/validator_spec.rb +79 -0
  65. data/vendor/active_support/core_ext/array/extract_options.rb +29 -0
  66. data/vendor/active_support/core_ext/class/attribute.rb +127 -0
  67. data/vendor/active_support/core_ext/kernel/singleton_class.rb +13 -0
  68. data/vendor/active_support/core_ext/module/remove_method.rb +11 -0
  69. metadata +205 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4e9023f2e2533170c453fff7af6571e8c95976b9
4
+ data.tar.gz: 74e2553bd21a054c5674f46f1ededa4d7b339093
5
+ SHA512:
6
+ metadata.gz: 341472a072828b2af26cb27ddfe4dfb2ef85dc1dea31af2df3a2fcdab8fc362a7d4b438afe605f89f71d20c5dbe4e2280e1e56c0b03f469f825b8945309530cf
7
+ data.tar.gz: 91e7a1556c9a53c5576c17194d0b416bbae63781e7180a802cfccec4fb8cf8ba409eed68ae208cc79ce83e1b76f6d52d6ba79bb8ecafc6d349682c29a2b339f4
data/.gitignore ADDED
@@ -0,0 +1,30 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+
5
+ # Runtime data
6
+ pids
7
+ *.pid
8
+ *.seed
9
+
10
+ # Directory for instrumented libs generated by jscoverage/JSCover
11
+ lib-cov
12
+
13
+ # Coverage directory used by tools like istanbul
14
+ coverage
15
+
16
+ # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17
+ .grunt
18
+
19
+ # node-waf configuration
20
+ .lock-wscript
21
+
22
+ # Compiled binary addons (http://nodejs.org/api/addons.html)
23
+ build/Release
24
+
25
+ # Dependency directory
26
+ # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
27
+ node_modules
28
+
29
+ # Ignore bundler config.
30
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem 'opal', :git => "https://github.com/catprintlabs/opal.git"
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ GIT
2
+ remote: https://github.com/catprintlabs/opal.git
3
+ revision: 3682db6f2b23a584787a68d5338a7ee9cb35565a
4
+ specs:
5
+ opal (0.7.1)
6
+ hike (~> 1.2)
7
+ sourcemap (~> 0.1.0)
8
+ sprockets (>= 2.2.3, < 4.0.0)
9
+ tilt (~> 1.4)
10
+
11
+ PATH
12
+ remote: .
13
+ specs:
14
+ reactive-ruby (0.7.3)
15
+ opal
16
+ opal-activesupport
17
+
18
+ GEM
19
+ remote: https://rubygems.org/
20
+ specs:
21
+ hike (1.2.3)
22
+ opal-activesupport (0.1.0)
23
+ opal (>= 0.5.0, < 1.0.0)
24
+ opal-jquery (0.4.0)
25
+ opal (>= 0.7.0, < 0.9.0)
26
+ opal-rspec (0.4.3)
27
+ opal (>= 0.7.0, < 0.9)
28
+ rack (1.6.4)
29
+ rack-protection (1.5.3)
30
+ rack
31
+ react-source (0.13.3)
32
+ sinatra (1.4.6)
33
+ rack (~> 1.4)
34
+ rack-protection (~> 1.4)
35
+ tilt (>= 1.3, < 3)
36
+ sourcemap (0.1.1)
37
+ sprockets (3.3.2)
38
+ rack (~> 1.0)
39
+ tilt (1.4.1)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ opal!
46
+ opal-jquery
47
+ opal-rspec
48
+ react-source (~> 0.12)
49
+ reactive-ruby!
50
+ sinatra
51
+
52
+ BUNDLED WITH
53
+ 1.10.6
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2015 Yi-Cheng Chang (http://github.com/zetachang)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,303 @@
1
+ # React.rb
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/react.rb.svg)](http://badge.fury.io/rb/react.rb)
4
+ [![Code Climate](https://codeclimate.com/github/zetachang/react.rb/badges/gpa.svg)](https://codeclimate.com/github/zetachang/react.rb)
5
+
6
+ **React.rb is an [Opal Ruby](http://opalrb.org) wrapper of [React.js library](http://facebook.github.io/react/)**.
7
+
8
+ It lets you write reactive UI components, with Ruby's elegance and compiled to run in JavaScript. :heart:
9
+
10
+ ## Installation
11
+
12
+ Currently this branch (0.8 in catprint labs) is being used with the following configuration.
13
+ It is suggested to begin with this
14
+ set of gems which is known to work and then add / remove them as needed. Let us know if you discover anything.
15
+
16
+ Currently this has been tested to some extent with rails 3x and 4x
17
+
18
+ ```ruby
19
+ gem 'react-rails', git: "https://github.com/catprintlabs/react-rails.git", :branch => 'isomorphic-methods-support' # you need this branch of react-rails
20
+ gem 'opal', git: "https://github.com/catprintlabs/opal.git"
21
+ gem 'opal-jquery', git: "https://github.com/catprintlabs/opal-jquery.git" # optional if you are using jquery
22
+ gem 'opal-rails' # not sure if you need this in all cases
23
+ gem 'opal-browser' # gets you things like intervals (every method)
24
+ gem 'opal-react', git: "https://github.com/catprintlabs/react.rb.git", :branch => 'opal-0.8'
25
+ gem 'reactive_record', git: "https://github.com/catprintlabs/reactive-record.git", :branch => 'rails4' # if you want to interface to active_record
26
+ gem 'react-bootstrap-rails' # if you want to use boot strap styles
27
+ gem 'react-router-rails', '~>0.13.3' # if you want a single page app router
28
+ gem 'reactor-router', git: "https://github.com/catprintlabs/reactor-router.git" # same as above
29
+ ```
30
+
31
+ In addition
32
+
33
+ ```ruby
34
+ # Gemfile
35
+ # gem 'react-rails', git: "https://github.com/catprintlabs/react-rails.git" # include if you want integration with rails
36
+ gem 'opal'
37
+
38
+ # gem 'opal', git: "https://github.com/catprintlabs/opal.git" # use this if you are stuck on rails 3.x
39
+ # gem 'opal-jquery', git: "https://github.com/catprintlabs/opal-jquery.git" # same as above
40
+
41
+ # include if you want integration with rails
42
+ # gem 'opal-rails'
43
+
44
+ # while not absolutely necessary you will probably want this at least for timers and such
45
+ # gem 'opal-browser'
46
+
47
+ gem 'opal-react', git: "https://github.com/catprintlabs/react.rb.git", :branch => 'opal-0.8'
48
+
49
+ # access active record models from opal!
50
+ # gem 'reactive_record', git: "https://github.com/catprintlabs/reactive-record.git"
51
+
52
+ # include if you want to use bootstrap
53
+ # gem 'react-bootstrap-rails'
54
+ ```
55
+
56
+ and in your Opal application,
57
+
58
+ ```ruby
59
+ require "opal-react"
60
+ require "react"
61
+
62
+ React.render(React.create_element('h1'){ "Hello World!" }, `document.body`)
63
+ ```
64
+
65
+ For a complete example covering most key features, as well as integration with a server (Sinatra, etc), see setup of [Examples](example/tutorial). For additional information on integrating Opal with a server see the [official docs](http://opalrb.org/docs/) of Opal.
66
+
67
+ ## React Overview
68
+
69
+ ### Basics
70
+
71
+ The biggest problem with react is that its almost too simple.
72
+
73
+ In react you define components. Components are simply classes that have a "render" method. The render method "draws" a chunk of
74
+ HTML.
75
+
76
+ Here is a very simple component:
77
+
78
+ ```ruby
79
+
80
+ require 'opal'
81
+ require 'opal-react'
82
+
83
+ class Hello
84
+ def render
85
+ "hello world"
86
+ end
87
+ end
88
+
89
+ # to use the component we first create an instance o
90
+
91
+ Include the `React::Component` mixin in a class to turn it into a react component
92
+
93
+ ```ruby
94
+ require 'opal'
95
+ require 'opal-react'
96
+
97
+ class HelloMessage
98
+
99
+ include React::Component # will create a new component named HelloMessage
100
+
101
+ MSG = {great: 'Cool!', bad: 'Cheer up!'}
102
+
103
+ optional_param :mood
104
+ required_param :name
105
+ define_state :foo, "Default greeting"
106
+
107
+ before_mount do # you can define life cycle callbacks inline
108
+ foo! "#{name}: #{MSG[mood]}" if mood # change the state of foo using foo!, read the state using foo
109
+ end
110
+
111
+ after_mount :log # you can also define life cycle callbacks by reference to a method
112
+
113
+ def log
114
+ puts "mounted!"
115
+ end
116
+
117
+ def render # render method MUST return just one component
118
+ div do # basic dsl syntax component_name(options) { ...children... }
119
+ span { "#{foo} #{name}!" } # all html5 components are defined with lower case text
120
+ end
121
+ end
122
+ end
123
+
124
+ class App
125
+ include React::Component
126
+
127
+ def render
128
+ HelloMessage name: 'John', mood: :great # new components are accessed via the class name
129
+ end
130
+ end
131
+
132
+ # later we will talk about nicer ways to do this: For now wait till doc is loaded
133
+ # then tell React to create an "App" and render it into the document body.
134
+
135
+ `window.onload = #{lambda {React.render(React.create_element(App), `document.body`)}}`
136
+
137
+ # -> console says: mounted!
138
+ ```
139
+
140
+ * Callback of life cycle could be created through helpers `before_mount`, `after_mount`, etc
141
+ * `this.props` is accessed through method `self.params`
142
+ * Use helper method `define_state` to create setter & getter of `this.state` for you
143
+ * For the detailed mapping to the original API, see [this issue](https://github.com/zetachang/react.rb/issues/2) for reference. Complete reference will come soon.
144
+
145
+ ### Element Building DSL
146
+
147
+ As a replacement of JSX, include `React::Component` and you can build `React.Element` hierarchy without all the `React.create_element` noises.
148
+
149
+ ```ruby
150
+ def render
151
+ div do
152
+ h1 { "Title" }
153
+ h2 { "subtitle"}
154
+ div(class_name: 'fancy', id: 'foo') { span { "some text #{interpolation}"} }
155
+ present FancyElement, fancy_props: '10'
156
+ end
157
+ end
158
+ ```
159
+
160
+ ### Props validation
161
+
162
+ 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,
163
+
164
+ ```ruby
165
+ class App
166
+ include React::Component
167
+
168
+ params do
169
+ requires :username, type: String
170
+ requires :enum, values: ['foo', 'bar', 'awesome']
171
+ requires :payload, type: Todo # yeah, a plain Ruby class
172
+ optional :filters, type: Array[String]
173
+ optional :flash_message, type: String, default: 'Welcome!' # no need to feed through `getDefaultProps`
174
+ end
175
+
176
+ def render
177
+ div
178
+ end
179
+ end
180
+ ```
181
+
182
+ ### Mixins
183
+
184
+ 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.
185
+
186
+ ```ruby
187
+ module SetInterval
188
+ def self.included(base)
189
+ base.class_eval do
190
+ before_mount { @interval = [] }
191
+ before_unmount do
192
+ # abort associated timer of a component right before unmount
193
+ @interval.each { |i| i.abort }
194
+ end
195
+ end
196
+ end
197
+
198
+ def set_interval(seconds, &block)
199
+ @interval << $window.every(seconds, &block)
200
+ end
201
+ end
202
+
203
+ class TickTock
204
+ include React::Component
205
+ include SetInterval
206
+
207
+ define_state(:seconds) { 0 }
208
+
209
+ before_mount do
210
+ set_interval(1) { self.seconds = self.seconds + 1 }
211
+ set_interval(1) { puts "Tick!" }
212
+ end
213
+
214
+ def render
215
+ span do
216
+ "React has been running for: #{self.seconds}"
217
+ end
218
+ end
219
+ end
220
+
221
+ React.render(React.create_element(TickTock), $document.body.to_n)
222
+
223
+ $window.after(5) do
224
+ React.unmount_component_at_node($document.body.to_n)
225
+ end
226
+
227
+ # => Tick!
228
+ # => ... for 5 times then stop ticking after 5 seconds
229
+ ```
230
+
231
+
232
+ ### A Simple Component
233
+
234
+ A ruby class which define method `render` is a valid component.
235
+
236
+ ```ruby
237
+ class HelloMessage
238
+ def render
239
+ React.create_element("div") { "Hello World!" }
240
+ end
241
+ end
242
+
243
+ puts React.render_to_static_markup(React.create_element(HelloMessage))
244
+
245
+ # => '<div>Hello World!</div>'
246
+ ```
247
+
248
+ ### More complicated one
249
+
250
+ 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.
251
+
252
+ ```ruby
253
+ class HelloMessage
254
+ def initialize(native)
255
+ @native = Native(native)
256
+ end
257
+
258
+ def component_will_mount
259
+ puts "will mount!"
260
+ end
261
+
262
+ def render
263
+ React.create_element("div") { "Hello #{@native[:props][:name]}!" }
264
+ end
265
+ end
266
+
267
+ puts React.render_to_static_markup(React.create_element(HelloMessage, name: 'John'))
268
+
269
+ # => will_mount!
270
+ # => '<div>Hello John!</div>'
271
+ ```
272
+ ## Example
273
+
274
+ * React Tutorial: see [example/react-tutorial](example/react-tutorial), the original CommentBox example.
275
+ * TodoMVC: see [example/todos](example/todos), your beloved TodoMVC <3.
276
+
277
+ ## TODOS
278
+
279
+ * Documentation
280
+ * API wrapping coverage of the original js library (pretty close though)
281
+ * React Native?
282
+
283
+ ## Developing
284
+
285
+ To run the test case of the project yourself.
286
+
287
+ 1. `git clone` the project
288
+ 2. `bundle install`
289
+ 3. `bundle exec rackup`
290
+ 4. Open `http://localhost:9292` to run the spec
291
+
292
+ ## Contributions
293
+
294
+ This project is still in early stage, so discussion, bug report and PR are really welcome :wink:.
295
+
296
+ ## Contact
297
+
298
+ [David Chang](http://github.com/zetachang)
299
+ [@zetachang](https://twitter.com/zetachang)
300
+
301
+ ## License
302
+
303
+ In short, React.rb is available under the MIT license. See the LICENSE file for more info.
data/config.ru ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ require "opal-rspec"
5
+ require "react/source"
6
+
7
+ Opal.append_path File.expand_path('../spec', __FILE__)
8
+
9
+ run Opal::Server.new { |s|
10
+ s.main = 'opal/rspec/sprockets_runner'
11
+ s.append_path 'spec'
12
+ s.append_path File.dirname(::React::Source.bundled_path_for("react-with-addons.js"))
13
+ s.debug = true
14
+ s.index_path = 'spec/reactjs/index.html.erb'
15
+ }
@@ -0,0 +1,7 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'opal'
4
+ gem 'opal-react', :path => '../..'
5
+ gem 'sinatra'
6
+ #gem 'opal-jquery'
7
+ gem 'react-source'