Class: Phlex::SGML

Inherits:
Object
  • Object
show all
Includes:
Helpers
Defined in:
lib/phlex/sgml.rb

Overview

**Standard Generalized Markup Language** for behaviour common to HTML and SVG.

Direct Known Subclasses

HTML, SVG

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeObject

This method is abstract.

Override to define an initializer for your component.

Note:

Your initializer will not receive a block passed to new. Instead, this block will be sent to #template when rendering.

Examples:

def initialize(articles:)
	@articles = articles
end


# File 'lib/phlex/sgml.rb', line 44

Class Method Details

.callObject

Render the view to a String. Arguments are delegated to new.



10
11
12
# File 'lib/phlex/sgml.rb', line 10

def call(...)
	new(...).call
end

.element_method?(method_name) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


33
34
35
36
37
38
39
40
41
# File 'lib/phlex/sgml.rb', line 33

def element_method?(method_name)
	return false unless instance_methods.include?(method_name)

	owner = instance_method(method_name).owner

	return true if owner.is_a?(Phlex::Elements) && owner.registered_elements[method_name]

	false
end

.method_added(method_name) ⇒ Object



72
73
74
75
76
# File 'lib/phlex/sgml.rb', line 72

def self.method_added(method_name)
	if method_name == :template
		Kernel.warn "⚠️ [DEPRECATION] Defining the `template` method on a Phlex component will not be supported in Phlex 2.0. Please rename `#{name}#template` to `#{name}#view_template` instead."
	end
end

.new(*args, **kwargs, &block) ⇒ Object

Note:

The block will not be delegated #initialize. Instead, it will be sent to #template when rendering.

Create a new instance of the component.



16
17
18
19
20
21
22
23
24
# File 'lib/phlex/sgml.rb', line 16

def new(*args, **kwargs, &block)
	if block
		object = super(*args, **kwargs, &nil)
		object.instance_variable_set(:@_content_block, block)
		object
	else
		super
	end
end

.rendered_at_least_once!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



27
28
29
30
# File 'lib/phlex/sgml.rb', line 27

def rendered_at_least_once!
	alias_method :__attributes__, :__final_attributes__
	alias_method :call, :__final_call__
end

Instance Method Details

#__final_call__(buffer = +"",, context: Phlex::Context.new, view_context: nil, parent: nil, fragments: nil, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/phlex/sgml.rb', line 103

def __final_call__(buffer = +"", context: Phlex::Context.new, view_context: nil, parent: nil, fragments: nil, &block)
	@_buffer = buffer
	@_context = context
	@_view_context = view_context
	@_parent = parent
	if @_rendered
	  warn "⚠️ [WARNING] You are rendering a component #{self.class.name} twice. This is not supported in Phlex 2.0."
	end
   @_rendered = true

	if fragments
		warn "⚠️ [WARNING] Selective Rendering is experimental, incomplete, and may change in future versions."
		@_context.target_fragments(fragments)
	end

	block ||= @_content_block

	return "" unless render?

	if !parent && Phlex::SUPPORTS_FIBER_STORAGE
		original_fiber_storage = Fiber[:__phlex_component__]
		Fiber[:__phlex_component__] = self
	end

	@_context.around_render do
		around_template do
			if block
				if is_a?(DeferredRender)
					__vanish__(self, &block)
					view_template
				else
					view_template do |*args|
						if args.length > 0
							yield_content_with_args(*args, &block)
						else
							yield_content(&block)
						end
					end
				end
			else
				view_template
			end
		end
	end

	unless parent
		if Phlex::SUPPORTS_FIBER_STORAGE
			Fiber[:__phlex_component__] = original_fiber_storage
		end
		buffer << context.buffer
	end
end

#await(task) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/phlex/sgml.rb', line 82

def await(task)
	case task
	when defined?(Concurrent::IVar) && Concurrent::IVar
		flush if task.pending?
		task.wait.value
	when defined?(Async::Task) && Async::Task
		flush if task.running?
		task.wait
	else
		raise ArgumentError, "Expected an asynchronous task / promise."
	end
end

#callObject

Renders the view and returns the buffer. The default buffer is a mutable String.



96
97
98
99
100
# File 'lib/phlex/sgml.rb', line 96

def call(...)
	__final_call__(...).tap do
		self.class.rendered_at_least_once!
	end
end

#capture(*args, &block) ⇒ String

Note:

This only works if the block’s receiver is the current component or the block returns a String.

Capture a block of output as a String.

Returns:

  • (String)


224
225
226
227
228
229
230
231
232
# File 'lib/phlex/sgml.rb', line 224

def capture(*args, &block)
	return "" unless block

	if args.length > 0
		@_context.capturing_into(+"") { yield_content_with_args(*args, &block) }
	else
		@_context.capturing_into(+"") { yield_content(&block) }
	end
end

#comment(&block) ⇒ nil

Output an HTML comment.

Returns:

  • (nil)


195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/phlex/sgml.rb', line 195

def comment(&block)
	context = @_context
	return if context.fragments && !context.in_target_fragment

	buffer = context.buffer

	buffer << "<!-- "
	yield_content(&block)
	buffer << " -->"

	nil
end

#contextObject

Access the current render context data

Returns:

  • the supplied context object, by default a Hash



158
159
160
# File 'lib/phlex/sgml.rb', line 158

def context
	@_context.user_context
end

#plain(content) ⇒ nil

Output text content. The text will be HTML-escaped.

Parameters:

  • 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`

Returns:

  • (nil)

See Also:

  • #format_object


166
167
168
169
170
171
172
# File 'lib/phlex/sgml.rb', line 166

def plain(content)
	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
end

#templateObject

This method is abstract.

Override to define a template for your component.

Examples:

def view_template
	h1 { "👋 Hello World!" }
end

Your template may yield a content block.

def view_template
	main {
		h1 { "Hello World" }
		yield
	}
end

Alternatively, you can delegate the content block to an element.

def view_template(&block)
	article(class: "card", &block)
end


68
69
70
# File 'lib/phlex/sgml.rb', line 68

def template
	yield
end

#unsafe_raw(content = nil) ⇒ nil

This method is very dangerous and should usually be avoided. It will output the given String without any HTML safety. You should never use this method to output unsafe user input.

Parameters:

  • content (String|nil) (defaults to: nil)

Returns:

  • (nil)


211
212
213
214
215
216
217
218
219
# File 'lib/phlex/sgml.rb', line 211

def unsafe_raw(content = nil)
	return nil unless content

	context = @_context
	return if context.fragments && !context.in_target_fragment

	context.buffer << content
	nil
end

#view_template(&block) ⇒ Object



78
79
80
# File 'lib/phlex/sgml.rb', line 78

def view_template(&block)
	template(&block)
end

#whitespace { ... } ⇒ nil

Output a whitespace character. This is useful for getting inline elements to wrap. If you pass a block, a whitespace will be output before and after yielding the block.

Yields:

  • If a block is given, it yields the block with no arguments.

Returns:

  • (nil)


177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/phlex/sgml.rb', line 177

def whitespace(&block)
	context = @_context
	return if context.fragments && !context.in_target_fragment

	buffer = context.buffer

	buffer << " "

	if block_given?
		yield_content(&block)
		buffer << " "
	end

	nil
end