fortitude 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +19 -19
  3. data/CHANGES.md +31 -0
  4. data/Gemfile +1 -0
  5. data/README-erector.md +1 -1
  6. data/lib/fortitude/erector.rb +32 -0
  7. data/lib/fortitude/method_templates/tag_method_template.rb.smpl +6 -6
  8. data/lib/fortitude/method_templates/text_method_template.rb.smpl +3 -3
  9. data/lib/fortitude/rails/railtie.rb +6 -4
  10. data/lib/fortitude/rails/renderer.rb +7 -4
  11. data/lib/fortitude/rails/template_handler.rb +18 -3
  12. data/lib/fortitude/rendering_context.rb +20 -2
  13. data/lib/fortitude/tags/render_widget_placeholder.rb +19 -0
  14. data/lib/fortitude/tags/tag.rb +18 -4
  15. data/lib/fortitude/tags/tag_return_value.rb +1 -1
  16. data/lib/fortitude/tags/tag_store.rb +4 -0
  17. data/lib/fortitude/tilt/fortitude_template.rb +6 -128
  18. data/lib/fortitude/version.rb +1 -1
  19. data/lib/fortitude/widget.rb +2 -0
  20. data/lib/fortitude/widget/files.rb +162 -0
  21. data/lib/fortitude/widget/integration.rb +5 -3
  22. data/lib/fortitude/widget/modules_and_subclasses.rb +17 -0
  23. data/lib/fortitude/widget/rendering.rb +12 -5
  24. data/lib/fortitude/widget/start_and_end_comments.rb +4 -2
  25. data/lib/fortitude/widget/tags.rb +6 -1
  26. data/lib/fortitude/widget/widget_class_inheritable_attributes.rb +7 -0
  27. data/spec/helpers/rails_server.rb +4 -0
  28. data/spec/rails/basic_rails_system_spec.rb +4 -0
  29. data/spec/rails/erector_coexistence_system_spec.rb +33 -0
  30. data/spec/rails/rendering_context_system_spec.rb +19 -3
  31. data/spec/rails/rendering_system_spec.rb +6 -0
  32. data/spec/rails/templates/basic_rails_system_spec/app/controllers/basic_rails_system_spec_controller.rb +5 -0
  33. data/spec/rails/templates/basic_rails_system_spec/app/views/basic_rails_system_spec/double_render_one.rb +5 -0
  34. data/spec/rails/templates/basic_rails_system_spec/app/views/basic_rails_system_spec/double_render_three.rb +5 -0
  35. data/spec/rails/templates/basic_rails_system_spec/app/views/basic_rails_system_spec/double_render_two.rb +9 -0
  36. data/spec/rails/templates/erector_coexistence_system_spec/app/controllers/erector_coexistence_system_spec_controller.rb +19 -0
  37. data/spec/rails/templates/erector_coexistence_system_spec/app/v/views/erector_coexistence_system_spec/erector_widget_in_app_v_views.rb +7 -0
  38. data/spec/rails/templates/erector_coexistence_system_spec/app/v/views/erector_coexistence_system_spec/fortitude_widget_in_app_v_views.rb +7 -0
  39. data/spec/rails/templates/erector_coexistence_system_spec/app/views/erector_coexistence_system_spec/erector_widget_in_app_views.rb +7 -0
  40. data/spec/rails/templates/erector_coexistence_system_spec/app/views/erector_coexistence_system_spec/fortitude_widget_in_app_views.rb +7 -0
  41. data/spec/rails/templates/erector_coexistence_system_spec/config/application.rb +25 -0
  42. data/spec/rails/templates/rendering_context_system_spec/app/controllers/rendering_context_system_spec_controller.rb +2 -2
  43. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/_current_element_nesting_intermediate.html.erb +3 -0
  44. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/current_element_nesting_child.rb +13 -0
  45. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/current_element_nesting_toplevel.rb +9 -0
  46. data/spec/rails/templates/rendering_context_system_spec/app/views/rendering_context_system_spec/start_end_widget_through_partials.rb +2 -2
  47. data/spec/system/convenience_methods_system_spec.rb +22 -0
  48. data/spec/system/inline_system_spec.rb +2 -2
  49. data/spec/system/record_tag_emission_system_spec.rb +71 -0
  50. data/spec/system/rendering_context_system_spec.rb +21 -0
  51. data/spec/system/setting_inheritance_system_spec.rb +52 -0
  52. data/spec/system/tag_return_value_system_spec.rb +7 -0
  53. data/spec/system/tilt_system_spec.rb +13 -18
  54. data/spec/system/widget_class_from_spec.rb +240 -0
  55. data/spec/system/widget_method_system_spec.rb +52 -0
  56. metadata +37 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25c2a3082f9eea925e6db1ad349f3d9ec45a9760
