Running command line commands from Thor executable - ruby

In my executable Ruby file I have the following:
#!/usr/bin/env ruby
require 'thor'
include Thor::Actions
class UI < Thor
# def self.source_root
# File.dirname(__FILE__)
# end
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcalmakecal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start
In the terminal when I run the file as is I get an empty line as Thor's run command is returning a NilClass.
However, when I un-comment the puts `ls ~` and comment out Thor's run method I get an output of my home directory as expected.
I'm having trouble figuring out why I can't get Thor's run method to work like Ruby's ticks.
Any ideas where I may have went wrong?
Thanks for looking

I didn't put the include statement inside my class and that messed things up. The code should be:
#!/usr/bin/env ruby
require 'makecal'
class UI < Thor
include Thor::Actions
# def self.source_root
# File.dirname(__FILE__)
# end
#
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start

Thor's documentation on this method is actually wrong and incomplete. It documents that it returns the "contents of the command" (which I assume means the standard output), but it, by defualt, does nothing.
But, you can, apparently, use the :capture option to get what you want:
unless options[:pretend]
config[:capture] ? `#{command}` : system("#{command}")
end
So, try doing
puts run("ls ~", :capture => true)
And see if that does it.

Related

Make Thor show message for top level command

Is there any way to make Thor show a general message for the top level command?
$my_command help
I'd like to show a welcome message here.
Commands:
my_command help [COMMAND]
The closest thing I can think of is adding a default task and using it to invoke the help task. You'd get this message when calling $my_command with no arguments
require 'thor'
class MyCLI < Thor
desc "hello NAME", "say hello to NAME"
def hello(name)
puts "Hello #{name}"
end
desc "greeting", "this is just a greeting"
def greeting
puts "Welcome to MyCLI"
invoke :help
end
default_task :greeting
end
MyCLI.start(ARGV)
# $my_command
# output:
# Welcome to MyCLI
# Commands:
# test.rb greeting # this is just a greeting
# test.rb hello NAME # say hello to NAME
# test.rb help [COMMAND] # Describe available commands or one spec...

How do i run Ruby script from command line ?

I've a file, which I can run from command line using:
ruby filename.rb
Which outputs:
12345
A different script containing:
def hi()
puts "hello"
end
does not return anything when I run it from the command-line.
How do I run this from the command line?
Add puts hi("John") to the bottom of the method:
def hi(name)
puts "hello"
end
puts hi("John")
Where "John" is whatever name you want it to be.
Then just run it as usual, ruby yourfilename.rb
Try putting this in filename.rb:
def hi()
puts "hello"
end
hi
Then run your code in the command line: with ruby filename.rb

Can't get bash to loop in chef

I am trying to run a loop over array in chef (The loop contains a bash command). Anyone has any idea on this ?
symlink_db = data_bag_item(“my”_db,”my”_db)
source = symlink_db[“sourceFile”]
instances = symlink_db["Instances"].split(',') <---Instances is a comma separated string in Databag
bash "create_link" do
puts "1: #{instances}" <-------Puts all instances correctly
instances.each do |instance|
puts "2: #{instance}" <------ This prints each instance in loop correctly
code <<-EOH
echo "ln -fs #{source} #{instance}"; <----- This is printed only for last instance in the loop
EOH
end
end
Appreciate if anyone can help soon.....Thanks
You need the bash resource inside your loop:
instances.each do |instance|
bash "create_link-#{instance}" do
code <<-EOH
echo "ln -fs #{source} #{instance}"
EOH
end
end
BTW, this is not idiomatic chef. You should simply use the link resource like this:
instances.each do |instance|
link instance do
to source
end
end
An advantage of this approach is that it makes your recipe cross-platform. It's also a lot more readable.

Run def in ruby program

I'm a beginner in programming and wrote this little program:
Test.rb:
# encoding: utf-8
require 'open-uri'
require 'nokogiri'
def parse_file
doc = Nokogiri::XML(File.open("test.xml"))
parse_xml(doc)
end
def parse_xml(doc)
doc.root.elements.each do |node|
parse_tracks(node)
end
end
def parse_tracks(node)
if node.node_name.eql? 'kapitel'
puts 'New Kapitel'
end
end
I know how to execute this code:
ruby test.rb
But how can I call the def parse_file?
Simply add whatever you want to the end of your file. Ruby scripts are simply scripts, they are being interpreted:
…
end
parse_file # ⇐ HERE YOU GO
You can either call the method at the end of your test.rb file:
def parse_file
# ...
end
parse_file
And run it with
$ ruby test.rb
Or leave the file as it is, require it as a library and call the method manually:
$ ruby -r test.rb -e "parse_file"
Rather than hard-coding your file path, you can pass it as an argument when calling your script. Arguments can be accessed via the ARGV array:
def parse_file(file)
doc = Nokogiri::XML(File.open(file))
parse_xml(doc)
end
parse_file(ARGV.first)
Now you can run it with:
$ ruby test.rb test.xml
Another option is to make the script executable. Add a shebang as the first line of you file:
#!/usr/bin/env ruby
And set the execute flag:
$ chmod +x test.rb
Now you can run it with:
$ ./test.rb test.xml
just add
parse_file
in the end of your ruby file

Checking if a Ruby program was executed or imported via require

How do you check if a Ruby file was imported via "require" or "load" and not simply executed from the command line?
For example:
Contents of foo.rb:
puts "Hello"
Contents of bar.rb
require 'foo'
Output:
$ ./foo.rb
Hello
$ ./bar.rb
Hello
Basically, I'd like calling bar.rb to not execute the puts call.
Change foo.rb to read:
if __FILE__ == $0
puts "Hello"
end
That checks __FILE__ - the name of the current ruby file - against $0 - the name of the script which is running.
if __FILE__ != $0 #if the file is not the main script which is running
quit #then quit
end
Put this on top of all code in foo.rb
For better readability you can also use $PROGRAM_NAME
if __FILE__ == $PROGRAM_NAME
puts "Executed via CLI #{__FILE__}"
else
puts 'Referred'
end
More info: What does __FILE__ == $PROGRAM_NAME mean in ruby?

Resources