Adding files when installing a gem - ruby

I'm writing a gem which needs a directory to store some config. I want to do this upon installation but I'm not sure how best to insert code into the installation process.
By adding the code to the Rakefile and adding spec.extensions = ["Rakefile"] to my gemspec, I've achieved what I want to do but this method means the installation process tells me I'm building native extensions; this is misleading.
Is there a built in way of doing this or via bundler? I'm assuming Bundler::GemHelper.install_tasks is close to what I'm after but I can't find helpful documentation.
EDIT: My current Rakefile.

It seems like the RubyGems designers intentionally left the option to run a script during installation... so I would say that the accepted way is to do the directory creation in the application.
The unix way is for the application to create the directory (vi and git do this).
FileUtils.mkdir_p is handy... it will save you from having to check if the directory is already there.

Related

How to enforce bundle install location

I come from a Python and JavaScript background.
When developing a JavaScript project, dependencies are installed in a node_modules directory in the project root.
When developing Python project, typically virtualenvwrapper is used. In this case dependencies are installed in a virtual environment, which is located in ~/.virtualenvs/<project_name> by default.
Now I need to use a ruby tool for a project. The tool that appears to be the most promising for a similar setup as described above, is bundler.
However, the default installation location for bundler is system-wide. I consider this to be harmful.
For one of my systems, it will prompt for a password, at which point I can still abort.
However, for my other system I can write into the global ruby installation. I'm using a homebrew installed ruby here. Bundle will just install dependencies globally.
I know I can specify the installation location by adding --path, but this is easy to forget.
One way to enforce an installation path is by committing .bundle/config. It would just have to contain this:
---
BUNDLE_PATH: "."
However, some googling around shows that it's not adviced to commit this file.
What is the recommended way to prevent accidental global installations using bundler?
Who's to say it will be accidental? It really depends on what context you're talking about here. I have my Ruby set up so that bundle install works without requiring sudo, it's all done through rbenv automatically. The same is true with rvm if done as a user-level install.
When it comes to deploying apps and you want to make sure it's deployed correctly, that's where tools like Capistrano come into play: Create a deployment script that will apply the correct procedure every time.
Checking in a .bundle/config is really rude from a dev perspective, just like checking in any other user-specific preferences you might have. It causes no end of conflict with other team members.

Gem creation: run code on installation

I want to create a gem that installs some binaries on "/usr/local/bin". In order to work, I need to run some "cp"/"ln"/"chmod" commands when the user (me) runs gem install mygem.
Is there any callback/method that is called at the installation and that I can override it?
UPDATE:
I found a better way to achieve it: gemspec has a section to add binary files on the system. I put the answer below, but I still wonder how to run code after/before gem installation.
See this https://github.com/rubygems/rubygems/issues/608 you have to run the default task after installation
I found a better way to achieve it: gemspec has a section to add binary files on the system.
Eg:
spec.bindir = "bin"
...
spec.executables << 'your_app'
Then, put your_app in bin.
PS: I'm the OP, but I will not accept this as solution because I still wonder how to run code after/before gem installation.

Creating Ruby gems with same name executables?

I want to have a Ruby Gem that will have the same executable as another Gem.
When called with command args it will either do something, or pass the command on to the other Gem.
The first problem I have is that it isn't able to run two same named executables. I get this error:
Bundler is using a binstub that was created for a different gem. This is deprecated, in future versions you may need to bundle binstub yourgem to work around a system/bundle conflict.
How can I have Gems with the same named executables and ensure that the target one executes?
You cannot rely on Bundler or Rubygems to manage this for you. All it does it copy an executable that you specified in your gem spec to its bin/ directory.
The first problem you'll have is that the executable that runs may be dependent on the order in which the gems were installed which you can't guarantee.
Another problem that you'll have is that you cannot execute code on gem installation so you will be unable to run code that would try to automate this set up for people who install your gem.
I believe your gem should provide a non-conflicting executable. You can then supply post install instructions in your gem spec that are displayed to a user installing the gem, in the README, in a blog post, etc. you can tell the user that they need to set up an alias that points to your executable. In all shells that I'm aware of aliases will be executed before filesystem executables.
For the times when people want to bypass your alias and execute the original executable you can tell people to escape the command, e.g. \original-gem. That bypasses alias and function lookup in most shells and will allow users to have your super awesome version as the default (thru the alias) and a way to easily access the original.

