9 ms·
“Did you mean?” Experience in Ruby
- timr 12y agoNeat. In case you're wondering, it's implemented using a levenshtein distance algorithm: https://www.omniref.com/ruby/gems/did_you_mean/0.6.0/symbols/DidYouMean::MethodMatcher/similar_methods https://www.omniref.com/ruby/gems/did_you_mean/0.6.0/symbols... and it works by extending the NameError exception: https://www.omniref.com/ruby/gems/did_you_mean/0.6.0/files/lib/did_you_mean/core_ext/name_error.rb https://www.omniref.com/ruby/gems/did_you_mean/0.6.0/files/l...
- lucaspiller 12y agoThe close_enough gem takes this one step further and uses this to 'patch' method_missing: http://decomplecting.org/blog/2013/03/01/code-typos-got-you-down-stop-worrying-with-close-enough/ http://decomplecting.org/blog/2013/03/01/code-typos-got-you-...
- inglor 12y agoThis sort of stuff should, at least in the 'easy' case be done at the editor level. Doesn't ruby have linter tooling for this? Still, props for the work.
- ryanto 12y agoRuby has a linters, but this sort of problem is hard to solve with a linter in a dynamically typed language. It's even harder in a Rails environment since Rails adds many methods to your classes at run time.
- kyllo 12y agoYeah, since it's a dynamically typed lang with inheritance and late binding, doesn't performing static analysis on Ruby code to determine whether a method is defined or not, basically require a solution to the halting problem? I'm under the impression that you have to actually execute Ruby code to find out with certainty where the methods it calls are defined.
- vidarh 12y agoYou can solve the "90%" problem statically. My Ruby-compiler-in-progress warns of methods that have not been seen, and I may eventually add some (entirely optional) pragma to allow hinting to reduce false positives (though getting that non-intrusive will be a fun challenge). But you are right, the general case does require a solution to the halting problem, something which is trivial to demonstrate very explicitly: eval(STDIN.gets) 42.will_i_halt? Put that in a file, and run it. Press enter, and it halts. Or cut and paste something like this, and it doesn't: class Fixnum; def will_i_halt?; loop {}; end; end And consider that even "require" is a practical equivalent to "eval", so trying to look for eval() calls and similar constructs and think you're safe doesn't work, unless you have a guarantee that the interpreter load paths will be the same when the code is run as what you think it'll be. But in more pragmatic terms, this is a real issue because many Ruby ORMs for example will add methods that depends on the current state of the databases they connect to, so many typical Ruby applications will actually validly use method names that are not explicitly defined anywhere.
- realharo 12y agoSuch things are usually solved by parsing the structured javadoc-like API documentation for classes and methods in addition to the code itself. At least that's how it's done in the PHP world and it works quite well. Obviously it's not going to cover 100% of the cases, but much better than nothing. Plus it incentivizes you to write this documentation in the first place, which you can then instantly bring up inside the IDE from any place where the method is used.
- syllogism 12y agoWhy though? Why not do it at the language level? When you're returning an error, you can be a bit slow. So why not do some extra computation and return a better error message?
- deleted 12y ago[deleted]
- PaulJulius 12y agoObviously this is a useful tool, and all the power to the author for finding what looks to be an excellent solution, but this line bothers me: >>> Sometimes I wasted hours and hours just because there is one character difference. I hate it. This shouldn't happen. Ever. This should not be a problem anymore. These are the sort of errors that we can catch immediately and should be caught immediately. From looking at the author's GitHub profile, it looks like he uses Emacs, presumably without a plugin that would give him IDE like features. I'm not going to tell him to go use a regular IDE, but it frustrates me that's we can't have those sort of tools available everywhere. (As a vim user myself I have high hopes for the neovim project and look forward to the day when it can be embedded inside a general sort of IDE.)
- jacques_chester 12y agoYuki works at Pivotal Labs in NYC. I work there too. We use whatever editor or IDE any given pair decides to use. In my day-to-day work I've used RubyMine (very popular in our west coast offices), Vim (popular in NYC), Emacs (popular with Mike Dalessio) and my own personal favourite, Sublime Text. I don't think solutions have to be either/or. Yuki's approach is simple and will cover lots of cases.
- rurounijones 12y agoOn the other hand, this gives a consistent experience and does not force people to mess around with plugins for their editor (if needed)
- vidarh 12y agoWhile you can catch some of these, for a language like Ruby, it's an incredibly hard problem to catch all of these errors immediately because the methods that can be called on a given named entity can not in the general case be known by statically inspecting the source, and you can not in general safely instantiate the application because even class definitions are executed and can have side effects, and the methods available can even vary based on environmental factors, such as whether or not you get a database connection, and what's in the database. Consider that it is a common pattern for Ruby ORM's to either use method_missing or dynamically define methods to correspond to the current (at connection time) set of columns present in your database. And "thanks" to the ability to monkey patch and redefining methods, even determining if something "obviously" safe like 42.to_s is not. There's no way for your editor to handle that unless you stand up a version of your app with an instrumented language environment and lets the editor poke around. Now that is possible with tools like Pry, etc., but it takes a lot more work to do safely (because your editor can't know if it can safely start your app).
- octref 12y ago>>> Sometimes I wasted hours and hours just becaue there is one charactor difference. I hate it. "because" misspelt.
- general_failure 12y agoI left a note on this as well. I think it's intentional. Also, there are two typos :-)
- MarcScott 12y agoI think that was intentional.
- ZoF 12y ago'Charactor' is also miss-spelt... It's intentional.
- xutopia 12y agoPretty sure it's intantional.
- brvs 12y agoI would love it if instead of quitting my program with an error, it just went ahead and called the method it thinks I'm referring to. This would remove a lot of unneeded friction from web development.
- rurounijones 12y agoBaaad idea, hides the errors and you have no idea if it will call the correct thing in the future too.
- ZoF 12y agoAgreed with this.
- deleted 12y ago[deleted]
- Too 12y agoThere is actually a python module that does something like that. It goes to the extreme to keep the program running no matter the error you make, arithmetic error are replaced with random results, missing functions skipped, exceptions silently swallowed etc etc. It is obviously a joke but they could benefit greatly from this feature ;)
- rectangletangle 12y agoFor those who are interested, I'm pretty sure this is what you're referring to https://github.com/ajalt/fuckitpy https://github.com/ajalt/fuckitpy. It's worth looking into for the documentation alone.
- Too 12y agoYES! Thank you FuckIt.py uses state-of-the-art technology to make sure your Python code runs whether it has any right to or not. Some code has an error? Fuck it. FuckIt.py uses a combination of dynamic compilation, Abstract Syntax Tree rewriting, live call stack modification, and love to get rid of all those pesky errors that make programming so hard. Still getting errors? Chain fuckit calls. This module is like violence: if it doesn't work, you just need more of it.
- general_failure 12y ago'Sometimes I wasted hours and hours just becaue there is one charactor difference. I hate it.' Not sure if the typos (Yeah, there are two) are intentional but I loved it :-)
- andrewchambers 12y agoThe value of static typing is more and more apparent. Recently I've played with ocaml and F# and it felt great compared to Java or C++.
- theGimp 12y agoAren't Java and C++ statically-typed as well?
- cbd1984 12y ago> Aren't Java and C++ statically-typed as well? Yeah, but not so you'd notice, coming from an ML or Haskell background. /sarcasm More seriously, Java and C++ (and C and Algol before them) fell into the trap of defining "data size specifications" as types: The discontinuity between "long long int" and "int" is one, as is the discontinuity between "float" and "double". The real type difference is between things which are semantically different, like "numeric value used to represent age in years, rounded to integral value", "numeric value used to represent age in days, rounded to integral value", and "numeric value used to represent weight in pounds, rounded to nearest hundredth". Foogol (Algol-derived) languages largely only got this when they embraced Smalltalk-style OO, and they kept their size specification pseudo-types, just to muddy the issue. Size specifications are useful when defining a wire protocol where the overhead of reading and writing an ASCII format with non-trivial syntax would kill your application, such that you need network-header style bits-on-the-wire protocol, and in file formats with similar constraints, but they're ultimately a low-level implementation detail. The way this interacts with tooling like editor autocomplete is that editors can do more for you when they know what kind of data you're passing around, as opposed to just how big it is and other trivialities.
- stretchwithme 12y agoI use Rubymine, which visually indicates when a variable is unused or doesn't exist. It has tons of other features that save you time and hassle.
- alexch 12y agoRubyMine FTW. It's amazing to me how completely Dwarf Fortress -- um, I mean vim and tmux -- have conquered the Ruby dev world.
- prairiedogg 12y agoI've been pairing with ruby / rails developers since 2010 and coming from statically typed languages, it's unbelievable how much time gets spent playing "guess the method name". Even in rich IDEs like RubyMine, the utter lack of context in any given file in rails leaves programmers typing their best guess of a method name, running the tests, rinse, repeat. This solution, while creative and laudable, solves a problem that shouldn't exist. It should either be solved by IDE/tooling in a dynamically typed language or by the compiler in a statically typed language. Stop guessing and let your tools do the hard work of remembering method names for you.
- rectangletangle 12y agoContext sensitive auto-complete is a godsend.
- jMyles 12y agoSeriously. Is there a good list of tools that provide it? In Python, the only one I've managed to love is PyDev. Supposedly Atom does it with the "script" package?
- sjm 12y agoFor Python I use jedi.el for Emacs (http://tkf.github.io/emacs-jedi/latest/ http://tkf.github.io/emacs-jedi/latest/). There's also anaconda-mode (https://github.com/proofit404/anaconda-mode https://github.com/proofit404/anaconda-mode).
- klibertp 12y agoJedi is really good. There are plugins for Vim (of course) too. Personally I believe that things like Jedi - external static code analysers in form of a library - are what we should be doing. It's not good for IDE writers - it lessens vendor lock-in - but for the users it's a win. Having the same, very good, completions in both Vim and Emacs made my life much simpler.
- 12y ago
- WalterBright 12y agoSome years back I put this feature in both the Digital Mars C/C++ compiler and the D language compiler. It's turned out to be popular and very useful. Compiler error messages are steadily improving from mere statements of what is wrong to suggestions for corrective action.
- derefr 12y agoA lot of people are recommending IDE-like tooling--but in truly dynamic language (one with a "living image" with path-dependent monkey-patched behavior that can't be replicated during static analysis, like Smalltalk--or, sometimes, Ruby) there's a more idiomatic way. In a dynamic language, if you're at all unsure of what code you need to write, then you don't write it in your editor in the first place. Instead, you build the expression you need, interactively, at the REPL—and then, once it works, you paste that into your editor. In dynamic languages, the "dead" code in modules is effectively a coagulation of previously "live" REPL incantations; to trust code that was written "dead" to work correctly "live" is madness (or just a recipe for really long iterations involving unit tests.) If you take this approach far enough, though, you do get a sort of IDE—something that manages your expression experiments and the context harnesses they need, and re-runs experiments when you edit their dependent formulae. I am, of course, talking about "notebook" interfaces like IPython's.
- prairiedogg 12y ago"something that manages your expression experiments and the context harnesses they need" This is the exact purpose of tests.
- derefr 12y agoNo: tests don't change, especially iteratively. If you're editing and re-running your tests in a loop (rather than editing and re-running the code in a loop against the tests), then your tests aren't doing anything related to "testing", because you're changing their pass/fail criteria with each edit. To do so is just to abuse a test suite+test runner as a REPL. On the other hand, once you know what you're doing, the expectation can be codified into a test (dead code) to assert that the live code maintains an equivalent property with no regressions. A "finished" IPython notebook can indeed be replaced with a regression test to ensure the behavior remains the way you previously determined it to be via experiment. (Though note that this is subtly different from functional testing: you're not asserting any preconceived notion of how an API "should" respond; you're just asserting that the API seems to hold to a certain contract—the one you discovered from your experimentation—and that it's a regression if it then goes against any of the parts of the discovered contract that you had come to rely upon.)
- jevin 12y agoI think this is an amazing gem. And I'm eager to use it on my Rails projects. On a side note, am I the only one who feels that autocomplete tend to get in the way when I'm coding?
- ASneakyFox 12y agoThe trick is to actually use it. If you auto complete then your coding should be typing 2-3 characters, hit enter, 2-3 characters, enter and so on. It should feel like you're entering hotkeys not typing. Only real typing should be defining variables and methods. Your coding speed can go way up depending on how good the autocomplete is.
- RVuRnvbM2e 12y agoWow. Talk about the wrong approach. When you're having to play trial-and-error to get the right method, you definitely have a problem with your tools - not the language! I don't know about other editors, but vim has great autocomplete support for ruby built right in. Because of this I don't often even type methods out in full anymore. And there's a great plugin for doco too: https://github.com/danchoi/ri.vim https://github.com/danchoi/ri.vim
- flowerpot 12y agoI see you used the Levenshtein algorithm to calculate the suggestions, very cool idea. I've noticed lately that it is being used quite more often than in the past. (may just be my perception)
- whizzkid 12y agoHow about implementing this in a way that it starts guessing method names while typing a method? In this case, you would solve the error while typing it. A simple dropdown with suggestion(s) would be great in Sublime Text.
- skatenerd 12y agoWho's gonna be the first person to hook this into method_missing()
- ChrisAntaki 12y ago> Sometimes I wasted hours and hours just becaue there is one charactor difference. I hate it. Haha, humans are much more able to parse meaning, despite a character being off here or there. Well, you've taken computers one step closer to humans. And you've made programming with Ruby friendlier. Great job!
- ndesaulniers 12y agoWhen I read that line you quoted, I wondered "how did the author ever finish the gem, since it didn't exist yet to help them with their typos?"
- modarts 12y agoOr just use some semblance of static typing and completely eliminate this class of bug.
- bradgessler 12y agoI hope somebody forks this and creates a version that automatically corrects the method for you at runtime. Why even show an error or throw an exception? Bonus if the corrections are cached for performance.
- allyant 12y agoWhat a horrible idea - what if the suggested method wasn't the intended one?
- bhaak 12y agoThis has already been done before: http://decomplecting.org/blog/2013/03/01/code-typos-got-you-down-stop-worrying-with-close-enough/ http://decomplecting.org/blog/2013/03/01/code-typos-got-you-...
- jarin 12y agoHaha this is maybe the worst idea ever.
- crystaln 12y agoHopefully you're joking. As if it wasn't already hard enough to figure out the code path in a ruby application, now we can make it largely indeterminate and dependent on an ever-changing fuzzy algorithm!
- mangecoeur 12y agoThis is really smart, really the sort of thing you wonder why no one thought of it before.
- deleted 12y ago[deleted]
- sleepingspider 12y agoStrange. As an ruby programmer, I never had such a need.
- ryan-allen 12y agoIt's almost like... statically typed languages!
- dankohn1 12y agoCould I also highly recommend making your project Rubocop-clean, and using pronto to run Rubocop on your CI server and make comments on your commits in Github. Rubocop warns against any methods you define that are not used at least once.
- mikecmpbll 12y agoNot sure how helpful this is, when it says there's no method called xyz, it's pretty obvious you called the wrong method, or you called it on the wrong thing. Your first thing should be checking that you didn't call the wrong method name.. which involves looking at the error which repeats the method name that you tried to call, and the object you called it on. Bizarre that this is a genuine hang-up for people.
- deleted 12y ago[deleted]
- thesz 12y agoGlorious Haskell Compiler suggests names for typos too.
- silveira 12y agoA python implementation of "Did you Mean?" by Peter Norvig http://norvig.com/spell-correct.html http://norvig.com/spell-correct.html
- annnnd 12y ago> Here is a good exmaple... Looks like "Did you mean" could be a nice extension to browser textboxes too. ;)
- joshdance 12y agoBlows my mind that IDEs and environments are not better at this. This is something that computers are good at, pattern recognition and scanning the whole file. Of course the it wouldn't work every time, an could make ridiculous suggestions, but I would love the computer to suggest something every time there is an issue. Even if it is wrong 90% of the time, if those guesses don't slow down the programmer the time saved would be huge.
- lnanek2 12y agoJava IDEs are better at this. JavaScript...well I saw NetBeans do it once and was amazed. Ruby...well it's impossible to do correctly as other posters have mentioned.
- imacomputer2 12y ago"Sometimes I wasted hours and hours just becaue there is one charactor difference." Oh thank God! I thought I was the only one.
- germs12 12y agoSeems like a bandaid approach to fixing a severed artery. The real problem is the lack of desire to read documentation. This also has the problem of sending someone down the wrong path when the wrong "solution" is suggested. Read more documentation and pay attention while you're programming.
- amckenna 12y agoI don't think this has to do with a lack of knowledge of documentation, it has to do with simple spelling errors. Quite a number of times I type a method name wrong and upon scanning the code don't see the missing, duplicated, or mistyped letter. This would help a lot with that.
- KedarMhaswade 12y ago"Did you mean?" is great, but "Do you mean?" would be better. Achieving latter in Ruby/JS/... certainly feels harder.