ovto 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +0 -3
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +13 -9
- data/README.md +3 -3
- data/Rakefile +2 -2
- data/book/api/actions.md +5 -5
- data/book/api/app.md +3 -3
- data/book/api/component.md +4 -6
- data/book/guides/tutorial.md +8 -8
- data/examples/sinatra/Gemfile.lock +3 -1
- data/examples/sinatra/ovto/app.rb +8 -8
- data/examples/static/Gemfile +1 -0
- data/examples/static/Gemfile.lock +5 -1
- data/examples/static/Rakefile +5 -0
- data/examples/static/app.rb +3 -3
- data/exe/ovto +59 -0
- data/index.html +0 -9
- data/lib/ovto/actions.rb +4 -0
- data/lib/ovto/component.rb +21 -3
- data/lib/ovto/runtime.rb +4 -57
- data/lib/ovto/version.rb +1 -1
- data/lib/ovto/wired_actions.rb +22 -2
- data/ovto.gemspec +1 -0
- metadata +20 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c16fab45131f98235cddc5a78d0128105dea5d60d4b5a2849980af71b21d40bf
|
4
|
+
data.tar.gz: cec1207210d7f94f3791655c0ed2bed8f7d91d0f579997c913a8e95b2afae438
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b142cc06e37df28acfee9f94ad9cb1ce46e2a565878f0078afb584f793e7365bb383c39f4aa38d7406b4681daab7499ce433d14984a5ab27f5417d286563757b
|
7
|
+
data.tar.gz: ef7c8e4d03dfedf31d4052b5c758d33e307f8211b5ef42e648267d1c1c502119dae4b2e0bfa4fc58e83152775e3ff76c6f1811fe3ed628eba4a6a42c7664736b
|
data/.gitmodules
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## HEAD
|
2
|
+
|
3
|
+
## v0.4.0 (2019-04-19)
|
4
|
+
|
5
|
+
New features
|
6
|
+
|
7
|
+
- `ovto new` command
|
8
|
+
- You can now omit `state:` in `render` method or actions
|
9
|
+
- Support embedding VDom directly (eg. which is compiled form markdown)
|
10
|
+
|
11
|
+
Example:
|
12
|
+
|
13
|
+
o 'div', `{nodeName: ....}`
|
14
|
+
|
15
|
+
|
1
16
|
## v0.3.0 (2018-12-24)
|
2
17
|
|
3
18
|
Breaking change
|
data/Gemfile.lock
CHANGED
@@ -1,36 +1,40 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ovto (0.
|
4
|
+
ovto (0.4.0)
|
5
5
|
opal (~> 0.11)
|
6
|
+
thor (~> 0.20)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
11
|
ast (2.4.0)
|
11
|
-
concurrent-ruby (1.1.
|
12
|
+
concurrent-ruby (1.1.5)
|
12
13
|
hike (1.2.3)
|
13
14
|
opal (0.11.4)
|
14
15
|
ast (>= 2.3.0)
|
15
16
|
hike (~> 1.2)
|
16
17
|
parser (= 2.3.3.1)
|
17
18
|
sourcemap (~> 0.1.0)
|
18
|
-
opal-rspec (0.
|
19
|
-
opal (>= 0.
|
20
|
-
|
19
|
+
opal-rspec (0.7.1)
|
20
|
+
opal (>= 0.11, < 0.12)
|
21
|
+
opal-sprockets
|
22
|
+
rake (~> 12.0)
|
23
|
+
opal-sprockets (0.4.3.0.11.0.3.7)
|
21
24
|
opal (~> 0.11.0)
|
22
|
-
sprockets (~> 3.
|
25
|
+
sprockets (~> 3.7)
|
23
26
|
tilt (>= 1.4)
|
24
27
|
parser (2.3.3.1)
|
25
28
|
ast (~> 2.2)
|
26
|
-
rack (2.0.
|
29
|
+
rack (2.0.7)
|
27
30
|
rake (12.3.2)
|
28
31
|
sourcemap (0.1.1)
|
29
32
|
sprockets (3.7.2)
|
30
33
|
concurrent-ruby (~> 1.0)
|
31
34
|
rack (> 1, < 3)
|
35
|
+
thor (0.20.3)
|
32
36
|
tilt (2.0.9)
|
33
|
-
yard (0.9.
|
37
|
+
yard (0.9.19)
|
34
38
|
|
35
39
|
PLATFORMS
|
36
40
|
ruby
|
@@ -44,4 +48,4 @@ DEPENDENCIES
|
|
44
48
|
yard
|
45
49
|
|
46
50
|
BUNDLED WITH
|
47
|
-
|
51
|
+
2.0.1
|
data/README.md
CHANGED
@@ -26,18 +26,18 @@ class MyApp < Ovto::App
|
|
26
26
|
end
|
27
27
|
|
28
28
|
class Actions < Ovto::Actions
|
29
|
-
def set_celsius(
|
29
|
+
def set_celsius(value:)
|
30
30
|
return {celsius: value}
|
31
31
|
end
|
32
32
|
|
33
|
-
def set_fahrenheit(
|
33
|
+
def set_fahrenheit(value:)
|
34
34
|
new_celsius = (value - 32) * 5 / 9.0
|
35
35
|
return {celsius: new_celsius}
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
class MainComponent < Ovto::Component
|
40
|
-
def render
|
40
|
+
def render
|
41
41
|
o 'div' do
|
42
42
|
o 'span', 'Celcius:'
|
43
43
|
o 'input', {
|
data/Rakefile
CHANGED
@@ -29,15 +29,15 @@ task :release do
|
|
29
29
|
cd('examples/sinatra'){ sh 'bundle update' }
|
30
30
|
cd('examples/static'){ sh 'bundle update' }
|
31
31
|
load 'lib/ovto/version.rb'
|
32
|
-
sh "git diff"
|
32
|
+
sh "git diff HEAD"
|
33
33
|
v = "v#{Ovto::VERSION}"
|
34
34
|
puts "release as #{v}? [y/N]"
|
35
35
|
break unless $stdin.gets.chomp == "y"
|
36
36
|
|
37
|
+
sh "gem build ovto" # First, make sure we can build gem
|
37
38
|
sh "bundle exec rake docs:build"
|
38
39
|
sh "git ci -am '#{v}'"
|
39
40
|
sh "git tag '#{v}'"
|
40
41
|
sh "git push origin master --tags"
|
41
|
-
sh "gem build ovto"
|
42
42
|
sh "gem push ovto-#{Ovto::VERSION}.gem"
|
43
43
|
end
|
data/book/api/actions.md
CHANGED
@@ -4,8 +4,8 @@ Actions are the only way to change the state. Actions must be defined as methods
|
|
4
4
|
the `Actions` class. Here is some more conventions:
|
5
5
|
|
6
6
|
- You must use keyword arguments
|
7
|
-
- You must provide `state:` keyword to receive the app state
|
8
7
|
- You must return state updates as a Hash. It will be merged into the app state.
|
8
|
+
- You can get the current state by `state` method
|
9
9
|
|
10
10
|
Example:
|
11
11
|
|
@@ -19,13 +19,13 @@ class MyApp < Ovto::App
|
|
19
19
|
end
|
20
20
|
|
21
21
|
class Actions < Ovto::Actions
|
22
|
-
def increment(
|
22
|
+
def increment(by:)
|
23
23
|
return {count: state.count + by}
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
27
|
class MainComponent < Ovto::Component
|
28
|
-
def render
|
28
|
+
def render
|
29
29
|
o 'span', state.count
|
30
30
|
o 'button', onclick: ->{ actions.increment(by: 1) }
|
31
31
|
end
|
@@ -61,7 +61,7 @@ Example:
|
|
61
61
|
|
62
62
|
```rb
|
63
63
|
class Actions < Ovto::Actions
|
64
|
-
def fetch_tasks
|
64
|
+
def fetch_tasks
|
65
65
|
Ovto.fetch('/tasks.json').then {|tasks_json|
|
66
66
|
actions.receive_tasks(tasks: tasks_json)
|
67
67
|
}.fail {|e|
|
@@ -69,7 +69,7 @@ Example:
|
|
69
69
|
}
|
70
70
|
end
|
71
71
|
|
72
|
-
def receive_tasks(
|
72
|
+
def receive_tasks(tasks_json:)
|
73
73
|
tasks = tasks_json.map{|item| Task.new(**item)}
|
74
74
|
return {tasks: tasks}
|
75
75
|
end
|
data/book/api/app.md
CHANGED
@@ -19,7 +19,7 @@ class MyApp < Ovto::App
|
|
19
19
|
end
|
20
20
|
|
21
21
|
class MainComponent < Ovto::Component
|
22
|
-
def render
|
22
|
+
def render
|
23
23
|
o 'input', type: 'button', value: 'Hello'
|
24
24
|
end
|
25
25
|
end
|
@@ -42,14 +42,14 @@ class MyApp < Ovto::App
|
|
42
42
|
end
|
43
43
|
|
44
44
|
class Actions < Ovto::Actions
|
45
|
-
def update_color
|
45
|
+
def update_color
|
46
46
|
new_idx = (state.color_idx + 1) % COLORS.length
|
47
47
|
return {color_idx: new_idx}
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
51
|
class MainComponent < Ovto::Component
|
52
|
-
def render
|
52
|
+
def render
|
53
53
|
o 'input', {
|
54
54
|
type: 'button',
|
55
55
|
value: 'Hello',
|
data/book/api/component.md
CHANGED
@@ -5,11 +5,11 @@ An Ovto app must have `MainComponent` class, a subclass of `Ovto::Component`.
|
|
5
5
|
## 'render' method
|
6
6
|
|
7
7
|
`render` is the only method you need to define in the `MainComponent` class.
|
8
|
-
|
8
|
+
You can get the global app state by calling `state` method.
|
9
9
|
|
10
10
|
```rb
|
11
11
|
class MainComponent < Ovto::Component
|
12
|
-
def render
|
12
|
+
def render
|
13
13
|
o 'div' do
|
14
14
|
o 'h1', 'Your todos'
|
15
15
|
o 'ul' do
|
@@ -27,7 +27,7 @@ It must take the global app state as a keyword argument `state:`.
|
|
27
27
|
If you missed the surrounding 'div' tag, Ovto raises an `MoreThanOneNode` error. `render` must create a single DOM node.
|
28
28
|
|
29
29
|
```rb
|
30
|
-
def render
|
30
|
+
def render
|
31
31
|
o 'h1', 'Your todos'
|
32
32
|
o 'ul' do
|
33
33
|
state.todos.each do |todo|
|
@@ -141,7 +141,7 @@ https://github.com/hyperapp/hyperapp#keys
|
|
141
141
|
|
142
142
|
# Main component
|
143
143
|
class MainComponent < Ovto::Component
|
144
|
-
def render
|
144
|
+
def render
|
145
145
|
o 'div' do
|
146
146
|
o 'h1', 'Your todos'
|
147
147
|
o TodoList, todos: state.todos
|
@@ -150,8 +150,6 @@ https://github.com/hyperapp/hyperapp#keys
|
|
150
150
|
end
|
151
151
|
```
|
152
152
|
|
153
|
-
For sub components, the `state:` keyword of `render` method is optional.
|
154
|
-
|
155
153
|
## Text node
|
156
154
|
|
157
155
|
Sometimes you may want to create a text node.
|
data/book/guides/tutorial.md
CHANGED
@@ -18,18 +18,18 @@ class MyApp < Ovto::App
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class Actions < Ovto::Actions
|
21
|
-
def set_celsius(
|
21
|
+
def set_celsius(value:)
|
22
22
|
return {celsius: value}
|
23
23
|
end
|
24
24
|
|
25
|
-
def set_fahrenheit(
|
25
|
+
def set_fahrenheit(value:)
|
26
26
|
new_celsius = (value - 32) * 5 / 9.0
|
27
27
|
return {celsius: new_celsius}
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
class MainComponent < Ovto::Component
|
32
|
-
def render
|
32
|
+
def render
|
33
33
|
o 'div' do
|
34
34
|
o 'span', 'Celcius:'
|
35
35
|
o 'input', {
|
@@ -103,7 +103,7 @@ class MyApp < Ovto::App
|
|
103
103
|
end
|
104
104
|
|
105
105
|
class MainComponent < Ovto::Component
|
106
|
-
def render
|
106
|
+
def render # Don't miss the `:`. This is not a typo but
|
107
107
|
o 'div' do # a "mandatory keyword argument".
|
108
108
|
o 'h1', "HELLO" # All of the Ovto methods take keyword arguments.
|
109
109
|
end
|
@@ -169,7 +169,7 @@ value with `MyApp::MainComponent`.
|
|
169
169
|
|
170
170
|
```rb
|
171
171
|
class MainComponent < Ovto::Component
|
172
|
-
def render
|
172
|
+
def render
|
173
173
|
o 'div' do
|
174
174
|
o 'span', 'Celcius:'
|
175
175
|
o 'input', type: 'text', value: state.celsius
|
@@ -199,7 +199,7 @@ Now you can know the value by `state.fahrenheit`. Update `MainComponent` to show
|
|
199
199
|
|
200
200
|
```
|
201
201
|
class MainComponent < Ovto::Component
|
202
|
-
def render
|
202
|
+
def render
|
203
203
|
o 'div' do
|
204
204
|
o 'span', 'Celcius:'
|
205
205
|
o 'input', type: 'text', value: state.celsius
|
@@ -224,7 +224,7 @@ the updates to the state. This return value is `merge`d into the global app stat
|
|
224
224
|
|
225
225
|
```rb
|
226
226
|
class Actions < Ovto::Actions
|
227
|
-
def set_celsius(
|
227
|
+
def set_celsius(value:)
|
228
228
|
return {celsius: value}
|
229
229
|
end
|
230
230
|
end
|
@@ -279,7 +279,7 @@ Then add an action `set_fahrenheit` to `MyApp::Actions`. This action convers the
|
|
279
279
|
Fahrenheit degree into Celsius and set it to the global state.
|
280
280
|
|
281
281
|
```rb
|
282
|
-
def set_fahrenheit(
|
282
|
+
def set_fahrenheit(value:)
|
283
283
|
new_celsius = (value - 32) * 5 / 9.0
|
284
284
|
return {celsius: new_celsius}
|
285
285
|
end
|
@@ -3,6 +3,7 @@ PATH
|
|
3
3
|
specs:
|
4
4
|
ovto (0.3.0)
|
5
5
|
opal (~> 0.11)
|
6
|
+
thor (~> 0.20)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
@@ -43,6 +44,7 @@ GEM
|
|
43
44
|
sprockets (3.7.2)
|
44
45
|
concurrent-ruby (~> 1.0)
|
45
46
|
rack (> 1, < 3)
|
47
|
+
thor (0.20.3)
|
46
48
|
tilt (2.0.9)
|
47
49
|
|
48
50
|
PLATFORMS
|
@@ -56,4 +58,4 @@ DEPENDENCIES
|
|
56
58
|
sinatra-contrib
|
57
59
|
|
58
60
|
BUNDLED WITH
|
59
|
-
|
61
|
+
2.0.1
|
@@ -27,7 +27,7 @@ class TodoApp < Ovto::App
|
|
27
27
|
end
|
28
28
|
|
29
29
|
class Actions < Ovto::Actions
|
30
|
-
def add_todo
|
30
|
+
def add_todo
|
31
31
|
new_todo = Todo.new(
|
32
32
|
id: state.todos.length + 1,
|
33
33
|
value: state.input,
|
@@ -39,15 +39,15 @@ class TodoApp < Ovto::App
|
|
39
39
|
}
|
40
40
|
end
|
41
41
|
|
42
|
-
def destroy_todo(
|
42
|
+
def destroy_todo(id:)
|
43
43
|
return {todos: state.todos.reject{|t| t.id == id}}
|
44
44
|
end
|
45
45
|
|
46
|
-
def destroy_completed_todos
|
46
|
+
def destroy_completed_todos
|
47
47
|
return {todos: state.todos.reject(&:done)}
|
48
48
|
end
|
49
49
|
|
50
|
-
def toggle_todo(
|
50
|
+
def toggle_todo(id:)
|
51
51
|
new_todos = state.todos.map{|t|
|
52
52
|
if t.id == id
|
53
53
|
t.merge(done: !t.done)
|
@@ -58,15 +58,15 @@ class TodoApp < Ovto::App
|
|
58
58
|
return {todos: new_todos}
|
59
59
|
end
|
60
60
|
|
61
|
-
def toggle_all(
|
61
|
+
def toggle_all(done:)
|
62
62
|
return {todos: state.todos.map{|t| t.merge(done: done)}}
|
63
63
|
end
|
64
64
|
|
65
|
-
def set_input(
|
65
|
+
def set_input(value:)
|
66
66
|
return {input: value}
|
67
67
|
end
|
68
68
|
|
69
|
-
def set_filter(
|
69
|
+
def set_filter(filter:)
|
70
70
|
return {filter: filter}
|
71
71
|
end
|
72
72
|
end
|
@@ -153,7 +153,7 @@ class TodoApp < Ovto::App
|
|
153
153
|
end
|
154
154
|
|
155
155
|
class MainComponent < Ovto::Component
|
156
|
-
def render
|
156
|
+
def render
|
157
157
|
o 'section.todoapp' do
|
158
158
|
o Header,
|
159
159
|
input: state.input
|
data/examples/static/Gemfile
CHANGED
@@ -3,12 +3,14 @@ PATH
|
|
3
3
|
specs:
|
4
4
|
ovto (0.3.0)
|
5
5
|
opal (~> 0.11)
|
6
|
+
thor (~> 0.20)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
11
|
ast (2.4.0)
|
11
12
|
hike (1.2.3)
|
13
|
+
ifchanged (1.0.1)
|
12
14
|
opal (0.11.4)
|
13
15
|
ast (>= 2.3.0)
|
14
16
|
hike (~> 1.2)
|
@@ -18,13 +20,15 @@ GEM
|
|
18
20
|
ast (~> 2.2)
|
19
21
|
rake (12.3.2)
|
20
22
|
sourcemap (0.1.1)
|
23
|
+
thor (0.20.3)
|
21
24
|
|
22
25
|
PLATFORMS
|
23
26
|
ruby
|
24
27
|
|
25
28
|
DEPENDENCIES
|
29
|
+
ifchanged
|
26
30
|
ovto!
|
27
31
|
rake
|
28
32
|
|
29
33
|
BUNDLED WITH
|
30
|
-
|
34
|
+
2.0.1
|
data/examples/static/Rakefile
CHANGED
data/examples/static/app.rb
CHANGED
@@ -10,18 +10,18 @@ class MyApp < Ovto::App
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class Actions < Ovto::Actions
|
13
|
-
def set_celsius(
|
13
|
+
def set_celsius(value:)
|
14
14
|
return {celsius: value}
|
15
15
|
end
|
16
16
|
|
17
|
-
def set_fahrenheit(
|
17
|
+
def set_fahrenheit(value:)
|
18
18
|
new_celsius = (value - 32) * 5 / 9.0
|
19
19
|
return {celsius: new_celsius}
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
class MainComponent < Ovto::Component
|
24
|
-
def render
|
24
|
+
def render
|
25
25
|
o 'div' do
|
26
26
|
o 'span', 'Celcius:'
|
27
27
|
o 'input', {
|
data/exe/ovto
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
require 'rack'
|
4
|
+
require 'thor'
|
5
|
+
require_relative '../lib/ovto/version'
|
6
|
+
|
7
|
+
module Ovto
|
8
|
+
class Cli < Thor
|
9
|
+
GEM_ROOT = "#{__dir__}/../"
|
10
|
+
|
11
|
+
APP_TYPES = %w(static sinatra)
|
12
|
+
desc "new APP_PATH", "Create an Ovto project (--type=any of #{APP_TYPES.inspect})"
|
13
|
+
option "type", type: :string, required: true
|
14
|
+
def new(app_path)
|
15
|
+
if File.exist?(app_path)
|
16
|
+
puts "Already exists: #{app_path}"
|
17
|
+
return
|
18
|
+
end
|
19
|
+
unless APP_TYPES.include?(options[:type])
|
20
|
+
puts "--type must be any of #{APP_TYPES.inspect}"
|
21
|
+
return
|
22
|
+
end
|
23
|
+
FileUtils.mkdir_p(app_path)
|
24
|
+
Dir.chdir(app_path) do
|
25
|
+
Dir["#{GEM_ROOT}/examples/#{options[:type]}/*"].each do |src_path|
|
26
|
+
FileUtils.cp_r(src_path, ".")
|
27
|
+
end
|
28
|
+
# Remove `path:` from the Gemfile
|
29
|
+
File.write("Gemfile", File.read('Gemfile').gsub(", path: '../../'", ""))
|
30
|
+
sh "bundle install"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "server", "Start local server"
|
35
|
+
option "port", aliases: :p, type: :numeric, default: 7521
|
36
|
+
def server
|
37
|
+
puts "Starting Ovto Server"
|
38
|
+
puts "(Open http://localhost:#{options[:port]}/index.html in the browser)"
|
39
|
+
puts "---"
|
40
|
+
if File.file?("config.ru")
|
41
|
+
sh "bundle exec rackup -p #{options[:port]}"
|
42
|
+
else
|
43
|
+
app = Rack::Directory.new(Dir.pwd)
|
44
|
+
Rack::Server.start(app: app, Port: options[:port])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def sh(*cmd)
|
51
|
+
puts cmd.join(' ')
|
52
|
+
system *cmd
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
puts "Ovto v#{Ovto::VERSION}"
|
58
|
+
Ovto::Cli.start
|
59
|
+
|
data/index.html
CHANGED
@@ -3,15 +3,6 @@
|
|
3
3
|
<head>
|
4
4
|
<meta charset="utf-8" />
|
5
5
|
<title>Ovto - Front-end framework for Rubyist</title>
|
6
|
-
|
7
|
-
<script src="http://cdnjs.cloudflare.com/ajax/libs/zepto/1.0rc1/zepto.min.js" type="text/javascript"></script>
|
8
|
-
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
|
9
|
-
|
10
|
-
<script type="text/javascript" charset="utf-8">
|
11
|
-
// this must be set absolutely before any other script on the app is loaded for IE7
|
12
|
-
document.domain = 'twitter.com';
|
13
|
-
</script>
|
14
|
-
|
15
6
|
<link href="https://fonts.googleapis.com/css?family=Rubik" rel="stylesheet">
|
16
7
|
<link rel="stylesheet" href="website/screen.css" type="text/css" media="screen" />
|
17
8
|
</head>
|
data/lib/ovto/actions.rb
CHANGED
data/lib/ovto/component.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'native'
|
2
|
+
|
1
3
|
module Ovto
|
2
4
|
class Component
|
3
5
|
# `render` tried to yield multiple nodes
|
@@ -21,16 +23,20 @@ module Ovto
|
|
21
23
|
''
|
22
24
|
end
|
23
25
|
|
26
|
+
def state
|
27
|
+
@wired_actions._app.state
|
28
|
+
end
|
29
|
+
|
24
30
|
private
|
25
31
|
|
26
32
|
# Render entire MyApp::MainComponent
|
27
33
|
# Called from runtime.rb
|
28
34
|
def render_view(state)
|
29
|
-
Ovto.debug_trace_log("rendering #{self}")
|
30
35
|
do_render(state: state)
|
31
36
|
end
|
32
37
|
|
33
38
|
def do_render(**args)
|
39
|
+
Ovto.debug_trace_log("rendering #{self}")
|
34
40
|
@vdom_tree = []
|
35
41
|
@done_render = false
|
36
42
|
@current_state = args[:state]
|
@@ -69,8 +75,12 @@ module Ovto
|
|
69
75
|
# o 'div' do
|
70
76
|
# o 'h1', 'Hello.'
|
71
77
|
# end
|
78
|
+
# o 'div', `{nodeName: ....}` # Inject VDom spec directly
|
72
79
|
def o(_tag_name, arg1=nil, arg2=nil, &block)
|
73
|
-
if
|
80
|
+
if native?(arg1)
|
81
|
+
attributes = {}
|
82
|
+
content = arg1
|
83
|
+
elsif arg1.is_a?(Hash)
|
74
84
|
attributes = arg1
|
75
85
|
content = arg2
|
76
86
|
elsif arg2 == nil
|
@@ -146,13 +156,21 @@ module Ovto
|
|
146
156
|
when content && block
|
147
157
|
raise ArgumentError, "o cannot take both content and block"
|
148
158
|
when content
|
149
|
-
|
159
|
+
if native?(content)
|
160
|
+
[content]
|
161
|
+
else
|
162
|
+
[content.to_s]
|
163
|
+
end
|
150
164
|
when block
|
151
165
|
@vdom_tree.push []
|
152
166
|
block_value = block.call
|
153
167
|
results = @vdom_tree.pop
|
154
168
|
if results.length > 0 # 'o' was called at least once
|
155
169
|
results
|
170
|
+
elsif native?(block_value)
|
171
|
+
# Inject VDom tree written in JS object
|
172
|
+
# eg. Embed markdown
|
173
|
+
[block_value]
|
156
174
|
elsif block_value.is_a?(String)
|
157
175
|
# When 'o' is never called in the child block, use the last value
|
158
176
|
# eg.
|
data/lib/ovto/runtime.rb
CHANGED
@@ -12,6 +12,10 @@ module Ovto
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def scheduleRender
|
15
|
+
# An action is invoked before Ovto::Runtime#run.
|
16
|
+
# Do nothing here because `scheduleRender` will eventually be called by #run
|
17
|
+
return unless @scheduleRender
|
18
|
+
|
15
19
|
@scheduleRender.call
|
16
20
|
end
|
17
21
|
end
|
@@ -94,63 +98,6 @@ return "";
|
|
94
98
|
return out
|
95
99
|
}
|
96
100
|
|
97
|
-
// function setPartialState(path, value, source) {
|
98
|
-
// var target = {}
|
99
|
-
// if (path.length) {
|
100
|
-
// target[path[0]] =
|
101
|
-
// path.length > 1
|
102
|
-
// ? setPartialState(path.slice(1), value, source[path[0]])
|
103
|
-
// : value
|
104
|
-
// return clone(source, target)
|
105
|
-
// }
|
106
|
-
// return value
|
107
|
-
// }
|
108
|
-
//
|
109
|
-
// function getPartialState(path, source) {
|
110
|
-
// var i = 0
|
111
|
-
// while (i < path.length) {
|
112
|
-
// source = source[path[i++]]
|
113
|
-
// }
|
114
|
-
// return source
|
115
|
-
// }
|
116
|
-
//
|
117
|
-
// function wireStateToActions(path, state, actions) {
|
118
|
-
// for (var key in actions) {
|
119
|
-
// typeof actions[key] === "function"
|
120
|
-
// ? (function(key, action) {
|
121
|
-
// actions[key] = function(data) {
|
122
|
-
// var result = action(data)
|
123
|
-
//
|
124
|
-
// if (typeof result === "function") {
|
125
|
-
// result = result(getPartialState(path, getState()), actions)
|
126
|
-
// }
|
127
|
-
//
|
128
|
-
// if (
|
129
|
-
// result &&
|
130
|
-
// result !== (state = getPartialState(path, getState())) &&
|
131
|
-
// !result.then // !isPromise
|
132
|
-
// ) {
|
133
|
-
// globalState = setPartialState(
|
134
|
-
// path,
|
135
|
-
// clone(state, result),
|
136
|
-
// getState()
|
137
|
-
// )
|
138
|
-
// scheduleRender(globalState)
|
139
|
-
// }
|
140
|
-
//
|
141
|
-
// return result
|
142
|
-
// }
|
143
|
-
// })(key, actions[key])
|
144
|
-
// : wireStateToActions(
|
145
|
-
// path.concat(key),
|
146
|
-
// (state[key] = clone(state[key])),
|
147
|
-
// (actions[key] = clone(actions[key]))
|
148
|
-
// )
|
149
|
-
// }
|
150
|
-
//
|
151
|
-
// return actions
|
152
|
-
// }
|
153
|
-
|
154
101
|
function getKey(node) {
|
155
102
|
return node ? node.key : null
|
156
103
|
}
|
data/lib/ovto/version.rb
CHANGED
data/lib/ovto/wired_actions.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'native'
|
1
2
|
require 'promise'
|
2
3
|
|
3
4
|
module Ovto
|
@@ -7,21 +8,40 @@ module Ovto
|
|
7
8
|
end
|
8
9
|
|
9
10
|
def method_missing(name, args_hash={})
|
10
|
-
|
11
|
+
Ovto.log_error {
|
12
|
+
invoke_action(name, args_hash)
|
13
|
+
}
|
11
14
|
end
|
12
15
|
|
13
16
|
def respond_to?(name)
|
14
17
|
@actions.respond_to?(name)
|
15
18
|
end
|
16
19
|
|
20
|
+
# internal
|
21
|
+
def _app
|
22
|
+
@app
|
23
|
+
end
|
24
|
+
|
17
25
|
private
|
18
26
|
|
19
27
|
# Call action and schedule rendering
|
20
28
|
def invoke_action(name, args_hash)
|
21
29
|
kwargs = {state: @app.state}.merge(args_hash)
|
22
30
|
state_diff = @actions.__send__(name, **kwargs)
|
23
|
-
return if state_diff.nil? ||
|
31
|
+
return if state_diff.nil? ||
|
32
|
+
state_diff.is_a?(Promise) || `!!state_diff.then` ||
|
33
|
+
# eg.
|
34
|
+
# def action1(state:)
|
35
|
+
# actions.action2 if some_condition #=> MyApp::State or nil
|
36
|
+
# end
|
37
|
+
state_diff.is_a?(Ovto::State)
|
24
38
|
|
39
|
+
if native?(state_diff)
|
40
|
+
raise "action `#{name}' returned js object: #{`name.toString()`}"
|
41
|
+
end
|
42
|
+
unless state_diff.is_a?(Hash)
|
43
|
+
raise "action `#{name}' must return hash but got #{state_diff.inspect}"
|
44
|
+
end
|
25
45
|
new_state = @app.state.merge(state_diff)
|
26
46
|
if new_state != @app.state
|
27
47
|
@runtime.scheduleRender
|
data/ovto.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ovto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yutaka HARA
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opal
|
@@ -24,11 +24,26 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.20'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.20'
|
27
41
|
description: Ovto is a client-side framework for Opal. You can write single-page apps
|
28
42
|
with Ruby.
|
29
43
|
email:
|
30
44
|
- yutaka.hara+github@gmail.com
|
31
|
-
executables:
|
45
|
+
executables:
|
46
|
+
- ovto
|
32
47
|
extensions: []
|
33
48
|
extra_rdoc_files: []
|
34
49
|
files:
|
@@ -123,6 +138,7 @@ files:
|
|
123
138
|
- examples/static/Rakefile
|
124
139
|
- examples/static/app.rb
|
125
140
|
- examples/static/index.html
|
141
|
+
- exe/ovto
|
126
142
|
- index.html
|
127
143
|
- lib/ovto.rb
|
128
144
|
- lib/ovto/actions.rb
|
@@ -158,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
174
|
version: '0'
|
159
175
|
requirements: []
|
160
176
|
rubyforge_project:
|
161
|
-
rubygems_version: 2.7.6
|
177
|
+
rubygems_version: 2.7.6.2
|
162
178
|
signing_key:
|
163
179
|
specification_version: 4
|
164
180
|
summary: Simple client-side framework for Opal
|