rvm is a shell command and its Ruby setting applies only to the current instance of the shell. So when you run sh "rvm use #{ruby_v}" you're changing the rvm version of the shell that you have invoked, and then exiting from that shell.
In addition, your Ruby program is an operating system process running the Ruby virtual machine, so when you make the call to RSpec::Core::RakeTask.new(:spec), you're still in that same OS process and Ruby version with which you started your script.
You'll need to run the rspec tests in the shell that you invoke and change the Ruby version on. I thought something like this would work:
`rvm use #{ruby_v}; rspec spec`
...but as you pointed out, it does not. You need to run the new shell as a "login shell" so that rvm is set up correctly. In addition, the new shell must be told that the thing you're invoking is a shell command and not a script or binary executable. In other words:
1) have your command explicitly invoke bash or zsh (sh did not work for me on my Mac).
2) specify (probably with -l) that it is a login shell.
3) specify (probably with -c) that you are executing a shell command (rvm) and not a script or executable.
I am using zsh as my shell, but you should be able to substitute bash in the code below and it should work (and of course put your rspec command in there):
2.3.0 :024 > puts `zsh -lc "rvm current"`
ruby-2.3.0
=> nil
2.3.0 :025 > puts `zsh -lc "rvm use jruby; rvm current"`
Using /Users/kbennett/.rvm/gems/jruby-9.0.5.0
jruby-9.0.5.0
=> nil
2.3.0 :026 > puts `zsh -lc "rvm current"`
ruby-2.3.0
=> nil
/usr/local/rvm/wrappers/ruby-2.1.1@projectX/rakeshould work (you have to adjust the path) - Stefanbashorzsh. Also the output appears on screen as soon as it's generated. - Lokesh