4
- data.tar.gz: 4a95b0676e6b63b98ca69148bedc517b98b4955f
3
+ metadata.gz: b8fe2be7aaffdb2b3e57d0b26fdacbc2c1124a57
4
+ data.tar.gz: 01ada85328794df979d33ccff7a2ea41f88425f3
5
5
  SHA512:
6
- metadata.gz: 88825dbca457537fb59373f3d345e119cd4b26d099befb5b56cea5885bf912161ff589775504657423e6b82b4852d7fead44df625af14bd226089dd644944ca2
7
- data.tar.gz: 8bca6d9fa509fa98cc8abe0c630a790f9ff2f7b98544096e147aa986367332a08408b6d252533f7894552d24963f76b8d4e83898bf42f91d098035ef4653c28a
6
+ metadata.gz: 7394aeae5282f4109dbbe772a882ae066043a253813fc63b6b4e0d1ebdabb31de3e998a66969c347b37262c3a3365af2d6a1bf084e15ed9a8f9a6afa9c672ff5
7
+ data.tar.gz: 58b2ad3cdddd71f0120f9039ab9112ecaa4fc542c2104e98565341898e36c6b247dd7c60c07f39cee47d4fb5c47f95f11b0d27bbb75a605050c41fe47d38bd51
@@ -3,14 +3,14 @@ rvm:
3
3
  - "1.9.3"
4
4
  - "2.0.0"
5
5
  - "2.1.2"
6
- - "jruby-1.7.12"
6
+ - "jruby-1.7.15"
7
7
  env:
8
- - FORTITUDE_SPECS_RAILS_VERSION=4.1.1
9
- - FORTITUDE_SPECS_RAILS_VERSION=4.0.5
10
- - FORTITUDE_SPECS_RAILS_VERSION=3.2.18
8
+ - FORTITUDE_SPECS_RAILS_VERSION=4.1.6
9
+ - FORTITUDE_SPECS_RAILS_VERSION=4.0.10
10
+ - FORTITUDE_SPECS_RAILS_VERSION=3.2.19
11
11
  - FORTITUDE_SPECS_RAILS_VERSION=3.1.12
12
12
  - FORTITUDE_SPECS_RAILS_VERSION=3.0.20
13
- - FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=4.1.1
13
+ - FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=4.1.6
14
14
  - FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=3.0.20
15
15
  before_script:
16
16
  - export JRUBY_OPTS="$JRUBY_OPTS -J-Xmx128m -J-Xms128m -J-Xss2048k"
@@ -18,11 +18,11 @@ matrix:
18
18
  exclude:
19
19
  # Rails 4.x doesn't support Ruby 1.8.7
20
20
  - rvm: 1.8.7
21
- env: FORTITUDE_SPECS_RAILS_VERSION=4.1.1
21
+ env: FORTITUDE_SPECS_RAILS_VERSION=4.1.6
22
22
  - rvm: 1.8.7
23
- env: FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=4.1.1
23
+ env: FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=4.1.6
24
24
  - rvm: 1.8.7
25
- env: FORTITUDE_SPECS_RAILS_VERSION=4.0.5
25
+ env: FORTITUDE_SPECS_RAILS_VERSION=4.0.10
26
26
  # 2014-06-19 ageweke -- ARGH. After trying about seventeen different things, no matter what I do,
27
27
  # Travis fails JRuby builds about 20% of the time with "Killed". Their documentation indicates that this
28
28
  # is likely an out-of-memory issue (i.e., entire VM's memory is consumed). However, I'm running JRuby with
@@ -34,17 +34,17 @@ matrix:
34
34
  # one manually to make sure there aren't other failures, too. This is very frustrating, but I can't seem to
35
35
  # find a way around it. If there's a fix out there somewhere, I'm all ears!
36
36
  allow_failures:
