ovto 0.6.2 → 0.7.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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile.lock +15 -16
  4. data/Rakefile +2 -9
  5. data/book/SUMMARY.md +15 -11
  6. data/book/book.toml +10 -0
  7. data/docs/.nojekyll +1 -0
  8. data/docs/404.html +189 -0
  9. data/docs/FontAwesome/css/font-awesome.css +4 -0
  10. data/docs/FontAwesome/fonts/FontAwesome.ttf +0 -0
  11. data/docs/FontAwesome/fonts/fontawesome-webfont.eot +0 -0
  12. data/docs/FontAwesome/fonts/fontawesome-webfont.svg +2671 -0
  13. data/docs/{gitbook/fonts/fontawesome → FontAwesome/fonts}/fontawesome-webfont.ttf +0 -0
  14. data/docs/FontAwesome/fonts/fontawesome-webfont.woff +0 -0
  15. data/docs/FontAwesome/fonts/fontawesome-webfont.woff2 +0 -0
  16. data/docs/api/Array.html +4 -4
  17. data/docs/api/Hash.html +4 -4
  18. data/docs/api/MightyInspect.html +238 -0
  19. data/docs/api/Ovto/Actions.html +4 -4
  20. data/docs/api/Ovto/App.html +4 -4
  21. data/docs/api/Ovto/Component/MoreThanOneNode.html +5 -5
  22. data/docs/api/Ovto/Component.html +4 -4
  23. data/docs/api/Ovto/Middleware/Actions.html +4 -4
  24. data/docs/api/Ovto/Middleware/Base.html +5 -5
  25. data/docs/api/Ovto/Middleware/Component.html +5 -5
  26. data/docs/api/Ovto/Middleware.html +8 -8
  27. data/docs/api/Ovto/PureComponent/StateIsNotAvailable.html +4 -4
  28. data/docs/api/Ovto/PureComponent.html +4 -4
  29. data/docs/api/Ovto/Runtime.html +4 -4
  30. data/docs/api/Ovto/State/MissingValue.html +4 -4
  31. data/docs/api/Ovto/State/UnknownStateKey.html +4 -4
  32. data/docs/api/Ovto/State.html +12 -12
  33. data/docs/api/Ovto/WiredActionSet.html +4 -4
  34. data/docs/api/Ovto/WiredActions.html +4 -4
  35. data/docs/api/Ovto.html +8 -8
  36. data/docs/api/_index.html +5 -5
  37. data/docs/api/actions.html +215 -426
  38. data/docs/api/app.html +226 -432
  39. data/docs/api/component.html +268 -480
  40. data/docs/api/fetch.html +188 -393
  41. data/docs/api/file.README.html +4 -4
  42. data/docs/api/frames.html +1 -1
  43. data/docs/api/index.html +4 -4
  44. data/docs/api/middleware.html +249 -460
  45. data/docs/api/pure_component.html +186 -398
  46. data/docs/api/state.html +226 -438
  47. data/docs/api/top-level-namespace.html +4 -4
  48. data/docs/ayu-highlight.css +78 -0
  49. data/docs/book.js +688 -0
  50. data/docs/book.toml +10 -0
  51. data/docs/clipboard.min.js +7 -0
  52. data/docs/css/chrome.css +545 -0
  53. data/docs/css/general.css +203 -0
  54. data/docs/css/print.css +54 -0
  55. data/docs/css/variables.css +255 -0
  56. data/docs/elasticlunr.min.js +10 -0
  57. data/docs/favicon.png +0 -0
  58. data/docs/favicon.svg +22 -0
  59. data/docs/fonts/OPEN-SANS-LICENSE.txt +202 -0
  60. data/docs/fonts/SOURCE-CODE-PRO-LICENSE.txt +93 -0
  61. data/docs/fonts/fonts.css +100 -0
  62. data/docs/fonts/open-sans-v17-all-charsets-300.woff2 +0 -0
  63. data/docs/fonts/open-sans-v17-all-charsets-300italic.woff2 +0 -0
  64. data/docs/fonts/open-sans-v17-all-charsets-600.woff2 +0 -0
  65. data/docs/fonts/open-sans-v17-all-charsets-600italic.woff2 +0 -0
  66. data/docs/fonts/open-sans-v17-all-charsets-700.woff2 +0 -0
  67. data/docs/fonts/open-sans-v17-all-charsets-700italic.woff2 +0 -0
  68. data/docs/fonts/open-sans-v17-all-charsets-800.woff2 +0 -0
  69. data/docs/fonts/open-sans-v17-all-charsets-800italic.woff2 +0 -0
  70. data/docs/fonts/open-sans-v17-all-charsets-italic.woff2 +0 -0
  71. data/docs/fonts/open-sans-v17-all-charsets-regular.woff2 +0 -0
  72. data/docs/fonts/source-code-pro-v11-all-charsets-500.woff2 +0 -0
  73. data/docs/guides/debugging.html +184 -390
  74. data/docs/guides/development.html +171 -383
  75. data/docs/guides/install.html +206 -409
  76. data/docs/guides/tutorial.html +309 -525
  77. data/docs/highlight.css +82 -0
  78. data/docs/highlight.js +6 -0
  79. data/docs/index.html +390 -391
  80. data/docs/mark.min.js +7 -0
  81. data/docs/print.html +958 -0
  82. data/docs/searcher.js +483 -0
  83. data/docs/searchindex.js +1 -0
  84. data/docs/searchindex.json +1 -0
  85. data/docs/tomorrow-night.css +102 -0
  86. data/examples/sinatra/Gemfile.lock +25 -25
  87. data/examples/static/Gemfile.lock +8 -8
  88. data/lib/ovto/component.rb +2 -3
  89. data/lib/ovto/version.rb +1 -1
  90. metadata +47 -26
  91. data/docs/gitbook/fonts/fontawesome/FontAwesome.otf +0 -0
  92. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.eot +0 -0
  93. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.svg +0 -685
  94. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.woff +0 -0
  95. data/docs/gitbook/fonts/fontawesome/fontawesome-webfont.woff2 +0 -0
  96. data/docs/gitbook/gitbook-plugin-fontsettings/fontsettings.js +0 -240
  97. data/docs/gitbook/gitbook-plugin-fontsettings/website.css +0 -291
  98. data/docs/gitbook/gitbook-plugin-highlight/ebook.css +0 -135
  99. data/docs/gitbook/gitbook-plugin-highlight/website.css +0 -434
  100. data/docs/gitbook/gitbook-plugin-lunr/lunr.min.js +0 -7
  101. data/docs/gitbook/gitbook-plugin-lunr/search-lunr.js +0 -59
  102. data/docs/gitbook/gitbook-plugin-search/lunr.min.js +0 -7
  103. data/docs/gitbook/gitbook-plugin-search/search-engine.js +0 -50
  104. data/docs/gitbook/gitbook-plugin-search/search.css +0 -35
  105. data/docs/gitbook/gitbook-plugin-search/search.js +0 -213
  106. data/docs/gitbook/gitbook-plugin-sharing/buttons.js +0 -90
  107. data/docs/gitbook/gitbook.js +0 -4
  108. data/docs/gitbook/images/apple-touch-icon-precomposed-152.png +0 -0
  109. data/docs/gitbook/images/favicon.ico +0 -0
  110. data/docs/gitbook/style.css +0 -9
  111. data/docs/gitbook/theme.js +0 -4
  112. data/docs/search_index.json +0 -1
