Class: RubyUIConverter::LocalsDetector
- Inherits:
-
Object
- Object
- RubyUIConverter::LocalsDetector
- Defined in:
- lib/ruby_ui_converter/locals_detector.rb
Overview
Heuristically detects the locals a partial expects, so the generated component can declare keyword arguments and private readers.
This is intentionally conservative and best-effort: it favors a few clearly detectable cases (local_assigns) plus bare identifiers that look like locals. Anything it misses can be added by hand to the generated component.
Constant Summary collapse
- KEYWORDS =
%w[ if elsif else end unless case when in while until for do begin rescue ensure return yield self nil true false and or not then break next redo retry def class module super defined lambda proc new raise puts print p require require_relative attr_reader attr_accessor attr_writer ].to_set
Instance Method Summary collapse
-
#initialize(tree) ⇒ LocalsDetector
constructor
A new instance of LocalsDetector.
-
#ivars ⇒ Object
Instance variables a top-level view reads from its controller (‘@products`), so the generated component can take them as keyword arguments.
- #locals ⇒ Object
Constructor Details
#initialize(tree) ⇒ LocalsDetector
Returns a new instance of LocalsDetector.
20 21 22 |
# File 'lib/ruby_ui_converter/locals_detector.rb', line 20 def initialize(tree) @tree = tree end |
Instance Method Details
#ivars ⇒ Object
Instance variables a top-level view reads from its controller (‘@products`), so the generated component can take them as keyword arguments. Excludes any ivar assigned within the template and class variables (`@@foo`). Strings are stripped first, like #locals, to avoid `@` inside literals (`“x@y.com”`).
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/ruby_ui_converter/locals_detector.rb', line 70 def ivars codes = [] collect(@tree.children, codes) found = Set.new assigned = Set.new codes.each do |code| without_strings = code.gsub(/"[^"]*"|'[^']*'/, " ") without_strings.scan(/(?<!@)@([a-zA-Z_]\w*)\s*=(?!=)/) { assigned << Regexp.last_match(1) } without_strings.scan(/(?<!@)@([a-zA-Z_]\w*)/) { found << Regexp.last_match(1) } end (found - assigned).to_a.sort end |
#locals ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 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 |
# File 'lib/ruby_ui_converter/locals_detector.rb', line 24 def locals codes = [] collect(@tree.children, codes) found = Set.new assigned = Set.new block_params = Set.new codes.each do |code| code.scan(/\|([^|]*)\|/) do Regexp.last_match(1).split(",").each do |param| block_params << param.strip.sub(/\A\*+/, "").sub(/:.*\z/, "").strip end end code.scan(/([a-z_]\w*)\s*=(?!=)/) { assigned << Regexp.last_match(1) } code.scan(/local_assigns\[:(\w+)\]/) { found << Regexp.last_match(1) } code.scan(/local_assigns\.fetch\(:(\w+)/) { found << Regexp.last_match(1) } end codes.each do |code| without_strings = code.gsub(/"[^"]*"|'[^']*'/, " ") without_strings.scan(/(?<![.\w:@$])([a-z_]\w*)/) do name = Regexp.last_match(1) after = Regexp.last_match.post_match next if after =~ /\A\s*\(/ # method call next if after =~ /\A\s*=(?!=)/ # assignment target next if after =~ /\A:(?!:)/ # keyword/hash key next if KEYWORDS.include?(name) next if RailsHelpers::HTML_HELPERS.include?(name) next if RailsHelpers::KNOWN_HELPERS.include?(name) next if block_params.include?(name) next if assigned.include?(name) found << name end end found.delete("local_assigns") found.to_a.sort end |