Repository: yippee-fun/phlex (ruby)

Issue:
Raise an error when `plain` is called with an object that can’t be formatted
We should extract a specialised private `__text__` method for `yield_content` that doesn’t raise.


Discussion:

Patch:
diff --git a/lib/phlex/elements.rb b/lib/phlex/elements.rb
--- a/lib/phlex/elements.rb
+++ b/lib/phlex/elements.rb
@@ -28,6 +28,7 @@ def registered_elements
 	# Register a custom element. This macro defines an element method for the current class and descendents only. There is no global element registry.
 	# @param method_name [Symbol]
 	# @param tag [String] the name of the tag, otherwise this will be the method name with underscores replaced with dashes.
+	# @return [Symbol] the name of the method created
 	# @note The methods defined by this macro depend on other methods from {SGML} so they should always be mixed into an {HTML} or {SVG} component.
 	# @example Register the custom element `<trix-editor>`
 	# 	register_element :trix_editor
diff --git a/lib/phlex/html.rb b/lib/phlex/html.rb
--- a/lib/phlex/html.rb
+++ b/lib/phlex/html.rb
@@ -30,12 +30,6 @@ def doctype
 			nil
 		end
 
-		# @deprecated use {#plain} instead.
-		def text(...)
-			warn "DEPRECATED: The `text` method has been deprecated in favour of `plain`. Please use `plain` instead. The `text` method will be removed in a future version of Phlex. Called from: #{caller.first}"
-			plain(...)
-		end
-
 		# Outputs an `<svg>` tag
 		# @return [nil]
 		# @see https://developer.mozilla.org/docs/Web/SVG/Element/svg
diff --git a/lib/phlex/sgml.rb b/lib/phlex/sgml.rb
--- a/lib/phlex/sgml.rb
+++ b/lib/phlex/sgml.rb
@@ -127,21 +127,12 @@ def __final_call__(buffer = +"", context: Phlex::Context.new, view_context: nil,
 		end
 
 		# Output text content. The text will be HTML-escaped.
+		# @param content [String, Symbol, Integer, void] the content to be output on the buffer. Strings, Symbols, and Integers are handled by `plain` directly, but any object can be handled by overriding `format_object`
 		# @return [nil]
+		# @see #format_object
 		def plain(content)
-			case content
-			when String
-				@_context.target << ERB::Escape.html_escape(content)
-			when Symbol
-				@_context.target << ERB::Escape.html_escape(content.name)
-			when Integer
-				@_context.target << ERB::Escape.html_escape(content.to_s)
-			when nil
-				nil
-			else
-				if (formatted_object = format_object(content))
-					@_context.target << ERB::Escape.html_escape(formatted_object)
-				end
+			unless __text__(content)
+				raise ArgumentError, "You've passed an object to plain that is not handled by format_object. See https://rubydoc.info/gems/phlex/Phlex/SGML#format_object-instance_method for more information"
 			end
 
 			nil
@@ -250,7 +241,7 @@ def __vanish__(*args)
 			nil
 		end
 
-		# Determines if the component should render. By default, it returns <code>true</code>.
+		# Determines if the component should render. By default, it returns `true`.
 		# @abstract Override to define your own predicate to prevent rendering.
 		# @return [Boolean]
 		def render?
@@ -258,6 +249,7 @@ def render?
 		end
 
 		# Format the object for output
+		# @abstract Override to define your own format handling for different object types. Please remember to call `super` in the case that the passed object doesn't match, so that object formatting can be added at different layers of the inheritance tree.
 		# @return [String]
 		def format_object(object)
 			case object
@@ -266,7 +258,7 @@ def format_object(object)
 			end
 		end
 
-		# @abstract Override this method to hook in around a template render. You can do things before and after calling <code>super</code> to render the template. You should always call <code>super</code> so that callbacks can be added at different layers of the inheritance tree.
+		# @abstract Override this method to hook in around a template render. You can do things before and after calling `super` to render the template. You should always call `super` so that callbacks can be added at different layers of the inheritance tree.
 		# @return [nil]
 		def around_template
 			before_template
@@ -276,13 +268,13 @@ def around_template
 			nil
 		end
 
-		# @abstract Override this method to hook in right before a template is rendered. Please remember to call <code>super</code> so that callbacks can be added at different layers of the inheritance tree.
+		# @abstract Override this method to hook in right before a template is rendered. Please remember to call `super` so that callbacks can be added at different layers of the inheritance tree.
 		# @return [nil]
 		def before_template
 			nil
 		end
 
-		# @abstract Override this method to hook in right after a template is rendered. Please remember to call <code>super</code> so that callbacks can be added at different layers of the inheritance tree.
+		# @abstract Override this method to hook in right after a template is rendered. Please remember to call `super` so that callbacks can be added at different layers of the inheritance tree.
 		# @return [nil]
 		def after_template
 			nil
@@ -298,7 +290,7 @@ def yield_content
 
 			original_length = target.length
 			content = yield(self)
-			plain(content) if original_length == target.length
+			__text__(content) if original_length == target.length
 
 			nil
 		end
@@ -312,7 +304,7 @@ def yield_content_with_no_args
 
 			original_length = target.length
 			content = yield
-			plain(content) if original_length == target.length
+			__text__(content) if original_length == target.length
 
 			nil
 		end
@@ -327,11 +319,34 @@ def yield_content_with_args(*args)
 
 			original_length = target.length
 			content = yield(*args)
-			plain(content) if original_length == target.length
+			__text__(content) if original_length == target.length
 
 			nil
 		end
 
+		# Performs the same task as the public method #plain, but does not raise an error if an unformattable object is passed
+		# @api private
+		def __text__(content)
+			case content
+			when String
+				@_context.target << ERB::Escape.html_escape(content)
+			when Symbol
+				@_context.target << ERB::Escape.html_escape(content.name)
+			when Integer
+				@_context.target << ERB::Escape.html_escape(content.to_s)
+			when nil
+				nil
+			else
+				if (formatted_object = format_object(content))
+					@_context.target << ERB::Escape.html_escape(formatted_object)
+				else
+					return false
+				end
+			end
+
+			true
+		end
+
 		# @api private
 		def __attributes__(**attributes)
 			__final_attributes__(**attributes).tap do |buffer|


Test patch:
diff --git a/test/phlex/view/text.rb b/test/phlex/view/plain.rb
similarity index 59%
rename from test/phlex/view/text.rb
rename to test/phlex/view/plain.rb
--- a/test/phlex/view/text.rb
+++ b/test/phlex/view/plain.rb
@@ -39,16 +39,15 @@ def template
 		end
 	end
 
-	with "deprecated text method" do
+	with "an object that has no special format_object handling" do
 		view do
 			def template
-				text "Depreacted"
+				plain Object.new
 			end
 		end
 
-		it "renders content and prints deprecation warning" do
-			expect(example).to receive(:warn).with("DEPRECATED: The `text` method has been deprecated in favour of `plain`. Please use `plain` instead. The `text` method will be removed in a future version of Phlex. Called from: test/phlex/view/text.rb:45:in `template'")
-			expect(output).to be == "Depreacted"
+		it "raises an ArgumentError" do
+			expect { output }.to raise_exception(ArgumentError)
 		end
 	end
 end