halorgium-actionpack 3.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5179 -0
- data/MIT-LICENSE +21 -0
- data/README +409 -0
- data/lib/abstract_controller.rb +16 -0
- data/lib/abstract_controller/base.rb +158 -0
- data/lib/abstract_controller/callbacks.rb +113 -0
- data/lib/abstract_controller/exceptions.rb +12 -0
- data/lib/abstract_controller/helpers.rb +151 -0
- data/lib/abstract_controller/layouts.rb +250 -0
- data/lib/abstract_controller/localized_cache.rb +49 -0
- data/lib/abstract_controller/logger.rb +61 -0
- data/lib/abstract_controller/rendering_controller.rb +188 -0
- data/lib/action_controller.rb +72 -0
- data/lib/action_controller/base.rb +168 -0
- data/lib/action_controller/caching.rb +80 -0
- data/lib/action_controller/caching/actions.rb +163 -0
- data/lib/action_controller/caching/fragments.rb +116 -0
- data/lib/action_controller/caching/pages.rb +154 -0
- data/lib/action_controller/caching/sweeping.rb +97 -0
- data/lib/action_controller/deprecated.rb +4 -0
- data/lib/action_controller/deprecated/integration_test.rb +2 -0
- data/lib/action_controller/deprecated/performance_test.rb +1 -0
- data/lib/action_controller/dispatch/dispatcher.rb +57 -0
- data/lib/action_controller/metal.rb +129 -0
- data/lib/action_controller/metal/benchmarking.rb +73 -0
- data/lib/action_controller/metal/compatibility.rb +145 -0
- data/lib/action_controller/metal/conditional_get.rb +86 -0
- data/lib/action_controller/metal/configuration.rb +28 -0
- data/lib/action_controller/metal/cookies.rb +105 -0
- data/lib/action_controller/metal/exceptions.rb +55 -0
- data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
- data/lib/action_controller/metal/flash.rb +162 -0
- data/lib/action_controller/metal/head.rb +27 -0
- data/lib/action_controller/metal/helpers.rb +115 -0
- data/lib/action_controller/metal/hide_actions.rb +47 -0
- data/lib/action_controller/metal/http_authentication.rb +312 -0
- data/lib/action_controller/metal/layouts.rb +171 -0
- data/lib/action_controller/metal/mime_responds.rb +317 -0
- data/lib/action_controller/metal/rack_convenience.rb +27 -0
- data/lib/action_controller/metal/redirector.rb +22 -0
- data/lib/action_controller/metal/render_options.rb +103 -0
- data/lib/action_controller/metal/rendering_controller.rb +57 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
- data/lib/action_controller/metal/rescuable.rb +13 -0
- data/lib/action_controller/metal/responder.rb +200 -0
- data/lib/action_controller/metal/session.rb +15 -0
- data/lib/action_controller/metal/session_management.rb +45 -0
- data/lib/action_controller/metal/streaming.rb +188 -0
- data/lib/action_controller/metal/testing.rb +39 -0
- data/lib/action_controller/metal/url_for.rb +41 -0
- data/lib/action_controller/metal/verification.rb +130 -0
- data/lib/action_controller/middleware.rb +38 -0
- data/lib/action_controller/notifications.rb +10 -0
- data/lib/action_controller/polymorphic_routes.rb +183 -0
- data/lib/action_controller/record_identifier.rb +91 -0
- data/lib/action_controller/testing/process.rb +111 -0
- data/lib/action_controller/testing/test_case.rb +345 -0
- data/lib/action_controller/translation.rb +13 -0
- data/lib/action_controller/url_rewriter.rb +204 -0
- data/lib/action_controller/vendor/html-scanner.rb +16 -0
- data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
- data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
- data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
- data/lib/action_dispatch.rb +70 -0
- data/lib/action_dispatch/http/headers.rb +33 -0
- data/lib/action_dispatch/http/mime_type.rb +231 -0
- data/lib/action_dispatch/http/mime_types.rb +23 -0
- data/lib/action_dispatch/http/request.rb +539 -0
- data/lib/action_dispatch/http/response.rb +290 -0
- data/lib/action_dispatch/http/status_codes.rb +42 -0
- data/lib/action_dispatch/http/utils.rb +20 -0
- data/lib/action_dispatch/middleware/callbacks.rb +50 -0
- data/lib/action_dispatch/middleware/params_parser.rb +79 -0
- data/lib/action_dispatch/middleware/rescue.rb +26 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
- data/lib/action_dispatch/middleware/stack.rb +116 -0
- data/lib/action_dispatch/middleware/static.rb +44 -0
- data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
- data/lib/action_dispatch/routing.rb +381 -0
- data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
- data/lib/action_dispatch/routing/mapper.rb +327 -0
- data/lib/action_dispatch/routing/route.rb +49 -0
- data/lib/action_dispatch/routing/route_set.rb +497 -0
- data/lib/action_dispatch/testing/assertions.rb +8 -0
- data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
- data/lib/action_dispatch/testing/assertions/model.rb +19 -0
- data/lib/action_dispatch/testing/assertions/response.rb +145 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
- data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
- data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
- data/lib/action_dispatch/testing/integration.rb +504 -0
- data/lib/action_dispatch/testing/performance_test.rb +15 -0
- data/lib/action_dispatch/testing/test_request.rb +83 -0
- data/lib/action_dispatch/testing/test_response.rb +131 -0
- data/lib/action_pack.rb +24 -0
- data/lib/action_pack/version.rb +9 -0
- data/lib/action_view.rb +58 -0
- data/lib/action_view/base.rb +308 -0
- data/lib/action_view/context.rb +44 -0
- data/lib/action_view/erb/util.rb +48 -0
- data/lib/action_view/helpers.rb +62 -0
- data/lib/action_view/helpers/active_model_helper.rb +306 -0
- data/lib/action_view/helpers/ajax_helper.rb +68 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
- data/lib/action_view/helpers/cache_helper.rb +39 -0
- data/lib/action_view/helpers/capture_helper.rb +168 -0
- data/lib/action_view/helpers/date_helper.rb +988 -0
- data/lib/action_view/helpers/debug_helper.rb +38 -0
- data/lib/action_view/helpers/form_helper.rb +1102 -0
- data/lib/action_view/helpers/form_options_helper.rb +600 -0
- data/lib/action_view/helpers/form_tag_helper.rb +495 -0
- data/lib/action_view/helpers/javascript_helper.rb +208 -0
- data/lib/action_view/helpers/number_helper.rb +311 -0
- data/lib/action_view/helpers/prototype_helper.rb +1309 -0
- data/lib/action_view/helpers/raw_output_helper.rb +9 -0
- data/lib/action_view/helpers/record_identification_helper.rb +20 -0
- data/lib/action_view/helpers/record_tag_helper.rb +58 -0
- data/lib/action_view/helpers/sanitize_helper.rb +259 -0
- data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
- data/lib/action_view/helpers/tag_helper.rb +151 -0
- data/lib/action_view/helpers/text_helper.rb +594 -0
- data/lib/action_view/helpers/translation_helper.rb +39 -0
- data/lib/action_view/helpers/url_helper.rb +639 -0
- data/lib/action_view/locale/en.yml +117 -0
- data/lib/action_view/paths.rb +80 -0
- data/lib/action_view/render/partials.rb +342 -0
- data/lib/action_view/render/rendering.rb +134 -0
- data/lib/action_view/safe_buffer.rb +28 -0
- data/lib/action_view/template/error.rb +101 -0
- data/lib/action_view/template/handler.rb +36 -0
- data/lib/action_view/template/handlers.rb +52 -0
- data/lib/action_view/template/handlers/builder.rb +17 -0
- data/lib/action_view/template/handlers/erb.rb +53 -0
- data/lib/action_view/template/handlers/rjs.rb +18 -0
- data/lib/action_view/template/resolver.rb +165 -0
- data/lib/action_view/template/template.rb +131 -0
- data/lib/action_view/template/text.rb +38 -0
- data/lib/action_view/test_case.rb +163 -0
- metadata +236 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "active_support/core_ext/class"
|
3
|
+
require "action_view/template/template"
|
4
|
+
|
5
|
+
module ActionView
|
6
|
+
# Abstract superclass
|
7
|
+
class Resolver
|
8
|
+
|
9
|
+
class_inheritable_accessor(:registered_details)
|
10
|
+
self.registered_details = {}
|
11
|
+
|
12
|
+
def self.register_detail(name, options = {})
|
13
|
+
registered_details[name] = lambda do |val|
|
14
|
+
val ||= yield
|
15
|
+
val |= [nil] unless options[:allow_nil] == false
|
16
|
+
val
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
register_detail(:locale) { [I18n.locale] }
|
21
|
+
register_detail(:formats) { Mime::SET.symbols }
|
22
|
+
register_detail(:handlers, :allow_nil => false) do
|
23
|
+
TemplateHandlers.extensions
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(options = {})
|
27
|
+
@cache = options[:cache]
|
28
|
+
@cached = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Normalizes the arguments and passes it on to find_template
|
32
|
+
def find(*args)
|
33
|
+
find_all(*args).first
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_all(name, details = {}, prefix = nil, partial = nil)
|
37
|
+
details = normalize_details(details)
|
38
|
+
name, prefix = normalize_name(name, prefix)
|
39
|
+
|
40
|
+
cached([name, details, prefix, partial]) do
|
41
|
+
find_templates(name, details, prefix, partial)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# This is what child classes implement. No defaults are needed
|
48
|
+
# because Resolver guarantees that the arguments are present and
|
49
|
+
# normalized.
|
50
|
+
def find_templates(name, details, prefix, partial)
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
|
54
|
+
def normalize_details(details)
|
55
|
+
details = details.dup
|
56
|
+
# TODO: Refactor this concern out of the resolver
|
57
|
+
details.delete(:formats) if details[:formats] == [:"*/*"]
|
58
|
+
registered_details.each do |k, v|
|
59
|
+
details[k] = v.call(details[k])
|
60
|
+
end
|
61
|
+
details
|
62
|
+
end
|
63
|
+
|
64
|
+
# Support legacy foo.erb names even though we now ignore .erb
|
65
|
+
# as well as incorrectly putting part of the path in the template
|
66
|
+
# name instead of the prefix.
|
67
|
+
def normalize_name(name, prefix)
|
68
|
+
handlers = TemplateHandlers.extensions.join('|')
|
69
|
+
name = name.to_s.gsub(/\.(?:#{handlers})$/, '')
|
70
|
+
|
71
|
+
parts = name.split('/')
|
72
|
+
return parts.pop, [prefix, *parts].compact.join("/")
|
73
|
+
end
|
74
|
+
|
75
|
+
def cached(key)
|
76
|
+
return yield unless @cache
|
77
|
+
return @cached[key] if @cached.key?(key)
|
78
|
+
@cached[key] = yield
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class PathResolver < Resolver
|
83
|
+
|
84
|
+
EXTENSION_ORDER = [:locale, :formats, :handlers]
|
85
|
+
|
86
|
+
def to_s
|
87
|
+
@path.to_s
|
88
|
+
end
|
89
|
+
alias to_path to_s
|
90
|
+
|
91
|
+
def find_templates(name, details, prefix, partial)
|
92
|
+
path = build_path(name, details, prefix, partial)
|
93
|
+
query(path, EXTENSION_ORDER.map { |ext| details[ext] })
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def build_path(name, details, prefix, partial)
|
99
|
+
path = ""
|
100
|
+
path << "#{prefix}/" unless prefix.empty?
|
101
|
+
path << (partial ? "_#{name}" : name)
|
102
|
+
path
|
103
|
+
end
|
104
|
+
|
105
|
+
def query(path, exts)
|
106
|
+
query = "#{@path}/#{path}"
|
107
|
+
exts.each do |ext|
|
108
|
+
query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << '}'
|
109
|
+
end
|
110
|
+
|
111
|
+
Dir[query].map do |path|
|
112
|
+
next if File.directory?(path)
|
113
|
+
source = File.read(path)
|
114
|
+
identifier = Pathname.new(path).expand_path.to_s
|
115
|
+
|
116
|
+
Template.new(source, identifier, *path_to_details(path))
|
117
|
+
end.compact
|
118
|
+
end
|
119
|
+
|
120
|
+
# # TODO: fix me
|
121
|
+
# # :api: plugin
|
122
|
+
def path_to_details(path)
|
123
|
+
# [:erb, :format => :html, :locale => :en, :partial => true/false]
|
124
|
+
if m = path.match(%r'(?:^|/)(_)?[\w-]+((?:\.[\w-]+)*)\.(\w+)$')
|
125
|
+
partial = m[1] == '_'
|
126
|
+
details = (m[2]||"").split('.').reject { |e| e.empty? }
|
127
|
+
handler = Template.handler_class_for_extension(m[3])
|
128
|
+
|
129
|
+
format = Mime[details.last] && details.pop.to_sym
|
130
|
+
locale = details.last && details.pop.to_sym
|
131
|
+
|
132
|
+
return handler, :format => format, :locale => locale, :partial => partial
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class FileSystemResolver < PathResolver
|
138
|
+
def initialize(path, options = {})
|
139
|
+
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
|
140
|
+
super(options)
|
141
|
+
@path = Pathname.new(path).expand_path
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# OMG HAX
|
146
|
+
# TODO: remove hax
|
147
|
+
class FileSystemResolverWithFallback < Resolver
|
148
|
+
def initialize(path, options = {})
|
149
|
+
super(options)
|
150
|
+
@paths = [FileSystemResolver.new(path, options), FileSystemResolver.new("", options), FileSystemResolver.new("/", options)]
|
151
|
+
end
|
152
|
+
|
153
|
+
def find_templates(*args)
|
154
|
+
@paths.each do |p|
|
155
|
+
template = p.find_templates(*args)
|
156
|
+
return template unless template.empty?
|
157
|
+
end
|
158
|
+
[]
|
159
|
+
end
|
160
|
+
|
161
|
+
def to_s
|
162
|
+
@paths.first.to_s
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This is so that templates compiled in this file are UTF-8
|
3
|
+
|
4
|
+
require 'set'
|
5
|
+
require "action_view/template/resolver"
|
6
|
+
|
7
|
+
module ActionView
|
8
|
+
class Template
|
9
|
+
extend TemplateHandlers
|
10
|
+
attr_reader :source, :identifier, :handler, :mime_type, :formats, :details
|
11
|
+
|
12
|
+
def initialize(source, identifier, handler, details)
|
13
|
+
@source = source
|
14
|
+
@identifier = identifier
|
15
|
+
@handler = handler
|
16
|
+
@details = details
|
17
|
+
@method_names = {}
|
18
|
+
|
19
|
+
format = details.delete(:format) || begin
|
20
|
+
# TODO: Clean this up
|
21
|
+
handler.respond_to?(:default_format) ? handler.default_format.to_sym.to_s : "html"
|
22
|
+
end
|
23
|
+
@mime_type = Mime::Type.lookup_by_extension(format.to_s)
|
24
|
+
@formats = [format.to_sym]
|
25
|
+
@formats << :html if format == :js
|
26
|
+
@details[:formats] = Array.wrap(format.to_sym)
|
27
|
+
end
|
28
|
+
|
29
|
+
def render(view, locals, &block)
|
30
|
+
ActiveSupport::Notifications.instrument(:render_template, :identifier => identifier) do
|
31
|
+
method_name = compile(locals, view)
|
32
|
+
view.send(method_name, locals, &block)
|
33
|
+
end
|
34
|
+
rescue Exception => e
|
35
|
+
if e.is_a?(TemplateError)
|
36
|
+
e.sub_template_of(self)
|
37
|
+
raise e
|
38
|
+
else
|
39
|
+
raise TemplateError.new(self, view.assigns, e)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# TODO: Figure out how to abstract this
|
44
|
+
def variable_name
|
45
|
+
@variable_name ||= identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
|
46
|
+
end
|
47
|
+
|
48
|
+
# TODO: Figure out how to abstract this
|
49
|
+
def counter_name
|
50
|
+
@counter_name ||= "#{variable_name}_counter".to_sym
|
51
|
+
end
|
52
|
+
|
53
|
+
# TODO: kill hax
|
54
|
+
def partial?
|
55
|
+
@details[:partial]
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
if defined?(Rails.root)
|
60
|
+
identifier.sub("#{Rails.root}/", '')
|
61
|
+
else
|
62
|
+
identifier
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def compile(locals, view)
|
68
|
+
method_name = build_method_name(locals)
|
69
|
+
|
70
|
+
return method_name if view.respond_to?(method_name)
|
71
|
+
|
72
|
+
locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join
|
73
|
+
|
74
|
+
code = @handler.call(self)
|
75
|
+
if code.sub!(/\A(#.*coding.*)\n/, '')
|
76
|
+
encoding_comment = $1
|
77
|
+
elsif defined?(Encoding) && Encoding.respond_to?(:default_external)
|
78
|
+
encoding_comment = "#coding:#{Encoding.default_external}"
|
79
|
+
end
|
80
|
+
|
81
|
+
source = <<-end_src
|
82
|
+
def #{method_name}(local_assigns)
|
83
|
+
old_output_buffer = output_buffer;#{locals_code};#{code}
|
84
|
+
ensure
|
85
|
+
self.output_buffer = old_output_buffer
|
86
|
+
end
|
87
|
+
end_src
|
88
|
+
|
89
|
+
if encoding_comment
|
90
|
+
source = "#{encoding_comment}\n#{source}"
|
91
|
+
line = -1
|
92
|
+
else
|
93
|
+
line = 0
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
ActionView::CompiledTemplates.module_eval(source, identifier, line)
|
98
|
+
method_name
|
99
|
+
rescue Exception => e # errors from template code
|
100
|
+
if logger = (view && view.logger)
|
101
|
+
logger.debug "ERROR: compiling #{method_name} RAISED #{e}"
|
102
|
+
logger.debug "Function body: #{source}"
|
103
|
+
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
|
104
|
+
end
|
105
|
+
|
106
|
+
raise ActionView::TemplateError.new(self, {}, e)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class LocalsKey
|
111
|
+
@hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
|
112
|
+
|
113
|
+
def self.get(*locals)
|
114
|
+
@hash_keys[*locals] ||= new(klass, format, locale)
|
115
|
+
end
|
116
|
+
|
117
|
+
attr_accessor :hash
|
118
|
+
def initialize(klass, format, locale)
|
119
|
+
@hash = locals.hash
|
120
|
+
end
|
121
|
+
|
122
|
+
alias_method :eql?, :equal?
|
123
|
+
end
|
124
|
+
|
125
|
+
def build_method_name(locals)
|
126
|
+
# TODO: is locals.keys.hash reliably the same?
|
127
|
+
@method_names[locals.keys.hash] ||=
|
128
|
+
"_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ActionView #:nodoc:
|
2
|
+
class TextTemplate < String #:nodoc:
|
3
|
+
HTML = Mime[:html]
|
4
|
+
|
5
|
+
def initialize(string, content_type = HTML)
|
6
|
+
super(string.to_s)
|
7
|
+
@content_type = Mime[content_type] || content_type
|
8
|
+
end
|
9
|
+
|
10
|
+
def details
|
11
|
+
{:formats => [@content_type.to_sym]}
|
12
|
+
end
|
13
|
+
|
14
|
+
def identifier
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
'text template'
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(*args)
|
23
|
+
to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def mime_type
|
27
|
+
@content_type
|
28
|
+
end
|
29
|
+
|
30
|
+
def formats
|
31
|
+
[mime_type]
|
32
|
+
end
|
33
|
+
|
34
|
+
def partial?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'active_support/test_case'
|
2
|
+
require 'action_controller/testing/test_case'
|
3
|
+
|
4
|
+
module ActionView
|
5
|
+
class Base
|
6
|
+
alias_method :initialize_without_template_tracking, :initialize
|
7
|
+
def initialize(*args)
|
8
|
+
@_rendered = { :template => nil, :partials => Hash.new(0) }
|
9
|
+
initialize_without_template_tracking(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_internal :rendered
|
13
|
+
end
|
14
|
+
|
15
|
+
class Template
|
16
|
+
alias_method :render_without_tracking, :render
|
17
|
+
def render(view, locals, &blk)
|
18
|
+
rendered = view.rendered
|
19
|
+
rendered[:partials][self] += 1 if partial?
|
20
|
+
rendered[:template] ||= []
|
21
|
+
rendered[:template] << self
|
22
|
+
render_without_tracking(view, locals, &blk)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class TestCase < ActiveSupport::TestCase
|
27
|
+
class TestController < ActionController::Base
|
28
|
+
attr_accessor :request, :response, :params
|
29
|
+
|
30
|
+
def self.controller_path
|
31
|
+
''
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@request = ActionController::TestRequest.new
|
36
|
+
@response = ActionController::TestResponse.new
|
37
|
+
|
38
|
+
@params = {}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
include ActionDispatch::Assertions
|
43
|
+
include ActionController::TestProcess
|
44
|
+
include ActionView::Context
|
45
|
+
|
46
|
+
include ActionController::PolymorphicRoutes
|
47
|
+
include ActionController::RecordIdentifier
|
48
|
+
|
49
|
+
include ActionView::Helpers
|
50
|
+
include ActionController::Helpers
|
51
|
+
|
52
|
+
class_inheritable_accessor :helper_class
|
53
|
+
attr_accessor :controller, :output_buffer, :rendered
|
54
|
+
|
55
|
+
setup :setup_with_controller
|
56
|
+
def setup_with_controller
|
57
|
+
@controller = TestController.new
|
58
|
+
@output_buffer = ActionView::SafeBuffer.new
|
59
|
+
@rendered = ''
|
60
|
+
|
61
|
+
self.class.send(:include_helper_modules!)
|
62
|
+
make_test_case_available_to_view!
|
63
|
+
end
|
64
|
+
|
65
|
+
def render(options = {}, local_assigns = {}, &block)
|
66
|
+
@rendered << output = _view.render(options, local_assigns, &block)
|
67
|
+
output
|
68
|
+
end
|
69
|
+
|
70
|
+
def protect_against_forgery?
|
71
|
+
false
|
72
|
+
end
|
73
|
+
|
74
|
+
class << self
|
75
|
+
def tests(helper_class)
|
76
|
+
self.helper_class = helper_class
|
77
|
+
end
|
78
|
+
|
79
|
+
def helper_class
|
80
|
+
if current_helper_class = read_inheritable_attribute(:helper_class)
|
81
|
+
current_helper_class
|
82
|
+
else
|
83
|
+
self.helper_class = determine_default_helper_class(name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def determine_default_helper_class(name)
|
88
|
+
name.sub(/Test$/, '').constantize
|
89
|
+
rescue NameError
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def helper_method(*methods)
|
94
|
+
# Almost a duplicate from ActionController::Helpers
|
95
|
+
methods.flatten.each do |method|
|
96
|
+
_helpers.module_eval <<-end_eval
|
97
|
+
def #{method}(*args, &block) # def current_user(*args, &block)
|
98
|
+
_test_case.send(%(#{method}), *args, &block) # test_case.send(%(current_user), *args, &block)
|
99
|
+
end # end
|
100
|
+
end_eval
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
def include_helper_modules!
|
106
|
+
helper(helper_class) if helper_class
|
107
|
+
include _helpers
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
def make_test_case_available_to_view!
|
113
|
+
test_case_instance = self
|
114
|
+
_helpers.module_eval do
|
115
|
+
define_method(:_test_case) { test_case_instance }
|
116
|
+
private :_test_case
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def _view
|
121
|
+
view = ActionView::Base.new(ActionController::Base.view_paths, _assigns, @controller)
|
122
|
+
view.class.send :include, _helpers
|
123
|
+
view
|
124
|
+
end
|
125
|
+
|
126
|
+
# Support the selector assertions
|
127
|
+
#
|
128
|
+
# Need to experiment if this priority is the best one: rendered => output_buffer
|
129
|
+
def response_from_page_or_rjs
|
130
|
+
HTML::Document.new(rendered.blank? ? output_buffer : rendered).root
|
131
|
+
end
|
132
|
+
|
133
|
+
EXCLUDE_IVARS = %w{
|
134
|
+
@output_buffer
|
135
|
+
@fixture_cache
|
136
|
+
@method_name
|
137
|
+
@_result
|
138
|
+
@loaded_fixtures
|
139
|
+
@test_passed
|
140
|
+
@view
|
141
|
+
}
|
142
|
+
|
143
|
+
def _instance_variables
|
144
|
+
instance_variables - EXCLUDE_IVARS
|
145
|
+
end
|
146
|
+
|
147
|
+
def _assigns
|
148
|
+
_instance_variables.inject({}) do |hash, var|
|
149
|
+
name = var[1..-1].to_sym
|
150
|
+
hash[name] = instance_variable_get(var)
|
151
|
+
hash
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def method_missing(selector, *args)
|
156
|
+
if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
|
157
|
+
@controller.__send__(selector, *args)
|
158
|
+
else
|
159
|
+
super
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|