rails - Redirecting console output to a file - ruby-on-rails

On a bash console, if I do this:
cd mydir
ls -l > mydir.txt
The > operator captures the standard input and redirects it to a file; so I get the listing of files in mydir.txt instead of in the standard output.
Is there any way to do something similar on the rails console?
I've got a ruby statement that generates lots of prints (~8k lines) and I'd like to be able to see it completely, but the console only "remembers" the last 1024 lines or so. So I thought about redirecting to a file - If anyone knows a better option, I'm all ears.

A quick one-off solution:
irb:001> f = File.new('statements.xml', 'w')
irb:002> f << Account.find(1).statements.to_xml
irb:003> f.close
Create a JSON fixture:
irb:004> f = File.new(Rails.root + 'spec/fixtures/qbo/amy_cust.json', 'w')
irb:005> f << JSON.pretty_generate((q.get :customer, 1).as_json)
irb:006> f.close

You can use override $stdout to redirect the console output:
$stdout = File.new('console.out', 'w')
You may also need to call this once:
$stdout.sync = true
To restore:
$stdout = STDOUT

Apart from Veger's answer, there is one of more way to do it which also provides many other additional options.
Just open your rails project directory and enter the command:
rails c | tee output.txt
tee command also has many other options which you can check out by:
man tee

If you write the following code in your environment file, it should work.
if "irb" == $0
config.logger = Logger.new(Rails.root.join('path_to_log_file.txt'))
end
You can also rotate the log file using
config.logger = Logger.new(Rails.root.join('path_to_log_file.txt'), number_of_files, file_roation_size_threshold)
For logging only active record related operations, you can do
ActiveRecord::Base.logger = Logger.new(Rails.root.join('path_to_log_file.txt'))
This also lets you have different logger config/file for different environments.

Using Hirb, you can choose to log only the Hirb output to a text file.
That makes you able to still see the commands you type in into the console window, and just the model output will go to the file.
From the Hirb readme:
Although views by default are printed to STDOUT, they can be easily modified to write anywhere:
# Setup views to write to file 'console.log'.
>> Hirb::View.render_method = lambda {|output| File.open("console.log", 'w') {|f| f.write(output) } }
# Doesn't write to file because Symbol doesn't have a view and thus defaults to irb's echo mode.
>> :blah
=> :blah
# Go back to printing Hirb views to STDOUT.
>> Hirb::View.reset_render_method

Use hirb. It automatically pages any output in irb that is longer than a screenful. Put this in a console session to see this work:
>> require 'rubygems'
>> require 'hirb'
>> Hirb.enable
For more on how this works, read this post.

Try using script utility if you are on Unix-based OS.
script -c "rails runner -e development lib/scripts/my_script.rb" report.txt
That helped me capture a Rails runner script's very-very long output easily to a file.
I tried using redirecting to a file but it got written only at the end of script.
That didn't helped me because I had few interactive commands in my script.
Then I used just script and then ran the rails runner in script session but it didn't wrote everything. Then I found this script -c "runner command here" output_file and it saved all the output as was desired. This was on Ubuntu 14.04 LTS
References:
https://askubuntu.com/questions/290322/how-to-get-and-copy-a-too-long-output-completely-in-terminal#comment1668695_715798
Writing Ruby Console Output to Text File

Related

Rake task to change all occurances of a method in a project

I am trying to write a rake task to rename all occurrences of a method in a ruby project. I have achieved this using the following command from the command line.
Basically
retention.group_by('bla').count
needs to be changed to
retention.group_by('bla').size
I managed to achieve this uisng the following from the command line
find . -name \*.rb -exec ruby -i -p -e "gsub(/(group_by(\(([^\)]+)\))).count/, '\1.size')" \;
I am now trying to do this from a rake task to make it straight forward to change in all our projects. Which is the easiest / most elegant way to do this ? Think I am close, its just selecting all files in a project directory I am stuck on.
This did the trick
namespace :rename do
task :gb_count_rename do
Dir.glob("**/*.rb").each do |file_name|
text = File.read(file_name)
content = text.gsub(/(group_by(\(([^\)]+)\))).count/, '\1.size')
File.open(file_name, "w") { |file| file << content }
end
end
end

Capture output of shell command, line by line, into an array

I want to capture the total number of rubocop offenses to determine whether my codebase is getting better or worse. I have almost no experience with ruby scripting.
This is my script so far:
#!/usr/bin/env ruby
#script/code_coverage
var = `rubocop ../ -f fuubar -o ../coverage/rubocop_results.txt -f offenses`
puts var
So I ./rails-app/script/code_coverage and my terminal displays
...
--
6844 Total
When I var.inspect I get a long string. I want to either read the output of rubocop ../ -f ... line by line (preferred) or capture each line of output into an array.
I would like to be able to do something like this:
var.each |line| do
if line.contains('total')
...
total = ...
end
Is this possible? I guess this would be similar to writing the output to a file and and then reading the file in line by line.
If you want to keep it simple, you can simply split your var string.
var = `rubocop ../ -f fuubar -o ../coverage/rubocop_results.txt -f offenses`.split("\n")
Then you can iterate on var like you wanted to.
use open3 library of ruby. Open3 grants you access to stdin, stdout, stderr and a thread to wait the child process when running another program. You can specify various attributes, redirections, current directory, etc., of the program as Process.spawn.
http://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html
require 'open3'
# Run lynx on this file.
cmd = "lynx -crawl -dump /data/feed/#{file_name}.html > /data/feed/#{file_name}"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
cmdout = stdout.read
$logger.debug "stdout is:" + stdout.read
$logger.debug "stderr is:" + stderr.read
end

Rails console history command (via pry) -- can it be grepped or tailed?

In Rails 4 rails console I can type history and it will behave just like the history command from the bash shell. E.g.:
[25] my_rails_project ยป history
1: Nomination
2: {:ad => "asdfsdasadf"}
3: Nomination.count
4: Nomination.count.to_sql
5: Nomination.all.class
6: Nomination.all.to_sql
...
Is there a way to search that history, e.g. history | grep Nomination? How about tail?
Note: When I initially wrote this question I thought the history command came from Rails itself, but it comes from the pry gem which I have in my system (my Gemfile specifies the jazz_hands gem which pulls in pry). Pry does in fact have a grep feature, e.g. history --grep Nomination will give me lines 1 and 3-6 above. It also has a tail feature. These are documented here: https://github.com/pry/pry/wiki/History
You can use ~/.irb-history for this purpose. So, the following can be used (you must be knowing how to do this, but this is only for reference):
tail -fn0 ~/.irb-history # for tailing
cat ~/.irb-history | grep something # for searching
Note that, you might have both the files: ~/.irb-history and ~/.irb_history, and any one of them can be more up to date than the other. I have not been able to resolve this mystery yet. So, use the one you find more suitable for yourself.
UPDATE: You can access history in a variable using the following logic (it took me a while to read the code Pry uses, try edit history inside pry):
def pry_history
arr = []
history = Pry::History.new
history.send(:read_from_file) do |line|
arr.push line.chomp
end
arr
end
Now, you can simply call pry_history to get an array of pry's history. You can further save it inside your .pryrc configuration file and use it whenever you want in pry.
Go to rails console
press <ctrl> + r and type few letters of the command.
use <ctrl> + r to choose other commands that match the search
use <ctrl> + <shift> + r to choose the command in the reverse direction
Exactly like the <ctrl> + r in bash shell
Probably this is what you are looking for:
def search_history(filter)
puts `cat ~/.irb-history | grep "#{filter}"`
end
It's worth noting that if you are using pry then the history file will be located at ~/.pry_history. You may also come across this history file .byebug_history.
I've added the following commands to my ~/.pryrc config file.
Pry.config.commands.alias_command 'find.history', 'hist -G'
Pry::Commands.command 'search.history', 'filter commands in the history using fzf and output the selected command' do
puts `cat ~/.pry_history | sort | uniq | fzf --tac --tiebreak=index --height=20`
end
Pry::Commands.command 'search.history.run', 'filter commands in the history using fzf and execute the selected command' do
_pry_.input = StringIO.new(`cat ~/.pry_history | sort | uniq | fzf --tac --tiebreak=index --height=20 | perl -pe 'chomp if eof'`)
end

Display terminal output on web browser?

Here is my case:
I want to use a web browser to connect to a Rails application that runs this example code on the server side:
Dir.chdir path_typed_in_by_user
system "ls -la"
I want the output of "ls -la" to be displayed on the web browser.
Is this possible somehow?
This links may help you run command line command into ruby ...
http://zhangxh.net/programming/ruby/6-ways-to-run-shell-commands-in-ruby/
Calling shell commands from Ruby
http://blog.jayfields.com/2006/06/ruby-kernel-system-exec-and-x.html
%x[command].each do |f|
value = f
end
try in a controller:
Dir.chdir path_typed_in_by_user
#out = system `ls -la` # !! look here !! " change `
in a view:

unix at command pass variable to shell script?

I'm trying to setup a simple timer that gets started from a Rails Application. This timer should wait out its duration and then start a shell script that will start up ./script/runner and complete the initial request. I need script/runner because I need access to ActiveRecord.
Here's my test lines in Rails
output = `at #{(Time.now + 60).strftime("%H:%M")} < #{Rails.root}/lib/parking_timer.sh STRING_VARIABLE`
return render :text => output
Then my parking_timer.sh looks like this
#!/bin/sh
~/PATH_TO_APP/script/runner -e development ~/PATH_TO_APP/lib/ParkingTimer.rb $1
echo "All Done"
Finally, ParkingTimer.rb reads the passed variable with
ARGV.each do|a|
puts "Argument: #{a}"
end
The problem is that the Unix command "at" doesn't seem to like variables and only wants to deal with filenames. I either get one of two errors depending on how I position "s
If I put quotes around the right hand side like so
... "~/PATH_TO_APP/lib/parking_timer.sh STRING_VARIABLE"
I get,
-bash: ~/PATH_TO_APP/lib/parking_timer.sh STRING_VARIABLE: No such file or directory
I I leave the quotes out, I get,
at: garbled time
This is all happening on a Mac OS 10.6 box running Rails 2.3 & Ruby 1.8.6
I've already messed around w/ BackgrounDrb, and decided its a total PITA. I need to be able to cancel the job at any time before it is due.
After playing around with irb a bit, here's what I found.
The backtick operator invokes the shell after ruby has done any interpretation necessary. For my test case, the strace output looked something like this:
execve("/bin/sh", ["sh", "-c", "echo at 12:57 < /etc/fstab"], [/* 67 vars */]) = 0
Since we know what it's doing, let's take a look at how your command will be executed:
/bin/sh -c "at 12:57 < RAILS_ROOT/lib/parking_timer.sh STRING_VARIABLE"
That looks very odd. Do you really want to pipe parking_timer.sh, the script, as input into the at command?
What you probably ultimately want is something like this:
/bin/sh -c "RAILS_ROOT/lib/parking_timer.sh STRING_VARIABLE | at 12:57"
Thus, the output of the parking_timer.sh command will become the input to the at command.
So, try the following:
output = `#{Rails.root}/lib/parking_timer.sh STRING_VARIABLE | at #{(Time.now + 60).strftime("%H:%M")}`
return render :text => output
You can always use strace or truss to see what's happening. For example:
strace -o strace.out -f -ff -p $IRB_PID
Then grep '^exec' strace.out* to see where the command is being executed.

Resources