Use "global" Thorfile - ruby

I want to use Thor with thor-scmversion to bump the version of my Chef cookbooks. The normal way of using Thor is to create a Thorfile in the project folder and have tasks implemented in there. For my use case I would have to create a Thorfile in every cookbook I write containing only
require 'thor/scmversion'
My question is, whether I can somehow put such a file in a "global" directory and point to it, when I run thor on the command line from within my project folder.
Edit
I followed #coderanger's advice and used thor install Thorfile. This creates a directory .thor in the user's home directory (in my case: /var/lib/jenkins/.thor) and a thor.yml file that includes a reference to the Thorfile I added with the upper command.
When I now run thor list, I get
$ thor list
version
-------
thor version:bump TYPE [PRERELEASE_TYPE] # Bump version number (type is major, minor, patch, prerelease or auto)
thor version:current # Show current SCM tagged version
but running thor version:current, I get the following error:
Could not find command "version:current".
So probably I missed something?

You can use thor install to set up a system-wide task. Bear in mind this might make things more difficult for other people since it won't be set up in git for them.

Related

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.

How to develop a Ruby GEM without having to install it first?

I'm developing a GEM that I've forked and I'm trying to modify it slightly for my app.
I'm finding it difficult and time consuming because for every change I make I have to
uninstall
build
re-install
run the app
Is there an easier way of which doesn't require repeating all steps above?
To use it in some app using bundler
If what you mean is for using it in a app to test it / use it, you can just specify a path for your gem or even point to a git repo in the Gemfile http://gembundler.com/gemfile.html
Like
gem "mygem", :path => "~/code/gems/mygem"
To use it as a standalone gem. i.e: like rspec or rake that can run outside of an app.
Just specify the path to your gem binary when running the gem command, like:
$ ~/path_to_my_gem/bin/mygem some args
If you can execute inside your gem directory (i.e: the command does not create files in the current directory, or needs any specific files from the current directory), just do this:
$ ./bin/mygem some args
Note that this last one is just for future reference, I think it's not applicable in the OP context.
use require_relative to include your files:
require_relative 'yourgem/yourclass'
This is the documentation for the function.

How to make Thor find templates for system installed .thor files?

I've created a .thor script for setting up a new ruby project just the way I like it. I'm using the Thor::Actions directory command to build the app entirely from a template directory structure, as opposed to defining them inline with heredocs. The script directory looks something like this:
rubynu.thor
template/
bin/
lib/
%app_name%.rb.tt
%app_name%
README.markdown
.gitignore
...
This works really great, and lets me easily visualize and change individual parts of the template as my taste changes.
But I can't figure out a nice way to get thor to find the template directory once the .thor file is system installed using thor install rubynu.thor. Install sticks a copy of the .thor file into ~/.thor but ignores the template/ directory, and so the templates aren't found anymore.
I don't want to hardcode the source_root path or manually copy over the template directory to ~/.thor. Is there something built-in to thor that handles installing templates along with the .thor file? It would be great if they could be packaged together when installed.
If not, what is the nicest way to get around this? Surely there are system installed thor tasks somewhere that use template files. How'd you do it? I suppose I could bypass thor install and provide this as a gem (though that seems like overkill), or bite the bullet and stick all the template definitions inline in a giant .thor file (less pleasant to make changes to the structure later).
For reference, here is the simple .thor file I'm using:
class Rubynu < Thor::Group
include Thor::Actions
argument :app_name
def self.source_root
File.dirname(__FILE__)
end
def apply_directory_template
directory 'template', app_name
end
end
Thanks!
If you set up your .thor file like this:
<my_thor_commands>/
templates/
bin/
lib/
...
main.thor
thor install <my_thor_command> will look for a file called main.thor, and then install it and anything else in <my_thor_command>. After that, you can rely on:
def self.source_root
File.dirname(__FILE__)
end
which will give you the path to the <my_thor_command> as it was installed.

New gem with Bundler, from a class

When we run the bundle gem new_gem command, a directory is created with those files:
create new_gem/Gemfile
create new_gem/Rakefile
create new_gem/.gitignore
create new_gem/new_gem.gemspec
create new_gem/lib/new_gem.rb
create new_gem/lib/new_gem/version.rb
By default, the file new_gem/lib/new_gem.rb is a module named NewGem.
My question is the following: how can I do if NewGem is a class? Rather then having NewGem::NewGem, I would like to just define this class (without a root module).
I tried to just replace module by class inside this file, and then make a local gem in order to test it, but after its installation, I can not load it in IRB (with require 'new_gem').
Thanks for your help.
You should ask yourself why you want to do this. The module is there to namespace your gem's code. Typically to provide a context for all the classes within, but even in a single class gem, this would help to provide conflicts with other code out in the world.
Unless your class is named SomethingThatCouldNeverPossiblyBeDefinedAnywhereElse, leaving that module in place is probably a good thing. And regardless of that, leaving the module intact is still a good thing as it's the convention, and what people expect when examining/using your code.
With that in mind, there are a few things you'd need to do if you wanted a single class gem.
The generated gemspec wants to require 'new_gem/version' to find it's version number. Change that to simply require 'new_gem'.
The gemspec also lists its contained files using git ls, and the generated gem package already has new_gem/version included in the pre-built git repo. Remove this:
git rm lib/new_gem/version.rb
Change your new_gem module to a class, as you did previously.
Remove the generated version.rb require from your class, and instead define the version there, e.g.:
class NewGem
VERSION = '0.0.1'
end
Finally install the gem via rake install. You won't be able to load it in IRB until you've done this.

Using thor for complex command line tool

i want to create a command line tool in Ruby using Thor. This tool should be packaged as a gem so that it is easily installed and uninstalled.
Creating and publishing the gem, I have done. I also created several Thor scripts which also work. However, I do not know how to combine them.
My aim is to be able to call my tool the following way:
mytool task param --options
mytool taskgroup:task param --options
I know how to make one Thor script to be executable. However, how do I make a bunch of thor scripts accessible throw one command?
According to the relevant Gem documentation, you could specify (in your .gemspec):
spec.executables = ['bin/foo', 'bin/bar']
spec.default_executable = 'bin/bar'
and have your gem install a bunch of executables (foo and bar). Or you write a wrapper for all your Thor scripts and specify:
spec.executables = ['bin/wrapper']
and have your gem install only one executable (wrapper).
The teletype gem (https://github.com/piotrmurach/tty) does an amazing job at setting up all the scaffolding for this. Create your project with teletype and then just fill in the implementation.

Resources