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.
I then write my code in the REPL. I can use 'ls' to look up available methods dynamically. Complex ActiveRecord queries are much easier to prototype. Finding the right method isn't usually too difficult. And pry supports prefix completion at the first level. Assign the result to a variable, and you can do more completion at the next level.
For loops and if-branches, I typically take the bit of data that is relevant to the loop body or that if branch, and work with it separately, to develop that branch. But it's more usual for me to use map and select than explicit loops in any case.
I copy each finished line of code from the repl into my editor, as and when I'm happy with it.
This method of working is also why I don't see any benefit from using RubyMine. I use emacs, and primarily I rely on global project regex (using helm-git-grep and helm-projectile) to navigate the system.
(A happy coincidence is that the default readline key bindings are emacs style, so a lot of what you learn in emacs maps straight over to the repl terminal.)
def foo(x): return x
a = foo("hello")
b = foo(34)
To infer the methods that you can call on `a` and `b` you have to trace through the `foo` function. You can't just run `foo` because what if the input is unknown or what if `foo` contains a loop or is recursive? def foo(x, i):
if i == 0: return x
else: return foo(x, i-1)
i = int(read_input())
a = foo("hello",i)
b = foo(34,i)
It gets even worse when you have a huge codebase, monkey patching, eval, and other features like that (which Rails uses in copious amounts).And yet, Hindley-Milner can do it. In general.
I've been working with dynamic and nontyped and weak typed and duck typed languages for over half of my life and you know what, it's getting ridiculous. They were never meant to support the team and project sizes we're forcing them into now.
Contrast with some Java I was doing recently (granted, without a Java IDE) and I found the whole cycle painfully slow. Even things the compiler picked up were a magnitude slower to find than when I was in ipython. And then there were plenty of things the compiler wouldn't get, which could take a good minute for me to discover from the time I made the edit. It's insane to me that people don't work in a REPL.
That's not to say it's a bad language per se, but as someone who works in lots of different languages, I find ruby to be the one where I'm most likely to fail to guess correctly and have to spend time looking up the method I want.
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.
Pry lets you call "binding.pry" anywhere in your program to dump you into a shell within that context, with full access to local variables etc.. And tab-completion and plenty of introspection features. I frequently find myself triggering Pry in the middle of handling http requests if something doesn't work, for example. Letting me inspect the environment, modify stuff, and when I exit the request is completed.
It can also do things (with some limitations) like bring up an editor to where the current method was defined, and let you edit and reload the code.
And you can attach to it remotely using Drb in case the app in question doesn't run attached to a terminal.
At this point it's almost criminal to do Ruby development without Pry.
TBH if I was writing anything large enough for this kind of stuff to get out of hand, I would seriously consider a statically typed language like Golang or C#/F#(which both have absolutely fantastic tooling). REPL's don't help the next person to come along figure out what your methods are taking in and what those calls return. But I digress.
I don't always cut Ruby, but when I do I cut it with Pry... Yeah.
def do_something
return binding.pry
do_something_but_does_not_work
end
result = do_something
process result
It might be very convenient if I put 'return binging.pry' just before the broken code. I can interactively fix the broken code and continue run outside of current method.I remember using it on my Smalltalk days at the university in 1996.
Of non-Smalltalk languages, the only one I can think of with anything like that is Erlang. You could easily enough build a code server in Ruby, but you'd have to explicitly include the library that implements it in your project, and start up a server thread to expose it to an IDE that wanted to talk to it, etc. And because of that, it wouldn't be "part of the language" to the point where tooling (like IDEs) would be built to expect it.
The real problem, though, is that people are coding in dynamic languages with no live image connected to the editing session at all: instead, the code is just dead text until they want to test it, at which point it gets injected into a fresh session, run once, and then the session is immediately discarded (creating what is possibly a completely different path-dependent monkey-patch execution sequence than would happen in production, or in a REPL, or...).
For some languages this happens out of necessity, but for most, it's just an artifact of the batch-processing mentality. All e.g. Light Table gives you, when you think about it, is a text editor with a connection to a live Clojure or Python image; and yet to many it seems to be a completely foreign interaction paradigm for programming.
Maybe you pasted some things in the wrong order, or maybe you redefined a function, but some data that was created using the old version of the function is still in the image.
If this is possible in your programming environment, then maybe the dead code is not worth keeping around, and we should only retain the live image.
In which case we need tools to version and diff and branch a live image.
Does a programming environment like that exist I wonder? Or do image based environments like Smalltalk let you export an image as text, like a DB can dump all the SQL required to recreate it?
Simple Smalltalk implementations are in 4 parts: the Smalltalk VM, the Smalltalk image file, the sources file and the changes file.
The image contains compiled code and objects, the sources file contains source code for some of the compiled code in the image (at least the source code provided by the vendor), and the changes file contains a log of changes made using the IDE.
Re-doing the changes recorded in the changes file should be sufficient to recreate the image up-to the last change.
In the late '80s multi person configuration management systems were developed for Smalltalk, see --
http://books.google.com/books?id=odx8WIDOcyIC&lpg=PA136&ots=...
Does anyone know an effective way to do this in the browser, with JavaScript?
Incidentally Dan Ingalls was a member of the original Smalltalk project.
This is the exact purpose of tests.
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.)
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/l...
http://decomplecting.org/blog/2013/03/01/code-typos-got-you-...
Compiler error messages are steadily improving from mere statements of what is wrong to suggestions for corrective action.
>>> 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.)
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).
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.
In dynamic languages you can't do this because you don't know the type that any given identifier is pointing to. The type could be completely arbitrary, I.E. coming from external input. You might think, "oh, well you could just check against all possible methods", and you'd be right, except for Ruby. Ruby allows you to override what happens when you call an undefined method, (method_missing) letting you execute completely arbitrary code that lets undefined methods look just like methods. You could call car.start_and_drive_to_the_bank, and set up the Car type so that it can handle methods like that, (perhaps calling car.start, and then car.drive(bank)) along with .start_and_drive_to_the_mall and whatever. In practice that's bad Ruby, but you still have to be able to handle that, Bad Ruby is still Valid Ruby.
So there's just no way to tell in Ruby whether any given method call is correct or not.
I have an idea to conventionalize method_missing overrides so that they're easier to analyze. Maybe define a regular expression on the class so that the analyzer can sort out what's likely to work at runtime and which messages aren't. Not sure how well it would work until Matz manages to implement static typing as he wants to do in the future. Until you can tell whether any given identifier is likely to be of a type that overrides method_missing, you'd be running the method_missing analyzer for all types on all method calls.
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.
Still, props for the work.
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.
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.
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?
On a side note, am I the only one who feels that autocomplete tend to get in the way when I'm coding?
Only real typing should be defining variables and methods.
Your coding speed can go way up depending on how good the autocomplete is.
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!
Not sure if the typos (Yeah, there are two) are intentional but I loved it :-)
Bizarre that this is a genuine hang-up for people.
It has tons of other features that save you time and hassle.
The first time he tried to compile with it, he used a program of roughly "Hello from PL/1". When he ran it, he got a division by zero error, because his string had been turned into an arithmetic expression. With the 1 turned into an I, which was then an unitialized variable, which then defaulted to 0.
Except you can find "On Error Resume Next" in "production" code. If I ever consider taking contracts doing Visual Basic, the contract will specify that any occurrence of "On Error Resume Next" automatically doubles my daily rate.
https://en.wikipedia.org/wiki/DWIM
>Critics of DWIM claimed that it was "tuned to the particular typing mistakes to which Teitelman was prone, and no others" and called it "Do What Teitelman Means" or "Do What Interlisp Means." - Guy L. Steele Jr., Richard P. Gabriel, "The Evolution of Lisp"
The person who bastardized and maintains the Jargon file is a racist, sexist nut job who built his career on attacking the Free Software movement, and who doesn't deserves anyone's respect or attention: http://rationalwiki.org/wiki/Eric_S._Raymond
Bonus if the corrections are cached for performance.
http://decomplecting.org/blog/2013/03/01/code-typos-got-you-...
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!
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
Looks like "Did you mean" could be a nice extension to browser textboxes too. ;)
In this case, you would solve the error while typing it.
A simple dropdown with suggestion(s) would be great in Sublime Text.
"because" misspelt.