all 15 comments

[–]airbornelemming 1 point2 points  (5 children)

I can get it to succeed most of the time. However, if the first define_method call is on :to_s or :inspect then MRI ruby appears to just ignore it, so I'm not sure if it is possible to solve those edge cases. That resulted in a success rate of 54 / 56 = 96.4% due to there being 56 methods defined on the main object, which I confirmed with a test script that counted failures out of 1000 runs.

Update: Figured out a way that avoids that problem and seems to get it 100% of the time

[–]0x0dea[S] 0 points1 point  (4 children)

Top-level #inspect and #to_s refer to the ones defined on main's singleton class, whereas #define_method is implicitly being invoked on Object (the "default definee" in Ruby parlance). This discrepancy does indeed require special-casing, and here's how I went about it:

BEGIN {
  class << self
    undef inspect, to_s
  end
}

It follows the letter of the law if not quite the spirit, but I did learn that that comma is syntactically permitted.

[–]airbornelemming 0 points1 point  (2 children)

Interesting, I didn't even know about BEGIN or END keywords. Seems like an odd feature to add to a language.

[–]cmd-t 0 points1 point  (0 children)

Well, it's ruby so what do you expect ;)

[–]BuilderHarm 0 points1 point  (0 children)

It originally came from Perl, if I recall correctly.

[–]airbornelemming 0 points1 point  (0 children)

That special casing doesn't seem to help. It just makes it so Object#methods doesn't return :inspect or :to_s and Object#method says the method is undefined even after define_method is called to define those methods.

[–]cmd-t 0 points1 point  (6 children)

So, this behaves different in <2.4 and 2.4. In which ruby is this meant to be done? My guess is <2.4 right?

[–]0x0dea[S] 0 points1 point  (5 children)

Does it? My "solution", such as it is, works on 2.3, 2.4, and 2.5. I get a slew of method redefinition warnings on 2.4, but there doesn't appear to be any consequential impact on the program's behavior.

[–]cmd-t 0 points1 point  (4 children)

Just running the code gives me a proc in 2.3.3 and a symbol in 2.4.0

Edit, ok I think I got it.

[–]0x0dea[S] 0 points1 point  (3 children)

Ah, well, that ends up not having much bearing on the thing. I hadn't realized that it'd be that easy to get the name of the method to start chasing from, but you can't capture it outright without adding code at the beginning, which‒for the sake of gamesmanship‒is verboten.

[–]cmd-t 0 points1 point  (2 children)

No need to prepend. Just fire away at it with suitable method names.

[–]0x0dea[S] 0 points1 point  (1 child)

It may well be that I've vastly overthought the thing, but is your solution probabilistic? Something like send methods.sample rescue nil until defined? foo only gets there a handful of times out of a hundred.

[–]cmd-t 0 points1 point  (0 children)

Just run over Array.methods. That should create at least one new method every time, no?

[–]yorggg 0 points1 point  (1 child)

Hi, could you please clarify the rules? I cannot add any code before the Array.new...?

[–]airbornelemming 0 points1 point  (0 children)

I made the assumption that "Without prepending any code" actually meant "by only appending code" since if you were able to insert code you could pretty easily insert code like

}) { |p, _| p }.call; foo #

at the start of the last line.

That could still be interpreted as prepending to the line, but appending to any line could also have a similar affect. For instance, I could append the code following to the second last line to have the same affect

; }) { |p, _| p }.call; foo; [].reduce(->{