ovto 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
-