ovto 0.2.0

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 (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.gitmodules +3 -0
  4. data/CHANGELOG.md +22 -0
  5. data/Gemfile +7 -0
  6. data/Gemfile.lock +57 -0
  7. data/LICENSE.txt +44 -0
  8. data/README.md +84 -0
  9. data/Rakefile +41 -0
  10. data/book/README.md +1 -0
  11. data/book/SUMMARY.md +13 -0
  12. data/book/api/actions.md +77 -0
  13. data/book/api/app.md +86 -0
  14. data/book/api/component.md +175 -0
  15. data/book/api/fetch.md +42 -0
  16. data/book/api/state.md +97 -0
  17. data/book/guides/debugging.md +23 -0
  18. data/book/guides/development.md +11 -0
  19. data/book/guides/tutorial.md +288 -0
  20. data/book/screenshot.png +0 -0
  21. data/docs/api/Ovto/Actions.html +135 -0
  22. data/docs/api/Ovto/App.html +531 -0
  23. data/docs/api/Ovto/Component/MoreThanOneNode.html +135 -0
  24. data/docs/api/Ovto/Component.html +350 -0
  25. data/docs/api/Ovto/Runtime.html +315 -0
  26. data/docs/api/Ovto/State/MissingValue.html +135 -0
  27. data/docs/api/Ovto/State/UnknownKey.html +135 -0
  28. data/docs/api/Ovto/State.html +699 -0
  29. data/docs/api/Ovto/WiredActions.html +343 -0
  30. data/docs/api/Ovto.html +319 -0
  31. data/docs/api/_index.html +229 -0
  32. data/docs/api/actions.html +398 -0
  33. data/docs/api/app.html +411 -0
  34. data/docs/api/class_list.html +51 -0
  35. data/docs/api/component.html +469 -0
  36. data/docs/api/css/common.css +1 -0
  37. data/docs/api/css/full_list.css +58 -0
  38. data/docs/api/css/style.css +499 -0
  39. data/docs/api/file.README.html +162 -0
  40. data/docs/api/file_list.html +56 -0
  41. data/docs/api/frames.html +17 -0
  42. data/docs/api/index.html +162 -0
  43. data/docs/api/js/app.js +248 -0
  44. data/docs/api/js/full_list.js +216 -0
  45. data/docs/api/js/jquery.js +4 -0
  46. data/docs/api/method_list.html +243 -0
  47. data/docs/api/state.html +430 -0
  48. data/docs/api/top-level-namespace.html +110 -0
  49. data/docs/gitbook/fonts/fontawesome/FontAwesome.otf +0 -0
  50. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.eot +0 -0
  51. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.svg +685 -0
  52. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.ttf +0 -0
  53. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.woff +0 -0
  54. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 +0 -0
  55. data/docs/gitbook/gitbook-plugin-fontsettings/fontsettings.js +240 -0
  56. data/docs/gitbook/gitbook-plugin-fontsettings/website.css +291 -0
  57. data/docs/gitbook/gitbook-plugin-highlight/ebook.css +135 -0
  58. data/docs/gitbook/gitbook-plugin-highlight/website.css +434 -0
  59. data/docs/gitbook/gitbook-plugin-lunr/lunr.min.js +7 -0
  60. data/docs/gitbook/gitbook-plugin-lunr/search-lunr.js +59 -0
  61. data/docs/gitbook/gitbook-plugin-search/lunr.min.js +7 -0
  62. data/docs/gitbook/gitbook-plugin-search/search-engine.js +50 -0
  63. data/docs/gitbook/gitbook-plugin-search/search.css +35 -0
  64. data/docs/gitbook/gitbook-plugin-search/search.js +213 -0
  65. data/docs/gitbook/gitbook-plugin-sharing/buttons.js +90 -0
  66. data/docs/gitbook/gitbook.js +4 -0
  67. data/docs/gitbook/images/apple-touch-icon-precomposed-152.png +0 -0
  68. data/docs/gitbook/images/favicon.ico +0 -0
  69. data/docs/gitbook/style.css +9 -0
  70. data/docs/gitbook/theme.js +4 -0
  71. data/docs/guides/debugging.html +355 -0
  72. data/docs/guides/development.html +361 -0
  73. data/docs/guides/tutorial.html +571 -0
  74. data/docs/index.html +422 -0
  75. data/docs/screenshot.png +0 -0
  76. data/docs/search_index.json +1 -0
  77. data/example/sinatra/Gemfile +6 -0
  78. data/example/sinatra/Gemfile.lock +59 -0
  79. data/example/sinatra/README.md +21 -0
  80. data/example/sinatra/app.rb +18 -0
  81. data/example/sinatra/config.ru +30 -0
  82. data/example/sinatra/ovto/app.rb +171 -0
  83. data/example/sinatra/public/style.css +4 -0
  84. data/example/sinatra/public/todomvc-app-css_index.css +376 -0
  85. data/example/sinatra/public/todomvc-common_base.css +141 -0
  86. data/example/sinatra/views/index.erb +21 -0
  87. data/example/static/Gemfile +3 -0
  88. data/example/static/Gemfile.lock +30 -0
  89. data/example/static/README.md +10 -0
  90. data/example/static/Rakefile +4 -0
  91. data/example/static/app.js +24808 -0
  92. data/example/static/app.rb +43 -0
  93. data/example/static/index.html +11 -0
  94. data/lib/ovto/actions.rb +10 -0
  95. data/lib/ovto/app.rb +58 -0
  96. data/lib/ovto/component.rb +191 -0
  97. data/lib/ovto/fetch.rb +53 -0
  98. data/lib/ovto/runtime.rb +388 -0
  99. data/lib/ovto/state.rb +69 -0
  100. data/lib/ovto/version.rb +3 -0
  101. data/lib/ovto/wired_actions.rb +33 -0
  102. data/lib/ovto.rb +50 -0
  103. data/ovto.gemspec +22 -0
  104. data/screenshot.png +0 -0
  105. metadata +161 -0
@@ -0,0 +1,571 @@
1
+
2
+ <!DOCTYPE HTML>
3
+ <html lang="" >
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
7
+ <title>Getting Started · GitBook</title>
8
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
9
+ <meta name="description" content="">
10
+ <meta name="generator" content="GitBook 3.2.3">
11
+
12
+
13
+
14
+
15
+ <link rel="stylesheet" href="../gitbook/style.css">
16
+
17
+
18
+
19
+
20
+ <link rel="stylesheet" href="../gitbook/gitbook-plugin-highlight/website.css">
21
+
22
+
23
+
24
+ <link rel="stylesheet" href="../gitbook/gitbook-plugin-search/search.css">
25
+
26
+
27
+
28
+ <link rel="stylesheet" href="../gitbook/gitbook-plugin-fontsettings/website.css">
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+ <meta name="HandheldFriendly" content="true"/>
53
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
54
+ <meta name="apple-mobile-web-app-capable" content="yes">
55
+ <meta name="apple-mobile-web-app-status-bar-style" content="black">
56
+ <link rel="apple-touch-icon-precomposed" sizes="152x152" href="../gitbook/images/apple-touch-icon-precomposed-152.png">
57
+ <link rel="shortcut icon" href="../gitbook/images/favicon.ico" type="image/x-icon">
58
+
59
+
60
+
61
+ <link rel="prev" href="../" />
62
+
63
+
64
+ </head>
65
+ <body>
66
+
67
+ <div class="book">
68
+ <div class="book-summary">
69
+
70
+
71
+ <div id="book-search-input" role="search">
72
+ <input type="text" placeholder="Type to search" />
73
+ </div>
74
+
75
+
76
+ <nav role="navigation">
77
+
78
+
79
+
80
+ <ul class="summary">
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+ <li class="chapter " data-level="1.1" data-path="../">
91
+
92
+ <a href="../">
93
+
94
+
95
+ Introduction
96
+
97
+ </a>
98
+
99
+
100
+
101
+ </li>
102
+
103
+ <li class="chapter active" data-level="1.2" data-path="tutorial.html">
104
+
105
+ <a href="tutorial.html">
106
+
107
+
108
+ Getting Started
109
+
110
+ </a>
111
+
112
+
113
+
114
+ </li>
115
+
116
+ <li class="chapter " data-level="1.3" >
117
+
118
+ <span>
119
+
120
+
121
+ API
122
+
123
+ </span>
124
+
125
+
126
+
127
+ <ul class="articles">
128
+
129
+
130
+ <li class="chapter " data-level="1.3.1" data-path="../api/app.html">
131
+
132
+ <a href="../api/app.html">
133
+
134
+
135
+ App
136
+
137
+ </a>
138
+
139
+
140
+
141
+ </li>
142
+
143
+ <li class="chapter " data-level="1.3.2" data-path="../api/state.html">
144
+
145
+ <a href="../api/state.html">
146
+
147
+
148
+ State
149
+
150
+ </a>
151
+
152
+
153
+
154
+ </li>
155
+
156
+ <li class="chapter " data-level="1.3.3" data-path="../api/actions.html">
157
+
158
+ <a href="../api/actions.html">
159
+
160
+
161
+ Actions
162
+
163
+ </a>
164
+
165
+
166
+
167
+ </li>
168
+
169
+ <li class="chapter " data-level="1.3.4" data-path="../api/component.html">
170
+
171
+ <a href="../api/component.html">
172
+
173
+
174
+ Component
175
+
176
+ </a>
177
+
178
+
179
+
180
+ </li>
181
+
182
+
183
+ </ul>
184
+
185
+ </li>
186
+
187
+ <li class="chapter " data-level="1.4" >
188
+
189
+ <span>
190
+
191
+
192
+ Guides
193
+
194
+ </span>
195
+
196
+
197
+
198
+ <ul class="articles">
199
+
200
+
201
+ <li class="chapter " data-level="1.4.1" data-path="debugging.html">
202
+
203
+ <a href="debugging.html">
204
+
205
+
206
+ Debugging
207
+
208
+ </a>
209
+
210
+
211
+
212
+ </li>
213
+
214
+ <li class="chapter " data-level="1.4.2" data-path="development.html">
215
+
216
+ <a href="development.html">
217
+
218
+
219
+ Development
220
+
221
+ </a>
222
+
223
+
224
+
225
+ </li>
226
+
227
+
228
+ </ul>
229
+
230
+ </li>
231
+
232
+
233
+
234
+
235
+ <li class="divider"></li>
236
+
237
+ <li>
238
+ <a href="https://www.gitbook.com" target="blank" class="gitbook-link">
239
+ Published with GitBook
240
+ </a>
241
+ </li>
242
+ </ul>
243
+
244
+
245
+ </nav>
246
+
247
+
248
+ </div>
249
+
250
+ <div class="book-body">
251
+
252
+ <div class="body-inner">
253
+
254
+
255
+
256
+ <div class="book-header" role="navigation">
257
+
258
+
259
+ <!-- Title -->
260
+ <h1>
261
+ <i class="fa fa-circle-o-notch fa-spin"></i>
262
+ <a href=".." >Getting Started</a>
263
+ </h1>
264
+ </div>
265
+
266
+
267
+
268
+
269
+ <div class="page-wrapper" tabindex="-1" role="main">
270
+ <div class="page-inner">
271
+
272
+ <div id="book-search-results">
273
+ <div class="search-noresults">
274
+
275
+ <section class="normal markdown-section">
276
+
277
+ <h1 id="getting-started">Getting Started</h1>
278
+ <p>This is a tutorial of making an Ovto app. We create a static app (.html + .js) here,
279
+ but you can embed Ovto apps into a Rails or Sinatra app (See <code>./example/*</code>).</p>
280
+ <p>This is the final Ruby code.</p>
281
+ <pre><code>require &apos;ovto&apos;
282
+
283
+ class MyApp &lt; Ovto::App
284
+ class State &lt; Ovto::State
285
+ item :celsius, default: 0
286
+
287
+ def fahrenheit
288
+ (celsius * 9 / 5.0) + 32
289
+ end
290
+ end
291
+
292
+ class Actions &lt; Ovto::Actions
293
+ def set_celsius(state:, value:)
294
+ return {celsius: value}
295
+ end
296
+
297
+ def set_fahrenheit(state:, value:)
298
+ new_celsius = (value - 32) * 5 / 9.0
299
+ return {celsius: new_celsius}
300
+ end
301
+ end
302
+
303
+ class View &lt; Ovto::Component
304
+ def render(state:)
305
+ o &apos;div&apos; do
306
+ o &apos;span&apos;, &apos;Celcius:&apos;
307
+ o &apos;input&apos;, {
308
+ type: &apos;text&apos;,
309
+ onchange: -&gt;(e){ actions.set_celsius(value: e.target.value.to_i) },
310
+ value: state.celsius
311
+ }
312
+ o &apos;span&apos;, &apos;Fahrenheit:&apos;
313
+ o &apos;input&apos;, {
314
+ type: &apos;text&apos;,
315
+ onchange: -&gt;(e){ actions.set_fahrenheit(value: e.target.value.to_i) },
316
+ value: state.fahrenheit
317
+ }
318
+ end
319
+ end
320
+ end
321
+ end
322
+
323
+ MyApp.run(id: &apos;ovto-view&apos;)
324
+ </code></pre><p>Let&apos;s take a look step-by-step.</p>
325
+ <h2 id="prerequisites">Prerequisites</h2>
326
+ <ul>
327
+ <li>Ruby</li>
328
+ <li>Bundler (<code>gem install bundler</code>)</li>
329
+ </ul>
330
+ <h2 id="setup">Setup</h2>
331
+ <p>Make a Gemfile:</p>
332
+ <pre><code>source &quot;https://rubygems.org&quot;
333
+ gem &quot;ovto&quot;, github: &apos;yhara/ovto&apos; # Use git master because ovto gem is not released yet
334
+ gem &apos;rake&apos;
335
+ </code></pre><p>Run <code>bundle install</code>.</p>
336
+ <h2 id="html">HTML</h2>
337
+ <p>Make an index.html:</p>
338
+ <pre><code class="lang-html"><span class="hljs-meta">&lt;!doctype html&gt;</span>
339
+ <span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
340
+ <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
341
+ <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;utf-8&quot;</span>&gt;</span>
342
+ <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&apos;text/javascript&apos;</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&apos;app.js&apos;</span>&gt;</span><span class="undefined"></span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
343
+ <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
344
+ <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
345
+ <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&apos;ovto-view&apos;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
346
+ <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&apos;ovto-debug&apos;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
347
+ <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
348
+ <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
349
+ </code></pre>
350
+ <h2 id="write-code">Write code</h2>
351
+ <p>app.rb:</p>
352
+ <pre><code class="lang-rb"><span class="hljs-keyword">require</span> <span class="hljs-string">&apos;ovto&apos;</span>
353
+
354
+ <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> &lt; Ovto::App</span>
355
+ <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">State</span> &lt; Ovto::State</span>
356
+ <span class="hljs-keyword">end</span>
357
+
358
+ <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Actions</span> &lt; Ovto::Actions</span>
359
+ <span class="hljs-keyword">end</span>
360
+
361
+ <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">View</span> &lt; Ovto::Component</span>
362
+ <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">render</span><span class="hljs-params">(<span class="hljs-symbol">state:</span>)</span></span> <span class="hljs-comment"># Don&apos;t miss the `:`. This is not a typo but</span>
363
+ o <span class="hljs-string">&apos;div&apos;</span> <span class="hljs-keyword">do</span> <span class="hljs-comment"># a &quot;mandatory keyword argument&quot;.</span>
364
+ o <span class="hljs-string">&apos;h1&apos;</span>, <span class="hljs-string">&quot;HELLO&quot;</span> <span class="hljs-comment"># All of the Ovto methods take keyword arguments.</span>
365
+ <span class="hljs-keyword">end</span>
366
+ <span class="hljs-keyword">end</span>
367
+ <span class="hljs-keyword">end</span>
368
+ <span class="hljs-keyword">end</span>
369
+
370
+ MyApp.run(<span class="hljs-symbol">id:</span> <span class="hljs-string">&apos;ovto-view&apos;</span>)
371
+ </code></pre>
372
+ <ul>
373
+ <li>The name <code>MyApp</code> is arbitrary.</li>
374
+ <li>The id <code>ovto-view</code> corresponds to the <code>div</code> tag in <code>index.html</code>.</li>
375
+ </ul>
376
+ <h2 id="compile">Compile</h2>
377
+ <p>Generate app.js from app.rb.</p>
378
+ <pre><code>$ bundle exec opal -c -g ovto app.rb &gt; app.js
379
+ </code></pre><p>(Compile will fail if there is a syntax error in your <code>app.rb</code>.)</p>
380
+ <p>Now you can run your app by opening <code>index.html</code> in your browser.</p>
381
+ <h2 id="trouble-shooting">Trouble shooting</h2>
382
+ <p>If you see HELLO, the setup is done. Otherwise, check the developer console
383
+ and you should see some error messages there.</p>
384
+ <p>For example if you misspelled <code>class State</code> to <code>class Stat</code>, you will see:</p>
385
+ <pre><code>app.js:5022 Uncaught $NameError {name: &quot;State&quot;, message: &quot;uninitialized constant MyApp::State&quot;, stack: &quot;State: uninitialized constant MyApp::State&quot;}
386
+ </code></pre><p>because an Ovto app must have a <code>State</code> class in its namespace.</p>
387
+ <h2 id="tips-auto-compile">(Tips: auto-compile)</h2>
388
+ <p>If you get tired to run <code>bundle exec opal</code> manually, try <code>ifchanged</code> gem:</p>
389
+ <ol>
390
+ <li>Add <code>gem &quot;ifchanged&quot;</code> to Gemfile</li>
391
+ <li><code>bundle install</code></li>
392
+ <li><code>bundle exec ifchanged ./app.rb --do &apos;bundle exec opal -c -g ovto app.rb &gt; app.js&apos;</code></li>
393
+ </ol>
394
+ <p>Now you just edit and save <code>app.rb</code> and it runs <code>opal -c</code> for you.</p>
395
+ <h2 id="add-some-state">Add some state</h2>
396
+ <p>In this tutorial, we make an app that convers Celsius and Fahrenheit degrees to
397
+ each other. First, add an item to <code>MyApp::State</code>.</p>
398
+ <pre><code class="lang-rb"> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">State</span> &lt; Ovto::State</span>
399
+ item <span class="hljs-symbol">:celsius</span>, <span class="hljs-symbol">default:</span> <span class="hljs-number">0</span>
400
+ <span class="hljs-keyword">end</span>
401
+ </code></pre>
402
+ <p>Now an item <code>celsius</code> is added to the global app state. Its value is <code>0</code> when
403
+ the app starts. You can read this value by <code>state.celsius</code>. Let&apos;s display the
404
+ value with <code>MyApp::View</code>.</p>
405
+ <pre><code class="lang-rb"> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">View</span> &lt; Ovto::Component</span>
406
+ <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">render</span><span class="hljs-params">(<span class="hljs-symbol">state:</span>)</span></span>
407
+ o <span class="hljs-string">&apos;div&apos;</span> <span class="hljs-keyword">do</span>
408
+ o <span class="hljs-string">&apos;span&apos;</span>, <span class="hljs-string">&apos;Celcius:&apos;</span>
409
+ o <span class="hljs-string">&apos;input&apos;</span>, <span class="hljs-symbol">type:</span> <span class="hljs-string">&apos;text&apos;</span>, <span class="hljs-symbol">value:</span> state.celsius
410
+ <span class="hljs-keyword">end</span>
411
+ <span class="hljs-keyword">end</span>
412
+ <span class="hljs-keyword">end</span>
413
+ </code></pre>
414
+ <p>Now you should see <code>Celsius: [0 ]</code> in the browser.</p>
415
+ <h2 id="add-a-method-to-state">Add a method to State</h2>
416
+ <p>Next, we want to know what degree is it in Fahrenheit. Let&apos;s add a method to
417
+ convert.</p>
418
+ <pre><code class="lang-rb"> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">State</span> &lt; Ovto::State</span>
419
+ item <span class="hljs-symbol">:celsius</span>, <span class="hljs-symbol">default:</span> <span class="hljs-number">0</span>
420
+
421
+ <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fahrenheit</span></span>
422
+ (celsius * <span class="hljs-number">9</span> / <span class="hljs-number">5.0</span>) + <span class="hljs-number">32</span>
423
+ <span class="hljs-keyword">end</span>
424
+ <span class="hljs-keyword">end</span>
425
+ </code></pre>
426
+ <p>Now you can know the value by <code>state.fahrenheit</code>. Update the <code>View</code> to show the value too.</p>
427
+ <pre><code> class View &lt; Ovto::Component
428
+ def render(state:)
429
+ o &apos;div&apos; do
430
+ o &apos;span&apos;, &apos;Celcius:&apos;
431
+ o &apos;input&apos;, type: &apos;text&apos;, value: state.celsius
432
+ o &apos;span&apos;, &apos;Fahrenheit:&apos;
433
+ o &apos;input&apos;, type: &apos;text&apos;, value: state.fahrenheit
434
+ end
435
+ end
436
+ end
437
+ </code></pre><h2 id="add-an-action">Add an action</h2>
438
+ <p>Now we know 0 degrees Celsius is 32 degrees Fahrenheit. But how about 10 degrees or
439
+ 100 degrees Celsius? Let&apos;s update the app to we can specify a Celsius value.</p>
440
+ <p>You may think that you can change the value with <code>state.celsius = 100</code>, but this is
441
+ prohibited. In Ovto, you can only modify app state with Actions.</p>
442
+ <p>Our first action looks like this. An action is a method defined in <code>MyApp::Actions</code>.
443
+ It takes an old state (and its own parameters) and returns a Hash that describes
444
+ the updates to the state. This return value is <code>merge</code>d into the global app state.</p>
445
+ <pre><code class="lang-rb"> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Actions</span> &lt; Ovto::Actions</span>
446
+ <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_celsius</span><span class="hljs-params">(<span class="hljs-symbol">state:</span>, <span class="hljs-symbol">value:</span>)</span></span>
447
+ <span class="hljs-keyword">return</span> {<span class="hljs-symbol">celsius:</span> value}
448
+ <span class="hljs-keyword">end</span>
449
+ <span class="hljs-keyword">end</span>
450
+ </code></pre>
451
+ <p>This action can be called by <code>actions.set_celsius</code> from the View. Replace the
452
+ first input tag with this:</p>
453
+ <pre><code class="lang-rb"> o <span class="hljs-string">&apos;input&apos;</span>, {
454
+ <span class="hljs-symbol">type:</span> <span class="hljs-string">&apos;text&apos;</span>,
455
+ <span class="hljs-symbol">onchange:</span> -&gt;(e){ actions.set_celsius(<span class="hljs-symbol">value:</span> e.target.value.to_i) },
456
+ <span class="hljs-symbol">value:</span> state.celsius
457
+ }
458
+ </code></pre>
459
+ <p><code>onchange:</code> is a special attribute that takes an event handler as its value.
460
+ The argument <code>e</code> is an instance of <code>Opal::Native</code> and wraps the event object of
461
+ JavaScript. In this case you can get the input string by <code>e.target.value</code>.</p>
462
+ <p>Now reload your browser and input <code>100</code> to the left input box. Next, press Tab key
463
+ (or click somewhere in the page) to commit the value. Then you should see <code>212</code>
464
+ in the right input box. 100 degrees Celsius is 212 degrees Fahrenheit!</p>
465
+ <h2 id="what-has-happend">What has happend</h2>
466
+ <p>In case you are curious, here is what happens when you give 100 to the input box.</p>
467
+ <ol>
468
+ <li>JavaScript&apos;s <code>onchange</code> event is executed.</li>
469
+ <li>Ovto calls the event handler.</li>
470
+ <li>It calls <code>actions.set_celsius</code>. <code>actions</code> is an instance of <code>Ovto::WiredActions</code>.
471
+ It is a proxy to the <code>MyApp::Actions</code>. It has the same methods as those in
472
+ <code>MyApp::Actions</code> but does some more:<ul>
473
+ <li>It passes <code>state</code> to the user-defined action.</li>
474
+ <li>It merges the result to the global app state.</li>
475
+ <li>It schedules re-rendering the view to represent the new state.</li>
476
+ </ul>
477
+ </li>
478
+ </ol>
479
+ <h2 id="reverse-conversion">Reverse conversion</h2>
480
+ <p>It is easy to update the app to support Fahrenheit-to-Celsius conversion.
481
+ The second input should be updated to:</p>
482
+ <pre><code class="lang-rb"> o <span class="hljs-string">&apos;input&apos;</span>, {
483
+ <span class="hljs-symbol">type:</span> <span class="hljs-string">&apos;text&apos;</span>,
484
+ <span class="hljs-symbol">onchange:</span> -&gt;(e){ actions.set_fahrenheit(<span class="hljs-symbol">value:</span> e.target.value.to_i) },
485
+ <span class="hljs-symbol">value:</span> state.fahrenheit
486
+ }
487
+ </code></pre>
488
+ <p>Then add an action <code>set_fahrenheit</code> to <code>MyApp::Actions</code>. This action convers the
489
+ Fahrenheit degree into Celsius and set it to the global state.</p>
490
+ <pre><code class="lang-rb"> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">set_fahrenheit</span><span class="hljs-params">(<span class="hljs-symbol">state:</span>, <span class="hljs-symbol">value:</span>)</span></span>
491
+ new_celsius = (value - <span class="hljs-number">32</span>) * <span class="hljs-number">5</span> / <span class="hljs-number">9.0</span>
492
+ <span class="hljs-keyword">return</span> {<span class="hljs-symbol">celsius:</span> new_celsius}
493
+ <span class="hljs-keyword">end</span>
494
+ </code></pre>
495
+ <p>Now your app should react to the change of the Fahrenheit value too. </p>
496
+
497
+
498
+ </section>
499
+
500
+ </div>
501
+ <div class="search-results">
502
+ <div class="has-results">
503
+
504
+ <h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
505
+ <ul class="search-results-list"></ul>
506
+
507
+ </div>
508
+ <div class="no-results">
509
+
510
+ <h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
511
+
512
+ </div>
513
+ </div>
514
+ </div>
515
+
516
+ </div>
517
+ </div>
518
+
519
+ </div>
520
+
521
+
522
+
523
+ <a href="../" class="navigation navigation-prev navigation-unique" aria-label="Previous page: Introduction">
524
+ <i class="fa fa-angle-left"></i>
525
+ </a>
526
+
527
+
528
+
529
+
530
+ </div>
531
+
532
+ <script>
533
+ var gitbook = gitbook || [];
534
+ gitbook.push(function() {
535
+ gitbook.page.hasChanged({"page":{"title":"Getting Started","level":"1.2","depth":1,"next":{"title":"API","level":"1.3","depth":1,"ref":"","articles":[{"title":"App","level":"1.3.1","depth":2,"path":"api/app.md","ref":"api/app.md","articles":[]},{"title":"State","level":"1.3.2","depth":2,"path":"api/state.md","ref":"api/state.md","articles":[]},{"title":"Actions","level":"1.3.3","depth":2,"path":"api/actions.md","ref":"api/actions.md","articles":[]},{"title":"Component","level":"1.3.4","depth":2,"path":"api/component.md","ref":"api/component.md","articles":[]}]},"previous":{"title":"Introduction","level":"1.1","depth":1,"path":"README.md","ref":"README.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":[],"pluginsConfig":{"highlight":{},"search":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"fontsettings":{"theme":"white","family":"sans","size":2},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"guides/tutorial.md","mtime":"2018-06-01T11:09:14.000Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2018-06-01T12:07:18.151Z"},"basePath":"..","book":{"language":""}});
536
+ });
537
+ </script>
538
+ </div>
539
+
540
+
541
+ <script src="../gitbook/gitbook.js"></script>
542
+ <script src="../gitbook/theme.js"></script>
543
+
544
+
545
+ <script src="../gitbook/gitbook-plugin-search/search-engine.js"></script>
546
+
547
+
548
+
549
+ <script src="../gitbook/gitbook-plugin-search/search.js"></script>
550
+
551
+
552
+
553
+ <script src="../gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
554
+
555
+
556
+
557
+ <script src="../gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
558
+
559
+
560
+
561
+ <script src="../gitbook/gitbook-plugin-sharing/buttons.js"></script>
562
+
563
+
564
+
565
+ <script src="../gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
566
+
567
+
568
+
569
+ </body>
570
+ </html>
571
+