37
- - rvm: jruby-1.7.12
38
- env: FORTITUDE_SPECS_RAILS_VERSION=4.1.1
39
- - rvm: jruby-1.7.12
40
- env: FORTITUDE_SPECS_RAILS_VERSION=4.0.5
41
- - rvm: jruby-1.7.12
42
- env: FORTITUDE_SPECS_RAILS_VERSION=3.2.18
43
- - rvm: jruby-1.7.12
37
+ - rvm: jruby-1.7.15
38
+ env: FORTITUDE_SPECS_RAILS_VERSION=4.1.6
39
+ - rvm: jruby-1.7.15
40
+ env: FORTITUDE_SPECS_RAILS_VERSION=4.0.10
41
+ - rvm: jruby-1.7.15
42
+ env: FORTITUDE_SPECS_RAILS_VERSION=3.2.19
43
+ - rvm: jruby-1.7.15
44
44
  env: FORTITUDE_SPECS_RAILS_VERSION=3.1.12
45
- - rvm: jruby-1.7.12
45
+ - rvm: jruby-1.7.15
46
46
  env: FORTITUDE_SPECS_RAILS_VERSION=3.0.20
47
- - rvm: jruby-1.7.12
48
- env: FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=4.1.1
49
- - rvm: jruby-1.7.12
47
+ - rvm: jruby-1.7.15
48
+ env: FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=4.1.6
49
+ - rvm: jruby-1.7.15
50
50
  env: FORTITUDE_NATIVE_EXTENSIONS=false FORTITUDE_SPECS_RAILS_VERSION=3.0.20
data/CHANGES.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Fortitude Releases
2
2
 
3
+ ## 0.0.5, 22 September 2014
4
+
5
+ * You can now load both Fortitude and Erector at the same time into a project, and it will "just work": Erector
6
+ widgets will render using Erector, and Fortitude widgets will render using Fortitude. (Fortitude takes over the
7
+ actual template engine registration for `.rb` files, and uses a trick to keep Erector from displacing it; it then
8
+ looks at the widget class being rendered, and delegates all Erector rendering directly to Erector.)
9
+ * When inside a widget, you can now render a sub-widget using `widget MyWidget.new(...)` — _i.e._, passing an
10
+ actual widget instance — or using `widget MyWidget, { :param1 => value1 }` — _i.e._, passing a widget
11
+ class and a `Hash` of assignments (which can be omitted if the widget doesn't have any `need`s).
12
+ * Fixed an issue where, _e.g._, calling `#render_to_string` on a Fortitude widget within a Rails controller, and then
13
+ also rendering a Fortitude widget as the template for that action, would cause a method to be called on `nil`.
14
+ * Added `Fortitude::RenderingContext#parent_widget`, which returns the parent widget of the current widget during
15
+ rendering at runtime. (In other words, this is not the superclass of the current widget, but the widget that caused
16
+ this widget to get rendered, using either `Fortitude::Widget#widget` or `render :partial => ...`.) This can, of
17
+ course, be `nil` if there is no current parent widget.
18
+ * Added `Fortitude::Widget.all_fortitude_superclasses`, which returns an `Array` of all superclasses of a widget up to,
19
+ but not including, `Fortitude::Widget` itself.
20
+ * Added `Fortitude::Widget.widget_class_from_file`, which accepts the path to a file and an array of "root" directories
21
+ to look under (_i.e._, assuming you're using something like Rails' autoloading mechanism), and returns the `Class`
22
+ object for the widget that's contained in that file. This uses a series of mechansims to try to detect the class
23
+ that's present in the file: a "magic comment" that can be present in the file, an array of class names to try
24
+ that you can pass in, the position of the class in the file hierarchy, and scanning the source text itself.
25
+ * Added a `record_tag_emission` class-level setting that tells a widget to call `#emitting_tag!` on the
26
+ `Fortitude::RenderingContext` when emitting a tag; you can use this to build various systems that need to know where
27
+ in the hierarchy of tags we are at the moment.
28
+ * The object being returned from Fortitude tag methods — which, in general, you should never use — now
29
+ inherits from `Object`, not `BasicObject`, so that some built-in methods like `#is_a?` can be safely called on it.
30
+ This is for use in some users' environments doing funny things with the Ruby runtime that end up calling methods
31
+ like that on the return values of widget `#content` methods, which very often just end up being the tag return
32
+ value object.
33
+
3
34
  ## 0.0.4, 24 June 2014
4
35
 
5
36
  * Added support for building a JRuby-specific gem to the gemspec, so that things work smoothly for JRuby users.
data/Gemfile CHANGED
@@ -3,3 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in fortitude.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'erector'
@@ -18,7 +18,7 @@ garbage as ERb/Erubis);
18
18
  * Full, complete native HTML5 support (with selectable X/HTML4.01 Strict/Transitional/Frameset doctypes);
