module Fortitude module Errors class Base < StandardError; end class MissingNeed < Base attr_reader :widget, :missing_needs, :assigns def initialize(widget, missing_needs, assigns) super(%{The widget #{widget} requires the following parameters to render, but they were not supplied: #{missing_needs.sort_by(&:to_s).join(", ")}}) @widget = widget @missing_needs = missing_needs @assigns = assigns end end class BlockPassedToNeedMethod < Base attr_reader :widget, :method_name def initialize(widget, method_name) super(%{You passed a block to a method that's a 'needs' method of a Fortitude widget, #{widget}. } + %{This can mean you've declared a 'need' with the same name as a Fortitude tag method (e.g., "needs :#{method_name}"), } + %{and think you're calling the method that will generate that tag, when you're actually calling a method } + %{that will ignore the block you passed and just return the value of that 'need'. If that is the case, try } + %{calling the tag with 'tag_' prefixed to it (e.g., 'tag_#{method_name}'), which does the same thing; if not, remove } + %{the block and try again.}) @widget = widget @method_name = method_name end end class ExtraAssigns < Base attr_reader :widget, :extra_assigns def initialize(widget, extra_assigns) super(%{The widget #{widget} does not accept the following parameters: #{extra_assigns.keys.sort_by(&:to_s).join(", ")}}) @widget = widget @extra_assigns = extra_assigns end end class InvalidElementNesting < Base attr_reader :widget, :enclosing_element_name, :enclosed_element_name def initialize(widget, enclosing_tag, enclosed_tag) message = %{The widget #{widget} tried to render an element that is not allowed by element nesting rules: you can't put a <#{enclosed_tag.name}> inside a <#{enclosing_tag.name}>.} if enclosing_tag.spec message << " (See '#{enclosing_tag.spec}' for more details.)" end super(message) @widget = widget @enclosing_tag = enclosing_tag @enclosed_tag = enclosed_tag end def enclosing_tag_name @enclosing_tag.name end def enclosed_tag_name @enclosed_tag.name end end class InvalidElementAttributes < Base attr_reader :widget, :invalid_attributes_hash, :allowed_attribute_names def initialize(widget, tag, invalid_attributes_hash, allowed_attribute_names) message = %{The widget #{widget} tried to render an element, <#{tag.name}>, with attributes that are not allowed: #{invalid_attributes_hash.inspect}. Only these attributes are allowed: #{allowed_attribute_names.sort_by(&:to_s).inspect}} if tag.spec message << " (See '#{tag.spec}' for more details.)" end super(message) @widget = widget @tag = tag @invalid_attributes_hash = invalid_attributes_hash @allowed_attribute_names = allowed_attribute_names end def tag_name @tag.name end end class DuplicateId < Base attr_reader :widget, :id, :already_used_widget, :already_used_tag_name, :tag_name def initialize(widget, id, already_used_widget, already_used_tag_name, tag_name) super(%{The widget #{widget} tried to use a DOM ID, '#{id}', that has already been used. It was originally used on a <#{already_used_tag_name}> tag within widget #{already_used_widget}, and is now trying to be used on a <#{tag_name}> tag.}) @widget = widget @id = id @already_used_widget = already_used_widget @already_used_tag_name = already_used_tag_name @tag_name = tag_name end end class DynamicAccessFromStaticMethod < Base attr_reader :widget, :static_method_name, :method_called def initialize(widget, static_method_name, method_called) super(%{The widget class #{widget.class.name} declared method #{static_method_name.inspect} to be static, but, when we went to make it static, we found that it called #{method_called.inspect}, and that accesses dynamic data; this therefore can't possibly be made static safely.}) @widget = widget @static_method_name = static_method_name @method_called = method_called end end class NoContentAllowed < Base attr_reader :widget def initialize(widget, tag) message = %{The widget #{widget} tried to render an element, <#{tag.name}>, with content inside it, but that element doesn't accept content.} if tag.spec message << " (See '#{tag.spec}' for more details.)" end super(message) @widget = widget @tag = tag end def tag_name @tag end end class NoReturnValueFromTag < Base attr_reader :method_name def initialize(method_name) super(%{You're trying to call a method, #{method_name.inspect}, on the return value of a Fortitude tag; tags don't return anything usable. (If you're migrating from Erector, this may be a place where you used Erector syntax for classes or IDs -- e.g., p.some_class, div.some_id!. Fortitude doesn't support these for important performance reasons; you simply need to convert these to "p :class => :some_class" or "div :id => :some_id".)}) @method_name = method_name end end class TagNotFound < Base attr_reader :tag_store, :tag_name def initialize(tag_store, tag_name) super(%{The tag store #{tag_store} has no tag named #{tag_name.inspect}.}) @tag_store = tag_store @tag_name = tag_name end end class NoBlockToYieldTo < Base attr_reader :widget def initialize(widget, local_jump_exception = nil) @local_jump_exception = local_jump_exception @widget = widget message = %{You're trying to call 'yield' (or 'yield_from_widget', or the Erector-compatibility method 'call_block') from the widget #{widget}; however, there is nothing to yield to. Fortitude looks for something to yield to in this order: 1. A block passed to a yield at render time directly (usually via the 'widget' call); 2. A block passed to the constructor of the widget; 3. The layout the widget is being rendered in. None of these exist here, and so calling 'yield', 'yield_from_widget', or 'call_block' is an undefined operation.} if @local_jump_exception message += %{ This was caused by a #{@local_jump_exception.class.name}, which is: #{@local_jump_exception}:\n #{@local_jump_exception.backtrace.join("\n ")}} end super(message) end end end end