volt 0.9.0.pre4 → 0.9.0.pre5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/VERSION +1 -1
- data/app/volt/tasks/live_query/live_query_pool.rb +0 -2
- data/lib/volt/controllers/actions.rb +101 -0
- data/lib/volt/controllers/model_controller.rb +45 -5
- data/lib/volt/models/buffer.rb +3 -0
- data/lib/volt/models/model.rb +3 -3
- data/lib/volt/models/persistors/base.rb +1 -0
- data/lib/volt/models/persistors/model_store.rb +8 -0
- data/lib/volt/page/bindings/content_binding.rb +25 -3
- data/lib/volt/page/bindings/html_safe/string_extension.rb +13 -0
- data/lib/volt/page/bindings/view_binding/controller_handler.rb +44 -0
- data/lib/volt/page/bindings/view_binding/grouped_controllers.rb +10 -22
- data/lib/volt/page/bindings/view_binding.rb +130 -61
- data/lib/volt/page/targets/base_section.rb +6 -1
- data/lib/volt/page/targets/dom_template.rb +1 -1
- data/lib/volt/reactive/computation.rb +2 -2
- data/lib/volt/utils/generic_counting_pool.rb +10 -7
- data/lib/volt/utils/generic_pool.rb +16 -0
- data/spec/apps/kitchen_sink/app/main/config/routes.rb +2 -0
- data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +4 -0
- data/spec/apps/kitchen_sink/app/main/views/main/html_safe.html +7 -0
- data/spec/apps/kitchen_sink/app/main/views/main/missing.html +13 -0
- data/spec/controllers/actions_spec.rb +148 -0
- data/spec/controllers/model_controller_spec.rb +31 -0
- data/spec/integration/missing_spec.rb +11 -0
- data/spec/integration/raw_html_binding.rb +9 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6b166ab0b3c9e33c493d7c65d65d3c5db8f9cdb
|
4
|
+
data.tar.gz: 406513b0bc558b964c2207cf6b9ee4f66796d65e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0350b5ca4ba46fc30c183be534f5e0ba4b0a4ba1af4cfedf4599a354d91a2f72865aaba9d639fe821001740874c9cc6b73d2dff095a673d3b128d22ca3bcd75c
|
7
|
+
data.tar.gz: 6ba8bd6674ea7057d27ab6259b203c8397c023b43c39eaf0d66573e36c44d56c1dc606e357a1d921016b3271101b78d7696d417896c697f3a2ed354c74e38446
|
data/CHANGELOG.md
CHANGED
@@ -22,9 +22,12 @@
|
|
22
22
|
- ```store``` is now available inside of specs. If it is accessed in a spec, the database will be cleaned after the spec.
|
23
23
|
- ```the_page``` is a shortcut to the page collection inside of specs. (Unfortunately, ```page``` is used by capybara, so for now we're using ```the_page```, we'll find a better solution in the future.)
|
24
24
|
- Add filtering to logging on password, and option to configure filtered args. Also, improve the way errors are displayed.
|
25
|
+
- You can now call raw in a content binding to render the raw html on the page. Use carefully, this can open you up to xss attacks. We reccomend never showing html from the user directly.
|
25
26
|
|
26
27
|
### Changed
|
27
28
|
- template bindings have been renamed to view. ```{{ view "path/for/view" }}``` instead of ```{{ template "path/for/view" }}```
|
29
|
+
- view bindings (formerly template) wait until the template's #loaded? method returns true (by .watch! ing it for changes)
|
30
|
+
- #loaded? on controllers now returns false if the model is set to a Promise, until the promise is resolved.
|
28
31
|
- the {action}_remove method had been changed to before_{action}_remove and after_{action}_remove to provide more hooks and a clearer understanding of when it is happening.
|
29
32
|
- the following were renamed to follow gem naming conventions:
|
30
33
|
- volt-user-templates (now volt-user_templates)
|
@@ -46,6 +49,7 @@
|
|
46
49
|
- Volt::TaskHandler is now Volt::Task
|
47
50
|
- Move testing gems to the generated Gemfile for projects
|
48
51
|
- ```if ENV['BROWSER']``` is no longer required around integration tests. We now use rspec filtering on ```type: :feature``` if you aren't running with ENV['BROWSER']
|
52
|
+
- ```go``` has been renamed to ```redirect_to``` to keep things consistent between ruby frameworks. (And to allow for go to be used elsewhere)
|
49
53
|
|
50
54
|
### Removed
|
51
55
|
- .false?, .true?, .or, and .and were removed since NilModels were removed. This means you get back a real nil value when accessing an undefined model attribute.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.0.
|
1
|
+
0.9.0.pre5
|
@@ -19,9 +19,7 @@ class LiveQueryPool < Volt::GenericPool
|
|
19
19
|
|
20
20
|
def updated_collection(collection, skip_channel)
|
21
21
|
# collection = collection.to_sym
|
22
|
-
# puts "RUN UPDATE FOR #{collection.inspect} - #{@pool.inspect}"
|
23
22
|
lookup_all(collection).each do |live_query|
|
24
|
-
# puts "UPDATE COLLECTION: #{collection} - #{live_query.inspect}"
|
25
23
|
live_query.run(skip_channel)
|
26
24
|
end
|
27
25
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# The Actions module adds helpers for setting up and using
|
2
|
+
# actions on a class. You can setup helpers for an action with
|
3
|
+
#
|
4
|
+
# setup_action_helpers_in_class(:before, :after)
|
5
|
+
#
|
6
|
+
# The above will setup before_action and after_action methods on
|
7
|
+
# the class. Typically setup_action_helpers_in_class will be run
|
8
|
+
# in a base class.
|
9
|
+
#
|
10
|
+
# before_action :require_login
|
11
|
+
module Volt
|
12
|
+
module Actions
|
13
|
+
# StopChainException inherits from Exception directly so it will not be handled by a
|
14
|
+
# default rescue.
|
15
|
+
class StopChainException < Exception ; end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
# Takes a list of action groups (as symbols). An action group is typically used for before/after, but
|
19
|
+
# can be used anytime you have multiple sets of actions. The method will create an {x}_action method for each
|
20
|
+
# group passed in.
|
21
|
+
def setup_action_helpers_in_class(*groups)
|
22
|
+
groups.each do |group|
|
23
|
+
# Setup a class attribute to track the
|
24
|
+
callbacks_var_name = :"#{group}_action_callbacks"
|
25
|
+
class_attribute(callbacks_var_name)
|
26
|
+
|
27
|
+
# Create the method on the class
|
28
|
+
define_singleton_method(:"#{group}_action") do |*args, &block|
|
29
|
+
# Add the block in place of the symbol
|
30
|
+
args.unshift(block) if block
|
31
|
+
|
32
|
+
raise "No callback symbol or block provided" unless args[0]
|
33
|
+
|
34
|
+
callbacks = send(callbacks_var_name)
|
35
|
+
|
36
|
+
unless callbacks
|
37
|
+
callbacks = []
|
38
|
+
send(:"#{callbacks_var_name}=", callbacks)
|
39
|
+
end
|
40
|
+
|
41
|
+
if args.last.is_a?(Hash)
|
42
|
+
options = args.pop
|
43
|
+
else
|
44
|
+
options = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
args.each do |callback|
|
48
|
+
callbacks << [callback, options]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# To run the actions on a class, call #run_actions passing in the group
|
56
|
+
# and the action being called on. If the callback chain was stopped with
|
57
|
+
# #stop_chain, it will return true, otherwise false.
|
58
|
+
def run_actions(group, action)
|
59
|
+
callbacks = self.class.send(:"#{group}_action_callbacks")
|
60
|
+
|
61
|
+
filtered_callbacks = filter_actions_by_only_exclude(callbacks || [], action)
|
62
|
+
|
63
|
+
begin
|
64
|
+
filtered_callbacks.each do |callback|
|
65
|
+
instance_eval(&callback)
|
66
|
+
end
|
67
|
+
|
68
|
+
return false
|
69
|
+
rescue StopChainException => e
|
70
|
+
return true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# The stop chain method can be called inside of a callback and it will
|
75
|
+
# raise an exception under the hood which will stop the chain and evaluation
|
76
|
+
# from where stop_chain is called.
|
77
|
+
def stop_chain
|
78
|
+
raise StopChainException
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.included(base)
|
82
|
+
base.send :extend, ClassMethods
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
# TODO: currently we filter during the call, we could maybe improve performance
|
87
|
+
# here by storing by action and having an all category as well.
|
88
|
+
def filter_actions_by_only_exclude(callbacks, action)
|
89
|
+
callbacks.select do |callback, options|
|
90
|
+
if options
|
91
|
+
# If there is an only, make sure the action is in the list.
|
92
|
+
options[:only].include?(action.to_sym)
|
93
|
+
else
|
94
|
+
# If no only, include it
|
95
|
+
true
|
96
|
+
end
|
97
|
+
end.map {|v| v[0] }
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -1,15 +1,21 @@
|
|
1
1
|
require 'volt/reactive/reactive_accessors'
|
2
|
+
require 'volt/controllers/actions'
|
2
3
|
|
3
4
|
module Volt
|
4
5
|
class ModelController
|
5
6
|
include ReactiveAccessors
|
7
|
+
include Actions
|
6
8
|
|
7
9
|
reactive_accessor :current_model
|
10
|
+
reactive_accessor :last_promise
|
8
11
|
|
9
12
|
# The section is assigned a reference to a "DomSection" which has
|
10
13
|
# the dom for the controllers view.
|
11
14
|
attr_accessor :section
|
12
15
|
|
16
|
+
# Setup before_action and after_action
|
17
|
+
setup_action_helpers_in_class(:before, :after)
|
18
|
+
|
13
19
|
# Container returns the node that is parent to all nodes in the section.
|
14
20
|
def container
|
15
21
|
section.container_node
|
@@ -40,11 +46,11 @@ module Volt
|
|
40
46
|
def model=(val)
|
41
47
|
if val.is_a?(Promise)
|
42
48
|
# Resolve the promise before setting
|
43
|
-
|
49
|
+
self.last_promise = val
|
44
50
|
|
45
51
|
val.then do |result|
|
46
52
|
# Only assign if nothing else has been assigned since we started the resolve
|
47
|
-
self.model = result if
|
53
|
+
self.model = result if self.last_promise == val
|
48
54
|
end.fail do |err|
|
49
55
|
Volt.logger.error("Unable to resolve promise assigned to model on #{inspect}")
|
50
56
|
end
|
@@ -53,7 +59,7 @@ module Volt
|
|
53
59
|
end
|
54
60
|
|
55
61
|
# Clear
|
56
|
-
|
62
|
+
self.last_promise = nil
|
57
63
|
|
58
64
|
# Start with a nil reactive value.
|
59
65
|
self.current_model ||= Model.new
|
@@ -106,8 +112,14 @@ module Volt
|
|
106
112
|
end
|
107
113
|
end
|
108
114
|
|
109
|
-
# Change the url params, similar to redirecting to a new url
|
110
115
|
def go(url)
|
116
|
+
Volt.logger.warn('Deprecation warning: `go` has been renamed to `redirect_to` for consistency with other frameworks.')
|
117
|
+
|
118
|
+
redirect_to(url)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Change the url
|
122
|
+
def redirect_to(url)
|
111
123
|
# We might be in the rendering loop, so wait until the next tick before
|
112
124
|
# we change the url
|
113
125
|
Timers.next_tick do
|
@@ -163,8 +175,36 @@ module Volt
|
|
163
175
|
$page.url.url_with(params)
|
164
176
|
end
|
165
177
|
|
178
|
+
# loaded? is a quick way to see if the model for the controller is loaded
|
179
|
+
# yet. If the model is there, it asks the model if its loaded. If the model
|
180
|
+
# was set to a promise, it waits for the promise to resolve.
|
166
181
|
def loaded?
|
167
|
-
|
182
|
+
if model.respond_to?(:loaded?)
|
183
|
+
# There is a model and it is loaded
|
184
|
+
return model.loaded?
|
185
|
+
elsif last_promise || model.is_a?(Promise)
|
186
|
+
# The model is a promise or is resolving
|
187
|
+
return false
|
188
|
+
else
|
189
|
+
# Otherwise, its loaded
|
190
|
+
return true
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def require_login(message="You must login to access this area.")
|
195
|
+
unless Volt.current_user_id
|
196
|
+
flash._notices << message
|
197
|
+
go '/login'
|
198
|
+
|
199
|
+
stop_chain
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Raw marks a string as html safe, so bindings can be rendered as html.
|
204
|
+
# With great power comes great responsibility.
|
205
|
+
def raw(str)
|
206
|
+
str = str.to_s unless str.is_a?(String)
|
207
|
+
str.html_safe
|
168
208
|
end
|
169
209
|
|
170
210
|
# Check if this controller responds_to method, or the model
|
data/lib/volt/models/buffer.rb
CHANGED
data/lib/volt/models/model.rb
CHANGED
@@ -80,7 +80,7 @@ module Volt
|
|
80
80
|
if @persistor
|
81
81
|
@persistor.loaded(initial_state)
|
82
82
|
else
|
83
|
-
change_state_to(:loaded_state, :loaded, false)
|
83
|
+
change_state_to(:loaded_state, initial_state || :loaded, false)
|
84
84
|
end
|
85
85
|
|
86
86
|
# Trigger the new event, pass in :new
|
@@ -293,8 +293,8 @@ module Volt
|
|
293
293
|
end
|
294
294
|
end
|
295
295
|
|
296
|
-
def new_model(
|
297
|
-
Volt::Model.class_at_path(options[:path]).new(
|
296
|
+
def new_model(*args)
|
297
|
+
Volt::Model.class_at_path(options[:path]).new(*args)
|
298
298
|
end
|
299
299
|
|
300
300
|
def new_array_model(attributes, options)
|
@@ -22,6 +22,14 @@ module Volt
|
|
22
22
|
@in_identity_map = false
|
23
23
|
end
|
24
24
|
|
25
|
+
def loaded(initial_state = nil)
|
26
|
+
if model.path == []
|
27
|
+
initial_state = :loaded
|
28
|
+
end
|
29
|
+
|
30
|
+
model.change_state_to(:loaded_state, initial_state)
|
31
|
+
end
|
32
|
+
|
25
33
|
def add_to_collection
|
26
34
|
@in_collection = true
|
27
35
|
ensure_setup
|
@@ -1,7 +1,11 @@
|
|
1
1
|
require 'volt/page/bindings/base_binding'
|
2
|
+
require 'volt/page/bindings/html_safe/string_extension'
|
2
3
|
|
3
4
|
module Volt
|
4
5
|
class ContentBinding < BaseBinding
|
6
|
+
HTML_ESCAPE_REGEXP = /[&"'><\n]/
|
7
|
+
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''', "\n" => "<br />\n" }
|
8
|
+
|
5
9
|
def initialize(page, target, context, binding_name, getter)
|
6
10
|
# puts "New Content Binding: #{self.inspect}"
|
7
11
|
super(page, target, context, binding_name)
|
@@ -20,14 +24,32 @@ module Volt
|
|
20
24
|
end
|
21
25
|
|
22
26
|
def update(value)
|
23
|
-
value
|
27
|
+
value = (value || '').to_s unless value.is_a?(String)
|
28
|
+
html_safe = value.html_safe?
|
24
29
|
|
25
30
|
# Exception values display the exception as a string
|
26
|
-
value
|
31
|
+
value = value.to_s
|
27
32
|
|
28
33
|
# Update the html in this section
|
29
34
|
# TODO: Move the formatter into another class.
|
30
|
-
|
35
|
+
|
36
|
+
# The html safe check lets us know that if string can be rendered
|
37
|
+
# directly as html
|
38
|
+
unless html_safe
|
39
|
+
# Escape any < and >, but convert newlines to br's, and fix quotes and
|
40
|
+
value = html_escape(value)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Assign the content
|
44
|
+
dom_section.html = value
|
45
|
+
# dom_section.text = value
|
46
|
+
end
|
47
|
+
|
48
|
+
def html_escape(str)
|
49
|
+
# https://github.com/opal/opal/issues/798
|
50
|
+
str.gsub(HTML_ESCAPE_REGEXP) do |char|
|
51
|
+
HTML_ESCAPE[char]
|
52
|
+
end
|
31
53
|
end
|
32
54
|
|
33
55
|
def remove
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
def html_safe
|
3
|
+
# Convert to a real string (opal uses native strings normally, so wrap so we can
|
4
|
+
# use instance variables)
|
5
|
+
str = String.new(self)
|
6
|
+
str.instance_variable_set('@html_safe', true)
|
7
|
+
str
|
8
|
+
end
|
9
|
+
|
10
|
+
def html_safe?
|
11
|
+
@html_safe
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Volt
|
2
|
+
class ControllerHandler
|
3
|
+
attr_reader :controller, :action
|
4
|
+
|
5
|
+
def initialize(controller, action)
|
6
|
+
@controller = controller
|
7
|
+
@action = action.to_sym
|
8
|
+
end
|
9
|
+
|
10
|
+
def call_action(stage_prefix=nil, stage_suffix=nil)
|
11
|
+
return unless @action
|
12
|
+
|
13
|
+
has_stage = stage_prefix || stage_suffix
|
14
|
+
|
15
|
+
if has_stage
|
16
|
+
method_name = @action
|
17
|
+
method_name = "#{stage_prefix}_#{method_name}" if stage_prefix
|
18
|
+
method_name = "#{method_name}_#{stage_suffix}" if stage_suffix
|
19
|
+
|
20
|
+
method_name = method_name.to_sym
|
21
|
+
else
|
22
|
+
method_name = @action
|
23
|
+
end
|
24
|
+
|
25
|
+
# If no stage, then we are calling the main action method,
|
26
|
+
# so we should call the before/after actions
|
27
|
+
unless has_stage
|
28
|
+
if @controller.run_actions(:before, @action)
|
29
|
+
# stop_chain was called
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if @controller.respond_to?(method_name)
|
35
|
+
@controller.send(method_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
@controller.run_actions(:after, @action) unless has_stage
|
39
|
+
|
40
|
+
# before_action chain was not stopped
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,39 +1,27 @@
|
|
1
1
|
# Some template bindings share the controller with other template bindings based
|
2
|
-
# on a name. This class
|
3
|
-
#
|
4
|
-
# #clear removes 1 from the count. When the count is 0, delete the controller.
|
2
|
+
# on a name. This class creates a cache based on the group_controller name and the
|
3
|
+
# controller class.
|
5
4
|
module Volt
|
6
5
|
class GroupedControllers
|
7
|
-
@@controllers = {}
|
8
|
-
|
9
6
|
def initialize(name)
|
10
7
|
@name = name
|
8
|
+
@@pool ||= GenericCountingPool.new
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
(controller
|
15
|
-
end
|
16
|
-
|
17
|
-
def set(controller)
|
18
|
-
@@controllers[@name] = [controller, 1]
|
11
|
+
def lookup_or_create(controller, &block)
|
12
|
+
@@pool.find(@name, controller, &block)
|
19
13
|
end
|
20
14
|
|
21
|
-
def
|
22
|
-
controller
|
15
|
+
def remove(controller)
|
16
|
+
@@pool.remove(@name, controller)
|
23
17
|
end
|
24
18
|
|
25
19
|
def clear
|
26
|
-
|
27
|
-
controller[1] -= 1
|
28
|
-
if controller[1] == 0
|
29
|
-
@@controllers.delete(@name)
|
30
|
-
end
|
20
|
+
@@pool.clear
|
31
21
|
end
|
32
22
|
|
33
|
-
|
34
|
-
|
35
|
-
def controller
|
36
|
-
@@controllers[@name]
|
23
|
+
def inspect
|
24
|
+
"<GroupedController @name:#{@name.inspect} #{@@pool.inspect}>"
|
37
25
|
end
|
38
26
|
end
|
39
27
|
end
|
@@ -2,6 +2,7 @@ require 'volt/page/bindings/base_binding'
|
|
2
2
|
require 'volt/page/template_renderer'
|
3
3
|
require 'volt/page/bindings/view_binding/grouped_controllers'
|
4
4
|
require 'volt/page/bindings/view_binding/view_lookup_for_path'
|
5
|
+
require 'volt/page/bindings/view_binding/controller_handler'
|
5
6
|
|
6
7
|
|
7
8
|
module Volt
|
@@ -31,15 +32,9 @@ module Volt
|
|
31
32
|
end.watch!
|
32
33
|
end
|
33
34
|
|
35
|
+
# update is called when the path string changes.
|
34
36
|
def update(path, section_or_arguments = nil, options = {})
|
35
37
|
Computation.run_without_tracking do
|
36
|
-
# Remove existing template and call _removed
|
37
|
-
controller_send(:"#{@action}_removed") if @action && @controller
|
38
|
-
if @current_template
|
39
|
-
@current_template.remove
|
40
|
-
@current_template = nil
|
41
|
-
end
|
42
|
-
|
43
38
|
@options = options
|
44
39
|
|
45
40
|
# A blank path needs to load a missing template, otherwise it tries to load
|
@@ -67,15 +62,57 @@ module Volt
|
|
67
62
|
# Sometimes we want multiple template bindings to share the same controller (usually
|
68
63
|
# when displaying a :Title and a :Body), this instance tracks those.
|
69
64
|
if @options && (controller_group = @options[:controller_group])
|
65
|
+
# Setup the grouped controller for the first time.
|
70
66
|
@grouped_controller = GroupedControllers.new(controller_group)
|
71
|
-
else
|
72
|
-
clear_grouped_controller
|
73
67
|
end
|
74
68
|
|
69
|
+
# If a controller is already starting, but not yet started, then remove it.
|
70
|
+
remove_starting_controller
|
71
|
+
|
75
72
|
full_path, controller_path = @view_lookup.path_for_template(path, section)
|
76
|
-
render_template(full_path, controller_path)
|
77
73
|
|
78
|
-
|
74
|
+
unless full_path
|
75
|
+
# if we don't have a full path, then we have a missing template
|
76
|
+
render_next_template(full_path, path)
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
@starting_controller_handler, generated_new, chain_stopped = create_controller_handler(full_path, controller_path)
|
81
|
+
|
82
|
+
# Check if chain was stopped when the action ran
|
83
|
+
if chain_stopped
|
84
|
+
# An action stopped the chain. When this happens, we stop running here.
|
85
|
+
remove_starting_controller
|
86
|
+
else
|
87
|
+
# None of the actions stopped the chain
|
88
|
+
|
89
|
+
# Wait until the controller is loaded before we actually render.
|
90
|
+
@waiting_for_load = -> { @starting_controller_handler.controller.loaded? }.watch_until!(true) do
|
91
|
+
render_next_template(full_path, path)
|
92
|
+
end
|
93
|
+
|
94
|
+
queue_clear_grouped_controller
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Called when the next template is ready to render
|
100
|
+
def render_next_template(full_path, path)
|
101
|
+
begin
|
102
|
+
remove_current_controller_and_template
|
103
|
+
|
104
|
+
# Switch the current template
|
105
|
+
@current_controller_handler = @starting_controller_handler
|
106
|
+
@starting_controller_handler = nil
|
107
|
+
|
108
|
+
# Also track the current controller directly
|
109
|
+
@controller = @current_controller_handler.controller if full_path
|
110
|
+
|
111
|
+
@waiting_for_load = nil
|
112
|
+
render_template(full_path || path)
|
113
|
+
rescue => e
|
114
|
+
Volt.logger.error("Error during render of template at #{path}: #{e.inspect}")
|
115
|
+
Volt.logger.error(e.backtrace)
|
79
116
|
end
|
80
117
|
end
|
81
118
|
|
@@ -101,41 +138,90 @@ module Volt
|
|
101
138
|
end
|
102
139
|
end
|
103
140
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
141
|
+
def remove_current_controller_and_template
|
142
|
+
# Remove existing controller and template and call _removed
|
143
|
+
if @current_controller_handler
|
144
|
+
@current_controller_handler.call_action('before', 'remove')
|
145
|
+
end
|
146
|
+
|
147
|
+
if @current_template
|
148
|
+
@current_template.remove
|
149
|
+
@current_template = nil
|
150
|
+
end
|
151
|
+
|
152
|
+
if @current_controller_handler
|
153
|
+
@current_controller_handler.call_action('after', 'remove')
|
154
|
+
end
|
155
|
+
|
156
|
+
if @grouped_controller && @current_controller_handler
|
157
|
+
# Remove a reference for the controller in the group.
|
158
|
+
@grouped_controller.remove(@current_controller_handler.controller.class)
|
159
|
+
end
|
108
160
|
|
109
161
|
@controller = nil
|
162
|
+
@current_controller_handler = nil
|
163
|
+
end
|
110
164
|
|
111
|
-
|
112
|
-
|
165
|
+
def remove_starting_controller
|
166
|
+
# Clear any previously running wait for loads. This is for when the path changes
|
167
|
+
# before the view actually renders.
|
168
|
+
if @waiting_for_load
|
169
|
+
@waiting_for_load.stop
|
170
|
+
end
|
113
171
|
|
114
|
-
|
115
|
-
|
172
|
+
if @starting_controller_handler
|
173
|
+
# Only call the after_..._removed because the dom never loaded.
|
174
|
+
@starting_controller_handler.call_action('after', 'removed')
|
175
|
+
@starting_controller_handler = nil
|
176
|
+
end
|
177
|
+
end
|
116
178
|
|
117
|
-
|
118
|
-
|
119
|
-
|
179
|
+
# Create controller handler loads up a controller inside of the controller handler for the paths
|
180
|
+
def create_controller_handler(full_path, controller_path)
|
181
|
+
# If arguments is nil, then an blank SubContext will be created
|
182
|
+
args = [SubContext.new(@arguments, nil, true)]
|
183
|
+
|
184
|
+
# get the controller class and action
|
185
|
+
controller_class, action = get_controller(controller_path)
|
186
|
+
controller_class ||= ModelController
|
187
|
+
|
188
|
+
generated_new = false
|
189
|
+
new_controller = Proc.new do
|
190
|
+
# Mark that we needed to generate a new controller instance (not reused
|
191
|
+
# from the group)
|
192
|
+
generated_new = true
|
193
|
+
# Setup the controller
|
194
|
+
controller_class.new(*args)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Fetch grouped controllers if we're grouping
|
198
|
+
if @grouped_controller
|
199
|
+
# Find the controller in the group, or create it
|
200
|
+
controller = @grouped_controller.lookup_or_create(controller_class, &new_controller)
|
120
201
|
else
|
121
|
-
#
|
122
|
-
|
202
|
+
# Just create the controller
|
203
|
+
controller = new_controller.call
|
204
|
+
end
|
123
205
|
|
124
|
-
|
125
|
-
# Setup the controller
|
126
|
-
@controller = controller_class.new(*args)
|
127
|
-
else
|
128
|
-
@controller = ModelController.new(*args)
|
129
|
-
end
|
206
|
+
handler = ControllerHandler.new(controller, action)
|
130
207
|
|
131
|
-
|
132
|
-
|
208
|
+
if generated_new
|
209
|
+
# Call the action
|
210
|
+
stopped = handler.call_action
|
133
211
|
|
134
|
-
|
135
|
-
|
212
|
+
if stopped
|
213
|
+
controller.instance_variable_set('@chain_stopped', true)
|
214
|
+
end
|
215
|
+
else
|
216
|
+
stopped = controller.instance_variable_get('@chain_stopped')
|
136
217
|
end
|
137
218
|
|
138
|
-
|
219
|
+
return handler, generated_new, stopped
|
220
|
+
end
|
221
|
+
|
222
|
+
# The context for templates can be either a controller, or the original context.
|
223
|
+
def render_template(full_path, path)
|
224
|
+
@current_template = TemplateRenderer.new(@page, @target, @controller, @binding_name, full_path, path)
|
139
225
|
|
140
226
|
call_ready
|
141
227
|
end
|
@@ -146,49 +232,32 @@ module Volt
|
|
146
232
|
# the dom if needed
|
147
233
|
# Only assign sections for action's, so we don't get AttributeSections bound
|
148
234
|
# also.
|
149
|
-
if @
|
235
|
+
if @controller.respond_to?(:section=)
|
150
236
|
@controller.section = @current_template.dom_section
|
151
237
|
end
|
152
238
|
|
153
|
-
|
239
|
+
# Call the ready callback on the controller
|
240
|
+
@current_controller_handler.call_action(nil, 'ready')
|
154
241
|
end
|
155
242
|
end
|
156
243
|
|
244
|
+
# Called when the binding is removed from the page
|
157
245
|
def remove
|
246
|
+
# Cleanup any starting controller
|
247
|
+
remove_starting_controller
|
248
|
+
|
158
249
|
@computation.stop
|
159
250
|
@computation = nil
|
160
251
|
|
161
|
-
|
162
|
-
|
163
|
-
clear_grouped_controller
|
164
|
-
|
165
|
-
if @current_template
|
166
|
-
# Remove the template if one has been rendered, when the template binding is
|
167
|
-
# removed.
|
168
|
-
@current_template.remove
|
169
|
-
end
|
252
|
+
remove_current_controller_and_template
|
170
253
|
|
171
254
|
super
|
172
|
-
|
173
|
-
if @controller
|
174
|
-
controller_send(:"after_#{@action}_remove") if @action
|
175
|
-
|
176
|
-
@controller = nil
|
177
|
-
end
|
178
255
|
end
|
179
256
|
|
180
257
|
private
|
181
|
-
|
182
|
-
# Sends the action to the controller if it exists
|
183
|
-
def controller_send(action_name)
|
184
|
-
if @controller.respond_to?(action_name)
|
185
|
-
@controller.send(action_name)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
258
|
# Fetch the controller class
|
190
259
|
def get_controller(controller_path)
|
191
|
-
|
260
|
+
raise "Invalid controller path: #{controller_path.inspect}" unless controller_path && controller_path.size > 0
|
192
261
|
|
193
262
|
action = controller_path[-1]
|
194
263
|
|
@@ -17,8 +17,13 @@ module Volt
|
|
17
17
|
fail 'not implemented'
|
18
18
|
end
|
19
19
|
|
20
|
+
def set_template
|
21
|
+
fail 'not implemented'
|
22
|
+
end
|
23
|
+
|
20
24
|
def set_content_to_template(page, template_name)
|
21
25
|
if self.is_a?(DomSection)
|
26
|
+
# DomTemplates are an optimization when working with the DOM (as opposed to other targets)
|
22
27
|
dom_template = (@@template_cache[template_name] ||= DomTemplate.new(page, template_name))
|
23
28
|
|
24
29
|
set_template(dom_template)
|
@@ -29,7 +34,7 @@ module Volt
|
|
29
34
|
html = template['html']
|
30
35
|
bindings = template['bindings']
|
31
36
|
else
|
32
|
-
html = "<div>-- < missing
|
37
|
+
html = "<div>-- < missing view or tag at #{template_name.inspect}, make sure it's component is included in dependencies.rb > --</div>"
|
33
38
|
bindings = {}
|
34
39
|
end
|
35
40
|
|
@@ -16,7 +16,7 @@ module Volt
|
|
16
16
|
html = template['html']
|
17
17
|
@bindings = template['bindings']
|
18
18
|
else
|
19
|
-
html = "<div>-- < missing
|
19
|
+
html = "<div>-- < missing view or tag at #{template_name.inspect}, make sure it's component is included in dependencies.rb > --</div>"
|
20
20
|
@bindings = {}
|
21
21
|
end
|
22
22
|
|
@@ -148,7 +148,7 @@ class Proc
|
|
148
148
|
# @param the value to match
|
149
149
|
# @return [Volt::Computation] the initial computation is returned.
|
150
150
|
def watch_until!(value, &block)
|
151
|
-
computation =
|
151
|
+
computation = Proc.new do |comp|
|
152
152
|
# First fetch the value
|
153
153
|
result = self.call
|
154
154
|
|
@@ -159,7 +159,7 @@ class Proc
|
|
159
159
|
block.call
|
160
160
|
|
161
161
|
# stop the computation
|
162
|
-
|
162
|
+
comp.stop
|
163
163
|
end
|
164
164
|
end.watch!
|
165
165
|
|
@@ -24,7 +24,8 @@ module Volt
|
|
24
24
|
|
25
25
|
# Lookups an item
|
26
26
|
def lookup(*args, &block)
|
27
|
-
|
27
|
+
# Note: must call without args because of https://github.com/opal/opal/issues/500
|
28
|
+
item = super
|
28
29
|
|
29
30
|
item[1]
|
30
31
|
end
|
@@ -34,12 +35,14 @@ module Volt
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def remove(*args)
|
37
|
-
item =
|
38
|
-
item
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
item = lookup_without_generate(*args)
|
39
|
+
if item
|
40
|
+
item[0] -= 1
|
41
|
+
|
42
|
+
if item[0] == 0
|
43
|
+
# Last one using this item has removed it.
|
44
|
+
super(*args)
|
45
|
+
end
|
43
46
|
end
|
44
47
|
end
|
45
48
|
end
|
@@ -42,6 +42,18 @@ module Volt
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
# Looks up the path without generating a new one
|
46
|
+
def lookup_without_generate(*args)
|
47
|
+
section = @pool
|
48
|
+
|
49
|
+
args.each_with_index do |arg, index|
|
50
|
+
section = section[arg]
|
51
|
+
return nil unless section
|
52
|
+
end
|
53
|
+
|
54
|
+
section
|
55
|
+
end
|
56
|
+
|
45
57
|
# Does the actual creating, if a block is not passed in, it calls
|
46
58
|
# #create on the class.
|
47
59
|
def create_new_item(*args)
|
@@ -97,6 +109,10 @@ module Volt
|
|
97
109
|
end
|
98
110
|
end
|
99
111
|
|
112
|
+
def inspect
|
113
|
+
"<#{self.class.to_s} #{@pool.inspect}>"
|
114
|
+
end
|
115
|
+
|
100
116
|
def print
|
101
117
|
puts '--- Running Queries ---'
|
102
118
|
|
@@ -8,6 +8,8 @@ client '/flash', action: 'flash'
|
|
8
8
|
client '/yield', action: 'yield'
|
9
9
|
client '/first_last', action: 'first_last'
|
10
10
|
client '/todos', controller: 'todos'
|
11
|
+
client '/html_safe', action: 'html_safe'
|
12
|
+
client '/missing', action: 'missing'
|
11
13
|
|
12
14
|
# Signup/login routes
|
13
15
|
client '/signup', component: 'user_templates', controller: 'signup'
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'volt/controllers/model_controller'
|
3
|
+
|
4
|
+
class BaseTestActions
|
5
|
+
include Volt::Actions
|
6
|
+
|
7
|
+
setup_action_helpers_in_class(:before, :after)
|
8
|
+
end
|
9
|
+
|
10
|
+
class TestActionsBlocks < BaseTestActions
|
11
|
+
before_action do
|
12
|
+
@ran_before1 = true
|
13
|
+
end
|
14
|
+
|
15
|
+
before_action do
|
16
|
+
@ran_before2 = true
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :ran_before1, :ran_before2
|
20
|
+
end
|
21
|
+
|
22
|
+
class TestActionsSymbolsBase < BaseTestActions
|
23
|
+
attr_accessor :ran_one, :ran_two
|
24
|
+
|
25
|
+
def run_one
|
26
|
+
@ran_one = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def run_two
|
30
|
+
@ran_two = true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class TestActionsSymbols < TestActionsSymbolsBase
|
35
|
+
before_action :run_one
|
36
|
+
before_action :run_two
|
37
|
+
end
|
38
|
+
|
39
|
+
class TestActions2 < BaseTestActions
|
40
|
+
end
|
41
|
+
|
42
|
+
class TestActionsMultipleSymbols < TestActionsSymbolsBase
|
43
|
+
before_action :run_one, :run_two
|
44
|
+
end
|
45
|
+
|
46
|
+
# Runs three actions, stopping the chanin after one
|
47
|
+
class TestStopCallbacks < BaseTestActions
|
48
|
+
before_action :run_one, :run_two, :run_three
|
49
|
+
attr_accessor :ran_one, :ran_two, :ran_end_of_two, :ran_three
|
50
|
+
|
51
|
+
def run_one
|
52
|
+
@ran_one = true
|
53
|
+
end
|
54
|
+
|
55
|
+
def run_two
|
56
|
+
@ran_two = true
|
57
|
+
stop_chain
|
58
|
+
@ran_end_of_two = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def run_three
|
62
|
+
@ran_three = true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class TestNoCallbacks < BaseTestActions
|
67
|
+
end
|
68
|
+
|
69
|
+
class TestOnlyCallbacks < TestActionsSymbolsBase
|
70
|
+
before_action :run_one, :run_two, only: [:new]
|
71
|
+
end
|
72
|
+
|
73
|
+
describe Volt::Actions do
|
74
|
+
it 'should trigger before actions via blocks' do
|
75
|
+
test_class = TestActionsBlocks.new
|
76
|
+
|
77
|
+
expect(test_class.ran_before1).to eq(nil)
|
78
|
+
expect(test_class.ran_before2).to eq(nil)
|
79
|
+
|
80
|
+
test_class.run_actions(:before, :index)
|
81
|
+
|
82
|
+
expect(test_class.ran_before1).to eq(true)
|
83
|
+
expect(test_class.ran_before2).to eq(true)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should trigger before actions via symbols' do
|
87
|
+
test_class = TestActionsSymbols.new
|
88
|
+
|
89
|
+
expect(test_class.ran_one).to eq(nil)
|
90
|
+
expect(test_class.ran_two).to eq(nil)
|
91
|
+
|
92
|
+
test_class.run_actions(:before, :index)
|
93
|
+
|
94
|
+
expect(test_class.ran_one).to eq(true)
|
95
|
+
expect(test_class.ran_two).to eq(true)
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should raise an exception if no symbol or block is provided' do
|
100
|
+
expect do
|
101
|
+
TestActions2.before_action
|
102
|
+
end.to raise_error(RuntimeError, "No callback symbol or block provided")
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should support multiple symbols passed an action helper' do
|
106
|
+
test_class = TestActionsMultipleSymbols.new
|
107
|
+
|
108
|
+
expect(test_class.ran_one).to eq(nil)
|
109
|
+
expect(test_class.ran_two).to eq(nil)
|
110
|
+
|
111
|
+
result = test_class.run_actions(:before, :index)
|
112
|
+
expect(result).to eq(false)
|
113
|
+
|
114
|
+
expect(test_class.ran_one).to eq(true)
|
115
|
+
expect(test_class.ran_two).to eq(true)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should stop the chain when #stop_chain is called and return false from #run_actions' do
|
119
|
+
test_class = TestStopCallbacks.new
|
120
|
+
|
121
|
+
result = test_class.run_actions(:before, :index)
|
122
|
+
expect(result).to eq(true)
|
123
|
+
|
124
|
+
expect(test_class.ran_one).to eq(true)
|
125
|
+
expect(test_class.ran_two).to eq(true)
|
126
|
+
expect(test_class.ran_end_of_two).to eq(nil)
|
127
|
+
expect(test_class.ran_three).to eq(nil)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should call without any callbacks' do
|
131
|
+
test_class = TestNoCallbacks.new
|
132
|
+
|
133
|
+
result = test_class.run_actions(:before, :index)
|
134
|
+
expect(result).to eq(false)
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should follow only limitations' do
|
138
|
+
test_only = TestOnlyCallbacks.new
|
139
|
+
|
140
|
+
test_only.run_actions(:before, :index)
|
141
|
+
expect(test_only.ran_one).to eq(nil)
|
142
|
+
expect(test_only.ran_two).to eq(nil)
|
143
|
+
|
144
|
+
test_only.run_actions(:before, :new)
|
145
|
+
expect(test_only.ran_one).to eq(true)
|
146
|
+
expect(test_only.ran_two).to eq(true)
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
if RUBY_PLATFORM != 'opal'
|
4
|
+
describe Volt::ModelController do
|
5
|
+
it 'should accept a promise as a model and resolve it' do
|
6
|
+
controller = Volt::ModelController.new
|
7
|
+
|
8
|
+
promise = Promise.new
|
9
|
+
|
10
|
+
controller.model = promise
|
11
|
+
|
12
|
+
expect(controller.model).to eq(nil)
|
13
|
+
|
14
|
+
promise.resolve(20)
|
15
|
+
|
16
|
+
expect(controller.model).to eq(20)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should not return true from loaded until the promise is resolved' do
|
20
|
+
controller = Volt::ModelController.new
|
21
|
+
|
22
|
+
promise = Promise.new
|
23
|
+
controller.model = promise
|
24
|
+
|
25
|
+
expect(controller.loaded?).to eq(false)
|
26
|
+
|
27
|
+
promise.resolve(Volt::Model.new)
|
28
|
+
expect(controller.loaded?).to eq(true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "missing tags and view's", type: :feature do
|
4
|
+
it 'should show a message about the missing tag/view' do
|
5
|
+
visit '/missing'
|
6
|
+
|
7
|
+
expect(page).to have_content('view or tag at "some/wrong/path"')
|
8
|
+
expect(page).to have_content('view or tag at "not/a/component"')
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: volt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.0.
|
4
|
+
version: 0.9.0.pre5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Stout
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -480,6 +480,7 @@ files:
|
|
480
480
|
- lib/volt/cli/new_gem.rb
|
481
481
|
- lib/volt/cli/runner.rb
|
482
482
|
- lib/volt/config.rb
|
483
|
+
- lib/volt/controllers/actions.rb
|
483
484
|
- lib/volt/controllers/http_controller.rb
|
484
485
|
- lib/volt/controllers/model_controller.rb
|
485
486
|
- lib/volt/data_stores/data_store.rb
|
@@ -544,8 +545,10 @@ files:
|
|
544
545
|
- lib/volt/page/bindings/content_binding.rb
|
545
546
|
- lib/volt/page/bindings/each_binding.rb
|
546
547
|
- lib/volt/page/bindings/event_binding.rb
|
548
|
+
- lib/volt/page/bindings/html_safe/string_extension.rb
|
547
549
|
- lib/volt/page/bindings/if_binding.rb
|
548
550
|
- lib/volt/page/bindings/view_binding.rb
|
551
|
+
- lib/volt/page/bindings/view_binding/controller_handler.rb
|
549
552
|
- lib/volt/page/bindings/view_binding/grouped_controllers.rb
|
550
553
|
- lib/volt/page/bindings/view_binding/view_lookup_for_path.rb
|
551
554
|
- lib/volt/page/bindings/yield_binding.rb
|
@@ -646,8 +649,10 @@ files:
|
|
646
649
|
- spec/apps/kitchen_sink/app/main/views/main/cookie_test.html
|
647
650
|
- spec/apps/kitchen_sink/app/main/views/main/first_last.html
|
648
651
|
- spec/apps/kitchen_sink/app/main/views/main/flash.html
|
652
|
+
- spec/apps/kitchen_sink/app/main/views/main/html_safe.html
|
649
653
|
- spec/apps/kitchen_sink/app/main/views/main/index.html
|
650
654
|
- spec/apps/kitchen_sink/app/main/views/main/main.html
|
655
|
+
- spec/apps/kitchen_sink/app/main/views/main/missing.html
|
651
656
|
- spec/apps/kitchen_sink/app/main/views/main/store.html
|
652
657
|
- spec/apps/kitchen_sink/app/main/views/main/yield.html
|
653
658
|
- spec/apps/kitchen_sink/app/main/views/todos/index.html
|
@@ -656,7 +661,9 @@ files:
|
|
656
661
|
- spec/apps/kitchen_sink/config.ru
|
657
662
|
- spec/apps/kitchen_sink/config/app.rb
|
658
663
|
- spec/apps/kitchen_sink/config/base/index.html
|
664
|
+
- spec/controllers/actions_spec.rb
|
659
665
|
- spec/controllers/http_controller_spec.rb
|
666
|
+
- spec/controllers/model_controller_spec.rb
|
660
667
|
- spec/controllers/reactive_accessors_spec.rb
|
661
668
|
- spec/extra_core/array_spec.rb
|
662
669
|
- spec/extra_core/blank_spec.rb
|
@@ -673,6 +680,8 @@ files:
|
|
673
680
|
- spec/integration/flash_spec.rb
|
674
681
|
- spec/integration/http_endpoints_spec.rb
|
675
682
|
- spec/integration/list_spec.rb
|
683
|
+
- spec/integration/missing_spec.rb
|
684
|
+
- spec/integration/raw_html_binding.rb
|
676
685
|
- spec/integration/templates_spec.rb
|
677
686
|
- spec/integration/url_spec.rb
|
678
687
|
- spec/integration/user_spec.rb
|
@@ -849,8 +858,10 @@ test_files:
|
|
849
858
|
- spec/apps/kitchen_sink/app/main/views/main/cookie_test.html
|
850
859
|
- spec/apps/kitchen_sink/app/main/views/main/first_last.html
|
851
860
|
- spec/apps/kitchen_sink/app/main/views/main/flash.html
|
861
|
+
- spec/apps/kitchen_sink/app/main/views/main/html_safe.html
|
852
862
|
- spec/apps/kitchen_sink/app/main/views/main/index.html
|
853
863
|
- spec/apps/kitchen_sink/app/main/views/main/main.html
|
864
|
+
- spec/apps/kitchen_sink/app/main/views/main/missing.html
|
854
865
|
- spec/apps/kitchen_sink/app/main/views/main/store.html
|
855
866
|
- spec/apps/kitchen_sink/app/main/views/main/yield.html
|
856
867
|
- spec/apps/kitchen_sink/app/main/views/todos/index.html
|
@@ -859,7 +870,9 @@ test_files:
|
|
859
870
|
- spec/apps/kitchen_sink/config.ru
|
860
871
|
- spec/apps/kitchen_sink/config/app.rb
|
861
872
|
- spec/apps/kitchen_sink/config/base/index.html
|
873
|
+
- spec/controllers/actions_spec.rb
|
862
874
|
- spec/controllers/http_controller_spec.rb
|
875
|
+
- spec/controllers/model_controller_spec.rb
|
863
876
|
- spec/controllers/reactive_accessors_spec.rb
|
864
877
|
- spec/extra_core/array_spec.rb
|
865
878
|
- spec/extra_core/blank_spec.rb
|
@@ -876,6 +889,8 @@ test_files:
|
|
876
889
|
- spec/integration/flash_spec.rb
|
877
890
|
- spec/integration/http_endpoints_spec.rb
|
878
891
|
- spec/integration/list_spec.rb
|
892
|
+
- spec/integration/missing_spec.rb
|
893
|
+
- spec/integration/raw_html_binding.rb
|
879
894
|
- spec/integration/templates_spec.rb
|
880
895
|
- spec/integration/url_spec.rb
|
881
896
|
- spec/integration/user_spec.rb
|