-
Notifications
You must be signed in to change notification settings - Fork 13
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
Improve connect behavior #19
Conversation
zhaocai
commented
Apr 6, 2013
- connect to any Vim server and get the required vimrunner functions sourced.
- open a new vim if the server is not available.
required vim runner functions sourced. 2) open a new vim if the server is not available.
also add filename_escape to edit command! |
failed rspec are related InvalidCommandError. I think ( Tested with MacVim ) Failures:
1) Vimrunner::Client#command raises an error for a non-existent Vim command
Failure/Error: expect {
expected Vimrunner::InvalidCommandError but nothing was raised
# ./spec/vimrunner/client_spec.rb:154:in `block (3 levels) in <module:Vimrunner>'
2) Vimrunner::InvalidCommandError has a useful message
Failure/Error: expect {
expected Exception with message matching /Not an editor command: nonexistent/ but nothing was raised
# ./spec/vimrunner/errors_spec.rb:24:in `block (2 levels) in <module:Vimrunner>' |
@@ -68,10 +67,16 @@ def start | |||
# Public: Connects to the running server by name, blocking if need be. | |||
# | |||
# Returns a new Client instance initialized with this Server. | |||
def connect | |||
def connect(options = {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather not have connect
spawn a new instance. It should be possible, even now, to do something like this:
# if you want to spawn a new server if it's not already there:
server = Server.new(:name => 'FOO')
if not server.connected?
server.start
end
# if you want to wait until someone spawns the server:
server = Server.new(:name => 'FOO')
server.connect
Do you have a use case that this doesn't cover?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have add the (:spawn => true)
option to connect.
# if you want to spawn a new server if it's not already there:
client = Server.new(:name => 'FOO').connect(:spawn => true)
# if you want to wait until someone spawns the server:
client = Server.new(:name => 'FOO').connect
Sorry it took a while to get around to looking at this. The specs are probably failing because you don't have a recent enough version of Vim. Version 7.3 at patchlevel 860 (I think) should work, that patch fixes a bug with error handling with the In any case, thank you for your work :). You found quite a few bugs I'd totally missed. I left you a few comments on the code, could you take a look at them before I merge it in? Some things I can adjust after merging, like coding style and documentation, but the |
@result = yield(connect) | ||
ensure | ||
r.close | ||
w.close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be @r
and @w
. Though, I'd rather remove this change instead, since I'd prefer connect
not to spawn a new instance.
I use macvim, the newest vim has |
about the server = Server.new(:name => 'FOO')
if not server.connected?
server.start
end with client = Server.new(:name => 'FOO').connect(:spawn => true) And the meaning for the option is clear. Anyway, it is up to you to decide. Not a big issue to me. |
It's true that it's shorter, but to me, this makes the Server.new(:name => 'FOO').start
Server.new(:name => 'FOO').connect(:spawn => true) So you can kind of use Everything else currently looks good to me, so after you remove it, I'll merge the PR. |
# if you want to spawn a new server if it's not already there:
server = Server.new(:name => 'FOO')
if not server.connected?
server.start
end still, the meaning of the code above does not intuitively feel right. I have not called |
That's a very good point. Now that I see the code example, it looks strange to me, too, but I think this is an issue of naming. I think a better name for # if you want to spawn a new server if it's not already there:
server = Server.new(:name => 'FOO')
if not server.running?
client = server.start
end
# if you want to connect to a running Vim instance:
server = Server.new(:name => 'FOO')
if server.running?
client = server.connect
else
raise "The server FOO is not started!"
end
# or, of course, in this case you can just try connect, which would block
server = Server.new(:name => 'FOO')
client = server.connect What do you think of this naming? |
compare: def connect(options= {})
server = Vimrunner::Server.new(options)
if not server.running?
client = server.start
else
client = server.connect
end
return client
end def connect(options = {} )
Vimrunner::Server.new(options).connect(:spawn => true)
end Suppose you are not the maintainer of the source code but a user. You just want to connect to a vim server and tell vim the execute sorry, originally I thought it is not a big deal about the In short, I think the API should reduce but introduce burden (examining all kinds of possible situations) to the caller. |
I wouldn't say "all kinds of possible situations" should be expected, but what you describe sounds like a useful enough use case that I would agree with. If it's come to this, though, I'd like to brainstorm some ideas on how to achieve this. @mudge, if you have thoughts on the matter, feel free to weigh in, I'd appreciate your feedback. First is Option 1, your initial implementation. The client = Server.new(:name => 'FOO').connect(:spawn => true) As I mentioned, I don't like this approach much. It puts too much functionality in The idea for client = Server.new(:name => 'FOO').start(:reuse => true) The To me, the common thread is that mixing up A simple Option 3 would be to just reimplement this helper method you demonstrated in the actual library, and call it class Server
def connect_or_start
if running?
connect
else
start
end
end
end
client = Server.new(:name => 'FOO').connect_or_start This has the drawback that you wouldn't really give it options, but then again, you shouldn't -- it's simply a shorthand method to optimize a use case. If you need more complicated calls, you could just implement the logic yourself. I'm not sure how much this is acceptable, though -- neither The last option I can think of at this time, Option 4 is to simply slice them up a bit more. Make # If you want to get the current `connect` behaviour
server = Server.new(:name => 'FOO')
server.wait_until_running
client = server.connect
# If you want to get the current `start` behaviour
server = Server.new(:name => 'FOO')
client = server.start
# If you want to get the new "connect if possible, else start"
server = Server.new(:name => 'FOO')
client = server.connect || server.start Not everything is a one-liner, but it's still quite concise and all of What do you think? Do you still prefer your original implementation, or does one of the other ones look better to you? Any different ideas? |
First of all, a few things I agree on:
optionsoption 2 ,
|
Yes, but that is two things. The fact that there's an "and" in there hints at this as well. Here's something else I realized -- Most of the initialization options actually belong to client = Server.new(:name => 'FOO').start({
:executable => '/opt/bin/gvim',
:foreground => false,
:vimrc => 'my_custom_vimrc'
}) So now, if you call client = Server.new(:name => 'FOO').connect(:timeout => 3, :start => {
:executable => '/opt/bin/gvim',
:foreground => false,
:vimrc => 'my_custom_vimrc'
}) But this is way too many options on a single method, and they change its behavior dramatically. I don't want to burden a single API call with so many responsibilities. There's no need for it considering you can easily make the check yourself. Compare with option 4: server = Server.new(:name => 'FOO')
client = server.connect(:timeout => 3)
if not client
puts "Couldn't connect to an existing Vim, starting server"
client = server.start({
:executable => '/opt/bin/gvim',
:foreground => false,
:vimrc => 'my_custom_vimrc'
})
end This is not more concise, but it's also not much more verbose. It gives you more flexibility over the decisions -- notice the As a side note, I'm starting to think that there might be a need for a different server, something like an
I don't think that checking for server = Server.new(:name => 'FOO')
# If you want to just try connecting to a Vim and it may or may not work, use
# `connect`:
client = server.connect
if not client
puts "Couldn't connect to server 'FOO', doing something else..."
# ....
end
# If you expect to be able to connect to a Vim with the given name, but for
# some reason you fail, then you should just raise by using `connect!` -- it's
# an exceptional situation:
client = server.connect!
client.do_stuff On my side, I'm starting to like option 4 more and more. The As I thought about this, I also remembered the conventions we currently have in place. We have Also, I don't think this is a good place for this discussion anymore. I'd like to merge your code in as it is right now, with your implementation of |
Please go ahead. After your explanation, I am 90% agree with you now. let me know when you finalize the code. |
I agree with the principle of providing simple, composable abstractions and then allowing people to build their own abstraction layers on top. In this case, the fact that I think this is something we're still trying to figure out for Vimrunner: what primitives should it expose and what is its primary use case. Is it an abstraction on top of Vim itself or just an abstraction over remote-controlling Vim (which is a little more specific)? |
Merged, thank you for your work. I've created a new issue to continue the discussion, #22. I won't release a new version, since |
I guess I can't really say. Vimrunner has a lot of convenience over the raw |
A new version has been pushed to rubygems, 0.3.0. |