Class: RailsAiContext::Tools::ValidateSemantics::RailsSemanticVisitor

Inherits:
Prism::Visitor
  • Object
show all
Defined in:
lib/rails_ai_context/tools/validate_semantics.rb

Constant Summary collapse

TOP_LEVEL_SCOPE =
"__top_level__"
CALLBACK_NAMES =
%i[
  before_validation after_validation before_save after_save
  before_create after_create before_update after_update
  before_destroy after_destroy after_commit after_rollback
].to_set.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRailsSemanticVisitor

Returns a new instance of RailsSemanticVisitor.



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 27

def initialize
  super
  @render_calls = []
  @route_helper_calls = []
  @validates_calls = []
  @permit_calls = []
  @callback_registrations = []
  @has_many_calls = []
  @local_method_names_by_scope = Hash.new { |hash, key| hash[key] = Set.new }
  @singleton_method_names_by_scope = Hash.new { |hash, key| hash[key] = Set.new }
  @scope_stack = [ TOP_LEVEL_SCOPE ]
  @method_context_stack = []
end

Instance Attribute Details

#callback_registrationsObject (readonly)

Returns the value of attribute callback_registrations.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def callback_registrations
  @callback_registrations
end

#has_many_callsObject (readonly)

Returns the value of attribute has_many_calls.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def has_many_calls
  @has_many_calls
end

#local_method_names_by_scopeObject (readonly)

Returns the value of attribute local_method_names_by_scope.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def local_method_names_by_scope
  @local_method_names_by_scope
end

#permit_callsObject (readonly)

Returns the value of attribute permit_calls.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def permit_calls
  @permit_calls
end

#render_callsObject (readonly)

Returns the value of attribute render_calls.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def render_calls
  @render_calls
end

#route_helper_callsObject (readonly)

Returns the value of attribute route_helper_calls.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def route_helper_calls
  @route_helper_calls
end

#singleton_method_names_by_scopeObject (readonly)

Returns the value of attribute singleton_method_names_by_scope.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def singleton_method_names_by_scope
  @singleton_method_names_by_scope
end

#validates_callsObject (readonly)

Returns the value of attribute validates_calls.



16
17
18
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 16

def validates_calls
  @validates_calls
end

Instance Method Details

#local_route_method_defined?(helper, scope, method_kind) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 41

def local_route_method_defined?(helper, scope, method_kind)
  case method_kind
  when :singleton
    @singleton_method_names_by_scope[scope].include?(helper)
  when :instance
    @local_method_names_by_scope[scope].include?(helper)
  else
    @local_method_names_by_scope[scope].include?(helper) ||
      @singleton_method_names_by_scope[scope].include?(helper)
  end
end

#visit_call_node(node) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 67

def visit_call_node(node)
  case node.name
  when :render     then extract_render(node)
  when :validates  then extract_validates(node)
  when :permit     then extract_permit(node)
  when :has_many   then extract_has_many(node)
  else
    if node.name.to_s.end_with?("_path", "_url") && node.receiver.nil?
      @route_helper_calls << {
        name: node.name.to_s,
        line: node.location.start_line,
        scope: current_scope,
        method_kind: current_method_kind
      }
    elsif CALLBACK_NAMES.include?(node.name) && node.receiver.nil?
      extract_callback(node)
    end
  end
  super
end

#visit_class_node(node) ⇒ Object



53
54
55
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 53

def visit_class_node(node)
  with_scope(node.constant_path&.slice) { super }
end

#visit_def_node(node) ⇒ Object



61
62
63
64
65
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 61

def visit_def_node(node)
  method_kind = node.receiver ? :singleton : :instance
  method_names_for(method_kind, current_scope) << node.name.to_s
  with_method_context(method_kind) { super }
end

#visit_module_node(node) ⇒ Object



57
58
59
# File 'lib/rails_ai_context/tools/validate_semantics.rb', line 57

def visit_module_node(node)
  with_scope(node.constant_path&.slice) { super }
end