fortitude 0.9.4-java → 0.9.5-java
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/.fix_bundler_for_jruby_17 +26 -0
- data/.gitignore +1 -0
- data/.travis.yml +33 -40
- data/CHANGES.md +44 -0
- data/CONTRIBUTORS.md +26 -0
- data/Rakefile +1 -1
- data/ext/com/fortituderuby/ext/fortitude/FortitudeNativeLibrary.java +45 -33
- data/ext/fortitude_native_ext/fortitude_native_ext.c +23 -23
- data/fortitude.gemspec +25 -8
- data/lib/fortitude/erector.rb +26 -18
- data/lib/fortitude/errors.rb +15 -4
- data/lib/fortitude/extensions/fortitude_ruby_ext.rb +35 -10
- data/lib/fortitude/rails/helpers.rb +59 -2
- data/lib/fortitude/rails/railtie.rb +238 -157
- data/lib/fortitude/rails/renderer.rb +15 -0
- data/lib/fortitude/rails/rendering_methods.rb +46 -33
- data/lib/fortitude/rails/template_handler.rb +49 -18
- data/lib/fortitude/rails/yielded_object_outputter.rb +3 -2
- data/lib/fortitude/rendering_context.rb +14 -5
- data/lib/fortitude/support/method_overriding.rb +90 -0
- data/lib/fortitude/support/staticized_method.rb +12 -0
- data/lib/fortitude/version.rb +1 -1
- data/lib/fortitude/widget/content.rb +4 -2
- data/lib/fortitude/widget/files.rb +17 -11
- data/lib/fortitude/widget/helpers.rb +7 -1
- data/lib/fortitude/widget/integration.rb +4 -0
- data/lib/fortitude/widget/localization.rb +63 -4
- data/lib/fortitude/widget/rendering.rb +17 -10
- data/lib/fortitude_jruby_native_ext.jar +0 -0
- data/spec/helpers/fortitude_rails_helpers.rb +26 -4
- data/spec/rails/capture_system_spec.rb +1 -1
- data/spec/rails/class_loading_system_spec.rb +16 -2
- data/spec/rails/complex_helpers_system_spec.rb +29 -0
- data/spec/rails/data_passing_system_spec.rb +2 -2
- data/spec/rails/development_mode_system_spec.rb +1 -1
- data/spec/rails/erector_coexistence_system_spec.rb +1 -1
- data/spec/rails/helpers_system_spec.rb +20 -2
- data/spec/rails/layouts_system_spec.rb +1 -1
- data/spec/rails/rendering_system_spec.rb +4 -4
- data/spec/rails/rules_system_spec.rb +2 -2
- data/spec/rails/templates/class_loading_system_spec/app/views/some_namespace/some_other_namespace/placeholder.rb +5 -0
- data/spec/rails/templates/complex_helpers_system_spec/app/controllers/complex_helpers_system_spec_controller.rb +4 -0
- data/spec/rails/templates/complex_helpers_system_spec/app/views/complex_helpers_system_spec/label_block_test.rb +9 -0
- data/spec/rails/templates/helpers_system_spec/app/controllers/helpers_system_spec_controller.rb +4 -0
- data/spec/rails/templates/helpers_system_spec/app/controllers/home_controller.rb +9 -0
- data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/rails_helpers_without_automatic_helper_access.rb +37 -0
- data/spec/rails/templates/helpers_system_spec/app/views/helpers_system_spec/url_helpers_without_automatic_helper_access.rb +45 -0
- data/spec/rails/templates/helpers_system_spec/config/initializers/host.rb +1 -0
- data/spec/rails/templates/helpers_system_spec/config/routes.rb +7 -0
- data/spec/rails/templates/static_method_system_spec/app/views/static_method_system_spec/localization.rb +1 -1
- data/spec/rails/templates/view_paths_system_spec/app/controllers/view_paths_system_spec_controller.rb +15 -0
- data/spec/rails/templates/view_paths_system_spec/config/application.rb +30 -0
- data/spec/rails/templates/view_paths_system_spec/view_path_one/baseone/basetwo/base_class_one.rb +5 -0
- data/spec/rails/templates/view_paths_system_spec/view_path_one/view_paths_system_spec/added_view_path.html.rb +5 -0
- data/spec/rails/templates/view_paths_system_spec/view_path_one/view_paths_system_spec/autoloading_from_added_view_path.html.rb +5 -0
- data/spec/rails/templates/view_paths_system_spec/view_path_two/view_paths_system_spec/added_view_path_from_controller.html.rb +5 -0
- data/spec/rails/templates/view_paths_system_spec/view_path_two/view_paths_system_spec/added_view_path_from_controller_with_impossible_to_guess_name.html.rb +14 -0
- data/spec/rails/view_paths_system_spec.rb +19 -0
- data/spec/system/escaping_system_spec.rb +10 -2
- data/spec/system/helpers_system_spec.rb +37 -6
- data/spec/system/inline_system_spec.rb +19 -0
- data/spec/system/static_method_system_spec.rb +16 -0
- data/spec/system/tag_rendering_system_spec.rb +4 -4
- data/spec/system/widget_class_from_spec.rb +39 -0
- data/spec/system/yield_system_spec.rb +53 -1
- metadata +90 -58
data/fortitude.gemspec
CHANGED
@@ -25,25 +25,42 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.extensions << "ext/fortitude_native_ext/extconf.rb"
|
26
26
|
end
|
27
27
|
|
28
|
-
activesupport_spec =
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
activesupport_spec = [ ">= 3.0" ]
|
29
|
+
ref_spec = [ ">= 1.0.5" ]
|
30
|
+
rake_spec = [ ">= 1.0" ]
|
31
|
+
json_spec = [ ">= 1.0" ]
|
32
|
+
|
33
|
+
if RUBY_VERSION =~ /^1\.8\./
|
34
|
+
activesupport_spec << "< 4.0"
|
35
|
+
ref_spec << "< 2.0.0"
|
36
|
+
rake_spec << "< 11.0.0"
|
37
|
+
json_spec << "< 2.0.0"
|
38
|
+
elsif RUBY_VERSION =~ /^1\.9\./
|
39
|
+
activesupport_spec << "< 5.0"
|
40
|
+
json_spec << "< 2.0.0"
|
41
|
+
elsif RUBY_VERSION =~ /^2\.[01]\./
|
42
|
+
activesupport_spec << "< 5.0"
|
32
43
|
end
|
33
44
|
|
34
45
|
s.add_dependency "activesupport", *activesupport_spec
|
35
|
-
s.add_dependency "ref",
|
46
|
+
s.add_dependency "ref", *ref_spec
|
47
|
+
|
48
|
+
s.add_development_dependency "rake", *rake_spec
|
49
|
+
s.add_development_dependency "json", *json_spec
|
36
50
|
|
37
51
|
s.add_development_dependency "bundler", "~> 1.5"
|
38
|
-
s.add_development_dependency "rake"
|
39
52
|
s.add_development_dependency "rspec", "~> 2.99"
|
40
53
|
s.add_development_dependency "rake-compiler"
|
41
|
-
s.add_development_dependency "json"
|
42
54
|
s.add_development_dependency "tilt", "~> 2.0"
|
43
|
-
s.add_development_dependency "oop_rails_server", ">= 0.0.
|
55
|
+
s.add_development_dependency "oop_rails_server", ">= 0.0.22"
|
44
56
|
|
45
57
|
# This is because i18n >= 0.7 is incompatible with Ruby 1.8.x.
|
46
58
|
if RUBY_VERSION =~ /^1\.8\./
|
47
59
|
s.add_development_dependency "i18n", "~> 0.6.0", "< 0.7.0"
|
48
60
|
end
|
61
|
+
|
62
|
+
# This is because 'tins' >= 1.7.0 is incompatible with Ruby < 2.0.0.
|
63
|
+
if RUBY_VERSION =~ /^1\./
|
64
|
+
s.add_development_dependency "tins", "< 1.7.0"
|
65
|
+
end
|
49
66
|
end
|
data/lib/fortitude/erector.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'fortitude/support/method_overriding'
|
2
|
+
|
1
3
|
module Fortitude
|
2
4
|
module Erector
|
3
5
|
class << self
|
@@ -31,6 +33,10 @@ module Fortitude
|
|
31
33
|
return is_erector_widget_class?(widget_class.superclass)
|
32
34
|
end
|
33
35
|
|
36
|
+
def erector_widget_base_class_if_available
|
37
|
+
::Erector::Widget if is_erector_available?
|
38
|
+
end
|
39
|
+
|
34
40
|
def is_erector_widget?(widget)
|
35
41
|
is_erector_widget_class?(widget.class)
|
36
42
|
end
|
@@ -48,27 +54,29 @@ module Fortitude
|
|
48
54
|
private
|
49
55
|
attr_reader :erector_output
|
50
56
|
end
|
51
|
-
end
|
52
|
-
end
|
53
57
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
58
|
+
module ErectorAbstractWidgetOverrides
|
59
|
+
def widget_uniwith_fortitude(original_method, target, assigns = {}, options = {}, &block)
|
60
|
+
if (target.kind_of?(::Class) && target < ::Fortitude::Widget)
|
61
|
+
target = target.new(assigns)
|
62
|
+
end
|
60
63
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
if target.kind_of?(::Fortitude::Widget)
|
65
|
+
rendering_context = ::Fortitude::RenderingContext.new(
|
66
|
+
:delegate_object => parent,
|
67
|
+
:output_buffer_holder => ::Fortitude::Erector::ErectorOutputBufferHolder.new(output),
|
68
|
+
:helpers_object => helpers)
|
69
|
+
return target.render_to(rendering_context, &block)
|
70
|
+
else
|
71
|
+
return original_method.call(target, assigns, options, &block)
|
72
|
+
end
|
69
73
|
end
|
70
74
|
end
|
71
|
-
|
72
|
-
alias_method_chain :widget, :fortitude
|
73
75
|
end
|
74
76
|
end
|
77
|
+
|
78
|
+
if ::Fortitude::Erector.is_erector_available?
|
79
|
+
::Fortitude::MethodOverriding.override_methods(
|
80
|
+
::Erector::AbstractWidget, ::Fortitude::Erector::ErectorAbstractWidgetOverrides, :fortitude,
|
81
|
+
[ :widget ])
|
82
|
+
end
|
data/lib/fortitude/errors.rb
CHANGED
@@ -153,16 +153,27 @@ you simply need to convert these to "p :class => :some_class" or
|
|
153
153
|
class NoBlockToYieldTo < Base
|
154
154
|
attr_reader :widget
|
155
155
|
|
156
|
-
def initialize(widget)
|
157
|
-
|
156
|
+
def initialize(widget, local_jump_exception = nil)
|
157
|
+
@local_jump_exception = local_jump_exception
|
158
|
+
@widget = widget
|
159
|
+
|
160
|
+
message = %{You're trying to call 'yield' (or 'yield_from_widget', or the Erector-compatibility method 'call_block')
|
158
161
|
from the widget #{widget}; however, there is nothing to yield to. Fortitude
|
159
162
|
looks for something to yield to in this order:
|
160
163
|
1. A block passed to a yield at render time directly (usually via the 'widget' call);
|
161
164
|
2. A block passed to the constructor of the widget;
|
162
165
|
3. The layout the widget is being rendered in.
|
163
166
|
None of these exist here, and so calling 'yield', 'yield_from_widget', or 'call_block' is an
|
164
|
-
undefined operation.}
|
165
|
-
|
167
|
+
undefined operation.}
|
168
|
+
|
169
|
+
if @local_jump_exception
|
170
|
+
message += %{
|
171
|
+
|
172
|
+
This was caused by a #{@local_jump_exception.class.name}, which is: #{@local_jump_exception}:\n
|
173
|
+
#{@local_jump_exception.backtrace.join("\n ")}}
|
174
|
+
end
|
175
|
+
|
176
|
+
super(message)
|
166
177
|
end
|
167
178
|
end
|
168
179
|
end
|
@@ -2,10 +2,35 @@ require 'erb'
|
|
2
2
|
|
3
3
|
::String.class_eval do
|
4
4
|
def fortitude_append_escaped_string(output)
|
5
|
+
_fortitude_append_escaped_string(output, false)
|
6
|
+
end
|
7
|
+
|
8
|
+
TABLE_FOR_ESCAPE_ATTRIBUTE_VALUE__ = {
|
9
|
+
'&' => '&',
|
10
|
+
'"' => '"'
|
11
|
+
}
|
12
|
+
|
13
|
+
PROC_FOR_ESCAPE_ATTRIBUTE_VALUE__ = Proc.new do |match|
|
14
|
+
TABLE_FOR_ESCAPE_ATTRIBUTE_VALUE__[match]
|
15
|
+
end
|
16
|
+
|
17
|
+
if RUBY_VERSION =~ /^1\.8\./
|
18
|
+
def _fortitude_append_escaped_string_for_value(output)
|
19
|
+
output.original_concat(self.gsub(/[&\"]/, &PROC_FOR_ESCAPE_ATTRIBUTE_VALUE__))
|
20
|
+
end
|
21
|
+
else
|
22
|
+
def _fortitude_append_escaped_string_for_value(output)
|
23
|
+
output.original_concat(self.gsub(/[&\"]/, TABLE_FOR_ESCAPE_ATTRIBUTE_VALUE__))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def _fortitude_append_escaped_string(output, for_attribute_value)
|
5
28
|
raise ArgumentError, "You can only append to a String" unless output.kind_of?(String)
|
6
29
|
|
7
30
|
if html_safe?
|
8
31
|
output.original_concat(self)
|
32
|
+
elsif for_attribute_value
|
33
|
+
_fortitude_append_escaped_string_for_value(output)
|
9
34
|
else
|
10
35
|
output.original_concat(ERB::Util.html_escape(self))
|
11
36
|
end
|
@@ -33,8 +58,8 @@ end
|
|
33
58
|
each do |key, value|
|
34
59
|
if value.kind_of?(Hash)
|
35
60
|
new_prefix = case prefix
|
36
|
-
when String then fortitude_append_to(key, prefix.dup)
|
37
|
-
when nil then fortitude_append_to(key, "".html_safe)
|
61
|
+
when String then fortitude_append_to(key, prefix.dup, false)
|
62
|
+
when nil then fortitude_append_to(key, "".html_safe, false)
|
38
63
|
else raise ArgumentError, "You can only use a String as a prefix"
|
39
64
|
end
|
40
65
|
|
@@ -52,19 +77,19 @@ end
|
|
52
77
|
else raise ArgumentError, "You can only use a String as a prefix"
|
53
78
|
end
|
54
79
|
|
55
|
-
fortitude_append_to(key, target)
|
80
|
+
fortitude_append_to(key, target, false)
|
56
81
|
|
57
82
|
if value == true
|
58
83
|
if allows_bare_attributes
|
59
84
|
# nothing here
|
60
85
|
else
|
61
86
|
target.original_concat(::Hash::FORTITUDE_EQUALS_QUOTE)
|
62
|
-
fortitude_append_to(key, target)
|
87
|
+
fortitude_append_to(key, target, false)
|
63
88
|
target.original_concat(::Hash::FORTITUDE_QUOTE)
|
64
89
|
end
|
65
90
|
else
|
66
91
|
target.original_concat(::Hash::FORTITUDE_EQUALS_QUOTE)
|
67
|
-
fortitude_append_to(value, target)
|
92
|
+
fortitude_append_to(value, target, true)
|
68
93
|
target.original_concat(::Hash::FORTITUDE_QUOTE)
|
69
94
|
end
|
70
95
|
end
|
@@ -75,17 +100,17 @@ end
|
|
75
100
|
end
|
76
101
|
|
77
102
|
private
|
78
|
-
def fortitude_append_to(object, output)
|
103
|
+
def fortitude_append_to(object, output, for_attribute_value)
|
79
104
|
case object
|
80
|
-
when String then object.
|
81
|
-
when Symbol then object.to_s.
|
105
|
+
when String then object._fortitude_append_escaped_string(output, for_attribute_value)
|
106
|
+
when Symbol then object.to_s._fortitude_append_escaped_string(output, for_attribute_value)
|
82
107
|
when Array then object.each_with_index do |o,i|
|
83
108
|
output.original_concat(" ") if i > 0
|
84
|
-
fortitude_append_to(o, output)
|
109
|
+
fortitude_append_to(o, output, for_attribute_value)
|
85
110
|
end
|
86
111
|
when nil then nil
|
87
112
|
when Integer then output.original_concat(object.to_s)
|
88
|
-
else object.to_s.
|
113
|
+
else object.to_s._fortitude_append_escaped_string(output, for_attribute_value)
|
89
114
|
end
|
90
115
|
end
|
91
116
|
end
|
@@ -4,20 +4,77 @@ module Fortitude
|
|
4
4
|
class << self
|
5
5
|
def helper(name, options = { })
|
6
6
|
@helpers ||= { }
|
7
|
-
@helpers[name] = options
|
7
|
+
@helpers[normalize_helper_name(name)] = options
|
8
8
|
end
|
9
9
|
|
10
10
|
def helper_options(name)
|
11
|
-
@helpers[name
|
11
|
+
@helpers[normalize_helper_name(name)]
|
12
12
|
end
|
13
13
|
|
14
14
|
def apply_refined_helpers_to!(o)
|
15
|
+
o.send(:include, ::Rails.application.routes.url_helpers)
|
15
16
|
@helpers.each do |name, options|
|
16
17
|
o.helper(name, options)
|
17
18
|
end
|
18
19
|
end
|
20
|
+
|
21
|
+
ALL_BUILTIN_HELPER_MODULES = {
|
22
|
+
ActionView::Helpers => %w{
|
23
|
+
ActiveModelHelper
|
24
|
+
ActiveModelInstanceTag
|
25
|
+
AssetTagHelper
|
26
|
+
AssetUrlHelper
|
27
|
+
AtomFeedHelper
|
28
|
+
CacheHelper
|
29
|
+
CaptureHelper
|
30
|
+
CsrfHelper
|
31
|
+
DateHelper
|
32
|
+
DebugHelper
|
33
|
+
FormHelper
|
34
|
+
FormOptionsHelper
|
35
|
+
FormTagHelper
|
36
|
+
JavaScriptHelper
|
37
|
+
NumberHelper
|
38
|
+
OutputSafetyHelper
|
39
|
+
RecordTagHelper
|
40
|
+
SanitizeHelper
|
41
|
+
TagHelper
|
42
|
+
TextHelper
|
43
|
+
TranslationHelper
|
44
|
+
UrlHelper
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
def declare_all_builtin_rails_helpers!
|
49
|
+
ALL_BUILTIN_HELPER_MODULES.each do |base_module, constant_names|
|
50
|
+
constant_names.each do |constant_name|
|
51
|
+
if base_module.const_defined?(constant_name)
|
52
|
+
helper_module = base_module.const_get(constant_name)
|
53
|
+
helper_module.public_instance_methods.each do |helper_method_name|
|
54
|
+
# This is because ActionView::Helpers::FormTagHelper exposes #embed_authenticity_token_in_remote_forms=
|
55
|
+
# as a public instance method. This seems like it should not be included as a helper.
|
56
|
+
# next if helper_method_name.to_s == 'embed_authenticity_token_in_remote_forms='
|
57
|
+
helper helper_method_name
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
helper :default_url_options
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def normalize_helper_name(name)
|
68
|
+
name.to_s.strip.downcase.to_sym
|
69
|
+
end
|
19
70
|
end
|
20
71
|
|
72
|
+
# This gives us all built-in Rails helpers, whether they're refined or not; our re-declarations of helpers,
|
73
|
+
# below, will override any of these. We need to grab all built-in Rails helpers because we want them all
|
74
|
+
# formally declared -- that is, even if +automatic_helper_access+ is set to +false+, built-in Rails helpers
|
75
|
+
# should still work properly.
|
76
|
+
declare_all_builtin_rails_helpers!
|
77
|
+
|
21
78
|
# tags/
|
22
79
|
# active_model_helper
|
23
80
|
# asset_tag_helper
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'fortitude/rendering_context'
|
2
2
|
require 'fortitude/rails/fortitude_rails_helpers'
|
3
|
+
require 'fortitude/support/method_overriding'
|
4
|
+
require 'thread'
|
3
5
|
|
4
6
|
if defined?(ActiveSupport)
|
5
7
|
ActiveSupport.on_load(:before_initialize) do
|
@@ -23,6 +25,33 @@ end
|
|
23
25
|
module Fortitude
|
24
26
|
module Rails
|
25
27
|
class Railtie < ::Rails::Railtie
|
28
|
+
class << self
|
29
|
+
def _fortitude_view_roots
|
30
|
+
@_fortitude_view_roots_mutex.synchronize do
|
31
|
+
raise "@_fortitude_view_roots has not yet been set" unless @_fortitude_view_roots
|
32
|
+
@_fortitude_view_roots
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def _fortitude_view_roots=(x)
|
37
|
+
@_fortitude_view_roots_mutex.synchronize do
|
38
|
+
if @_fortitude_view_roots_locked
|
39
|
+
raise "@_fortitude_view_roots was locked, and cannot be changed. It was locked at:\n #{@_fortitude_view_roots_locked}"
|
40
|
+
end
|
41
|
+
|
42
|
+
@_fortitude_view_roots = x
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def _lock_fortitude_view_roots!
|
47
|
+
@_fortitude_view_roots_mutex.synchronize do
|
48
|
+
@_fortitude_view_roots_locked ||= caller.join("\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@_fortitude_view_roots_mutex = Mutex.new
|
54
|
+
|
26
55
|
config.after_initialize do
|
27
56
|
if Fortitude.refine_rails_helpers
|
28
57
|
require 'fortitude/rails/helpers'
|
@@ -45,14 +74,14 @@ module Fortitude
|
|
45
74
|
# Why so hard?
|
46
75
|
#
|
47
76
|
# We're trying to do something that ActiveSupport::Dependencies -- which is what Rails uses for
|
48
|
-
# class autoloading -- doesn't really support. We want
|
77
|
+
# class autoloading -- doesn't really support. We want all view paths to be on the autoload path,
|
49
78
|
# because there are now Ruby classes living there. (It usually isn't just because all that's there
|
50
79
|
# are template source files, not actual Ruby code.) That isn't an issue, though -- adding it
|
51
80
|
# is trivial (just do
|
52
|
-
# <tt>ActiveSupport::Dependencies.autoload_paths
|
81
|
+
# <tt>ActiveSupport::Dependencies.autoload_paths += ::Rails.application.paths['app/views'].expanded</tt>).
|
53
82
|
#
|
54
|
-
# The real issue is that we want the class <tt>app/views/foo/bar.rb</tt> to define a class
|
55
|
-
# <tt>Views::Foo::Bar</tt>, not just plain <tt>Foo::Bar</tt>. This is what's different from what
|
83
|
+
# The real issue is that we want the class (<em>e.g.</em>) <tt>app/views/foo/bar.rb</tt> to define a class
|
84
|
+
# called <tt>Views::Foo::Bar</tt>, not just plain <tt>Foo::Bar</tt>. This is what's different from what
|
56
85
|
# ActiveSupport::Dependencies normally supports; it expects the filesystem path underneath the
|
57
86
|
# root to be exactly identical to the fully-qualified class name.
|
58
87
|
#
|
@@ -62,208 +91,260 @@ module Fortitude
|
|
62
91
|
# potential for conflicts is enormous.
|
63
92
|
#
|
64
93
|
# As such, we have this code. We'll walk through it step-by-step; note that at the end we *do*
|
65
|
-
# add
|
94
|
+
# add all view paths to the autoload path, so all this code is doing is just dealing with the fact that
|
66
95
|
# the fully-qualified classname (<tt>Views::Foo::Bar</tt>) has one extra component on the front of it
|
67
96
|
# (<tt>Views::</tt>) when compared to the subpath (<tt>foo/bar.rb</tt>) underneath what's on the autoload
|
68
97
|
# path (<tt>app/views</tt>).
|
69
98
|
|
70
|
-
# Go compute our
|
71
|
-
|
99
|
+
# Go compute our view roots.
|
100
|
+
#
|
101
|
+
# Rails 3.0.x doesn't define #expanded on ::Rails::Paths::Path; it also has a different way of getting at
|
102
|
+
# the view paths (<tt>::Rails.application.paths.app.views</tt>, rather than
|
103
|
+
# <tt>::Rails.application.paths['app/views']</tt>). So, if we're on Rails 3.0.x, we simply inline the
|
104
|
+
# equivalent code here.
|
105
|
+
view_roots = if ::Rails.version =~ /^3\.0\./
|
106
|
+
paths = ::Rails.application.paths.app.views
|
107
|
+
|
108
|
+
result = []
|
72
109
|
|
73
|
-
|
74
|
-
|
75
|
-
|
110
|
+
paths.each do |p|
|
111
|
+
root_path = p.instance_variable_get("@root")
|
112
|
+
root = if root_path then root_path.path else ::Rails.root end
|
113
|
+
glob = p.instance_variable_get("@glob")
|
76
114
|
|
77
|
-
|
78
|
-
@@_fortitude_views_root
|
79
|
-
end
|
115
|
+
path = File.expand_path(p, root)
|
80
116
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
#
|
85
|
-
# The original method says:
|
86
|
-
#
|
87
|
-
# "Does the provided path_suffix correspond to an autoloadable module?
|
88
|
-
# Instead of returning a boolean, the autoload base for this module is
|
89
|
-
# returned."
|
90
|
-
#
|
91
|
-
# So, we just need to strip off the leading +views/+ from the +path_suffix+,
|
92
|
-
# and see if that maps to a directory underneath <tt>app/views/</tt>; if so,
|
93
|
-
# we'll return the path to <tt>.../app/views/</tt>. Otherwise, we just
|
94
|
-
# delegate back to the superclass method.
|
95
|
-
def autoloadable_module_with_fortitude?(path_suffix)
|
96
|
-
if path_suffix =~ %r{^views(/.*)?$}i
|
97
|
-
# If we got here, then we were passed a subpath of views/....
|
98
|
-
subpath = $1
|
99
|
-
|
100
|
-
if subpath.blank? || File.directory?(File.join(@@_fortitude_views_root, subpath))
|
101
|
-
return @@_fortitude_views_root
|
117
|
+
if glob && File.directory?(path)
|
118
|
+
Dir.chdir(path) do
|
119
|
+
result.concat(Dir.glob(glob).map { |file| File.join path, file }.sort)
|
102
120
|
end
|
103
|
-
|
104
|
-
|
105
|
-
with_fortitude_views_removed_from_autoload_path do
|
106
|
-
autoloadable_module_without_fortitude?(path_suffix)
|
121
|
+
else
|
122
|
+
result << path
|
107
123
|
end
|
108
124
|
end
|
109
125
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
126
|
+
result.uniq!
|
127
|
+
result
|
128
|
+
else
|
129
|
+
::Rails.application.paths['app/views'].expanded
|
130
|
+
end
|
131
|
+
|
132
|
+
::Fortitude::Rails::Railtie._fortitude_view_roots = view_roots
|
133
|
+
|
134
|
+
module ActiveSupportDependenciesOverrides
|
135
|
+
class << self
|
136
|
+
# When we delegate back to original methods, we want them to act as if
|
137
|
+
# all view roots are _not_ on the autoload path. In order to be thread-safe
|
138
|
+
# about that, we couple this method with our override of the writer side of the
|
139
|
+
# <tt>mattr_accessor :autoload_paths</tt>, which simply prefers the thread-local
|
140
|
+
# that we set to the actual underlying variable.
|
141
|
+
def with_fortitude_views_removed_from_autoload_path
|
142
|
+
begin
|
143
|
+
Thread.current[:_fortitude_autoload_paths_override] =
|
144
|
+
::ActiveSupport::Dependencies.autoload_paths -
|
145
|
+
::Fortitude::Rails::Railtie._fortitude_view_roots
|
146
|
+
|
147
|
+
yield
|
148
|
+
ensure
|
149
|
+
Thread.current[:_fortitude_autoload_paths_override] = nil
|
150
|
+
end
|
123
151
|
end
|
124
152
|
end
|
125
153
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
class_eval <<-EOS
|
130
|
-
def self.autoload_paths
|
131
|
-
Thread.current[:_fortitude_autoload_paths_override] || @@autoload_paths
|
154
|
+
module Common
|
155
|
+
def autoload_paths_uniwith_fortitude(original_method)
|
156
|
+
Thread.current[:_fortitude_autoload_paths_override] || original_method.call
|
132
157
|
end
|
133
|
-
EOS
|
134
158
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
#
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
159
|
+
# This is the method that gets called to auto-generate namespacing empty
|
160
|
+
# modules (_e.g._, the toplevel <tt>Views::</tt> module) for directories
|
161
|
+
# under an autoload path.
|
162
|
+
#
|
163
|
+
# The original method says:
|
164
|
+
#
|
165
|
+
# "Does the provided path_suffix correspond to an autoloadable module?
|
166
|
+
# Instead of returning a boolean, the autoload base for this module is
|
167
|
+
# returned."
|
168
|
+
#
|
169
|
+
# So, we just need to strip off the leading +views/+ from the +path_suffix+,
|
170
|
+
# and see if that maps to a directory underneath one of our view roots; if so,
|
171
|
+
# we'll return the path to that view root. Otherwise, we just
|
172
|
+
# delegate back to the superclass method.
|
173
|
+
def autoloadable_module_uniwith_fortitude?(original_method, path_suffix)
|
174
|
+
if path_suffix =~ %r{^(views)(/.*)?$}i
|
175
|
+
# If we got here, then we were passed a subpath of views/....
|
176
|
+
prefix = $1
|
177
|
+
subpath = $2
|
178
|
+
|
179
|
+
if subpath.blank?
|
180
|
+
::Fortitude::Rails::Railtie._fortitude_view_roots.each do |view_root|
|
181
|
+
return view_root if File.basename(view_root).strip.downcase == prefix.strip.downcase
|
182
|
+
end
|
183
|
+
else
|
184
|
+
::Fortitude::Rails::Railtie._fortitude_view_roots.each do |view_root|
|
185
|
+
return view_root if File.directory?(File.join(view_root, subpath))
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
ActiveSupportDependenciesOverrides.with_fortitude_views_removed_from_autoload_path do
|
191
|
+
original_method.call(path_suffix)
|
192
|
+
end
|
152
193
|
end
|
153
194
|
|
154
|
-
|
155
|
-
|
156
|
-
|
195
|
+
# The original method says:
|
196
|
+
#
|
197
|
+
# "Search for a file in autoload_paths matching the provided suffix."
|
198
|
+
#
|
199
|
+
# So, we just look to see if the given +path_suffix+ is specifying something like
|
200
|
+
# <tt>views/foo/bar</tt> or the fully-qualified version thereof; if so, we glue it together properly,
|
201
|
+
# removing the initial <tt>views/</tt> first. (Otherwise, the mechanism would expect
|
202
|
+
# <tt>Views::Foo::Bar</tt> to show up in <tt>app/views/views/foo/bar</tt> (yes, a double
|
203
|
+
# +views+), since <tt>app/views</tt> is on the autoload path.)
|
204
|
+
def search_for_file_uniwith_fortitude(original_method, path_suffix)
|
205
|
+
# Remove any ".rb" extension, if present...
|
206
|
+
new_path_suffix = path_suffix.sub(/(\.rb)?$/, "")
|
207
|
+
|
208
|
+
found_subpath = nil
|
209
|
+
if new_path_suffix =~ %r{^views(/.*)$}i
|
210
|
+
found_subpath = $1
|
211
|
+
else
|
212
|
+
::Fortitude::Rails::Railtie._fortitude_view_roots.each do |view_root|
|
213
|
+
if new_path_suffix =~ %r{^#{Regexp.escape(view_root)}(/.*)$}i
|
214
|
+
found_subpath = $1
|
215
|
+
break
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
157
219
|
|
158
|
-
if
|
159
|
-
|
220
|
+
if found_subpath
|
221
|
+
::Fortitude::Rails::Railtie._fortitude_view_roots.each do |view_root|
|
222
|
+
full_path = File.join(view_root, "#{found_subpath}")
|
223
|
+
directory = File.dirname(full_path)
|
160
224
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
225
|
+
if File.directory?(directory)
|
226
|
+
filename = File.basename(full_path)
|
227
|
+
|
228
|
+
regexp1 = /^_?#{Regexp.escape(filename)}\./
|
229
|
+
regexp2 = /\.rb$/i
|
230
|
+
applicable_entries = Dir.entries(directory).select do |entry|
|
231
|
+
((entry == filename) || (entry =~ regexp1 && entry =~ regexp2)) && File.file?(File.join(directory, entry))
|
232
|
+
end
|
233
|
+
|
234
|
+
return nil if applicable_entries.length == 0
|
167
235
|
|
168
|
-
|
169
|
-
|
170
|
-
|
236
|
+
# Prefer those without an underscore
|
237
|
+
without_underscore = applicable_entries.select { |e| e !~ /^_/ }
|
238
|
+
applicable_entries = without_underscore if without_underscore.length > 0
|
171
239
|
|
172
|
-
|
173
|
-
|
240
|
+
entry_to_use = applicable_entries.sort_by { |e| e.length }.reverse.first
|
241
|
+
return File.join(directory, entry_to_use)
|
242
|
+
end
|
243
|
+
end
|
174
244
|
end
|
175
|
-
end
|
176
245
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
246
|
+
# Make sure that we remove the views autoload path before letting the rest of
|
247
|
+
# the dependency mechanism go searching for files, or else <tt>app/views/foo/bar.rb</tt>
|
248
|
+
# *will* be found when looking for just <tt>::Foo::Bar</tt>.
|
249
|
+
ActiveSupportDependenciesOverrides.with_fortitude_views_removed_from_autoload_path do
|
250
|
+
original_method.call(path_suffix)
|
251
|
+
end
|
252
|
+
end
|
181
253
|
end
|
182
|
-
|
183
|
-
alias_method_chain :search_for_file, :fortitude
|
184
254
|
end
|
185
255
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
256
|
+
::Fortitude::MethodOverriding.override_methods(
|
257
|
+
::ActiveSupport::Dependencies, ActiveSupportDependenciesOverrides::Common, :fortitude,
|
258
|
+
[ :search_for_file, :autoloadable_module?, :autoload_paths ])
|
259
|
+
|
260
|
+
eigenclass = ::ActiveSupport::Dependencies.module_eval "class << self; self; end"
|
261
|
+
::Fortitude::MethodOverriding.override_methods(
|
262
|
+
eigenclass, ActiveSupportDependenciesOverrides::Common, :fortitude,
|
263
|
+
[ :autoload_paths ])
|
264
|
+
|
265
|
+
module RailsEngineOverrides
|
266
|
+
# Two important comments here:
|
267
|
+
#
|
268
|
+
# 1: We also need to patch ::Rails::Engine.eager_load! so that it loads classes under all view roots. However, we
|
269
|
+
# can't just add them to the normal eager load paths, because that will allow people to do "require 'foo/bar'"
|
270
|
+
# and have it match app/views/foo/bar.rb, which we don't want. So, instead, we load these classes ourselves.
|
271
|
+
# Note that we ALSO have to do things slightly differently than Rails does it, because we need to skip loading
|
272
|
+
# 'foo.rb' if 'foo.html.rb' exists -- and because we have to require the fully-qualified pathname, since
|
273
|
+
# app/views is not actually on the load path.
|
274
|
+
#
|
275
|
+
# 2: I (ageweke) added this very late in the path of Fortitude development, after trying to use Fortitude in a
|
276
|
+
# deployment (production) environment in which widgets just weren't getting loaded at all. Yet there's something
|
277
|
+
# I don't understand: clearly, without this code, widgets will not be eager-loaded (which is probably not a
|
278
|
+
# great thing for performance reasons)...but I think they still should get auto-loaded and hence actually work
|
279
|
+
# just fine. But they don't in that environment (you'll get errors like "uninitialized constant Views::Base").
|
280
|
+
# Since I understand what's going on and have the fix for it here, that's fine...except that I can't seem to
|
281
|
+
# write a spec for it, because I don't know how to actually *make* it fail. If anybody comes along later and
|
282
|
+
# knows what would make it fail (and I double-checked, and we don't have autoloading disabled in production or
|
283
|
+
# anything like that), let me know, so that I can write a spec for this. Thanks!
|
284
|
+
def eager_load_uniwith_fortitude!(original_method)
|
285
|
+
original_method.call
|
207
286
|
eager_load_fortitude_views!
|
208
287
|
end
|
209
288
|
|
210
289
|
def eager_load_fortitude_views!
|
211
|
-
|
212
|
-
|
213
|
-
|
290
|
+
::Fortitude::Rails::Railtie._fortitude_view_roots.each do |load_path|
|
291
|
+
all_files = Dir.glob("#{load_path}/**/*.rb")
|
292
|
+
matcher = /\A#{Regexp.escape(load_path.to_s)}\/(.*)\.rb\Z/
|
214
293
|
|
215
|
-
|
216
|
-
|
217
|
-
|
294
|
+
all_files.sort.each do |full_path|
|
295
|
+
filename = File.basename(full_path, ".rb")
|
296
|
+
directory = File.dirname(full_path)
|
218
297
|
|
219
|
-
|
220
|
-
|
298
|
+
longer_name_regex = /^#{Regexp.escape(filename)}\..+\.rb$/i
|
299
|
+
longer_name = Dir.entries(directory).detect { |e| e =~ longer_name_regex }
|
221
300
|
|
222
|
-
|
223
|
-
|
301
|
+
unless longer_name
|
302
|
+
require_dependency File.join('views', full_path.sub(matcher, '\1'))
|
303
|
+
end
|
224
304
|
end
|
225
305
|
end
|
226
306
|
end
|
227
|
-
|
228
|
-
alias_method_chain :eager_load!, :fortitude
|
229
307
|
end
|
230
308
|
|
231
|
-
|
232
|
-
|
233
|
-
# app.config.eager_load_paths << views_root
|
309
|
+
::Fortitude::MethodOverriding.override_methods(
|
310
|
+
::Rails::Engine, RailsEngineOverrides, :fortitude, [ :eager_load! ])
|
234
311
|
|
235
|
-
#
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
312
|
+
# And, finally, this is where we add our view roots to the set of autoload paths.
|
313
|
+
::ActiveSupport::Dependencies.autoload_paths += view_roots
|
314
|
+
|
315
|
+
module ActionViewPathResolverOverrides
|
316
|
+
# This is our support for partials. Fortitude doesn't really have a distinction between
|
317
|
+
# partials and "full" templates -- everything is just a widget, which is much more elegant --
|
318
|
+
# but we still want you to be able to render a widget <tt>Views::Foo::Bar</tt> by saying
|
319
|
+
# <tt>render :partial => 'foo/bar'</tt> (from ERb, although you can do it from Fortitude if
|
320
|
+
# you want for some reason, too).
|
321
|
+
#
|
322
|
+
# Normally, ActionView only looks for partials in files starting with an underscore. We
|
323
|
+
# do want to allow this, too (in the above case, if you define the widget in the file
|
324
|
+
# <tt>app/views/foo/_bar.rb</tt>, it will still work fine); however, we also want to allow
|
325
|
+
# you to define it in a file that does _not_ start with an underscore ('cause these are
|
326
|
+
# Ruby classes, and that's just plain weird).
|
327
|
+
#
|
328
|
+
# So, we patch #find_templates: if it's looking for a partial, doesn't find one, and is
|
329
|
+
# searching Fortitude templates (the +.rb+ handler), then we try again, turning off the
|
330
|
+
# +partial+ flag, and return that instead.
|
331
|
+
def find_templates_uniwith_fortitude(original_method, name, prefix, partial, details, *args)
|
332
|
+
templates = original_method.call(name, prefix, partial, details, *args)
|
253
333
|
if partial && templates.empty? && details[:handlers] && details[:handlers].include?(:rb)
|
254
|
-
templates =
|
334
|
+
templates = original_method.call(name, prefix, false, details.merge(:handlers => [ :rb ]), *args)
|
255
335
|
end
|
256
336
|
templates
|
257
337
|
end
|
258
|
-
|
259
|
-
alias_method_chain :find_templates, :fortitude
|
260
338
|
end
|
261
339
|
|
340
|
+
::Fortitude::MethodOverriding.override_methods(
|
341
|
+
::ActionView::PathResolver, ActionViewPathResolverOverrides, :fortitude, [ :find_templates ])
|
342
|
+
|
262
343
|
require "fortitude/rails/template_handler"
|
263
344
|
require "fortitude/rails/rendering_methods"
|
264
345
|
|
265
|
-
::
|
266
|
-
::
|
346
|
+
::Fortitude::Rails::RenderingMethods.include_into!(::ActionController::Base)
|
347
|
+
::Fortitude::Rails::RenderingMethods.include_into!(::ActionMailer::Base)
|
267
348
|
end
|
268
349
|
end
|
269
350
|
end
|