Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@ -m gives "Error: Cannot find method code." and $ is giving syntax error #2254

Open
zenspider opened this issue Aug 17, 2022 · 4 comments
Open

Comments

@zenspider
Copy link

[8] pry(#<Ticket>)> @ -m
Error: Cannot find method code.
[13] pry(#<Ticket>)> $ self.attribute_was
Error: (eval):2: syntax error
[14] pry(#<Ticket>)> self.method(:attribute_was).source_location
=> ["/Users/ryan.davis/.gem/repos/zendesk-rails51/gems/activerecord-5.1.7/lib/active_record/attribute_methods/dirty.rb", 216]

Basically, pry is able to show surrounding context, but any use of method_source (I'm assuming) seems to be totally broken and I can't figure out why. I've already cleared out my pryrc to no avail.

Some context: this was working fine and then work gave me a new machine. I switched over from intel to arm... but this stuff works on my personal arm machine, so IDGI.

I can't introspect on Pry itself because of the above errors, so I'm at a bit of a loss here. Tell me what to poke at and I'll poke at it.

9985 % gem list pry method_source byebug pry-byebug coderay | sort -u
byebug (11.1.3)
coderay (1.1.2)
method_source (1.0.0)
pry (0.13.1)
pry-byebug (3.9.0)
pry-remote (0.1.8)
@andrehjr
Copy link
Member

That's really odd 🤔 I've tried the same using the gem versions. Can you run the following cmds and let me know the result:

self.method(:attribute_was).source

MethodSource.source_helper(self.method(:attribute_was).source_location)

Pry.last_internal_error.backtrace 

Pry.last_internal_error.class

Pry::CodeObject.lookup("self.attribute_was", pry_instance).source

pry_instance.current_binding.eval('self.method(:attribute_was).source')

pry_instance.binding_stack.map(&:source_location)

pry_instance.binding_stack.last.eval('self.class.name')

This should at least point us if it's something in pry or method_source. Sorry for the long list!

@zenspider
Copy link
Author

self.method(:attribute_was).source

#>>> self.method(:attribute_was).source_location
# => ["/Users/ryan.davis/.gem/repos/zendesk-rails51/gems/activerecord-5.1.7/lib/active_record/attribute_methods/dirty.rb",
 216]
#>>> self.method(:attribute_was).source
MethodSource::SourceNotFoundError: Could not parse source for attribute_was: (eval):2: syntax error
from /Users/ryan.davis/.gem/repos/zendesk-rails51/gems/method_source-1.0.0/lib/method_source.rb:29:in `rescue in source_helper'
Caused by SyntaxError: (eval):2: syntax error
from /Users/ryan.davis/.gem/repos/zendesk-rails51/gems/method_source-1.0.0/lib/method_source/code_helpers.rb:71:in `eval'

MethodSource.source_helper(self.method(:attribute_was).source_location)

skipping this one because of error above

Pry.last_internal_error.backtrace

#>>> Pry.last_internal_error.backtrace
NoMethodError: undefined method `backtrace' for nil:NilClass

Pry.last_internal_error.class

skipping

Pry::CodeObject.lookup("self.attribute_was", pry_instance).source

#>>> Pry::CodeObject.lookup("self.attribute_was", pry_instance).source
MethodSource::SourceNotFoundError: (eval):2: syntax error
from /Users/ryan.davis/.gem/repos/zendesk-rails51/gems/pry-0.13.1/lib/pry/method.rb:594:in `rescue in ruby_source'
Caused by SyntaxError: (eval):2: syntax error
from /Users/ryan.davis/.gem/repos/zendesk-rails51/gems/method_source-1.0.0/lib/method_source/code_helpers.rb:71:in `eval'
#>>> Pry::CodeObject.lookup("self.attribute_was", pry_instance)
# => #<Pry::Method:0x0000000109501428
 @method=#<Method: ActiveRecord::AttributeMethods::Dirty#attribute_was>,
 @visibility=nil>

pry_instance.current_binding.eval('self.method(:attribute_was).source')

skipping

pry_instance.binding_stack.map(&:source_location)

#>>> pry_instance.binding_stack.map(&:source_location)
# => [["/Users/ryan.davis/Code/zendesk/zendesk/app/models/users/roles.rb", 207]]

pry_instance.binding_stack.last.eval('self.class.name')

#>>> pry_instance.binding_stack.last.eval('self.class.name')
# => "User"

@andrehjr
Copy link
Member

Thanks for the additional details. I've tried this on Rails 5.1.7 app too and still trying to reproduce and understand what's happening here.

It does look like a problem with method_source, as calling self.method(:attribute_was).source fails.

MethodSource tries to 'eval' the code until it finds a complete expression. Can you run:

file, line = self.method(:attribute_was).source_location ; File.readlines(file)[(line-1)..(line+5)]

So we can see what the code that should be being eval'd looks like? For me, it returns:

> file, line = self.method(:attribute_was).source_location ; File.readlines(file)[(line-1)..(line+5)]
=> ["      def attribute_was(*)\n",
 "        emit_warning_if_needed(\"attribute_was\", \"attribute_before_last_save\")\n",
 "        super\n",
 "      end\n",
 "\n",
 "      def attribute_change(*)\n",
 "        emit_warning_if_needed(\"attribute_change\", \"saved_change_to_attribute\")\n"]

Another idea would be to monkey-patch https://github.com/banister/method_source/blob/master/lib/method_source/code_helpers.rb#L66 to see what method_source is trying to eval when it breaks with a SyntaxError.

@zenspider
Copy link
Author

Yup yup. Same thing.

#>>> file, line = self.method(:attribute_was).source_location ; File.readlines(file)[(line-1)..(line+5)]

# => ["      def attribute_was(*_attr)\n",
 "        emit_warning_if_needed(\"attribute_was\", \"attribute_before_last_save\")\n",
 "        super\n",
 "      end\n",
 "\n",
 "      def attribute_change(*_attr)\n",
 "        emit_warning_if_needed(\"attribute_change\", \"saved_change_to_attribute\")\n"]

Doping complete_expression I can see:

#>>> File.readlines("/Users/ryan.davis/.pryrc")[45..50]
{:COMPLETE=>"File.readlines(\"/Users/ryan.davis/.pryrc\")[45..50]\n"}
# => ["class Array\n",
 "  def grep_vg\n",
 "    grep_v %r%/gems/%\n",
 "  end\n",
 "end\n",
 "\n"]
#>>> $ [].grep_vg
{:COMPLETE=>"  def grep_vg\n"}
{:COMPLETE=>"  def grep_vg\n"}
Error: (eval):2: syntax error
{:COMPLETE=>""}

so it is indeed a syntax error... just not sure WHY it is a syntax error at that level.

Why I seem to be seeing, and no clue why this is different this time around (new machine and all, but Gemfile.lock should put me right, right?)

[].method(:grep_vg).source

winds up calling: def expression_at(".pryrc", 47)
which calls: extract_first_expression(relevant_lines..., 0)
which calls: complete_expression?(relevant_lines[0])

that last one is the "eval clean or raise" ... but it shouldn't be "or raise"... it should be "eval clean or false" so it appends the next line of source and tries again. Yes, I think this is it...

module MethodSource
  module CodeHelpers
    def complete_expression?(str)
      old_verbose = $VERBOSE
      $VERBOSE = nil
      catch(:valid) do
        eval("BEGIN{throw :valid}\n#{str}")
      end
      # Assert that a line which ends with a , or \ is incomplete.
      str !~ /[,\\]\s*\z/
    rescue IncompleteExpression, SyntaxError # Added SyntaxError Here!!!
      false
    ensure
      $VERBOSE = old_verbose
    end
  end
end

why is this coming up now?!? I have NO clue. Who is supposed to be raising IncompleteExpression (not ruby?). Ah, it isn't raised... it's a === matcher and it is looking at the message on the SyntaxErrors...

OK. I think this is dumb, but probably the culprit:

9980 % ruby31 -e "  def grep_vg\n" # 2.7+ seem to output this
-e:1: syntax error, unexpected backslash, expecting ';' or '\n'
  def grep_vg\n
9981 % ruby26 -e "  def grep_vg\n"
-e:1: syntax error
  def grep_vg\n

Why am I having a hard time now?!?! I have NO idea. TBH it seems dumb. I had a hell of a time getting a build of ruby 2.6 working on arm64 w/ ruby-install ... it appears postmodern refuses to maintain any patches ... had I installed via rbenv or something else maybe this would work fine?!? I dunno... I do know that my company is most likely migrating to 2.7 sometime next week.

If this really is a one off... (how? why?)... then ignore this ticket. I have a workaround and I'm moving to a version where this Just Works™ already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants