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 the method to `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
# 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 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)


219
220
221
222
223
224
225
226
227
# File 'lib/phlex/sgml.rb', line 219

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)


190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/phlex/sgml.rb', line 190

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



153
154
155
# File 'lib/phlex/sgml.rb', line 153

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


161
162
163
164
165
166
167
# File 'lib/phlex/sgml.rb', line 161

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)


206
207
208
209
210
211
212
213
214
# File 'lib/phlex/sgml.rb', line 206

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)


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/phlex/sgml.rb', line 172

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