volt 0.9.0.pre4 → 0.9.0.pre5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|