data/docs/index.html CHANGED
@@ -1,417 +1,416 @@
1
-
2
1
  <!DOCTYPE HTML>
3
- <html lang="" >
2
+ <html lang="en" class="sidebar-visible no-js light">
4
3
  <head>
4
+ <!-- Book generated using mdBook -->
5
5
  <meta charset="UTF-8">
6
- <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
7
- <title>Introduction · 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.2">
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
-
6
+ <title>Getting Started - Ovto Reference Manual</title>
32
7
 
33
-
34
8
 
35
-
36
-
37
-
38
-
39
-
9
+ <!-- Custom HTML head -->
40
10
 
41
-
42
-
43
-
44
-
45
-
46
-
47
-
11
+ <meta name="description" content="">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1">
13
+ <meta name="theme-color" content="#ffffff" />
48
14
 
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
- <link rel="next" href="guides/tutorial.html" />
61
-
62
-
15
+ <link rel="icon" href="favicon.svg">
16
+ <link rel="shortcut icon" href="favicon.png">
17
+ <link rel="stylesheet" href="css/variables.css">
18
+ <link rel="stylesheet" href="css/general.css">
19
+ <link rel="stylesheet" href="css/chrome.css">
20
+ <link rel="stylesheet" href="css/print.css" media="print">
21
+
22
+ <!-- Fonts -->
23
+ <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
24
+ <link rel="stylesheet" href="fonts/fonts.css">
25
+
26
+ <!-- Highlight.js Stylesheets -->
27
+ <link rel="stylesheet" href="highlight.css">
28
+ <link rel="stylesheet" href="tomorrow-night.css">
29
+ <link rel="stylesheet" href="ayu-highlight.css">
30
+
31
+ <!-- Custom theme stylesheets -->
63
32
 
