ruby2html 1.6.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +197 -0
- data/LICENSE +21 -0
- data/README.md +155 -225
- data/ext/ruby2html/attributes.c +200 -0
- data/ext/ruby2html/buffer.h +43 -0
- data/ext/ruby2html/content.c +120 -0
- data/ext/ruby2html/extconf.rb +36 -9
- data/ext/ruby2html/html_escape.c +252 -0
- data/ext/ruby2html/ruby2html.c +15 -107
- data/ext/ruby2html/ruby2html.h +32 -0
- data/ext/ruby2html/tag_render.c +179 -0
- data/lib/gem/ruby2html/component.rb +118 -0
- data/lib/gem/ruby2html/component_helper.rb +36 -15
- data/lib/gem/ruby2html/html_beautifier_middleware.rb +55 -9
- data/lib/gem/ruby2html/rails_components/base_component.rb +10 -1
- data/lib/gem/ruby2html/rails_components/button_to.rb +3 -3
- data/lib/gem/ruby2html/rails_components/form_with.rb +41 -67
- data/lib/gem/ruby2html/rails_components/image_tag.rb +3 -3
- data/lib/gem/ruby2html/rails_components/link_to.rb +3 -3
- data/lib/gem/ruby2html/rails_components/output_capture.rb +41 -0
- data/lib/gem/ruby2html/rails_components/template_collector.rb +62 -0
- data/lib/gem/ruby2html/rails_components/template_compiler.rb +92 -0
- data/lib/gem/ruby2html/rails_components/template_helpers.rb +77 -0
- data/lib/gem/ruby2html/rails_helper.rb +8 -4
- data/lib/gem/ruby2html/railtie.rb +104 -25
- data/lib/gem/ruby2html/render/pure_ruby.rb +202 -0
- data/lib/gem/ruby2html/render.rb +60 -98
- data/lib/gem/ruby2html/version.rb +1 -1
- data/lib/gem/ruby2html.rb +28 -7
- metadata +22 -78
- data/lib/ruby2html/ruby2html.so +0 -0
- data/ruby2html.gemspec +0 -43
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
# Only ERB's C escaper (erb >= 4), not the template engine. Absent on
|
|
5
|
+
# JRuby/TruffleRuby: PureRuby.escape then uses its regex fallback.
|
|
6
|
+
require 'erb/escape'
|
|
7
|
+
rescue LoadError
|
|
8
|
+
nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module Ruby2html
|
|
12
|
+
# Pure-Ruby twin of the C extension's Ruby2html::Native (ext/ruby2html),
|
|
13
|
+
# used on JRuby, when the extension isn't built, or with
|
|
14
|
+
# RUBY2HTML_DISABLE_EXT=1. The specs render everything with both and
|
|
15
|
+
# compare. The rules are documented once, in the C sources.
|
|
16
|
+
#
|
|
17
|
+
# Written for JITs (YJIT, the JVM): generated tag methods without splats,
|
|
18
|
+
# everything appended with String#<< to one buffer, and escaping that
|
|
19
|
+
# returns the string itself when there is nothing to escape.
|
|
20
|
+
module PureRuby
|
|
21
|
+
INVALID_ATTRIBUTE_NAME = %r{[\x00-\x20\x7f"'<>/=]}
|
|
22
|
+
STRING_BOOLEAN = /\A(?:data-|aria-|(?:draggable|spellcheck|contenteditable)\z)/
|
|
23
|
+
MAX_NESTING = 32 # see R2H_MAX_NESTING in attributes.c
|
|
24
|
+
ESCAPABLE = /[&<>"']/
|
|
25
|
+
ESCAPABLE_BYTES = /[&<>"']/n
|
|
26
|
+
ESCAPES = { '&' => '&', '<' => '<', '>' => '>', '"' => '"', "'" => ''' }.freeze
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
# CRuby's ERB::Escape (erb >= 4, in C) is the fastest option and also
|
|
30
|
+
# returns its argument untouched when it is clean.
|
|
31
|
+
if RUBY_ENGINE == 'ruby' && defined?(ERB::Escape)
|
|
32
|
+
# May return str itself: only for appending to the buffer.
|
|
33
|
+
def escape(str)
|
|
34
|
+
ERB::Escape.html_escape(utf8_compatible(str))
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
def escape(str)
|
|
38
|
+
str = utf8_compatible(str)
|
|
39
|
+
# A UTF-8 regex raises on invalid bytes; Native passes them through.
|
|
40
|
+
return str.b.gsub(ESCAPABLE_BYTES, ESCAPES).force_encoding(Encoding::UTF_8) unless str.valid_encoding?
|
|
41
|
+
|
|
42
|
+
str.match?(ESCAPABLE) ? str.gsub(ESCAPABLE, ESCAPES) : str
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Like Native.escape_html: never hands back the caller's mutable string.
|
|
47
|
+
def escape_html(obj)
|
|
48
|
+
str = obj.to_s
|
|
49
|
+
escaped = escape(str)
|
|
50
|
+
escaped.equal?(str) && !str.frozen? ? str.dup : escaped
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# See r2h_utf8_compatible in html_escape.c.
|
|
54
|
+
def utf8_compatible(str)
|
|
55
|
+
case str.encoding
|
|
56
|
+
when Encoding::UTF_8, Encoding::US_ASCII then str
|
|
57
|
+
when Encoding::BINARY then str.dup.force_encoding(Encoding::UTF_8)
|
|
58
|
+
else str.ascii_only? ? str : str.encode(Encoding::UTF_8)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def define_tag(method_name, tag, void)
|
|
63
|
+
source = void ? void_tag_source(method_name, tag) : tag_source(method_name, tag)
|
|
64
|
+
# The magic comment is per eval: without it every tag literal allocates.
|
|
65
|
+
module_eval("# frozen_string_literal: true\n#{source}", __FILE__, __LINE__)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
def tag_source(method_name, tag)
|
|
70
|
+
<<~RUBY
|
|
71
|
+
def #{method_name}(content = nil, **attributes)
|
|
72
|
+
buffer = @current_output
|
|
73
|
+
if attributes.empty?
|
|
74
|
+
buffer << '<#{tag}>'
|
|
75
|
+
else
|
|
76
|
+
__r2h_open_tag(buffer, '<#{tag}', attributes)
|
|
77
|
+
buffer << '>'
|
|
78
|
+
end
|
|
79
|
+
if block_given?
|
|
80
|
+
size = buffer.bytesize
|
|
81
|
+
result = yield
|
|
82
|
+
__r2h_block_result(buffer, result) if buffer.bytesize == size
|
|
83
|
+
elsif content.instance_of?(String)
|
|
84
|
+
buffer << PureRuby.escape(content)
|
|
85
|
+
else
|
|
86
|
+
__r2h_text(buffer, content)
|
|
87
|
+
end
|
|
88
|
+
buffer << '</#{tag}>'
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
RUBY
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def void_tag_source(method_name, tag)
|
|
95
|
+
<<~RUBY
|
|
96
|
+
def #{method_name}(_content = nil, **attributes)
|
|
97
|
+
if attributes.empty?
|
|
98
|
+
@current_output << '<#{tag} />'
|
|
99
|
+
else
|
|
100
|
+
buffer = @current_output
|
|
101
|
+
__r2h_open_tag(buffer, '<#{tag}', attributes)
|
|
102
|
+
buffer << ' />'
|
|
103
|
+
end
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
RUBY
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def plain(text)
|
|
111
|
+
__r2h_text(@current_output, text)
|
|
112
|
+
nil
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def component(html)
|
|
116
|
+
@current_output << PureRuby.utf8_compatible(html.to_s) unless html.nil?
|
|
117
|
+
nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private
|
|
121
|
+
def __r2h_text(buffer, obj)
|
|
122
|
+
case obj
|
|
123
|
+
when nil then nil
|
|
124
|
+
when String
|
|
125
|
+
safe = !obj.instance_of?(String) && __r2h_html_safe?(obj)
|
|
126
|
+
buffer << (safe ? PureRuby.utf8_compatible(obj) : PureRuby.escape(obj))
|
|
127
|
+
when Symbol, Integer then buffer << PureRuby.escape(obj.to_s)
|
|
128
|
+
else
|
|
129
|
+
buffer << (__r2h_html_safe?(obj) ? PureRuby.utf8_compatible(obj.to_s) : PureRuby.escape(obj.to_s))
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def __r2h_block_result(buffer, result)
|
|
134
|
+
__r2h_text(buffer, result) if result.is_a?(String) || result.is_a?(Symbol) || result.is_a?(Numeric)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def __r2h_html_safe?(obj)
|
|
138
|
+
obj.respond_to?(:html_safe?) && obj.html_safe?
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Writes `<tag attr="..."`. If an attribute raises and the caller rescues,
|
|
142
|
+
# a half-written start tag would turn whatever is appended next into
|
|
143
|
+
# markup, so the buffer is rolled back to before the tag.
|
|
144
|
+
def __r2h_open_tag(buffer, open, attributes)
|
|
145
|
+
mark = buffer.bytesize
|
|
146
|
+
buffer << open
|
|
147
|
+
__r2h_attributes(buffer, attributes, nil)
|
|
148
|
+
rescue Exception # rubocop:disable Lint/RescueException -- re-raised; any exception leaves the tag open
|
|
149
|
+
buffer.replace(buffer.byteslice(0, mark)) if !buffer.frozen? && buffer.bytesize >= mark
|
|
150
|
+
raise
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def __r2h_attributes(buffer, attributes, prefix, depth = 0)
|
|
154
|
+
raise ArgumentError, "attributes nested more than #{MAX_NESTING} levels deep" if depth > MAX_NESTING
|
|
155
|
+
|
|
156
|
+
attributes.each do |key, value|
|
|
157
|
+
next if value.nil?
|
|
158
|
+
|
|
159
|
+
name = key.is_a?(Symbol) ? key.name : key.to_s
|
|
160
|
+
raise ArgumentError, "attribute name can't be empty" if name.empty?
|
|
161
|
+
|
|
162
|
+
name = PureRuby.utf8_compatible(name)
|
|
163
|
+
name = "#{prefix}-#{__r2h_dasherize(name)}" if prefix
|
|
164
|
+
# Match bytes when the name isn't valid UTF-8 (a UTF-8 regex would raise).
|
|
165
|
+
checked = name.valid_encoding? ? name : name.b
|
|
166
|
+
raise ArgumentError, "invalid attribute name: #{name.inspect}" if INVALID_ATTRIBUTE_NAME.match?(checked)
|
|
167
|
+
|
|
168
|
+
case value
|
|
169
|
+
when String then buffer << ' ' << name << '="' << PureRuby.escape(value) << '"'
|
|
170
|
+
when true then buffer << ' ' << name << (STRING_BOOLEAN.match?(name) ? '="true"' : '')
|
|
171
|
+
when false then buffer << ' ' << name << '="false"' if STRING_BOOLEAN.match?(name)
|
|
172
|
+
when Hash then __r2h_attributes(buffer, value, name, depth + 1)
|
|
173
|
+
when Array then buffer << ' ' << name << '="' << __r2h_tokens(value) << '"'
|
|
174
|
+
else buffer << ' ' << name << '="' << PureRuby.escape(value.to_s) << '"'
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def __r2h_dasherize(name)
|
|
180
|
+
return name.tr('_', '-') if name.valid_encoding?
|
|
181
|
+
|
|
182
|
+
name.b.tr('_', '-').force_encoding(Encoding::UTF_8)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def __r2h_tokens(tokens)
|
|
186
|
+
__r2h_collect_tokens(tokens, [], 1).join(' ')
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def __r2h_collect_tokens(tokens, collected, depth)
|
|
190
|
+
raise ArgumentError, "attributes nested more than #{MAX_NESTING} levels deep" if depth > MAX_NESTING
|
|
191
|
+
|
|
192
|
+
tokens.each do |token|
|
|
193
|
+
if token.is_a?(Array)
|
|
194
|
+
__r2h_collect_tokens(token, collected, depth + 1)
|
|
195
|
+
elsif token
|
|
196
|
+
collected << PureRuby.escape(token.to_s)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
collected
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
data/lib/gem/ruby2html/render.rb
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require 'ruby2html/ruby2html'
|
|
5
|
-
rescue LoadError
|
|
6
|
-
puts 'ruby2html not installed'
|
|
7
|
-
end
|
|
3
|
+
require_relative 'render/pure_ruby'
|
|
8
4
|
|
|
9
5
|
module Ruby2html
|
|
6
|
+
# Loads the C extension (Ruby2html::Native). Without it (JRuby, a failed
|
|
7
|
+
# build, or RUBY2HTML_DISABLE_EXT=1) the pure-Ruby twin is used instead.
|
|
8
|
+
# Installed gems find the extension on the load path; this repo builds it
|
|
9
|
+
# into lib/ruby2html.
|
|
10
|
+
def self.load_native_extension
|
|
11
|
+
return false if ENV['RUBY2HTML_DISABLE_EXT'] == '1'
|
|
12
|
+
|
|
13
|
+
begin
|
|
14
|
+
require 'ruby2html/ruby2html'
|
|
15
|
+
rescue LoadError
|
|
16
|
+
require_relative '../../ruby2html/ruby2html'
|
|
17
|
+
end
|
|
18
|
+
defined?(Native) ? true : false
|
|
19
|
+
rescue LoadError
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
private_class_method :load_native_extension
|
|
23
|
+
|
|
24
|
+
# The module providing tag methods, #plain and #component: Native or PureRuby.
|
|
25
|
+
IMPLEMENTATION = load_native_extension ? Native : PureRuby
|
|
26
|
+
|
|
27
|
+
def self.native?
|
|
28
|
+
IMPLEMENTATION != PureRuby
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.escape_html(obj)
|
|
32
|
+
IMPLEMENTATION.escape_html(obj)
|
|
33
|
+
end
|
|
34
|
+
|
|
10
35
|
class Render
|
|
11
36
|
HTML5_TAGS = %w[
|
|
12
37
|
a abbr address area article aside audio b base bdi bdo blockquote body br button canvas caption
|
|
@@ -19,107 +44,45 @@ module Ruby2html
|
|
|
19
44
|
].freeze
|
|
20
45
|
|
|
21
46
|
VOID_ELEMENTS = %w[area base br col embed hr img input link meta param source track wbr].freeze
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
estimated_size += 32 if options.any?
|
|
33
|
-
estimated_size += content.length if content
|
|
34
|
-
tag_content = String.new(capacity: estimated_size)
|
|
35
|
-
tag_content << '<#{tag}'
|
|
36
|
-
fast_buffer_append(tag_content, fast_attributes_to_s(options))
|
|
37
|
-
#{if is_void
|
|
38
|
-
'tag_content << \' />\''
|
|
39
|
-
else
|
|
40
|
-
<<-TAG_LOGIC
|
|
41
|
-
tag_content << '>'
|
|
42
|
-
if block
|
|
43
|
-
prev_output = @current_output
|
|
44
|
-
nested_content = String.new(capacity: 1024)
|
|
45
|
-
@current_output = nested_content
|
|
46
|
-
block_result = block.call
|
|
47
|
-
@current_output = prev_output
|
|
48
|
-
if block_result.is_a?(String)
|
|
49
|
-
fast_buffer_append(tag_content, fast_escape_html(block_result))
|
|
50
|
-
else
|
|
51
|
-
fast_buffer_append(tag_content, nested_content)
|
|
52
|
-
end
|
|
53
|
-
elsif content
|
|
54
|
-
fast_buffer_append(tag_content, fast_escape_html(content))
|
|
55
|
-
end
|
|
56
|
-
tag_content << '</#{tag}>'
|
|
57
|
-
TAG_LOGIC
|
|
58
|
-
end}
|
|
59
|
-
fast_buffer_append(@current_output, tag_content)
|
|
60
|
-
end
|
|
61
|
-
RUBY
|
|
62
|
-
end.join("\n")
|
|
47
|
+
# Rails helpers that write their markup into the ruby2html buffer, mapped
|
|
48
|
+
# to their RailsComponents wrapper (shared by Render and Component).
|
|
49
|
+
RAILS_HELPER_COMPONENTS = { link_to: :LinkTo, button_to: :ButtonTo, image_tag: :ImageTag, form_with: :FormWith }.freeze
|
|
50
|
+
# Context ivars that would clobber the renderer's own state if copied.
|
|
51
|
+
SKIPPED_IVAR_PREFIXES = %w[@_ @output @current_output @context @root].freeze
|
|
52
|
+
|
|
53
|
+
# Both implementations get the tags so specs can compare them in one process.
|
|
54
|
+
[PureRuby, IMPLEMENTATION].uniq.each do |implementation|
|
|
55
|
+
HTML5_TAGS.each { |tag| implementation.define_tag(tag.tr('-', '_'), tag, VOID_ELEMENTS.include?(tag)) }
|
|
56
|
+
end
|
|
63
57
|
|
|
64
|
-
|
|
65
|
-
class_eval(METHOD_DEFINITIONS, __FILE__, __LINE__ + 1)
|
|
58
|
+
include IMPLEMENTATION
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
# No `output` reader: it would shadow the <output> tag method.
|
|
68
61
|
attr_accessor :current_output
|
|
69
62
|
|
|
70
63
|
def initialize(context = nil, &root)
|
|
71
64
|
@context = context
|
|
72
65
|
@root = root
|
|
73
|
-
@output = String.new(capacity: 4096)
|
|
66
|
+
@output = String.new(capacity: 4096, encoding: Encoding::UTF_8)
|
|
74
67
|
@current_output = @output
|
|
75
68
|
end
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
template_path = template_path.sub("#{Rails.root}/", '')
|
|
82
|
-
comment_start = "<!-- BEGIN #{template_path} -->"
|
|
83
|
-
comment_end = "<!-- END #{template_path} -->"
|
|
84
|
-
|
|
85
|
-
final_result = String.new(capacity: result.length + comment_start.length + comment_end.length)
|
|
86
|
-
final_result << comment_start
|
|
87
|
-
final_result << result
|
|
88
|
-
final_result << comment_end
|
|
89
|
-
final_result.html_safe
|
|
90
|
-
end if defined?(ActionView)
|
|
91
|
-
|
|
70
|
+
# Without arguments renders the root block and returns the HTML (a
|
|
71
|
+
# SafeBuffer under ActiveSupport). With arguments it is the context's
|
|
72
|
+
# render (partials, components), appended to the output.
|
|
92
73
|
def render(*args, **options, &block)
|
|
93
|
-
|
|
74
|
+
copy_instance_variables if @context && !@__vars_copied
|
|
94
75
|
|
|
95
|
-
return plain @context.render(*args, **options, &block) if !args.empty? || !options.empty? ||
|
|
76
|
+
return plain @context.render(*args, **options, &block) if !args.empty? || !options.empty? || block
|
|
96
77
|
|
|
97
78
|
instance_exec(&@root)
|
|
98
|
-
|
|
99
|
-
result = ActiveSupport::SafeBuffer.new(result) if defined?(ActiveSupport)
|
|
100
|
-
result
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def respond_to?(method_name, include_private = false)
|
|
104
|
-
HTML5_TAGS.include?(method_name.to_s.tr('_', '-')) || super
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def plain(text)
|
|
108
|
-
if defined?(ActiveSupport) && (text.is_a?(ActiveSupport::SafeBuffer) || text.html_safe?)
|
|
109
|
-
fast_buffer_append(@current_output, text)
|
|
110
|
-
else
|
|
111
|
-
fast_buffer_append(@current_output, fast_escape_html(text.to_s))
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def component(component_output)
|
|
116
|
-
fast_buffer_append(@current_output, component_output)
|
|
79
|
+
defined?(ActiveSupport::SafeBuffer) ? ActiveSupport::SafeBuffer.new(@output) : @output
|
|
117
80
|
end
|
|
118
81
|
|
|
119
82
|
private
|
|
120
|
-
def method_missing(method_name,
|
|
83
|
+
def method_missing(method_name, ...)
|
|
121
84
|
if @context.respond_to?(method_name)
|
|
122
|
-
@context.send(method_name,
|
|
85
|
+
@context.send(method_name, ...)
|
|
123
86
|
else
|
|
124
87
|
super
|
|
125
88
|
end
|
|
@@ -129,26 +92,25 @@ module Ruby2html
|
|
|
129
92
|
@context.respond_to?(method_name) || super
|
|
130
93
|
end
|
|
131
94
|
|
|
132
|
-
|
|
95
|
+
# Resolved per call (const_get with a Symbol; autoloaded on first use).
|
|
96
|
+
RAILS_HELPER_COMPONENTS.each do |method, component_name|
|
|
133
97
|
define_method(method) do |*args, **options, &block|
|
|
134
|
-
|
|
135
|
-
constant.new(self, @context, method, *args, **options).render(&block)
|
|
98
|
+
RailsComponents.const_get(component_name).new(self, @context, method, *args, **options).render(&block)
|
|
136
99
|
end
|
|
137
100
|
end if defined?(ActionView)
|
|
138
101
|
|
|
139
102
|
def escape_html(text)
|
|
140
|
-
|
|
103
|
+
IMPLEMENTATION.escape_html(text)
|
|
141
104
|
end
|
|
142
105
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
@annotate_rendered_view_with_filenames = Rails.application.config.action_view.annotate_rendered_view_with_filenames
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def set_instance_variables
|
|
106
|
+
# Templates read the view's assigns (@users, ...) as their own ivars.
|
|
107
|
+
def copy_instance_variables
|
|
149
108
|
@context.instance_variables.each do |name|
|
|
109
|
+
next if name.start_with?(*SKIPPED_IVAR_PREFIXES)
|
|
110
|
+
|
|
150
111
|
instance_variable_set(name, @context.instance_variable_get(name))
|
|
151
112
|
end
|
|
113
|
+
@__vars_copied = true
|
|
152
114
|
end
|
|
153
115
|
end
|
|
154
116
|
end
|
data/lib/gem/ruby2html.rb
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require '
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
require file
|
|
9
|
-
end
|
|
3
|
+
# Entry point. Loads only the renderer eagerly; everything else is autoloaded
|
|
4
|
+
# on first use, so `require 'ruby2html'` outside Rails stays small and fast
|
|
5
|
+
# (no Prism, no ActionView glue, no htmlbeautifier).
|
|
6
|
+
require_relative 'ruby2html/version'
|
|
7
|
+
require_relative 'ruby2html/render'
|
|
10
8
|
|
|
11
9
|
module Ruby2html
|
|
12
10
|
class Error < StandardError; end
|
|
11
|
+
|
|
12
|
+
autoload :Component, File.expand_path('ruby2html/component', __dir__)
|
|
13
|
+
autoload :ComponentHelper, File.expand_path('ruby2html/component_helper', __dir__)
|
|
14
|
+
autoload :RailsHelper, File.expand_path('ruby2html/rails_helper', __dir__)
|
|
15
|
+
autoload :HtmlBeautifierMiddleware, File.expand_path('ruby2html/html_beautifier_middleware', __dir__)
|
|
16
|
+
|
|
17
|
+
# Rails helper wrappers and the .html.rb template compiler (needs Prism).
|
|
18
|
+
module RailsComponents
|
|
19
|
+
{
|
|
20
|
+
OutputCapture: 'output_capture',
|
|
21
|
+
BaseComponent: 'base_component',
|
|
22
|
+
LinkTo: 'link_to',
|
|
23
|
+
ButtonTo: 'button_to',
|
|
24
|
+
ImageTag: 'image_tag',
|
|
25
|
+
FormWith: 'form_with',
|
|
26
|
+
TemplateHelpers: 'template_helpers',
|
|
27
|
+
TemplateCompiler: 'template_compiler'
|
|
28
|
+
}.each { |name, file| autoload name, File.expand_path("ruby2html/rails_components/#{file}", __dir__) }
|
|
29
|
+
end
|
|
13
30
|
end
|
|
31
|
+
|
|
32
|
+
# Template handler + Railtie. Registers lazily via ActiveSupport.on_load, so
|
|
33
|
+
# it costs nothing until ActionView loads; a no-op without ActiveSupport.
|
|
34
|
+
require_relative 'ruby2html/railtie' if defined?(ActiveSupport)
|
metadata
CHANGED
|
@@ -1,84 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby2html
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- sebi
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
-
dependencies:
|
|
12
|
-
- !ruby/object:Gem::Dependency
|
|
13
|
-
name: htmlbeautifier
|
|
14
|
-
requirement: !ruby/object:Gem::Requirement
|
|
15
|
-
requirements:
|
|
16
|
-
- - ">="
|
|
17
|
-
- !ruby/object:Gem::Version
|
|
18
|
-
version: '1.4'
|
|
19
|
-
type: :runtime
|
|
20
|
-
prerelease: false
|
|
21
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
-
requirements:
|
|
23
|
-
- - ">="
|
|
24
|
-
- !ruby/object:Gem::Version
|
|
25
|
-
version: '1.4'
|
|
26
|
-
- !ruby/object:Gem::Dependency
|
|
27
|
-
name: rake
|
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
|
29
|
-
requirements:
|
|
30
|
-
- - "~>"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '13.0'
|
|
33
|
-
type: :development
|
|
34
|
-
prerelease: false
|
|
35
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
-
requirements:
|
|
37
|
-
- - "~>"
|
|
38
|
-
- !ruby/object:Gem::Version
|
|
39
|
-
version: '13.0'
|
|
40
|
-
- !ruby/object:Gem::Dependency
|
|
41
|
-
name: rake-compiler
|
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - "~>"
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: '1.2'
|
|
47
|
-
type: :development
|
|
48
|
-
prerelease: false
|
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - "~>"
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: '1.2'
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: minitest
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - "~>"
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '5.14'
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - "~>"
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '5.14'
|
|
68
|
-
- !ruby/object:Gem::Dependency
|
|
69
|
-
name: benchmark-ips
|
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
|
71
|
-
requirements:
|
|
72
|
-
- - "~>"
|
|
73
|
-
- !ruby/object:Gem::Version
|
|
74
|
-
version: '2.10'
|
|
75
|
-
type: :development
|
|
76
|
-
prerelease: false
|
|
77
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
-
requirements:
|
|
79
|
-
- - "~>"
|
|
80
|
-
- !ruby/object:Gem::Version
|
|
81
|
-
version: '2.10'
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
82
12
|
description: Ruby2HTML empowers developers to write view logic in pure Ruby, seamlessly
|
|
83
13
|
converting it into clean, well-formatted HTML. Enhance your templating workflow,
|
|
84
14
|
improve readability, and leverage the full power of Ruby in your views. Features
|
|
@@ -91,10 +21,19 @@ extensions:
|
|
|
91
21
|
- ext/ruby2html/extconf.rb
|
|
92
22
|
extra_rdoc_files: []
|
|
93
23
|
files:
|
|
24
|
+
- CHANGELOG.md
|
|
25
|
+
- LICENSE
|
|
94
26
|
- README.md
|
|
27
|
+
- ext/ruby2html/attributes.c
|
|
28
|
+
- ext/ruby2html/buffer.h
|
|
29
|
+
- ext/ruby2html/content.c
|
|
95
30
|
- ext/ruby2html/extconf.rb
|
|
31
|
+
- ext/ruby2html/html_escape.c
|
|
96
32
|
- ext/ruby2html/ruby2html.c
|
|
33
|
+
- ext/ruby2html/ruby2html.h
|
|
34
|
+
- ext/ruby2html/tag_render.c
|
|
97
35
|
- lib/gem/ruby2html.rb
|
|
36
|
+
- lib/gem/ruby2html/component.rb
|
|
98
37
|
- lib/gem/ruby2html/component_helper.rb
|
|
99
38
|
- lib/gem/ruby2html/html_beautifier_middleware.rb
|
|
100
39
|
- lib/gem/ruby2html/rails_components/base_component.rb
|
|
@@ -102,34 +41,39 @@ files:
|
|
|
102
41
|
- lib/gem/ruby2html/rails_components/form_with.rb
|
|
103
42
|
- lib/gem/ruby2html/rails_components/image_tag.rb
|
|
104
43
|
- lib/gem/ruby2html/rails_components/link_to.rb
|
|
44
|
+
- lib/gem/ruby2html/rails_components/output_capture.rb
|
|
45
|
+
- lib/gem/ruby2html/rails_components/template_collector.rb
|
|
46
|
+
- lib/gem/ruby2html/rails_components/template_compiler.rb
|
|
47
|
+
- lib/gem/ruby2html/rails_components/template_helpers.rb
|
|
105
48
|
- lib/gem/ruby2html/rails_helper.rb
|
|
106
49
|
- lib/gem/ruby2html/railtie.rb
|
|
107
50
|
- lib/gem/ruby2html/render.rb
|
|
51
|
+
- lib/gem/ruby2html/render/pure_ruby.rb
|
|
108
52
|
- lib/gem/ruby2html/version.rb
|
|
109
|
-
- lib/ruby2html/ruby2html.so
|
|
110
|
-
- ruby2html.gemspec
|
|
111
53
|
homepage: https://github.com/sebyx07/ruby2html
|
|
112
54
|
licenses:
|
|
113
55
|
- MIT
|
|
114
56
|
metadata:
|
|
115
57
|
homepage_uri: https://github.com/sebyx07/ruby2html
|
|
116
58
|
source_code_uri: https://github.com/sebyx07/ruby2html
|
|
59
|
+
changelog_uri: https://github.com/sebyx07/ruby2html/blob/main/CHANGELOG.md
|
|
60
|
+
bug_tracker_uri: https://github.com/sebyx07/ruby2html/issues
|
|
61
|
+
rubygems_mfa_required: 'true'
|
|
117
62
|
rdoc_options: []
|
|
118
63
|
require_paths:
|
|
119
64
|
- lib/gem
|
|
120
|
-
- lib
|
|
121
65
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
66
|
requirements:
|
|
123
67
|
- - ">="
|
|
124
68
|
- !ruby/object:Gem::Version
|
|
125
|
-
version: 3.
|
|
69
|
+
version: 3.1.0
|
|
126
70
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
71
|
requirements:
|
|
128
72
|
- - ">="
|
|
129
73
|
- !ruby/object:Gem::Version
|
|
130
74
|
version: '0'
|
|
131
75
|
requirements: []
|
|
132
|
-
rubygems_version: 3.6.
|
|
76
|
+
rubygems_version: 3.6.9
|
|
133
77
|
specification_version: 4
|
|
134
78
|
summary: Transform Ruby code into beautiful, structured HTML with C-optimized performance
|
|
135
79
|
test_files: []
|
data/lib/ruby2html/ruby2html.so
DELETED
|
Binary file
|
data/ruby2html.gemspec
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'lib/gem/ruby2html/version'
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = 'ruby2html'
|
|
7
|
-
spec.version = Ruby2html::VERSION
|
|
8
|
-
spec.authors = ['sebi']
|
|
9
|
-
spec.email = ['gore.sebyx@yahoo.com']
|
|
10
|
-
|
|
11
|
-
spec.summary = 'Transform Ruby code into beautiful, structured HTML with C-optimized performance'
|
|
12
|
-
spec.description = 'Ruby2HTML empowers developers to write view logic in pure Ruby, ' \
|
|
13
|
-
'seamlessly converting it into clean, well-formatted HTML. ' \
|
|
14
|
-
'Enhance your templating workflow, improve readability, and ' \
|
|
15
|
-
'leverage the full power of Ruby in your views. ' \
|
|
16
|
-
'Features include Rails integration, custom component support, ' \
|
|
17
|
-
'automatic HTML beautification, and C-optimized rendering performance.'
|
|
18
|
-
spec.homepage = 'https://github.com/sebyx07/ruby2html'
|
|
19
|
-
spec.license = 'MIT'
|
|
20
|
-
spec.required_ruby_version = '>= 3.0.0'
|
|
21
|
-
|
|
22
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
|
23
|
-
spec.metadata['source_code_uri'] = spec.homepage
|
|
24
|
-
|
|
25
|
-
# Include C extension
|
|
26
|
-
spec.extensions = ['ext/ruby2html/extconf.rb']
|
|
27
|
-
|
|
28
|
-
# Include both lib and ext directories
|
|
29
|
-
spec.files = Dir.glob('{lib,ext}/{**/*,*}') +
|
|
30
|
-
['README.md', File.basename(__FILE__)]
|
|
31
|
-
|
|
32
|
-
# Set require paths for both the gem and extension
|
|
33
|
-
spec.require_paths = %w[lib/gem lib]
|
|
34
|
-
|
|
35
|
-
# Runtime dependencies
|
|
36
|
-
spec.add_dependency 'htmlbeautifier', '>= 1.4'
|
|
37
|
-
|
|
38
|
-
# Development dependencies
|
|
39
|
-
spec.add_development_dependency 'rake', '~> 13.0'
|
|
40
|
-
spec.add_development_dependency 'rake-compiler', '~> 1.2'
|
|
41
|
-
spec.add_development_dependency 'minitest', '~> 5.14'
|
|
42
|
-
spec.add_development_dependency 'benchmark-ips', '~> 2.10'
|
|
43
|
-
end
|