Module: RubyUIConverter::RailsHelpers
- Defined in:
- lib/ruby_ui_converter/rails_helpers.rb
Overview
Best-effort translation of common Rails view helpers found inside <%= %> into Phlex/RubyUI equivalents. Anything not understood is emitted as a bare call (phlex-rails registers these as output helpers that write to the buffer themselves) or, for the few that return a string, through a raw call.
Constant Summary collapse
- HTML_HELPERS =
Rails helpers that produce HTML. Under phlex-rails these are output helpers (they write to the buffer and return nil), so an unmapped one is emitted as a bare call — except STRING_HELPERS below, which return a value.
%w[ link_to button_to image_tag video_tag audio_tag content_tag tag form_with form_for fields_for label_tag text_field_tag mail_to link_to_unless link_to_if sanitize simple_format raw safe_join time_tag favicon_link_tag stylesheet_link_tag javascript_include_tag ].freeze
- STRING_HELPERS =
The subset of HTML_HELPERS that RETURN a string instead of writing to the Phlex buffer, so they must be wrapped in a raw call to appear in the output.
%w[sanitize safe_join raw strip_tags].freeze
- KNOWN_HELPERS =
Helpers that return plain (already-escaped or scalar) values.
%w[ t l translate localize number_to_currency number_with_delimiter number_to_percentage pluralize truncate current_user current_page? params session flash request cookies asset_path image_path url_for polymorphic_path time_ago_in_words distance_of_time_in_words dom_id dom_class notice alert content_for cycle render ].freeze
Class Method Summary collapse
- .build_locals(arg_list) ⇒ Object
-
.content_tag_call(code) ⇒ Object
content_tag(:div, “hi”, class: “x”) -> div(class: “x”) { “hi” }.
- .html_helper?(code) ⇒ Boolean
-
.image_tag_call(code) ⇒ Object
image_tag “logo.png”, alt: “Logo” -> img(src: “logo.png”, alt: “Logo”).
-
.link_target(path) ⇒ Object
Targets that are not strings or route helper calls (e.g. a record: ‘link_to “Show”, user`) need url_for to resolve to a path.
-
.link_to_call(code, ruby_ui: false) ⇒ Object
link_to “Text”, path, class: “x” -> a(href: path, class: “x”) { “Text” } With ruby_ui enabled -> Link(href: path, class: “x”) { “Text” }.
- .matches_helper?(code, helpers) ⇒ Boolean
-
.render_call(code, transformer) ⇒ Object
render “shared/header” / render partial: “x”, locals: .. / render “form”, a: 1.
- .safe ⇒ Object
-
.split_args(string) ⇒ Object
Splits a top-level argument list, respecting strings and nested brackets.
- .string_helper?(code) ⇒ Boolean
- .strip_parens(string) ⇒ Object
-
.transform(code, node, transformer, builder) ⇒ Object
Attempts to emit a transformed helper.
Class Method Details
.build_locals(arg_list) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 112 def build_locals(arg_list) return nil if arg_list.nil? || arg_list.empty? pairs = arg_list.map do |arg| if arg =~ /\Alocals:\s*\{(.*)\}\z/m Regexp.last_match(1).strip else arg end end result = pairs.reject(&:empty?).join(", ") result.empty? ? nil : result end |
.content_tag_call(code) ⇒ Object
content_tag(:div, “hi”, class: “x”) -> div(class: “x”) { “hi” }
163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 163 def content_tag_call(code) rest = strip_parens(code.sub(/\Acontent_tag\b/, "").strip) args = split_args(rest) return nil if args.length < 2 name = args[0].sub(/\A:/, "").gsub(/['"]/, "") content = args[1] = args[2..] || [] call = .empty? ? name : "#{name}(#{.join(", ")})" "#{call} { #{content} }" end |
.html_helper?(code) ⇒ Boolean
77 78 79 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 77 def html_helper?(code) matches_helper?(code, HTML_HELPERS) end |
.image_tag_call(code) ⇒ Object
image_tag “logo.png”, alt: “Logo” -> img(src: “logo.png”, alt: “Logo”)
152 153 154 155 156 157 158 159 160 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 152 def image_tag_call(code) rest = strip_parens(code.sub(/\Aimage_tag\b/, "").strip) args = split_args(rest) return nil if args.empty? src, * = args attrs = ["src: #{src}"] + "img(#{attrs.join(", ")})" end |
.link_target(path) ⇒ Object
Targets that are not strings or route helper calls (e.g. a record: ‘link_to “Show”, user`) need url_for to resolve to a path.
144 145 146 147 148 149 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 144 def link_target(path) return path if path.start_with?('"', "'") # literal string return path if path =~ /\A(\w+_)?(path|url)\b/ # route helper call "url_for(#{path})" end |
.link_to_call(code, ruby_ui: false) ⇒ Object
link_to “Text”, path, class: “x” -> a(href: path, class: “x”) { “Text” } With ruby_ui enabled -> Link(href: path, class: “x”) { “Text” }
129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 129 def link_to_call(code, ruby_ui: false) return nil if code =~ /\bdo\b/ # block form handled elsewhere rest = strip_parens(code.sub(/\Alink_to\b/, "").strip) args = split_args(rest) return nil if args.length < 2 text, path, * = args attrs = ["href: #{link_target(path)}"] + call = ruby_ui ? "Link" : "a" "#{call}(#{attrs.join(", ")}) { #{text} }" end |
.matches_helper?(code, helpers) ⇒ Boolean
85 86 87 88 89 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 85 def matches_helper?(code, helpers) helpers.any? do |helper| code == helper || code.start_with?("#{helper}(") || code.start_with?("#{helper} ") end end |
.render_call(code, transformer) ⇒ Object
render “shared/header” / render partial: “x”, locals: .. / render “form”, a: 1
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 92 def render_call(code, transformer) rest = strip_parens(code.sub(/\Arender\b/, "").strip) args = split_args(rest) return nil if args.empty? first = args[0] first = Regexp.last_match(1).strip if first =~ /\Apartial:\s*(.+)\z/m match = first.match(/\A["']([^"']+)["']\z/) return nil unless match const = Naming.partial_const( match[1], base_namespace: transformer.base_namespace, current_namespace_parts: transformer.current_namespace_parts ) locals = build_locals(args[1..]) locals ? "render #{const}.new(#{locals})" : "render #{const}.new" end |
.safe ⇒ Object
224 225 226 227 228 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 224 def safe yield rescue StandardError nil end |
.split_args(string) ⇒ Object
Splits a top-level argument list, respecting strings and nested brackets.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 176 def split_args(string) args = [] depth = 0 current = +"" quote = nil string.each_char do |char| if quote current << char quote = nil if char == quote next end case char when '"', "'" quote = char current << char when "(", "[", "{" depth += 1 current << char when ")", "]", "}" depth -= 1 current << char when "," if depth.zero? args << current.strip current = +"" else current << char end else current << char end end args << current.strip unless current.strip.empty? args end |
.string_helper?(code) ⇒ Boolean
81 82 83 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 81 def string_helper?(code) matches_helper?(code, STRING_HELPERS) end |
.strip_parens(string) ⇒ Object
215 216 217 218 219 220 221 222 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 215 def strip_parens(string) stripped = string.strip if stripped.start_with?("(") && stripped.end_with?(")") stripped[1..-2].strip else stripped end end |
.transform(code, node, transformer, builder) ⇒ Object
Attempts to emit a transformed helper. Returns true when it wrote something to the builder, false otherwise.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/ruby_ui_converter/rails_helpers.rb', line 36 def transform(code, node, transformer, builder) stripped = code.strip if stripped == "yield" || stripped =~ /\Ayield\b/ builder.line(stripped) return true end if stripped.start_with?("render") rendered = safe { render_call(stripped, transformer) } # phlex-rails' #render handles model objects / relations and writes to # the buffer itself, so the object/collection fallback is a bare call. builder.line(rendered || stripped) return true end if stripped.start_with?("link_to") rendered = safe { link_to_call(stripped, ruby_ui: transformer.config.ruby_ui?) } return builder.line(rendered) && true if rendered end if stripped.start_with?("image_tag") rendered = safe { image_tag_call(stripped) } return builder.line(rendered) && true if rendered end if stripped.start_with?("content_tag") rendered = safe { content_tag_call(stripped) } return builder.line(rendered) && true if rendered end if html_helper?(stripped) # Output helpers write to the buffer (bare call); string-returning ones # need a raw call to be emitted. builder.line(string_helper?(stripped) ? transformer.config.raw_call(stripped) : stripped) return true end false end |