19
19
  * Enforces HTML element-nesting and attribute-name rules, and enforce ID uniqueness across a page (configurable, and off by default);
20
20
  * In development, beautiful HTML comments around each widget, showing what class is being rendered, the values of all variables supplied to that class, and the nesting depth of that widget;
21
- * Fully compatible with Ruby 1.8.7-2.1.x, JRuby 1.7.11, and Rails 3.0.x-4.1.x;
21
+ * Fully compatible with Ruby 1.8.7-2.1.x, JRuby 1.7.15, and Rails 3.0.x-4.1.x;
22
22
  * Full Tilt support, and can be used with or without Rails;
23
23
  * Much more thorough Rails support — all known Rails integration points have been resolved, and it should work
24
24
  as smoothly with Rails as does (_e.g._) ERb/Erubis;
@@ -0,0 +1,32 @@
1
+ module Fortitude
2
+ module Erector
3
+ class << self
4
+ def is_erector_available?
5
+ @is_erector_available ||= begin
6
+ begin
7
+ gem 'erector'
8
+ rescue Gem::LoadError => le
9
+ # ok
10
+ end
11
+
12
+ begin
13
+ require 'erector'
14
+ rescue LoadError => le
15
+ # ok
16
+ end
17
+
18
+ if defined?(::Erector::Widget) then :yes else :no end
19
+ end
20
+
21
+ @is_erector_available == :yes
22
+ end
23
+
24
+ def is_erector_widget_class?(widget_class)
25
+ return false unless is_erector_available?
26
+ return true if widget_class == ::Erector::Widget
27
+ return false if widget_class == ::Object
28
+ return is_erector_widget_class?(widget_class.superclass)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,9 +1,9 @@
1
1
  def #{method_name}(content_or_attributes = nil, attributes = nil)
2
2
  o = @_fortitude_output_buffer_holder.output_buffer
3
- rc = @_fortitude_rendering_context # :if needs_element_rules || needs_formatting
3
+ rc = @_fortitude_rendering_context # :if record_emitting_tag || needs_formatting
4
4
 
5
- this_tag = #{tag_object_const} # :if needs_element_rules || needs_attribute_rules || needs_id_uniqueness
6
- rc.record_tag(self, this_tag) do # :if needs_element_rules
5
+ this_tag = #{tag_object_const} # :if record_emitting_tag || needs_attribute_rules || needs_id_uniqueness
6
+ rc.emitting_tag!(self, this_tag, content_or_attributes, attributes) do # :if record_emitting_tag
7
7
  format_output = rc.format_output? # :if needs_formatting
8
8
  if format_output # :if needs_formatting
9
9
  rc.needs_newline! # :if needs_formatting && newline_before
@@ -36,7 +36,7 @@ def #{method_name}(content_or_attributes = nil, attributes = nil)
36
36
  elsif (! attributes)