64
33
  </head>
65
34
  <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>
35
+ <div id="body-container">
36
+ <!-- Provide site root to javascript -->
37
+ <script>
38
+ var path_to_root = "";
39
+ var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
40
+ </script>
41
+
42
+ <!-- Work around some values being stored in localStorage wrapped in quotes -->
43
+ <script>
44
+ try {
45
+ var theme = localStorage.getItem('mdbook-theme');
46
+ var sidebar = localStorage.getItem('mdbook-sidebar');
47
+
48
+ if (theme.startsWith('"') && theme.endsWith('"')) {
49
+ localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
50
+ }
51
+
52
+ if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
53
+ localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
54
+ }
55
+ } catch (e) { }
56
+ </script>
57
+
58
+ <!-- Set the theme before any content is loaded, prevents flash -->
59
+ <script>
60
+ var theme;
61
+ try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
62
+ if (theme === null || theme === undefined) { theme = default_theme; }
63
+ var html = document.querySelector('html');
64
+ html.classList.remove('no-js')
65
+ html.classList.remove('light')
66
+ html.classList.add(theme);
67
+ html.classList.add('js');
68
+ </script>
69
+
70
+ <!-- Hide / unhide sidebar before it is displayed -->
71
+ <script>
72
+ var html = document.querySelector('html');
73
+ var sidebar = null;
74
+ if (document.body.clientWidth >= 1080) {
75
+ try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
76
+ sidebar = sidebar || 'visible';
77
+ } else {
78
+ sidebar = 'hidden';
79
+ }
80
+ html.classList.remove('sidebar-visible');
81
+ html.classList.add("sidebar-" + sidebar);
82
+ </script>
83
+
84
+ <nav id="sidebar" class="sidebar" aria-label="Table of contents">
85
+ <div class="sidebar-scrollbox">
86
+ <ol class="chapter"><li class="chapter-item expanded "><a href="guides/tutorial.html" class="active"><strong aria-hidden="true">1.</strong> Getting Started</a></li><li class="chapter-item expanded "><a href="guides/install.html"><strong aria-hidden="true">2.</strong> Install</a></li><li class="chapter-item expanded affix "><li class="part-title">API</li><li class="chapter-item expanded "><a href="api/app.html"><strong aria-hidden="true">3.</strong> Ovto::App</a></li><li class="chapter-item expanded "><a href="api/state.html"><strong aria-hidden="true">4.</strong> Ovto::State</a></li><li class="chapter-item expanded "><a href="api/actions.html"><strong aria-hidden="true">5.</strong> Ovto::Actions</a></li><li class="chapter-item expanded "><a href="api/component.html"><strong aria-hidden="true">6.</strong> Ovto::Component</a></li><li class="chapter-item expanded "><a href="api/pure_component.html"><strong aria-hidden="true">7.</strong> Ovto::PureComponent</a></li><li class="chapter-item expanded "><a href="api/middleware.html"><strong aria-hidden="true">8.</strong> Ovto::Middleware</a></li><li class="chapter-item expanded "><a href="api/fetch.html"><strong aria-hidden="true">9.</strong> Ovto.fetch</a></li><li class="chapter-item expanded affix "><li class="part-title">Guides</li><li class="chapter-item expanded "><a href="guides/debugging.html"><strong aria-hidden="true">10.</strong> Debugging</a></li><li class="chapter-item expanded "><a href="guides/development.html"><strong aria-hidden="true">11.</strong> Development</a></li></ol>
87
+ </div>
88
+ <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
89
+ </nav>
90
+
91
+ <div id="page-wrapper" class="page-wrapper">
92
+
93
+ <div class="page">
94
+ <div id="menu-bar-hover-placeholder"></div>
95
+ <div id="menu-bar" class="menu-bar sticky bordered">
96
+ <div class="left-buttons">
97
+ <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
98
+ <i class="fa fa-bars"></i>
99
+ </button>
100
+ <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
101
+ <i class="fa fa-paint-brush"></i>
102
+ </button>
103
+ <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
104
+ <li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
105
+ <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
106
+ <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
107
+ <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
108
+ <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
109
+ </ul>
110
+ <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
111
+ <i class="fa fa-search"></i>
112
+ </button>
113
+ </div>
74
114
 
