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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbe9fd351db11fdad3445d8a44c356e4343c789a4ce0521cbfc1b70d5c72eed1
4
- data.tar.gz: 9c37eaf812a82accfc9e9da7ba6c1e5bea62c90a27b5965f13ddd514a38cdba5
3
+ metadata.gz: c16fab45131f98235cddc5a78d0128105dea5d60d4b5a2849980af71b21d40bf
4
+ data.tar.gz: cec1207210d7f94f3791655c0ed2bed8f7d91d0f579997c913a8e95b2afae438
5
5
  SHA512:
6
- metadata.gz: 35caabda59fef24ff185b829ce794c4e4cc23645790c33ba544245ecc0fd66d4d78a005190afbba9d07c9edf5e9b33bd62fb4a5496234c1ede06fd14e31d4565
7
- data.tar.gz: b5654ce1ffed9aba99eafc4905828bdd525b4b3f461667fc013058ad943455fab6e332e0a20808f779a3128f56225907b89c2c3b0e1daf0139b9ff1cf4a03d92
6
+ metadata.gz: b142cc06e37df28acfee9f94ad9cb1ce46e2a565878f0078afb584f793e7365bb383c39f4aa38d7406b4681daab7499ce433d14984a5ab27f5417d286563757b
7
+ data.tar.gz: ef7c8e4d03dfedf31d4052b5c758d33e307f8211b5ef42e648267d1c1c502119dae4b2e0bfa4fc58e83152775e3ff76c6f1811fe3ed628eba4a6a42c7664736b
data/.gitmodules CHANGED
@@ -1,3 +0,0 @@
1
- [submodule "opal-rspec"]
2
- path = opal-rspec
3
- url = git://github.com/opal/opal-rspec.git
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.3.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.4)
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.6.2)
19
- opal (>= 0.10.0, < 0.12)
20
- opal-sprockets (0.4.2.0.11.0.3.1)
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.1)
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.6)
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.16)
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
- 1.17.1
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(state:, value:)
29
+ def set_celsius(value:)
30
30
  return {celsius: value}
31
31
  end
32
32
 
33
- def set_fahrenheit(state:, value:)
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(state:)
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(state:, by:)
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(state:)
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(state:)
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(state:, tasks_json:)
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(state:)
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(state:)
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(state:)
52
+ def render
53
53
  o 'input', {
54
54
  type: 'button',
55
55
  value: 'Hello',
@@ -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
- It must take the global app state as a keyword argument `state:`.
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(state:)
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(state:)
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(state:)
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.
@@ -18,18 +18,18 @@ class MyApp < Ovto::App
18
18
  end
19
19
 
20
20
  class Actions < Ovto::Actions
21
- def set_celsius(state:, value:)
21
+ def set_celsius(value:)
22
22
  return {celsius: value}
23
23
  end
24
24
 
25
- def set_fahrenheit(state:, value:)
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(state:)
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(state:) # Don't miss the `:`. This is not a typo but
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(state:)
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(state:)
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(state:, value:)
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(state:, value:)
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
- 1.17.1
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(state:)
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(state:, id:)
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(state:)
46
+ def destroy_completed_todos
47
47
  return {todos: state.todos.reject(&:done)}
48
48
  end
49
49
 
50
- def toggle_todo(state:, id:)
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(state:, done:)
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(state:, value:)
65
+ def set_input(value:)
66
66
  return {input: value}
67
67
  end
68
68
 
69
- def set_filter(state:, 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(state:)
156
+ def render
157
157
  o 'section.todoapp' do
158
158
  o Header,
159
159
  input: state.input
@@ -1,3 +1,4 @@
1
1
  source "https://rubygems.org"
2
2
  gem "ovto", path: '../../'
3
3
  gem 'rake'
4
+ gem 'ifchanged'
@@ -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
- 1.17.1
34
+ 2.0.1
@@ -2,3 +2,8 @@ desc 'compile into js'
2
2
  task :default do
3
3
  sh 'bundle exec opal -c -g ovto app.rb > app.js'
4
4
  end
5
+
6
+ desc 'start auto-compiling'
7
+ task :watch do
8
+ sh 'ifchanged app.rb -d "bundle exec rake"'
9
+ end
@@ -10,18 +10,18 @@ class MyApp < Ovto::App
10
10
  end
11
11
 
12
12
  class Actions < Ovto::Actions
13
- def set_celsius(state:, value:)
13
+ def set_celsius(value:)
14
14
  return {celsius: value}
15
15
  end
16
16
 
17
- def set_fahrenheit(state:, value:)
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(state:)
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
@@ -6,5 +6,9 @@ module Ovto
6
6
  def actions
7
7
  @wired_actions
8
8
  end
9
+
10
+ def state
11
+ @wired_actions._app.state
12
+ end
9
13
  end
10
14
  end
@@ -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 arg1.is_a?(Hash)
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
- [content.to_s]
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
@@ -1,3 +1,3 @@
1
1
  module Ovto
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -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
- invoke_action(name, args_hash)
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? || state_diff.is_a?(Promise) || `!!state_diff.then`
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
@@ -19,4 +19,5 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "opal", '~> 0.11'
22
+ spec.add_dependency "thor", '~> 0.20'
22
23
  end
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.3.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: 2018-12-24 00:00:00.000000000 Z
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