37
37
  _fortitude_raise_no_content_allowed_error(#{tag_object_const}) # :if ! content_allowed
38
38
  o.#{concat_method}(#{open_const})
39
- rc.record_tag(self, FORTITUDE_TEXT_PSEUDOTAG) { } unless content_or_attributes.instance_variable_get("@html_safe") # :if needs_element_rules
39
+ rc.emitting_tag!(self, FORTITUDE_TEXT_PSEUDOTAG, content_or_attributes, nil) { } unless content_or_attributes.instance_variable_get("@html_safe") # :if record_emitting_tag
40
40
  content_or_attributes.to_s.fortitude_append_escaped_string(o) # :if escape_direct_content
41
41
  o.#{concat_method}(content_or_attributes.to_s) # :if ! escape_direct_content
42
42
  if block_given?
@@ -52,7 +52,7 @@ def #{method_name}(content_or_attributes = nil, attributes = nil)
52
52
  attributes.fortitude_append_as_attributes(o, nil)
53
53
  o.#{concat_method}(#{partial_open_end_const})
54
54
 
55
- rc.record_tag(self, FORTITUDE_TEXT_PSEUDOTAG) { } unless content_or_attributes.instance_variable_get("@html_safe") # :if needs_element_rules
55
+ rc.emitting_tag!(self, FORTITUDE_TEXT_PSEUDOTAG, content_or_attributes, nil) { } unless content_or_attributes.instance_variable_get("@html_safe") # :if record_emitting_tag
56
56
  content_or_attributes.to_s.fortitude_append_escaped_string(o) # :if escape_direct_content
57
57
  o.#{concat_method}(content_or_attributes.to_s) # :if ! escape_direct_content
58
58
  if block_given?
@@ -62,7 +62,7 @@ def #{method_name}(content_or_attributes = nil, attributes = nil)
62
62
  o.#{concat_method}(#{close_const})
63
63
  end
64
64
  rc.needs_newline! if format_output # :if needs_formatting && newline_before
65
- end # :if needs_element_rules
65
+ end # :if record_emitting_tag
66
66
 
67
67
  FORTITUDE_NO_RETURN_VALUE_FROM_TAGS
68
68
  end
@@ -1,9 +1,9 @@
1
1
  def tag_text(s)
2
2
  @_fortitude_rendering_context.about_to_output_non_whitespace! # :if format_output
3
3
 
4
- unless s.instance_variable_get("@html_safe") # :if needs_element_rules
5
- @_fortitude_rendering_context.record_tag(self, FORTITUDE_TEXT_PSEUDOTAG) { } # :if needs_element_rules
6
- end # :if needs_element_rules
4
+ unless s.instance_variable_get("@html_safe") # :if record_emitting_tag
5
+ @_fortitude_rendering_context.emitting_tag!(self, FORTITUDE_TEXT_PSEUDOTAG, s, nil) { } # :if record_emitting_tag
6
+ end # :if record_emitting_tag
7
7
 
8
8
  s.to_s.fortitude_append_escaped_string(@_fortitude_output_buffer_holder.output_buffer)
9
9
  end
@@ -197,8 +197,10 @@ module Fortitude
197
197
  # So, instead, we simply transform <tt>render :widget => ...</tt> into a <tt>render :text => ...</tt> of the
198
198
  # widget's output, and let Rails take it away from there.
199
199
  ::ActionController::Base.class_eval do
200
- def fortitude_rendering_context(options)
201
- @_fortitude_rendering_context ||= create_fortitude_rendering_context(options)
200
+ def fortitude_rendering_context_for(delegate_object, yield_block)
201
+ @_fortitude_rendering_contexts ||= { }
202
+ @_fortitude_rendering_contexts[delegate_object.object_id] ||= create_fortitude_rendering_context(
203
+ :delegate_object => delegate_object, :yield_block => yield_block)
202
204
  end
203
205
 
204
206
  def create_fortitude_rendering_context(options)
@@ -208,7 +210,7 @@ module Fortitude
208
210
  def render_with_fortitude(*args, &block)
209
211
  if (options = args[0]).kind_of?(Hash)
210
212
  if (widget = options[:widget])
211
- rendering_context = fortitude_rendering_context(:delegate_object => self)
213
+ rendering_context = fortitude_rendering_context_for(self, nil)
212
214
  widget.render_to(rendering_context)
213
215
 
214
216
  options = options.dup
@@ -220,7 +222,7 @@ module Fortitude
220
222
  elsif (widget_block = options[:inline]) && (options[:type] == :fortitude)
221
223
  options.delete(:inline)
222
224
 
223
- rendering_context = fortitude_rendering_context(:delegate_object => self)
225
+ rendering_context = fortitude_rendering_context_for(self, nil)
224
226
  widget_class = Class.new(Fortitude::Widgets::Html5)
225
227
  widget_class.use_instance_variables_for_assigns(true)
226
228
  widget_class.extra_assigns(:use)
@@ -1,4 +1,5 @@
1
1
  require 'fortitude/rendering_context'
2
+ require 'fortitude/erector'
2
3
 
3
4
  ::ActiveSupport::SafeBuffer.class_eval do
4
5
  alias_method :fortitude_concat, :original_concat
@@ -10,7 +11,11 @@ module Fortitude
10
11
  class Renderer
11
12
  class << self
12
13
  # TODO: Refactor this and render :widget => ... support into one method somewhere.
13
- def render(widget_class, template_handler, local_assigns, &block)
14
+ def render(widget_class, template_handler, local_assigns, is_partial, &block)
15
+ if ::Fortitude::Erector.is_erector_widget_class?(widget_class)
16
+ return ::Erector::Rails.render(widget_class, template_handler, local_assigns, is_partial, &block)
17
+ end
18
+
14
19
  total_assigns = template_handler.assigns.symbolize_keys.merge(local_assigns.symbolize_keys)
15
20
 
16
21
  needed_assigns = if widget_class.extra_assigns == :use
@@ -21,9 +26,7 @@ module Fortitude
21
26
 
22
27
  widget = widget_class.new(needed_assigns)
23
28
  template_handler.with_output_buffer do
24
- rendering_context_options = { :delegate_object => template_handler, :yield_block => block }
25
- controller = template_handler.controller
26
- rendering_context = controller.fortitude_rendering_context(rendering_context_options)
29
+ rendering_context = template_handler.controller.fortitude_rendering_context_for(template_handler, block)
27
30
 
28
31
  # TODO: Refactor this -- both passing it into the constructor and setting yield_block here is gross.
29
32
  #
@@ -6,10 +6,10 @@ module Fortitude
6
6
  def call(template, &block)
7
7
  require_dependency template.identifier
8
8
  widget_class_name = "views/#{template.identifier =~ %r(views/([^.]*)(\..*)?\.rb) && $1}".camelize
9
- is_partial = File.basename(template.identifier) =~ /^_/
9
+ is_partial = !! (File.basename(template.identifier) =~ /^_/)
10
10
 
11
11
  <<-SRC
12
- Fortitude::Rails::Renderer.render(#{widget_class_name}, self, local_assigns) { |*args| yield *args }
12
+ Fortitude::Rails::Renderer.render(#{widget_class_name}, self, local_assigns, #{is_partial.inspect}) { |*args| yield *args }
13
13
  SRC
14
14
  end
15
15
 
@@ -20,4 +20,19 @@ module Fortitude
20
20
  end
21
21
  end
22
22
 
23
- ActionView::Template.register_template_handler :rb, Fortitude::Rails::TemplateHandler.new
23
+ ::ActionView::Template.class_eval do
24
+ class << self
25
+ def _fortitude_register_template_handler!
26
+ register_template_handler_without_fortitude(:rb, Fortitude::Rails::TemplateHandler.new)
27
+ end
28
+
29
+ def register_template_handler_with_fortitude(*args, &block)
30
+ register_template_handler_without_fortitude(*args, &block)
31
+ ActionView::Template._fortitude_register_template_handler!
32
+ end
33
+
34
+ alias_method_chain :register_template_handler, :fortitude
35
+ end
36
+ end
37
+
38
+ ActionView::Template._fortitude_register_template_handler!
@@ -1,4 +1,5 @@
1
1
  require 'fortitude/support/instance_variable_set'
2
+ require 'fortitude/tags/render_widget_placeholder'
2
3
 
3
4
  module Fortitude
4
5
  class RenderingContext
@@ -66,9 +67,14 @@ module Fortitude
66
67
  !! @attribute_validation_disabled
67
68
  end
68
69
 
70
+ def record_render(args, &block)
71
+ record_widget(::Fortitude::Tags::RenderWidgetPlaceholder.new(args), &block)
72
+ end
73
+
69
74
  def record_widget(widget)
70
75
  start_widget!(widget)
71
76
  @current_widget_nesting << widget
77
+ @current_element_nesting << widget
72
78
  begin
73
79
  yield
74
80
  ensure
@@ -76,6 +82,10 @@ module Fortitude
76
82
  unless last.equal?(widget)
77
83
  raise "Something horrible happened -- the last widget we started was #{last}, but now we're ending #{widget}?!?"
78
84
  end
85
+ last = @current_element_nesting.pop
86
+ unless last.equal?(widget)
87
+ raise "Something horrible happened -- the last element we started was #{last}, but now we're ending #{widget}?!?"
88
+ end
79
89
  end_widget!(widget)
80
90
  end
81
91
  end
@@ -92,8 +102,12 @@ module Fortitude
92
102
  @current_widget_nesting.length - 1
93
103
  end
94
104
 
95
- def record_tag(widget, tag_object)
96
- validate_element_for_rules(widget, tag_object)
105
+ def parent_widget
106
+ @current_widget_nesting[-2]
107
+ end
108
+
109
+ def emitting_tag!(widget, tag_object, content_or_attributes, attributes)
110
+ validate_element_for_rules(widget, tag_object) if widget.class.enforce_element_nesting_rules
97
111
  @current_element_nesting << tag_object
98
112
 
99
113
  begin
@@ -106,6 +120,10 @@ module Fortitude
106
120
  end
107
121
  end
108
122
 
123
+ def current_element_nesting
124
+ @current_element_nesting
125
+ end
126
+
109
127
  def format_output?
110
128
  true
111
129
  end
@@ -0,0 +1,19 @@
1
+ module Fortitude
2
+ module Tags
3
+ class RenderWidgetPlaceholder
4
+ attr_reader :render_args
5
+
6
+ def initialize(render_args)
7
+ @render_args = render_args
8
+ end
9
+
10
+ def name
11
+ :_fortitude_render_widget_placeholder
12
+ end
13
+
14
+ def validate_can_enclose!(widget, tag_object)
15
+ # nothing here, always OK
16
+ end
17
+ end
18
+ end
19
+ end
@@ -116,7 +116,9 @@ module Fortitude
116
116
  end
117
117
 
118
118
  def define_method_on!(mod, options = {})
119
- options.assert_valid_keys(:enforce_element_nesting_rules, :enforce_attribute_rules, :enable_formatting, :enforce_id_uniqueness, :close_void_tags)
119
+ options.assert_valid_keys(
120
+ :record_emitting_tag, :enforce_attribute_rules, :enable_formatting,
121
+ :enforce_id_uniqueness, :close_void_tags)
120
122
 
121
123
  unless mod.respond_to?(:fortitude_tag_support_included?) && mod.fortitude_tag_support_included?
122
124
  mod.send(:include, ::Fortitude::Tags::TagSupport)
@@ -147,8 +149,8 @@ module Fortitude
147
149
  end
148
150
 
149
151
  text = Fortitude::MethodTemplates::SimpleTemplate.template('tag_method_template').result(
150
- :name => name.to_s, :method_name => "tag_#{name}".to_s, :yield_call => yield_call, :concat_method => CONCAT_METHOD,
151
- :needs_element_rules => !! options[:enforce_element_nesting_rules],
152
+ :name => name.to_s, :method_name => generated_method_name.to_s, :yield_call => yield_call, :concat_method => CONCAT_METHOD,
153
+ :record_emitting_tag => (!! options[:record_emitting_tag]),
152
154
  :needs_attribute_rules => !! options[:enforce_attribute_rules],
153
155
  :needs_id_uniqueness => !! options[:enforce_id_uniqueness],
154
156
  :needs_formatting => needs_formatting, :content_allowed => @content_allowed,
@@ -160,7 +162,19 @@ module Fortitude
160
162
  :partial_open_alone_end_const => tag_constant_name(:PARTIAL_OPEN_ALONE_END))
161
163
 
162
164
  mod.module_eval(text)
163
- mod.alias_method(name, "tag_#{name}")
165
+ aliased_method_names.each { |an| mod.alias_method(an, generated_method_name) }
166
+ end
167
+
168
+ def generated_method_name
169
+ "tag_#{name}"
170
+ end
171
+
172
+ def aliased_method_names
173
+ [ name ]
174
+ end
175
+
176
+ def all_method_names
177
+ [ generated_method_name ] + aliased_method_names
164
178
  end
165
179
 
166
180
  private
@@ -2,7 +2,7 @@ require 'fortitude/errors'
2
2
 
3
3
  module Fortitude
4
4
  module Tags
5
- TAG_RETURN_VALUE_SUPERCLASS = if defined?(::BasicObject) then ::BasicObject else ::Object end
5
+ TAG_RETURN_VALUE_SUPERCLASS = ::Object
6
6
 
7
7
  class TagReturnValue < TAG_RETURN_VALUE_SUPERCLASS
8
8
  def method_missing(name, *args)
@@ -37,6 +37,10 @@ module Fortitude
37
37
  out
38
38
  end
39
39
 
40
+ def tag_names
41
+ tags.keys
42
+ end
43
+
40
44
  def tags_added!(tags)
41
45
  tags_changed!(tags)
42
46
  end