75
-
76
- <nav role="navigation">
77
-
115
+ <h1 class="menu-title">Ovto Reference Manual</h1>
78
116
 
117
+ <div class="right-buttons">
118
+ <a href="print.html" title="Print this book" aria-label="Print this book">
119
+ <i id="print-button" class="fa fa-print"></i>
120
+ </a>
79
121
 
80
- <ul class="summary">
81
-
82
-
122
+ </div>
123
+ </div>
124
+
125
+ <div id="search-wrapper" class="hidden">
126
+ <form id="searchbar-outer" class="searchbar-outer">
127
+ <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
128
+ </form>
129
+ <div id="searchresults-outer" class="searchresults-outer hidden">
130
+ <div id="searchresults-header" class="searchresults-header"></div>
131
+ <ul id="searchresults">
132
+ </ul>
133
+ </div>
134
+ </div>
135
+
136
+ <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
137
+ <script>
138
+ document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
139
+ document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
140
+ Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
141
+ link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
142
+ });
143
+ </script>
144
+
145
+ <div id="content" class="content">
146
+ <main>
147
+ <h1 id="getting-started"><a class="header" href="#getting-started">Getting Started</a></h1>
148
+ <p>This is a tutorial of making an Ovto app. We create a static app (.html + .js) here,
149
+ but you can embed Ovto apps into a Rails or Sinatra app (See <code>./examples/*</code>).</p>
150
+ <p>This is the final Ruby code.</p>
151
+ <pre><code class="language-rb">require 'ovto'
152
+
153
+ class MyApp &lt; Ovto::App
154
+ class State &lt; Ovto::State
155
+ item :celsius, default: 0
156
+
157
+ def fahrenheit
158
+ (celsius * 9 / 5.0) + 32
159
+ end
160
+ end
161
+
162
+ class Actions &lt; Ovto::Actions
163
+ def set_celsius(value:)
164
+ return {celsius: value}
165
+ end
166
+
167
+ def set_fahrenheit(value:)
168
+ new_celsius = (value - 32) * 5 / 9.0
169
+ return {celsius: new_celsius}
170
+ end
171
+ end
172
+
173
+ class MainComponent &lt; Ovto::Component
174
+ def render
175
+ o 'div' do
176
+ o 'span', 'Celcius:'
177
+ o 'input', {
178
+ type: 'text',
179
+ onchange: -&gt;(e){ actions.set_celsius(value: e.target.value.to_i) },
180
+ value: state.celsius
181
+ }
182
+ o 'span', 'Fahrenheit:'
183
+ o 'input', {
184
+ type: 'text',
185
+ onchange: -&gt;(e){ actions.set_fahrenheit(value: e.target.value.to_i) },
186
+ value: state.fahrenheit
187
+ }
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ MyApp.run(id: 'ovto')
194
+ </code></pre>
195
+ <p>Let's take a look step-by-step.</p>
196
+ <h2 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h2>
197
+ <ul>
198
+ <li>Ruby</li>
199
+ <li>Bundler (<code>gem install bundler</code>)</li>
200
+ </ul>
201
+ <h2 id="setup"><a class="header" href="#setup">Setup</a></h2>
202
+ <p>Make a Gemfile:</p>
203
+ <pre><code class="language-rb">source &quot;https://rubygems.org&quot;
204
+ gem &quot;ovto&quot;, github: 'yhara/ovto' # Use git master because ovto gem is not released yet
205
+ gem 'rake'
206
+ </code></pre>
207
+ <p>Run <code>bundle install</code>.</p>
208
+ <h2 id="html"><a class="header" href="#html">HTML</a></h2>
209
+ <p>Make an index.html:</p>
210
+ <pre><code class="language-html">&lt;!doctype html&gt;
211
+ &lt;html&gt;
212
+ &lt;head&gt;
213
+ &lt;meta charset=&quot;utf-8&quot;&gt;
214
+ &lt;script type='text/javascript' src='app.js'&gt;&lt;/script&gt;
215
+ &lt;/head&gt;
216
+ &lt;body&gt;
217
+ &lt;div id='ovto'&gt;&lt;/div&gt;
218
+ &lt;div id='ovto-debug'&gt;&lt;/div&gt;
219
+ &lt;/body&gt;
220
+ &lt;/html&gt;
221
+ </code></pre>
222
+ <h2 id="write-code"><a class="header" href="#write-code">Write code</a></h2>
223
+ <p>app.rb:</p>
224
+ <pre><code class="language-rb">require 'ovto'
225
+
226
+ class MyApp &lt; Ovto::App
227
+ class State &lt; Ovto::State
228
+ end
229
+
230
+ class Actions &lt; Ovto::Actions
231
+ end
232
+
233
+ class MainComponent &lt; Ovto::Component
234
+ def render # Don't miss the `:`. This is not a typo but
235
+ o 'div' do # a &quot;mandatory keyword argument&quot;.
236
+ o 'h1', &quot;HELLO&quot; # All of the Ovto methods take keyword arguments.
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ MyApp.run(id: 'ovto')
243
+ </code></pre>
244
+ <ul>
245
+ <li>The name <code>MyApp</code> is arbitrary.</li>
246
+ <li>The id <code>ovto</code> corresponds to the <code>div</code> tag in <code>index.html</code>.</li>
247
+ </ul>
248
+ <h2 id="compile"><a class="header" href="#compile">Compile</a></h2>
249
+ <p>Generate app.js from app.rb.</p>
250
+ <pre><code>$ bundle exec opal -c -g ovto app.rb &gt; app.js
251
+ </code></pre>
252
+ <p>(Compile will fail if there is a syntax error in your <code>app.rb</code>.)</p>
253
+ <p>Now you can run your app by opening <code>index.html</code> in your browser.</p>
254
+ <h2 id="trouble-shooting"><a class="header" href="#trouble-shooting">Trouble shooting</a></h2>
255
+ <p>If you see HELLO, the setup is done. Otherwise, check the developer console
256
+ and you should see some error messages there.</p>
257
+ <p>For example if you misspelled <code>class State</code> to <code>class Stat</code>, you will see:</p>
258
+ <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;}
259
+ </code></pre>
260
+ <p>because an Ovto app must have a <code>State</code> class in its namespace.</p>
261
+ <h2 id="tips-auto-compile"><a class="header" href="#tips-auto-compile">(Tips: auto-compile)</a></h2>
262
+ <p>If you get tired to run <code>bundle exec opal</code> manually, try <code>ifchanged</code> gem:</p>
263
+ <ol>
264
+ <li>Add <code>gem &quot;ifchanged&quot;</code> to Gemfile</li>
265
+ <li><code>bundle install</code></li>
266
+ <li><code>bundle exec ifchanged ./app.rb --do 'bundle exec opal -c -g ovto app.rb &gt; app.js'</code></li>
267
+ </ol>
268
+ <p>Now you just edit and save <code>app.rb</code> and it runs <code>opal -c</code> for you.</p>
269
+ <h2 id="add-some-state"><a class="header" href="#add-some-state">Add some state</a></h2>
270
+ <p>In this tutorial, we make an app that convers Celsius and Fahrenheit degrees to
271
+ each other. First, add an item to <code>MyApp::State</code>.</p>
272
+ <pre><code class="language-rb"> class State &lt; Ovto::State
273
+ item :celsius, default: 0
274
+ end
275
+ </code></pre>
276
+ <p>Now an item <code>celsius</code> is added to the global app state. Its value is <code>0</code> when
277
+ the app starts. You can read this value by <code>state.celsius</code>. Let's display the
278
+ value with <code>MyApp::MainComponent</code>.</p>
279
+ <pre><code class="language-rb"> class MainComponent &lt; Ovto::Component
280
+ def render
281
+ o 'div' do
282
+ o 'span', 'Celcius:'
283
+ o 'input', type: 'text', value: state.celsius
284
+ end
285
+ end
286
+ end
287
+ </code></pre>
288
+ <p>Now you should see <code>Celsius: [0 ]</code> in the browser.</p>
289
+ <h2 id="add-a-method-to-state"><a class="header" href="#add-a-method-to-state">Add a method to State</a></h2>
290
+ <p>Next, we want to know what degree is it in Fahrenheit. Let's add a method to
291
+ convert.</p>
292
+ <pre><code class="language-rb"> class State &lt; Ovto::State
293
+ item :celsius, default: 0
294
+
295
+ def fahrenheit
296
+ (celsius * 9 / 5.0) + 32
297
+ end
298
+ end
299
+ </code></pre>
300
+ <p>Now you can know the value by <code>state.fahrenheit</code>. Update <code>MainComponent</code> to show the value too.</p>
301
+ <pre><code class="language-rb"> class MainComponent &lt; Ovto::Component
302
+ def render
303
+ o 'div' do
304
+ o 'span', 'Celcius:'
305
+ o 'input', type: 'text', value: state.celsius
306
+ o 'span', 'Fahrenheit:'
307
+ o 'input', type: 'text', value: state.fahrenheit
308
+ end
309
+ end
310
+ end
311
+ </code></pre>
312
+ <h2 id="add-an-action"><a class="header" href="#add-an-action">Add an action</a></h2>
313
+ <p>Now we know 0 degrees Celsius is 32 degrees Fahrenheit. But how about 10 degrees or
314
+ 100 degrees Celsius? Let's update the app to we can specify a Celsius value.</p>
315
+ <p>You may think that you can change the value with <code>state.celsius = 100</code>, but this is
316
+ prohibited. In Ovto, you can only modify app state with Actions.</p>
317
+ <p>Our first action looks like this. An action is a method defined in <code>MyApp::Actions</code>.
318
+ It takes an old state (and its own parameters) and returns a Hash that describes
319
+ the updates to the state. This return value is <code>merge</code>d into the global app state.</p>
320
+ <pre><code class="language-rb"> class Actions &lt; Ovto::Actions
321
+ def set_celsius(value:)
322
+ return {celsius: value}
323
+ end
324
+ end
325
+ </code></pre>
326
+ <p>This action can be called by <code>actions.set_celsius</code> from MainComponent. Replace the
327
+ first input tag with this:</p>
328
+ <pre><code class="language-rb"> o 'input', {
329
+ type: 'text',
330
+ onchange: -&gt;(e){ actions.set_celsius(value: e.target.value.to_i) },
331
+ value: state.celsius
332
+ }
333
+ </code></pre>
334
+ <p><code>onchange:</code> is a special attribute that takes an event handler as its value.
335
+ The argument <code>e</code> is an instance of <code>Opal::Native</code> and wraps the event object of
336
+ JavaScript. In this case you can get the input string by <code>e.target.value</code>.</p>
337
+ <p>Now reload your browser and input <code>100</code> to the left input box. Next, press Tab key
338
+ (or click somewhere in the page) to commit the value. Then you should see <code>212</code>
339
+ in the right input box. 100 degrees Celsius is 212 degrees Fahrenheit!</p>
340
+ <h2 id="what-has-happend"><a class="header" href="#what-has-happend">What has happend</a></h2>
341
+ <p>In case you are curious, here is what happens when you give 100 to the input box.</p>
342
+ <ol>
343
+ <li>JavaScript's <code>onchange</code> event is executed.</li>
344
+ <li>Ovto calls the event handler.</li>
345
+ <li>It calls <code>actions.set_celsius</code>. <code>actions</code> is an instance of <code>Ovto::WiredActions</code>.
346
+ It is a proxy to the <code>MyApp::Actions</code>. It has the same methods as those in
347
+ <code>MyApp::Actions</code> but does some more:</li>
348
+ </ol>
349
+ <ul>
350
+ <li>It passes <code>state</code> to the user-defined action.</li>
351
+ <li>It merges the result to the global app state.</li>
352
+ <li>It schedules re-rendering the view to represent the new state.</li>
353
+ </ul>
354
+ <h2 id="reverse-conversion"><a class="header" href="#reverse-conversion">Reverse conversion</a></h2>
355
+ <p>It is easy to update the app to support Fahrenheit-to-Celsius conversion.
356
+ The second input should be updated to:</p>
357
+ <pre><code class="language-rb"> o 'input', {
358
+ type: 'text',
359
+ onchange: -&gt;(e){ actions.set_fahrenheit(value: e.target.value.to_i) },
360
+ value: state.fahrenheit
361
+ }
362
+ </code></pre>
363
+ <p>Then add an action <code>set_fahrenheit</code> to <code>MyApp::Actions</code>. This action convers the
364
+ Fahrenheit degree into Celsius and set it to the global state.</p>
365
+ <pre><code class="language-rb"> def set_fahrenheit(value:)
366
+ new_celsius = (value - 32) * 5 / 9.0
367
+ return {celsius: new_celsius}
368
+ end
369
+ </code></pre>
370
+ <p>Now your app should react to the change of the Fahrenheit value too. </p>
371
+
372
+ </main>
373
+
374
+ <nav class="nav-wrapper" aria-label="Page navigation">
375
+ <!-- Mobile navigation buttons -->
376
+
377
+ <a rel="next" href="guides/install.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
378
+ <i class="fa fa-angle-right"></i>
379
+ </a>
380
+
381
+ <div style="clear: both"></div>
382
+ </nav>
383
+ </div>
384
+ </div>
83
385
 
84
-
386
+ <nav class="nav-wide-wrapper" aria-label="Page navigation">
85
387
 
86
-
87
-
88
-
89
-
90
- <li class="chapter active" 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 " data-level="1.2" data-path="guides/tutorial.html">
104
-
105
- <a href="guides/tutorial.html">
106
-
107
-
108
- Getting Started
109
-
110
- </a>
111
-
112
-
113
-
114
- </li>
115
-
116
- <li class="chapter " data-level="1.3" data-path="guides/install.html">
117
-
118
- <a href="guides/install.html">
119
-
120
-
121
- Install
122
-
123
- </a>
124
-
125
-
126
-
127
- </li>
128
-
129
- <li class="chapter " data-level="1.4" >
130
-
131
- <span>
132
-
133
-
134
- API
135
-
136
- </span>
137
-
138
-
139
-
140
- <ul class="articles">
141
-
142
-
143
- <li class="chapter " data-level="1.4.1" data-path="api/app.html">
144
-
145
- <a href="api/app.html">
146
-
147
-
148
- Ovto::App
149
-
150
- </a>
151
-
152
-
153
-
154
- </li>
155
-
156
- <li class="chapter " data-level="1.4.2" data-path="api/state.html">
157
-
158
- <a href="api/state.html">
159
-
160
-
161
- Ovto::State
162
-
163
- </a>
164
-
165
-
166
-
167
- </li>
168
-
169
- <li class="chapter " data-level="1.4.3" data-path="api/actions.html">
170
-
171
- <a href="api/actions.html">
172
-
173
-
174
- Ovto::Actions
175
-
176
- </a>
177
-
178
-
179
-
180
- </li>
181
-
182
- <li class="chapter " data-level="1.4.4" data-path="api/component.html">
183
-
184
- <a href="api/component.html">
185
-
186
-
187
- Ovto::Component
188
-
189
- </a>
190
-
191
-
192
-
193
- </li>
194
-
195
- <li class="chapter " data-level="1.4.5" data-path="api/pure_component.html">
196
-
197
- <a href="api/pure_component.html">
198
-
199
-
200
- Ovto::PureComponent
201
-
202
- </a>
203
-
204
-
205
-
206
- </li>
207
-
208
- <li class="chapter " data-level="1.4.6" data-path="api/middleware.html">
209
-
210
- <a href="api/middleware.html">
211
-
212
-
213
- Ovto::Middleware
214
-
215
- </a>
216
-
217
-
218
-
219
- </li>
220
-
221
- <li class="chapter " data-level="1.4.7" data-path="api/fetch.html">
222
-
223
- <a href="api/fetch.html">
224
-
225
-
226
- Ovto.fetch
227
-
228
- </a>
229
-
230
-
231
-
232
- </li>
233
-
234
-
235
- </ul>
236
-
237
- </li>
238
-
239
- <li class="chapter " data-level="1.5" >
240
-
241
- <span>
242
-
243
-
244
- Guides
245
-
246
- </span>
247
-
248
-
249
-
250
- <ul class="articles">
251
-
252
-
253
- <li class="chapter " data-level="1.5.1" data-path="guides/debugging.html">
254
-
255
- <a href="guides/debugging.html">
256
-
257
-
258
- Debugging
259
-
260
- </a>
261
-
262
-
263
-
264
- </li>
265
-
266
- <li class="chapter " data-level="1.5.2" data-path="guides/development.html">
267
-
268
- <a href="guides/development.html">
269
-
270
-
271
- Development
272
-
273
- </a>
274
-
275
-
276
-
277
- </li>
278
-
279
-
280
- </ul>
281
-
282
- </li>
283
-
284
-
285
-
286
-
287
- <li class="divider"></li>
288
-
289
- <li>
290
- <a href="https://www.gitbook.com" target="blank" class="gitbook-link">
291
- Published with GitBook
292
- </a>
293
- </li>
294
- </ul>
388
+ <a rel="next" href="guides/install.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
389
+ <i class="fa fa-angle-right"></i>
390
+ </a>
391
+ </nav>
295
392
 
393
+ </div>
296
394
 
297
- </nav>
298
-
299
-
300
- </div>
301
395
 
302
- <div class="book-body">
303
-
304
- <div class="body-inner">
305
-
306
-
307
-
308
- <div class="book-header" role="navigation">
309
-
310
-
311
- <!-- Title -->
312
- <h1>
313
- <i class="fa fa-circle-o-notch fa-spin"></i>
314
- <a href="." >Introduction</a>
315
- </h1>
316
- </div>
317
-
318
-
319
-
320
-
321
- <div class="page-wrapper" tabindex="-1" role="main">
322
- <div class="page-inner">
323
-
324
- <div id="book-search-results">
325
- <div class="search-noresults">
326
-
327
- <section class="normal markdown-section">
328
-
329
- <h1 id="ovto">Ovto</h1>
330
- <p>Client-side framework for Rubyist</p>
331
- <p><img src="../ovtologo.png" alt="logo"></p>
332
- <h2 id="overview">Overview</h2>
333
- <p>Ovto is a micro-framework built with <a href="https://opalrb.com" target="_blank">Opal</a>. With Ovto, you can develop SPA(Single-Page Application)s with Ruby.</p>
334
- <p>There are only four classes to understand Ovto:</p>
335
- <ul>
336
- <li>Ovto::App (The application)</li>
337
- <li>Ovto::State (An immutable object that represents application state)</li>
338
- <li>Ovto::Actions (Methods that modifies the app state)</li>
339
- <li>Ovto::Component (Defines DOMs for a given app state)</li>
340
- </ul>
341
- <p><a href="guides/tutorial.html">Getting Started</a></p>
342
396
 
343
-
344
- </section>
345
-
346
- </div>
347
- <div class="search-results">
348
- <div class="has-results">
349
-
350
- <h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
351
- <ul class="search-results-list"></ul>
352
-
353
- </div>
354
- <div class="no-results">
355
-
356
- <h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
357
-
358
- </div>
359
- </div>
360
- </div>
361
397
 
362
- </div>
363
- </div>
364
-
365
- </div>
398
+ <script>
399
+ window.playground_copyable = true;
400
+ </script>
366
401
 
367
-
368
-
369
-
370
- <a href="guides/tutorial.html" class="navigation navigation-next navigation-unique" aria-label="Next page: Getting Started">
371
- <i class="fa fa-angle-right"></i>
372
- </a>
373
-
374
-
375
-
376
- </div>
377
402
 
378
- <script>
379
- var gitbook = gitbook || [];
380
- gitbook.push(function() {
381
- gitbook.page.hasChanged({"page":{"title":"Introduction","level":"1.1","depth":1,"next":{"title":"Getting Started","level":"1.2","depth":1,"path":"guides/tutorial.md","ref":"guides/tutorial.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":"readme.md","mtime":"2018-12-23T17:33:22.000Z","type":"markdown"},"gitbook":{"version":"3.2.2","time":"2021-10-21T23:18:11.678Z"},"basePath":".","book":{"language":""}});
382
- });
383
- </script>
384
- </div>
403
+ <script src="elasticlunr.min.js"></script>
404
+ <script src="mark.min.js"></script>
405
+ <script src="searcher.js"></script>
385
406
 
386
-
387
- <script src="gitbook/gitbook.js"></script>
388
- <script src="gitbook/theme.js"></script>
389
-
390
-
391
- <script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
392
-
393
-
394
-
395
- <script src="gitbook/gitbook-plugin-search/search.js"></script>
396
-
397
-
398
-
399
- <script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
400
-
401
-
402
-
403
- <script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
404
-
405
-
406
-
407
- <script src="gitbook/gitbook-plugin-sharing/buttons.js"></script>
408
-
409
-
410
-
411
- <script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
412
-
413
-
407
+ <script src="clipboard.min.js"></script>
408
+ <script src="highlight.js"></script>
409
+ <script src="book.js"></script>
410
+
411
+ <!-- Custom JS scripts -->
414
412
 
413
+
414
+ </div>
415
415
  </body>
416
416
  </html>
417
-