forked from ruby-hyperloop/ruby-hyperloop.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfeed.xml
1247 lines (1061 loc) · 97.2 KB
/
feed.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Blog Name</title>
<subtitle>Blog subtitle</subtitle>
<id>http://blog.url.com/</id>
<link href="http://blog.url.com/"/>
<link href="http://blog.url.com/feed.xml" rel="self"/>
<updated>2017-02-28T00:00:00+00:00</updated>
<author>
<name>Blog Author</name>
</author>
<entry>
<title>Spring 2017 COMPS Release</title>
<link rel="alternate" href="http://blog.url.com/blog/2017/02/28/spring-2017-comps-release/"/>
<id>http://blog.url.com/blog/2017/02/28/spring-2017-comps-release/</id>
<published>2017-02-28T00:00:00+00:00</published>
<updated>2017-04-13T10:46:52+01:00</updated>
<author>
<name>Article Author</name>
</author>
<content type="html"><p>Spring 2017 heralds a major Hyperloop release. This release will be the first where we have introduced the 5 architectural constructs focused on making it easier to write Isomorphic applications.</p>
<p>This release includes a new version and renaming of all of the Hyperloop gems as well as several new concepts and gems.</p>
<p>These release notes cover the following topics:</p>
<ul>
<li><a href="#release-overview">Release Overview</a></li>
<li><a href="#gem-changes">Gem changes</a></li>
<li><a href="#new-folder-layout">New folder layout</a></li>
<li><a href="#base-class-names">Base class names</a></li>
</ul>
<h2 id="release-overview">Release Overview</h2>
<p>This release consists of:</p>
<ul>
<li>Introduction of COMPS (Components, Operations, Models, Policies and Stores) architectural concepts</li>
<li>Introduction of Hyper-Operation gem</li>
<li>Introduction of Hyper-Store gem</li>
<li>Introduction of Hyper-Spec gem</li>
<li>Introduction of a centralized Hyperloop configuration gem</li>
<li>Renaming of HyperMesh gem to Hyper-Model</li>
<li>Renaming of Express gem to Hyperloop-JS</li>
<li>Changes to state syntax from bang(!) notation to mutate method</li>
<li>Changes to all base class names (Hyperloop::Component, Hyperloop::Model, etc) for consistency</li>
<li>Changes to the location of files in a Rails project</li>
<li>New Hyperloop JS based on latest gems</li>
<li>New HyperRails gem</li>
<li>New website documentation, lived-code editing, new styling and new branding</li>
</ul>
<h2 id="gem-changes">Gem changes</h2>
<h4 id="version-numbers-and-content">Version Numbers and Content</h4>
<table><thead>
<tr>
<th>gem</th>
<th>version</th>
<th>notes</th>
</tr>
</thead><tbody>
<tr>
<td>hyper-loop</td>
<td>0.8</td>
<td>initial release</td>
</tr>
<tr>
<td>hyper-store</td>
<td>0.2.2</td>
<td>initial release</td>
</tr>
<tr>
<td>hyper-operation</td>
<td>0.5.4</td>
<td>initial release</td>
</tr>
<tr>
<td>hyper-component</td>
<td>0.12.5</td>
<td>latest hyper-react + pending fixes + compatibility <code>requires</code> (see below)</td>
</tr>
<tr>
<td>hyper-model</td>
<td>0.6.0</td>
<td>hyper-mesh 0.5.x + fixes + dependence on hyper-store and hyper-operation gems</td>
</tr>
<tr>
<td>hyperloop-js</td>
<td>0.1</td>
<td>latest gems + decoupling of Hyperloop and Opal</td>
</tr>
</tbody></table>
<h4 id="hyper-component-compatibility">Hyper-Component compatibility</h4>
<p>The hyper-component gem will include 3 compatibility modes, determined by which file you require in <code>components.rb.</code></p>
<ul>
<li><strong>Hyperloop Standard</strong>: (<code>require &#39;hyper-component&#39;</code>) In this mode you will use the new hyperloop syntax for all names, macros etc. I.e. components are defined as subclasses of <code>Hyperloop::Component</code> or using <code>Hyperloop::Component::Mixin</code>. States are changed using the <code>mutate</code> objectrather than the exclamation notation. States are declared using the <code>state</code> macro.</li>
<li><strong>HyperReact Compatibility</strong>: (<code>require &#39;hyper-react&#39;</code>) In this mode you can use either syntax, but you will get deprecation warnings, as this mode <em>will</em> go away. This mode will be provided as a bridge so developers can use Operations and Stores without having to make changes to existing components.</li>
<li><strong>DSL Only</strong> (<code>require &#39;hyper-react-dsl&#39;</code>) In this mode you will use the new syntax, however, the DSL will be limited to the base feature set provided by react.js. This mainly applies to states acting as stores. The advantage will be smaller payload size. Initially, this mode not exist but the code will be set up to support it easily in the future</li>
</ul>
<p>In addition, we will make one more release to the hyper-react and hyper-mesh gems that simply provides the hyper-component and hyper-model functionality, plus a deprecation warning. The intent is that the next time you update these gems, you will get the warning, and will know to change to the new gem names.</p>
<h4 id="store-and-operation-interoperability">Store and Operation interoperability</h4>
<p>Stores depend on <code>Hyperloop::Application::Boot</code>, which is an operation defined in the Operation gem. So that you can use stores without operations, the store gem will define a very basic boot operation <em>unless</em> Hyperloop::Application::Boot is already defined.</p>
<h4 id="hyperloop-js">Hyperloop.JS</h4>
<p>Hyperloop.JS now supports Compoennts, Operations and Stores.</p>
<p>There is no gem here, just JavaScript files. We will have two: hyperloop.js which includes Components, Operations and Stores and opal-compiler.js which includes Opal and Opal Compiler.</p>
<h2 id="new-folder-layout">New folder layout</h2>
<p>There is a folder layout within a Rails project.</p>
<p>Old folder layout:</p>
<pre class="highlight plaintext"><code>/app/views/components &lt;-- HyperReact components
/app/models/public &lt;-- HyperMesh models
/app/models &lt;-- server-only models
/app/views/components.rb &lt;-- component manifest
/app/policies &lt;-- HyperMesh policies
</code></pre>
<p>New folder layout:</p>
<pre class="highlight plaintext"><code>/app/hyperloop/components &lt;-- components
/app/hyperloop/models &lt;-- isomorphic models
/app/models &lt;-- server-only models
/app/hyperloop/operations &lt;-- isomorphic operations
/app/operations &lt;-- server-only operations
/app/hyperloop/stores &lt;-- stores
/app/hyperloop/hyperloop.rb &lt;-- hyperloop manifest
/app/policies &lt;-- policies
</code></pre>
<h2 id="base-classes-and-mixins">Base classes and Mixins</h2>
<p>Hyperloop base classes follow a consistent naming convention:</p>
<ul>
<li><code>Hyperloop::Operation</code></li>
<li><code>Hyperloop::Store</code></li>
<li><code>Hyperloop::Policy</code></li>
</ul>
<p>You can inherit from the class:</p>
<pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">Cart</span> <span class="o">&lt;</span> <span class="no">Hyperloop</span><span class="o">::</span><span class="no">Store</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">end</span>
</code></pre>
<p>Or mixin the module:</p>
<pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">Cart</span>
<span class="kp">include</span> <span class="no">Hyperloop</span><span class="o">::</span><span class="no">Store</span><span class="o">::</span><span class="no">Mixin</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">end</span>
</code></pre>
<p>Mixins available:</p>
<ul>
<li><code>Hyperloop::Store::Mixin</code></li>
<li><code>Hyperloop::Policy::Mixin</code></li>
</ul>
</content>
</entry>
<entry>
<title>Editing Flux Loop verses Decoupling</title>
<link rel="alternate" href="http://blog.url.com/blog/2017/01/28/editing-flux-loop-verses-decoupling/"/>
<id>http://blog.url.com/blog/2017/01/28/editing-flux-loop-verses-decoupling/</id>
<published>2017-01-28T00:00:00+00:00</published>
<updated>2017-04-11T18:41:54+01:00</updated>
<author>
<name>Article Author</name>
</author>
<content type="html"><p>@catmando</p>
<p>This started as some thoughts about when to use notation like</p>
<pre class="highlight ruby"><code><span class="no">AddItemToCart</span><span class="p">(</span><span class="ss">item: </span><span class="n">sku</span><span class="p">,</span> <span class="ss">qty: </span><span class="mi">1</span><span class="p">)</span> <span class="c1"># Use an operation</span>
<span class="c1"># vs</span>
<span class="no">Cart</span><span class="p">.</span><span class="nf">addItem</span><span class="p">(</span><span class="ss">item: </span><span class="n">sku</span><span class="p">,</span> <span class="ss">qty: </span><span class="mi">1</span><span class="p">)</span> <span class="c1"># Use a method on the Store</span>
</code></pre>
<p>Which in thinking it through (the answer is &#39;always use the Operation&#39;, read on for details) led me to understand what I think is the real truth about the &quot;flux loop.&quot; And the answer to that is, it is nothing really to do with the &quot;data flow&quot; but with the coupling between parts of the system.</p>
<p>Actions (and Operations, Mutations, and to some extent decorators - maybe) provide a way to decouple elements of the system.</p>
<p>In the above example, why is the Operation better? Sometime in the future, you may want to note that the current user showed interest in an SKU whenever that SKU gets added to the cart. Where does this additional code go? If you have gone down the path of directly calling <code>Cart.addItem</code> you have no place to logically add this code. You can add it the Cart, but this now couples the Cart to some other model like UserInterests. The two are pretty unrelated. So you would end up moving the logic upwards and that puts it where it belonged in the first place: the AddItemToCart Operation.</p>
<p>Having Operations (which are basically the same as Actions + Action Creators + the Dispatcher) and using them <em>whenever data is mutated</em> is a really good rule of thumb which is simple to understand, helps structure the code in a way that leaves it more maintainable, less brittle, and more reusable.</p>
<p>It also creates a &quot;one-way data flow&quot; but the problem is that I can create a system with one-way data flow that does not provide me with good decoupling between parts of the system. I can also in perfectly good flux architecture still make dumb design decisions.</p>
<p>Here are three good things that having a central point like the Dispatcher or Operations solves:</p>
<ol>
<li><strong>Decoupling Interface from Implementation</strong>
The flux Action paradigm decouples the Action protocol from the implementation completely. An Action is a separate object from the Store receiving the action. Some event handler calls the action, and the Store registers with the action. In fact, you can have multiple Stores respond to the same Action. Cool!</li>
</ol>
<p>But even without a Dispatcher you get all the biggest benefit which is the decoupling. So I think its important to understand the first goal is to give a separate name to the Action (or Operation) and which can then be associated whatever Stores need to be updated.</p>
<ol>
<li><p><strong>Debuggability</strong>*
Running everything through the Action-Dispatcher (or an Operation base class) means that you can easily trace all actions/operations. If you are using immutable data you can have even more fun. This is good!</p></li>
<li><p><strong>Keeping Store Concerns Clean</strong>
Without some entity such as Actions to decouple Stores from <em>each other</em> you end up with Store A, knowing too much about Store B. So to emphasize the earlier example: we have a cart, we want to add an item. Great. But now you also want to update a &quot;User Interest List&quot; with any item a user has added to a cart. So the naive implementation would probably have the Cart &quot;add item&quot; mechanism call some method on the UserInterestList Store. Now the Cart which seems like the more &quot;fundamental&quot; class, is linked to the UserInterestList, and the spagetti begins to tangle. </p></li>
</ol>
<p>This is a huge problem everywhere. The &quot;Action&quot; solution is a simplified version of the TrailBlazer Operation, which itself is derived from the Mutation gem. So the problem has been around for a while, and the solutions that work are similiar.</p>
<p>And here is and example of something Actions or Operations and having a central dispatcher does not solve:</p>
<p><strong>Bad class protocol design</strong><br>
We can describe how to &quot;kill&quot; a role playing character many ways. </p>
<pre class="highlight ruby"><code><span class="no">Person</span><span class="p">.</span><span class="nf">set_is_alive</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">boolean</span><span class="p">)</span> <span class="c1"># normal method call</span>
<span class="p">{</span><span class="ss">type: :set_is_alive</span><span class="p">,</span> <span class="ss">payload: </span><span class="p">{</span><span class="ss">id: </span><span class="nb">id</span><span class="p">,</span> <span class="ss">boolean: </span><span class="n">boolean</span><span class="p">}}</span> <span class="c1"># flux action</span>
<span class="no">SetIsAlive</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">boolean</span><span class="p">)</span> <span class="c1"># Operation / Action Creator</span>
<span class="c1"># BAD! what if u change "alive-ness" to be a scale instead of yes/no?</span>
<span class="no">Person</span><span class="p">.</span><span class="nf">set_life_level</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">integer</span><span class="p">)</span> <span class="c1"># normal method call</span>
<span class="p">{</span><span class="ss">type: :set_life_level</span><span class="p">,</span> <span class="ss">payload: </span><span class="p">{</span><span class="ss">id: </span><span class="nb">id</span><span class="p">,</span> <span class="ss">level: </span><span class="n">level</span><span class="p">}}</span> <span class="c1"># flux action</span>
<span class="no">SetLifeLevel</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">level</span><span class="p">)</span> <span class="c1"># Operation / Action Creator</span>
<span class="c1"># STILL BAD! Its less brittle but it still reveals too much implemenation</span>
<span class="no">Person</span><span class="p">.</span><span class="nf">kill</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span>
<span class="p">{</span><span class="ss">type: :kill</span><span class="p">,</span> <span class="ss">data: </span><span class="p">{</span><span class="ss">id: </span><span class="nb">id</span><span class="p">}}</span>
<span class="no">Kill</span><span class="p">(</span><span class="nb">id</span><span class="p">)</span> <span class="c1"># Operation / Action Creator</span>
<span class="c1"># This is a much better protocol!!!</span>
</code></pre>
<p>Regardless of whether I think of my system in terms of Classes and methods, actions, or operations, I can build good protocols or bad protocols. Just declaring that I use &quot;actions&quot; to define my system does not solve this problem. People must realize that &quot;Actions&quot; are just another way to describe messages to move data between elements of the system. Just changing terminology from methods, classes or procedure calls to &#39;Actions&#39; and &#39;Stores&#39; solves nothing.</p>
<p>So there are three good reasons to use an architecture that centralizes the mutation of stores to a single point (or a single class) plus one thing such an architecture does not solve. <strong>But note: No place in that discussion did we say anything about one-way data flow.</strong> That is a side effect and frankly a distraction I think. There are going to be times where its best to violate the &quot;one-way data flow&quot; but that does not mean you have to in any way give up good design principles.</p>
<p>I think its much easier and clearer to think in terms of who mutates the stores. Providing an answer like &quot;in general it should be the Operations&quot;, is a good starting point to discovering the best way to decouple the system. I don&#39;t think saying &quot;make the data flow one way&quot; is as helpful.</p>
<h4 id="how-is-this-going-to-work-in-hyperloop">How is this going to work in Hyperloop</h4>
<p>Here is the basic approach:</p>
<pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">AddItemToCart</span> <span class="o">&lt;</span> <span class="no">HyperOperation</span>
<span class="n">param</span> <span class="ss">:sku</span>
<span class="n">param</span> <span class="ss">qty: </span><span class="mi">1</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">Cart</span> <span class="o">&lt;</span> <span class="no">HyperStore</span>
<span class="n">state_reader</span> <span class="ss">items: </span><span class="no">Hash</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="o">|</span><span class="n">h</span><span class="p">,</span> <span class="n">k</span><span class="o">|</span> <span class="n">h</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">},</span> <span class="ss">scope: :class</span>
<span class="n">receives</span> <span class="no">AddItemToCart</span><span class="p">,</span> <span class="ss">scope: :class</span> <span class="k">do</span>
<span class="n">state</span><span class="p">.</span><span class="nf">items!</span><span class="p">[</span><span class="n">params</span><span class="p">.</span><span class="nf">sku</span><span class="p">]</span> <span class="o">+=</span> <span class="n">params</span><span class="p">.</span><span class="nf">qty</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>(+) Nice and easy<br>
(-) Adds (maybe) 2 lines to every mutator (<code>class ... end</code>)<br>
(+) Allows for other stores to participate in the Operation<br>
(+) Clearly corresponds to the Flux model (i.e. Operation == Action + Action Creator + Dispatcher) </p>
<h3 id="improving-on-the-above">Improving on the above</h3>
<p>In many cases there is a &quot;default&quot; association between the Operation and the Store. You can see this in the names <code>Cart</code> and <code>AddItemToCart</code>. This is very common in real world examples. Given this it makes sense to namespace the actions with the store:</p>
<pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">Cart</span> <span class="o">&lt;</span> <span class="no">HyperStore</span>
<span class="k">class</span> <span class="nc">AddItem</span> <span class="o">&lt;</span> <span class="no">HyperOperation</span>
<span class="n">param</span> <span class="ss">:sku</span>
<span class="n">param</span> <span class="ss">qty: </span><span class="mi">1</span>
<span class="k">end</span>
<span class="n">state_reader</span> <span class="ss">items: </span><span class="no">Hash</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="o">|</span><span class="n">h</span><span class="p">,</span> <span class="n">k</span><span class="o">|</span> <span class="n">h</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">},</span> <span class="ss">scope: :class</span>
<span class="n">receives</span> <span class="no">AddItem</span><span class="p">,</span> <span class="ss">scope: :class</span> <span class="k">do</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">end</span>
<span class="k">end</span>
</code></pre>
<p>We have not changed much, but things look much logical. You would say:</p>
<pre class="highlight ruby"><code> <span class="no">Cart</span><span class="p">.</span><span class="nf">items</span> <span class="c1"># works just like a scope</span>
<span class="no">Cart</span><span class="o">::</span><span class="no">AddItem</span><span class="p">(.</span><span class="nf">.</span><span class="o">.</span><span class="p">)</span> <span class="c1"># stands out!!! must be a mutator</span>
</code></pre>
<p>You can still have other unrelated Stores receive AddItem:</p>
<pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">UserInterestList</span> <span class="o">&lt;</span> <span class="no">HyperStore</span>
<span class="n">receives</span> <span class="no">Cart</span><span class="o">::</span><span class="no">AddItem</span><span class="p">,</span> <span class="ss">scope: :class</span> <span class="k">do</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">end</span>
<span class="k">end</span>
</code></pre>
<p>And because we know that Cart is by default related to AddItem, we can make sure that Cart always receives AddItem first, thus doing away with a common reason for needing to explicitly specify the order that Stores should receive an action.</p>
<p>If it&#39;s not obvious which class the Operation belongs (you can probably see it right in the name) to then it really is its own thing and should be placed in its own namespace. So for example:
<code>ruby
class ResetToDefaults &lt; HyperOperation
end
</code>
Clearly there is no associated Store, so ResetToDefaults stands alone.</p>
<p>While it&#39;s a little more typing (2 lines) you now can give a robust specification to the parameters coming into the Operation. This seems important if the rule of thumb is that Operations are controlling mutations of our Stores</p>
<pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">Cart</span> <span class="o">&lt;</span> <span class="no">HyperStore</span>
<span class="k">class</span> <span class="nc">AddItem</span> <span class="o">&lt;</span> <span class="no">HyperOperation</span>
<span class="n">param</span> <span class="ss">:sku</span><span class="p">,</span> <span class="ss">type: </span><span class="no">String</span><span class="p">,</span> <span class="ss">matches: </span><span class="no">SKU_PATTERN</span>
<span class="n">param</span> <span class="ss">qty: </span><span class="mi">1</span><span class="p">,</span> <span class="ss">type: </span><span class="no">Numeric</span><span class="p">,</span> <span class="ss">minimum: </span><span class="mi">1</span>
<span class="k">end</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">end</span>
</code></pre>
<p>Finally note that nesting the declaration of the Operation inside a Store, does not prevent you from adding special logic not related to the Store elsewhere:</p>
<pre class="highlight ruby"><code><span class="c1"># some where else in the code:</span>
<span class="k">class</span> <span class="nc">Cart</span><span class="o">::</span><span class="no">AddItem</span> <span class="o">&lt;</span> <span class="no">HyperOperation</span>
<span class="k">def</span> <span class="nf">execute</span>
<span class="no">ConfirmItemAvailability</span><span class="p">(</span><span class="ss">sku: </span><span class="n">sku</span><span class="p">).</span><span class="nf">then</span> <span class="p">{</span> <span class="k">super</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Other questions:</p>
<ul>
<li><p><strong>Can Stores Invoke Operations</strong>
In general no. Stores should be kept as simple as possible. If possible move invocation of the Operation upwards into another Operation&#39;s execute method. The obvious exception would be if the Store is providing a stream of data from an asynchronous source. In this case, a Store&#39;s &#39;getter&#39; is going to detect the Data has run out, and can invoke an Operation to get more. The Operation will be asynchronous and when it resolves can inform the Store that it can update its state with new data. The way Operations, states, and promises work together make this straight forward to do.</p></li>
<li><p><strong>Can Operations Read From Stores</strong>
Yes. Often an Operation will read from one Store to determine if it should update another store. </p></li>
<li><p><strong>Can Operations Invoke Other Operations</strong>
Yes. Note that Operations return promises, so asynchronous operation is assumed, Operations can be easily chained.</p></li>
</ul>
</content>
</entry>
<entry>
<title>Comparing Redux with Hyperloop</title>
<link rel="alternate" href="http://blog.url.com/blog/2017/01/17/comparing-redux-with-hyperloop/"/>
<id>http://blog.url.com/blog/2017/01/17/comparing-redux-with-hyperloop/</id>
<published>2017-01-17T00:00:00+00:00</published>
<updated>2017-04-11T18:41:54+01:00</updated>
<author>
<name>Article Author</name>
</author>
<content type="html"><p>@catmando</p>
<p>In trying to find how Hyperloop models and flux-stores relate, I was rereading the Redux tutorials. After having been away from that for a while I was amazed how clean Hyperloop&#39;s HyperReact DSL is compared to the typical JSX code.</p>
<p>For example here is a comparison of <a href="https://github.com/reactjs/redux/tree/master/examples/todomvc">Redux TodoMVC</a> and <a href="https://github.com/ruby-hyperloop/todo-tutorial">Hyperloop TodoMVC</a> which provide the same Todo UI and function. (* <em>note that the code presented is slightly different from the linked Hyperloop tutorial as it uses the most recent version of the DSL.</em>)</p>
<p>Here are the component code files, which are roughly divided the same way between the two apps.</p>
<table><thead>
<tr>
<th>JS files</th>
<th>React/Redux size</th>
<th>Hyperloop size</th>
<th>Ruby Files</th>
</tr>
</thead><tbody>
<tr>
<td>Footer.js</td>
<td>71</td>
<td>29</td>
<td>footer_link.rb, footer.rb</td>
</tr>
<tr>
<td>Header.js, MainSection.js</td>
<td>103</td>
<td>25</td>
<td>index.rb</td>
</tr>
<tr>
<td>TodoItem.js</td>
<td>65</td>
<td>21</td>
<td>todo_item.rb</td>
</tr>
<tr>
<td>TodoTextInput.js</td>
<td>53</td>
<td>20</td>
<td>edit_item.rb</td>
</tr>
<tr>
<td>Total</td>
<td>292</td>
<td>95</td>
<td></td>
</tr>
</tbody></table>
<p>In addition there are the following &quot;store/action/model&quot; definition files.</p>
<table><thead>
<tr>
<th>JS files</th>
<th>React/Redux size</th>
<th>Hyperloop size</th>
<th>Ruby Files</th>
</tr>
</thead><tbody>
<tr>
<td>action/index.js</td>
<td>8</td>
<td></td>
<td></td>
</tr>
<tr>
<td>constants/...</td>
<td>9</td>
<td></td>
<td></td>
</tr>
<tr>
<td>reducers/todos.js</td>
<td>55</td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td>4</td>
<td>models/public/todo.rb</td>
</tr>
<tr>
<td>total</td>
<td>72</td>
<td>4</td>
<td></td>
</tr>
</tbody></table>
<table><thead>
<tr>
<th></th>
<th>React/Redux</th>
<th>Hyperloop</th>
</tr>
</thead><tbody>
<tr>
<td>Total</td>
<td>364</td>
<td>99</td>
</tr>
</tbody></table>
<p>Note that not only is the Hyperloop version less than 1/3 the size, it is persisting and synchronizing the todo list across multiple browsers! </p>
<p>There is nothing wrong with more lines of code, as long as the extra code is adding extra comprehension and making the code easier to maintain. Unfortunately, I would say this is not the case!</p>
<p>I looked specifically at the TodoItem.js (65 SLOC) file and compared it to todo_item.rb (21 SLOC) file.</p>
<p>First, there is a preamble in the JS file (4 lines) which does not exist in the ruby file.</p>
<pre class="highlight javascript"><code><span class="kr">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">Component</span><span class="p">,</span> <span class="nx">PropTypes</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">'react'</span>
<span class="kr">import</span> <span class="nx">classnames</span> <span class="nx">from</span> <span class="s1">'classnames'</span>
<span class="kr">import</span> <span class="nx">TodoTextInput</span> <span class="nx">from</span> <span class="s1">'./TodoTextInput'</span>
</code></pre>
<p>Then we have the class wrapper which is essentially the same 2 lines in JS vs Ruby:</p>
<pre class="highlight javascript"><code><span class="kr">export</span> <span class="k">default</span> <span class="kr">class</span> <span class="nx">TodoItem</span> <span class="kr">extends</span> <span class="nx">Component</span> <span class="p">{</span>
<span class="p">...</span>
<span class="p">}</span>
</code></pre><pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">TodoItem</span> <span class="o">&lt;</span> <span class="no">React</span><span class="o">::</span><span class="no">Component</span><span class="o">::</span><span class="no">Base</span>
<span class="p">.</span><span class="nf">.</span><span class="p">.</span>
<span class="nf">end</span>
</code></pre>
<p>Then we define the properties, and state (11 lines in JSX vs 3 in Ruby)</p>
<pre class="highlight javascript"><code> <span class="kr">static</span> <span class="nx">propTypes</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">todo</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">object</span><span class="p">.</span><span class="nx">isRequired</span><span class="p">,</span>
<span class="na">editTodo</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">isRequired</span><span class="p">,</span>
<span class="na">deleteTodo</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">isRequired</span><span class="p">,</span>
<span class="na">completeTodo</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">func</span><span class="p">.</span><span class="nx">isRequired</span>
<span class="p">}</span>
<span class="nx">state</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">editing</span><span class="p">:</span> <span class="kc">false</span>
<span class="p">}</span>
</code></pre><pre class="highlight ruby"><code> <span class="n">param</span> <span class="ss">:todo</span><span class="p">,</span> <span class="ss">type: </span><span class="no">Todo</span>
<span class="n">define_state</span> <span class="ss">editing: </span><span class="kp">false</span>
</code></pre>
<p>The JS version is simply more verbose. In addition the JS code has an additional 3 declarations for the <code>deleteTodo</code>, <code>editTodo</code> and <code>completeTodo</code> params. Because Hyperloop uses ActiveRecord, reactive (read flux) methods like <code>delete</code> and the <code>complete</code> accessor are built into the <code>Todo</code> model - no extra charge! </p>
<p>In the JS file we now have 2 helper methods (13 SLOC) which don&#39;t exist in the Ruby version:</p>
<pre class="highlight javascript"><code> <span class="nx">handleDoubleClick</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="na">editing</span><span class="p">:</span> <span class="kc">true</span> <span class="p">})</span>
<span class="p">}</span>
<span class="nx">handleSave</span> <span class="o">=</span> <span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">text</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">text</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">deleteTodo</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">editTodo</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">text</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="na">editing</span><span class="p">:</span> <span class="kc">false</span> <span class="p">})</span>
<span class="p">}</span>
</code></pre>
<p>These methods are defined in blocks directly in the Ruby render method, so there is a bit of a stylistic choice here. If we had pulled them out as methods <code>handleDoubleClick</code> would also be three lines long, but <code>handleSave</code> would only be four lines, as once again ActiveRecord is going to make handling the Todo&#39;s internal state easier.</p>
<p>Finally we get to the <code>render</code> method. In React/Redux it looks like this:
```javascript
render() {
const { todo, completeTodo, deleteTodo } = this.props</p>
<pre class="highlight plaintext"><code>let element
if (this.state.editing) {
element = (
&lt;TodoTextInput text={todo.text}
editing={this.state.editing}
onSave={(text) =&gt; this.handleSave(todo.id, text)} /&gt;
)
} else {
element = (
&lt;div className="view"&gt;
&lt;input className="toggle"
type="checkbox"
checked={todo.completed}
onChange={() =&gt; completeTodo(todo.id)} /&gt;
&lt;label onDoubleClick={this.handleDoubleClick}&gt;
{todo.text}
&lt;/label&gt;
&lt;button className="destroy"
onClick={() =&gt; deleteTodo(todo.id)} /&gt;
&lt;/div&gt;
)
}
return (
&lt;li className={classnames({
completed: todo.completed,
editing: this.state.editing
})}&gt;
{element}
&lt;/li&gt;
)
</code></pre>
<p>}
```</p>
<p>Before we look at the details of these 34 lines (vs 15 in Ruby) there are some JS statements which are simply not needed in Ruby, and which really clutter up reading the code. These are:</p>
<pre class="highlight javascript"><code> <span class="kr">const</span> <span class="p">{</span> <span class="nx">todo</span><span class="p">,</span> <span class="nx">completeTodo</span><span class="p">,</span> <span class="nx">deleteTodo</span> <span class="p">}</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span>
<span class="kd">let</span> <span class="nx">element</span>
<span class="p">...</span>
<span class="nx">element</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">...</span>
<span class="p">)</span>
<span class="p">...</span>
<span class="nx">element</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">...</span>
<span class="p">)</span>
<span class="p">...</span>
<span class="k">return</span> <span class="p">(</span>
<span class="p">...</span>
<span class="p">)</span>
</code></pre>
<p>These 8 lines which are almost 25% of the JS render method, and add very little clarity to the method. What do these 8 lines do?</p>
<p>First we reassign the props to intermediate constants presumably to save a little time, and to make it so we can shorten <code>this.props[:todo]</code> to just <code>todo</code>. In Hyperloop you access props more directly using the <code>params</code> object which takes care of accessing and caching the property, so you would say <code>params.todo</code>. <em>A note: originally you could just say <code>todo</code> without the <code>params.</code> prefix, but it was determined that made the code harder to read. So this behavior is being deprecated. A case where more typing is helpful.</em></p>
<p>Then (for stylistic reasons I assume) we compute the child of the <code>li</code> element before actually generating the element. Perhaps the mix of JSX and JS code would quickly get confusing if nested too deeply?</p>
<p>Finally, you have to wrap the whole thing in a return statement, which is just an artifact of JS.</p>
<p>Basically what I see happening here is that JS/JSX is more verbose, so in order to add comprehension, the flow of the code is broken up, methods are added, and intermediate values are introduced. The result is a snowball effect.</p>
<p>Here is complete ruby class for comparison.
```ruby
class TodoItem &lt; React::Component::Base</p>
<p>param :todo, type: Todo
define_state editing: false</p>
<p>render(LI, class: &#39;todo-item&#39;) do
if state.editing
EditItem(todo: todo).
on(:save) do
todo.delete if todo.text.blank?
state.editing! false
end.
on(:cancel) { state.editing! false }
else
INPUT(class: :toggle, type: :checkbox, checked: params.todo.completed).
on(:click) { params.todo.update(completed: !params.todo.completed }
LABEL { params.todo.title }.on(:doubleClick) { state.editing! true }
A(class: :destroy).on(:click) { params.todo.destroy }
end
end
end
```</p>
<p>and here is the complete JSX class:
```jsx
import React, { Component, PropTypes } from &#39;react&#39;
import classnames from &#39;classnames&#39;
import TodoTextInput from &#39;./TodoTextInput&#39;</p>
<p>export default class TodoItem extends Component {
static propTypes = {
todo: PropTypes.object.isRequired,
editTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired,
completeTodo: PropTypes.func.isRequired
}</p>
<p>state = {
editing: false
}</p>
<p>handleDoubleClick = () =&gt; {
this.setState({ editing: true })
}</p>
<p>handleSave = (id, text) =&gt; {
if (text.length === 0) {
this.props.deleteTodo(id)
} else {
this.props.editTodo(id, text)
}
this.setState({ editing: false })
}</p>
<p>render() {
const { todo, completeTodo, deleteTodo } = this.props</p>
<pre class="highlight plaintext"><code>let element
if (this.state.editing) {
element = (
&lt;TodoTextInput text={todo.text}
editing={this.state.editing}
onSave={(text) =&gt; this.handleSave(todo.id, text)} /&gt;
)
} else {
element = (
&lt;div className="view"&gt;
&lt;input className="toggle"
type="checkbox"
checked={todo.completed}
onChange={() =&gt; completeTodo(todo.id)} /&gt;
&lt;label onDoubleClick={this.handleDoubleClick}&gt;
{todo.text}
&lt;/label&gt;
&lt;button className="destroy"
onClick={() =&gt; deleteTodo(todo.id)} /&gt;
&lt;/div&gt;
)
}
return (
&lt;li className={classnames({
completed: todo.completed,
editing: this.state.editing
})}&gt;
{element}
&lt;/li&gt;
)
</code></pre>
<p>}
}
```</p>
<p>I didn&#39;t intend this to be such a rant, and it probably sounds more negative than I intend this to be.</p>
<p>Hyperloop is built on top of React, which is a great library. The problem is that JS just doesn&#39;t have the expressive power especially when it comes to meta-programming and creating DSLs that Ruby does. Instead of a nice clean syntax the mix of HTML and JS presented by JSX is confusing, and to de-confuse things you add more code. Furthermore, because Hyperloop is also built on tried and true of ActiveRecord, again you have an increase in comprehension with a reduction in code.</p>
</content>
</entry>
<entry>
<title>Hyperloop is born</title>
<link rel="alternate" href="http://blog.url.com/blog/2016/09/08/Hyperloop-is-born/"/>
<id>http://blog.url.com/blog/2016/09/08/Hyperloop-is-born/</id>
<published>2016-09-08T06:50:00+01:00</published>
<updated>2017-04-11T18:41:54+01:00</updated>
<author>
<name>Article Author</name>
</author>
<content type="html"><p>Reactrb is being renamed Ruby Hyperloop to reflect the change in emphasis of the project. We have chosen Hyperloop as an umbrella name for the project as it is more expansive and allows us to build out Hyperloop as a web application framework.</p>
<p>React and Reactrb (being renamed HyperReact) remain fundamental parts of this project.</p>
<h2 id="gems">Gems</h2>
<p>All of the Hyperloop core gems will take on a Hyper-name. The naming convention will be HyperReact when discussion the gem and the actual gem will be <code>hyper-rect</code>. All of the gems will follow this convention.</p>
<ul>
<li>Reactrb becomes <strong>HyperReact</strong></li>
<li>Reactrb Router becomes <strong>HyperRouter</strong></li>
<li>Reactive Record and Synchromesh will be merged to become one gem, <strong>HyperMesh</strong></li>
<li>Reactrb Rails Generator becomes <strong>HyperRails</strong></li>
<li>Reactrb Express becomes <strong>Hyperloop Express</strong></li>
</ul>
<h2 id="website">Website</h2>
<ul>
<li>Reactrb.org is changing to <strong>ruby-hyperloop.io</strong></li>
<li>The goal of this refactor is to reposition Reactrb as an umbrella project for Reactrb and associated Isomorphic ruby technologies</li>
<li>The emphasis of the site will be to show how simple Reactrb is to use and also to show best practice for taking it further (Stores, etc). There will be a few tutorials.</li>
<li>The new Reactrb.org will not try to mirroring the React(JS) site – but will have its own identity and structure but it will use as much of the existing Reactrb content as possible</li>
<li>Remove all the original React(JS) text and structure (basically remove everything that comes from the original React site and does not pertain to Reactrb)</li>
<li>New fresh looking design</li>
<li>The new site documentation will include Architectural and + Pattern discussions, describing best practice when working with React like components and stores</li>
<li>There will be a section on Reactrb development tools (Opal Console) and techniques</li>
<li>All of the above Gem’s documentation should be on reactrb.org. The individual Gem’s Read-me’s should be minimal and refer to each Gem’s page on reactrb.org so we can emphasize that these gems are a part of the same family and explain how they work together include installation, usage and best practice instructions for use with:
<ul>
<li>Rails</li>
<li>Sinatra</li>
<li>Webpack &amp; NPM</li>
</ul></li>
<li>Will still include Live Ruby examples through Opal Playground</li>
<li>The site will continue to be hosted on Github pages but the underlying technology will change to:
<ul>
<li>Reactrb Express</li>
<li>Middleman</li>
</ul></li>
</ul>
<p>The changes will be made over time so some Gems, Docs and Tutorials might reference Reactrb or their previous names.</p>
</content>
</entry>
<entry>
<title>Reactrb v0.8.5</title>
<link rel="alternate" href="http://blog.url.com/blog/2016/06/29/reactrb-v0-8-5/"/>
<id>http://blog.url.com/blog/2016/06/29/reactrb-v0-8-5/</id>
<published>2016-06-29T01:00:00+01:00</published>
<updated>2017-04-11T18:41:54+01:00</updated>
<author>
<name>Article Author</name>
</author>
<content type="html"><p>Wow - its already been a hot sweaty summer around here in Reactrb land. First off after a lot of discussion and thinking we have decided to consistently rename everything <strong>Reactrb</strong>. We are sad to see the &quot;dot&quot; go, but this way the name is consistent everywhere, twitter handle, domain name, github org name, etc.</p>
<p>Within the <a href="https://github.com/reactrb">github org</a> we will use the reactb prefix for all gems and repos unless it really doesn&#39;t make sense. So you will find in the repo:</p>
<ul>
<li>reactrb-express (formerly inline-reactive-ruby)</li>
<li>reactrb-examples (looking help here to clean these up...)</li>
<li>reactrb-router (formerly reactive-router)</li>
<li>reactrb-rails-generator (formerly reactive<em>rails</em>generator)</li>
</ul>
<p>For the moment reactive-record is going to keep its name, just because its so much fun. There is a concept to make a gem called reactrb-model that would be the base for reactive-record, but would be agnostic to the persistence mechanism.</p>
<p>This name change and reorganization should help make finding out about Reactrb easier, but its not going to help anybody write code faster or better. So we wanted to at least get in a few improvements as well:</p>
<ul>
<li><a href="#you-pick-your-react-version">You Pick Your React Version</a></li>
<li><a href="#better-native-imports">Better Native Imports</a></li>
<li><a href="#render-call-back">Render Call Back</a></li>
<li><a href="#caps-tag-names">CAPS Tag Names</a></li>
</ul>
<h2 id="you-pick-your-react-version">You Pick Your React Version</h2>
<p>We really needed this one... With every gem and javascript component bundle pulling for a different version of react, Reactrb needed to step out of the way!</p>
<p>Reactrb is now tested with React V13-V15, and by default does <em>not</em> include any version when you <code>require &#39;reactrb&#39;</code>. </p>
<p>This gives you at least three ways to include React source into your assets:</p>
<ol>
<li><p>If you are using Webpack or another Javascript dependency manager, then let the Javascript tool chain work out which version to use. </p>
<p>Just make sure that you include both <code>react</code> and <code>react-dom</code> as Reactrb needs both.</p></li>
<li><p>If you are using the react-rails gem then do a <code>require &#39;react&#39;</code> just before you do a <code>require &#39;reactrb&#39;</code> in your <code>components.rb</code> file. </p>
<p>This will load the version compatible with react-rails.</p></li>
<li><p>If you are using react-rails <em>and</em> a Javascript dependency manager, then check <a href="https://github.com/reactjs/react-rails/blob/master/VERSIONS.md">here</a> for the version that react-rails wants, and include that version explicitly with <code>npm</code> or whatever tool you are using on the JS side.</p>
<p>This will let the JS tool chain manage the dependencies, but insure you have a compatible version for react-rails.</p></li>
<li><p>Otherwise Reactrb includes (but does not require) several versions of react source. Just add <code>require &#39;react-latest&#39;</code> right above wherever you do a <code>require &#39;hyper-react&#39;</code>. </p>
<p>If you want another version do <code>require &#39;react-v14&#39;</code> or <code>require &#39;react-v13&#39;</code></p></li>
</ol>
<h2 id="better-native-imports">Better Native Imports</h2>
<p>Previously you could not import single javascript components into the Reactrb namespace. They had to be wrapped is some kind of library structure for the <code>NativeLibrary</code> class to work. </p>
<p>We wanted to keep <code>NativeLibrary</code> as strictly the mechanism that imports libraries of components, and so we added the <code>imports</code> directive to <code>React::Component</code>.</p>
<p>So now you can say:</p>
<pre class="highlight ruby"><code><span class="k">class</span> <span class="nc">Griddle</span> <span class="o">&lt;&lt;</span> <span class="no">React</span><span class="o">::</span><span class="no">Component</span><span class="o">::</span><span class="no">Base</span>
<span class="n">imports</span> <span class="s1">'Griddle'</span>
<span class="k">end</span>
</code></pre>
<p>Now once you install the the <a href="http://griddlegriddle.github.io/Griddle/">Griddle</a> Javascript component you can use <code>Griddle</code> like any other HyperReact component.</p>
<p><em>But wait there&#39;s more...</em></p>
<p>Importing a ton of libraries this way could get tedious especially if you are using something like Webpack anyway to manage which components to include.</p>
<p>To keep things easy, you can opt in to <em>auto-import</em> by simply adding <code>require &#39;hyper-react/auto-import&#39;</code> after you <code>require hyper-react</code>.</p>
<p>With auto-importing enabled a component like <code>Griddle</code> or a library like <code>ReactBootstrap</code> will automatically be available to your HyperReact components.</p>
<p>See <a href="/using-javascript-components.html">Using Javascript Components</a> for more details.</p>
<h2 id="render-call-back">Render Call back</h2>
<p>Up till now we have been defining the render method as just that <em>an instance method in your component class.</em> That&#39;s cool, and that still works, however for a couple of reasons we felt having a call back to define the render method would be handy. </p>
<ol>
<li><p><strong>Render methods are too large:</strong> Even using helper methods to keep things small, render methods often exceed the normal 10 line ruby style guide recommendation. </p>
<p>That is not a problem in itself - after all recommendations are just that. However if you are using tools like RuboCop, then it&#39;s sad when every single one of your components has a warning flag. You can turn off that cop of course, but then lose a very valuable check that most of the times should be followed. </p>
<p>By allowing render to be defined as a call back, you get rid of this problem.</p></li>
<li><p><strong>Get Rid of Boiler Plate:</strong> All components must have a single outer container, and for many components this container and its parameters are static. So the new render call back lets you specify the container component and its parameters as params to the callback. This eliminates two unnecessary lines per component, plus an unneeded level of indentation, and I think when used properly it makes things clearer.</p></li>
<li><p><strong>Consistency:</strong> All the other lifecycle methods are defined as callbacks, so its nice to have render fit in.</p></li>
</ol>
<p>Meanwhile the <code>Element[...].render</code> method which can be used to mount a top level component to a DOM element, has been updated to follow the same syntax as well. So for example to mount a component you can just say <code>Element[&#39;#top-level&#39;].render App</code>.</p>
<p>This is not a big deal but I think you should try it out, and see if it doesn&#39;t lead to more readable components.</p>
<h2 id="caps-tag-names">CAPS Tag Names</h2>
<p>Its been suggested that especially for beginners its a little hard to parse the DSL. You don&#39;t know which method is what, and its hard to tell the difference between tags like <code>select</code> and other helper methods. One way to solve this is to write the built-in tag names in all caps, which the DSL now supports.</p>
<p>It was a small thing, so we went ahead and added it. Tell us what you think!</p>
</content>
</entry>
<entry>
<title>Getting Started with Reactrb and Rails</title>
<link rel="alternate" href="http://blog.url.com/blog/2016/01/26/getting-started-with-reactrb-and-rails/"/>
<id>http://blog.url.com/blog/2016/01/26/getting-started-with-reactrb-and-rails/</id>
<published>2016-01-26T16:29:00+00:00</published>
<updated>2017-04-11T18:41:54+01:00</updated>
<author>
<name>Article Author</name>
</author>
<content type="html"><p><a href="//facebook.github.io/react/">React.js</a> support for rails is provided
<a href="https://github.com/reactjs/react-rails">react-rails</a> gem.</p>
<p>From its project page, React-rails can:</p>
<ul>
<li> Provide various react builds to your asset bundle</li>
<li> Transform .jsx in the asset pipeline</li>
<li> Render components into views and mount them via view helper &amp; react_ujs</li>
<li> Render components server-side with prerender: true</li>
<li> Generate components with a Rails generator</li>
<li> Be extended with custom renderers, transformers and view helpers</li>
</ul>
<p>While <code>react-rails</code> provides easy integration with Rails, a Rails
developer cannot leverage the full benefits of React.js, particularly
isomorphic/<a href="https://medium.com/@mjackson/universal-javascript-4761051b7ae9#.rxrgqe5wb">universal</a>
domain logic code and views since different languages are used on
server and client
sides. <a href="https://github.com/zetachang/react.rb">React.rb/reactive-ruby</a>
(<strong>react.rb</strong> from here on) builds on top of <code>react-rails</code> by allowing
one to write React components in Ruby, courtesy of
<a href="http://opalrb.org">Opal</a>. Now the Rails programmer can also enjoy
universal domain logic and views written in Ruby via react.js.</p>
<p>The focus of this article will be limited to just getting <code>react.rb</code>
up and running on Rails from scratch.</p>
<h1 id="generate-a-rails-project-that-uses-opal">Generate a rails project that uses Opal</h1>
<p>The easiest way to create a Rails project that uses <a href="http://opalrb.org">Opal</a> is to use the
<code>--javascript=opal</code> option. Manual instructions on how add Opal
support to an existing Rails project are given on the <a href="https://github.com/opal/opal-rails">opal-rails</a>
site. Create a new Rails project with the following command:</p>
<pre class="highlight plaintext"><code>% rails new getting-started-react-rails --javascript=opal
</code></pre>
<h1 id="add-react-rb-gems-to-gemfile">Add react.rb gems to Gemfile</h1>
<p>To use <code>react.rb</code>, you need to add 3 gems to your Gemfile:
reactive-ruby<sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup>, react-rails and therubyracer</p>
<pre class="highlight ruby"><code> <span class="n">gem</span> <span class="s1">'reactive-ruby'</span><span class="p">,</span> <span class="s1">'0.7.29'</span> <span class="c1"># nail down compatible version w/ pre 0.14 react-rails</span>
<span class="n">gem</span> <span class="s1">'react-rails'</span><span class="p">,</span> <span class="s1">'1.3.2'</span> <span class="c1"># react.rb not compatible ith 1.4.* yet so use this one</span>
<span class="n">gem</span> <span class="s1">'opal-rails'</span> <span class="c1"># already added w/the --javascript=opal option</span>
<span class="n">gem</span> <span class="s1">'therubyracer'</span><span class="p">,</span> <span class="ss">platforms: :ruby</span> <span class="c1"># Required for server side prerendering</span>
</code></pre>
<p>Run <code>bundle install</code> after these have been added to your Gemfile.</p>
<h3 id="update">Update</h3>
<p>Since this article was written there has been Rails generator code
that has been written as a
<a href="https://rubygems.org/gems/reactrb-rails-generator">standalone gem</a>
that is pending integration with react.rb gem. Some of conventions
described in this article, which currently match that of existing
documentation and sample Rails project in react.rb will likely be
changing as part of that.</p>
<h1 id="convert-application-js-to-application-js-rb">Convert application.js to application.js.rb</h1>
<p>When using opal-rails, it is recommented<sup><a id="fnr.2" class="footref" href="#fn.2">2</a></sup>
to convert the application.js file to application.js.rb. Make yours look
like this:</p>
<pre class="highlight ruby"><code> <span class="c1"># app/assets/javascripts/application.js.rb</span>
<span class="nb">require</span> <span class="s1">'opal'</span>
<span class="nb">require</span> <span class="s1">'opal_ujs'</span>
<span class="nb">require</span> <span class="s1">'turbolinks'</span>
<span class="nb">require</span> <span class="s1">'react'</span>
<span class="nb">require</span> <span class="s1">'react_ujs'</span>
<span class="nb">require</span> <span class="s1">'components'</span> <span class="c1"># to include isomorphic react components on the client</span>
<span class="n">require_tree</span> <span class="s1">'.'</span>
</code></pre>
<h1 id="setup-for-isomorphic3-react-components">Setup for isomorphic<sup><a id="fnr.3" class="footref" href="#fn.3">3</a></sup> React components</h1>
<p>A big perk of react.js is isomorphic code (same code on server and
client side), which leads to A united UI layer. As mentioned before
<a href="https://github.com/reactjs/react-rails">react-rails</a> provides server rendered react.js components, as well as
other perks as detailed in this <a href="http://bensmithett.com/server-rendered-react-components-in-rails/">this article</a>. This quote from the
aforementioned article gives one a sense of how big a perk this is.</p>
<blockquote>
<p>The Holy Grail. The united UI layer. Serve up real HTML on first page load, then kick off a client side JS app. All without duplicating a single line of UI code.</p>
</blockquote>
<p>Those who have struggled with duplicated views on front and back ends,
in different languages should appreciate that sentiment. To support
isomorphic react.rb components you need to setup a structure for these
<strong>shared</strong> components. The current convention is to make a
<code>app/views/components</code> directory containing the components and a
<code>components.rb</code> manifest file that will require all the <code>react.rb</code>
components, like so:</p>
<pre class="highlight ruby"><code> <span class="c1"># app/views/components.rb</span>
<span class="nb">require</span> <span class="s1">'opal'</span>
<span class="nb">require</span> <span class="s1">'reactive-ruby'</span>
<span class="n">require_tree</span> <span class="s1">'./components'</span>
</code></pre>
<p>You may have noticed that, that the <code>application.js.rb</code> we created
<code>require</code>s this components.rb file to compile these universal
<code>react.rb</code> components.</p>
<h1 id="make-a-controller-to-demonstrate-react-components">Make a controller to demonstrate react components</h1>
<p>We will be demonstrating several types of components as
examples. Let&#39;s make a dedicated controller to demo these components with
dedicated actions for each case.</p>
<pre class="highlight shell"><code> % rails g controller home isomorphic iso_convention search_path client_only
</code></pre>
<h1 id="create-your-first-react-component">Create your first React Component</h1>
<p>So now that we&#39;re setup for isomorphic components, lets make our first
react.rb component. We&#39;ll start with a simple &quot;Hello World&quot;
component. This component takes a single, required param message of
type <code>String</code>. Note, param in <code>react.rb</code> corresonds to prop in
react.js; <code>react.rb</code> calls props &quot;params&quot; to provide a more Rails
familiar API. The component renders this message param in an <strong>h1</strong> element,
and renders a button that, when clicked, calls <code>alert()</code> with the same
message.</p>
<p>Put the following into this file <strong>app/views/components/hello.rb</strong>:</p>
<pre class="highlight ruby"><code> <span class="k">class</span> <span class="nc">Hello</span>
<span class="kp">include</span> <span class="no">React</span><span class="o">::</span><span class="no">Component</span>
<span class="n">required_param</span> <span class="ss">:what</span><span class="p">,</span> <span class="ss">type: </span><span class="no">String</span>
<span class="k">def</span> <span class="nf">message</span>
<span class="s2">"Hello </span><span class="si">#{</span><span class="n">what</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">render</span>
<span class="n">div</span> <span class="p">{</span>
<span class="n">h1</span> <span class="p">{</span> <span class="n">message</span> <span class="p">}</span>
<span class="n">button</span> <span class="p">{</span><span class="s2">"Press me"</span><span class="p">}.</span><span class="nf">on</span><span class="p">(</span><span class="ss">:click</span><span class="p">)</span> <span class="p">{</span><span class="n">alert</span> <span class="n">message</span><span class="p">}</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>You can render the <code>Hello</code> component directly without needing a
template file in your controller with
<code>render_component()</code>. <code>render_component()</code> takes an optional (more on
this later) class name of the component and any parameters you wish to
pass the component. Implement the <code>isomorphic</code> action in the
<code>HomeController</code> like so</p>
<pre class="highlight ruby"><code> <span class="k">class</span> <span class="nc">HomeController</span> <span class="o">&lt;</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">isomorphic</span>
<span class="n">render_component</span> <span class="s1">'Hello'</span><span class="p">,</span> <span class="ss">message: </span><span class="s1">'World'</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Start the server, then visit <a href="http://localhost:3000/home/isomorphic"><a href="http://localhost:3000/home/isomorphic">http://localhost:3000/home/isomorphic</a></a> to
view the component. By default, react.rb prerenders the component on
the server (the reverse of react-rails&#39; <code>react_component()</code>, but you can force Rails to NOT prerender by appending
?no_prerender=1 to the url, like so</p>
<pre class="highlight plaintext"><code>http://localhost:3000/home/isomorphic?no_prerender=1
</code></pre>
<p>Let&#39;s take a quick look at the HTML returned by the server in both cases (formatted to be more human-readable)</p>
<p>For <a href="http://localhost:3000/home/isomorphic"><a href="http://localhost:3000/home/isomorphic">http://localhost:3000/home/isomorphic</a></a>
we see the <strong>h1</strong> and button rendered from the server:</p>
<pre class="highlight html"><code> <span class="nt">&lt;div</span> <span class="na">data-react-class=</span><span class="s">"React.TopLevelRailsComponent"</span>
<span class="na">data-react-props=</span><span class="s">"{&amp;quot;render_params&amp;quot;:{&amp;quot;message&amp;quot;:&amp;quot;World&amp;quot;},&amp;quot;component_name&amp;quot;:&amp;quot;Hello&amp;quot;,&amp;quot;controller&amp;quot;:&amp;quot;Home&amp;quot;}"</span><span class="nt">&gt;</span>
<span class="nt">&lt;div</span> <span class="na">data-reactid=</span><span class="s">".3hx9dqn6rk"</span>
<span class="na">data-react-checksum=</span><span class="s">"487927662"</span><span class="nt">&gt;</span>
<span class="nt">&lt;h1</span> <span class="na">data-reactid=</span><span class="s">".3hx9dqn6rk.0"</span><span class="nt">&gt;</span>Hello World<span class="nt">&lt;/h1&gt;</span>
<span class="nt">&lt;button</span> <span class="na">data-reactid=</span><span class="s">".3hx9dqn6rk.1"</span><span class="nt">&gt;</span>Press me<span class="nt">&lt;/button&gt;</span>
<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre>
<p>For <a href="http://localhost:3000/home/isomorphic?no_prerender=1"><a href="http://localhost:3000/home/isomorphic?no_prerender=1">http://localhost:3000/home/isomorphic?no_prerender=1</a></a>
there is no prerendering and the rendering is done by the client</p>
<pre class="highlight html"><code> <span class="nt">&lt;div</span> <span class="na">data-react-class=</span><span class="s">"React.TopLevelRailsComponent"</span>
<span class="na">data-react-props=</span><span class="s">"{&amp;quot;render_params&amp;quot;:{&amp;quot;message&amp;quot;:&amp;quot;World&amp;quot;},&amp;quot;component_name&amp;quot;:&amp;quot;Hello&amp;quot;,&amp;quot;controller&amp;quot;:&amp;quot;Home&amp;quot;}"</span><span class="nt">&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre>
<h1 id="rails-conventions-isomorphic-i-e-universal-components-and-the-default-component">Rails conventions, isomorphic (i.e. universal) components and the &quot;default&quot; component</h1>
<p>In the Rails tradition of convention over configuration, you can
structure/name your components to match your controllers to support a
&quot;default&quot; component, i.e. a component you do NOT need to specify, for
a controller action. To make a default component for the
<code>HomeController#iso_convention</code> action, create the following file:</p>
<pre class="highlight ruby"><code> <span class="c1"># app/views/components/home/iso_convention.rb</span>
<span class="k">module</span> <span class="nn">Components</span>
<span class="k">module</span> <span class="nn">Home</span>
<span class="k">class</span> <span class="nc">IsoConvention</span>