What can I remove from Ruby and still have it support Rake/gems?

I'm building a large .NET project using Rake . We committed the Ruby environment to our source control and install gems to this "local" environment (like Albacore, Nokogiri, etc). We're essentially following this guidance, using the RubyInstaller for Windows zip package.
trunk/
source/
packages/
ruby/ <-- ruby here!
build.bat <-- helper scripts (call Ruby/rake)
Solution.sln
However, our source control server is remotely hosted, on a virtual machine, and the link speed is slow. I've read that some people have trimmed down the Ruby environment, like in the Machine.Specifications project. But, that looks extreme! (is there even gem support there?)
I could just start deleting files and directories to see what works, but there must be some known set of files that can be removed and still support basic Ruby, Rake, and gems?
From my own experimentation and investigation, it's kind of hard to determine what's "required" and what's optional. There are some files that appear very safe and easy to remove and others that I'd rather not play with. My results below only save about 5 MB... probably not enough to warrant doing this at all.
bin
The ruby/bin directory contains many batch scripts that are simply helpers to invoke the ruby executable with the correct "applicaton", like Rake or Gem. For example, rake.bat contains this line
#"%~dp0ruby.exe" "%~dpn0" %*
You can replace this with the right comamnd in your build.bat script (assuming it's "up" one level above the ruby environment, probably at the solution root)
#"%~dp0ruby\bin\ruby.exe" "%~dp0ruby\bin\rake" %*
You could dump the rest of the batch scripts, but then you'll have a little more trouble installing gems into the local environment.
cmd> ruby\bin\ruby.exe ruby\bin\gem install <whatever>
And, as of Ruby 1.9.3, that's only saving you 1.38KB. I'm sure some of those other non-extension files in this directory can be removed, but, without knowing what they do, it's unsafe to proceed.
include (175 KB)
The ruby/include directory appears to contain only C header files for developing against Ruby (I'm winging it here). I removed it and everything ran fine.
lib/tcltk (4.7 MB)
The ruby/lib/tcltk looks a lot like the include directory, but for Tcl programming.
lib/ruby
The ruby/lib/ruby directory contains the gems for this installation and a whole lot more scary stuff. I'd stay out of this directory unless you want to inadvertently cripple your environment.
share (27 KB)
The ruby/share directory appears to contain only help pages, dump 'em!

How to develop a gem in staging environment?

I am trying to hack through a forked gem (buildr). As such I cloned it from github and began to butcher the code. The official gem is installed on my system (under /usr/lib/ruby.../gems/buildr...). There is an executable which I need to use in my dev process - buildr.
Now I want the buildr executable and the library to point to my forked repo and not the default gem installation. This would be for this gem only. As such, the changes I make against the forked repo is usable directly for testing and so forth.
I would guess I need to load my library prior to the system gem loading. Can somebody recommend the best way to do so?
I did something similar for work when the Spreadsheet gem broke backward compatibility. I put the previous versions code in it's own module and just renamed the gem my-spreadsheet and installed that (I really wanted some of the features of the new gem but I also didn't want to rewrite all my previous code at that point).
If it's just a binary you want to override you could always do some PATH magic, setting the directory of your binary first and thus make sure you always override. But personally I'd prefer making my own copy with a new name and installing that.
you could bump the version in the gemspec for your fork. Then when you install your version of the gem, it will use your (newer) version by default.
change buildr.gemspec
#...
spec.version = '1.3.4.dev'
#...
Then
$ gem build buildr.gemspec
$ sudo gem install buildr-1.3.4.dev.gem
and it should work.

Resources