Есть ли способ достичь grep-подобных функций при выходе внутри консоли Rails

136
14

В оболочке я могу сделать


$ cat name_of_file_with_a_lot_of_text | grep "What I am looking for"

Внутри консоли Rails я могу достичь чего-то подобного, скажем, когда я запускаю команду, а выход огромен, особенно скажем, запрос БД.
Я знаю, что он выводит его как YAML, но это не то, что я ищу.


Спасибо.

спросил(а) 2021-01-19T15:38:09+03:00 2 месяца, 3 недели назад
1
Решение
194

Да, вы можете. Метод называется gr... ждать его... ep. Ruby grep работает с String, Array и многими другими встроенными объектами. Например, чтобы получить все методы to_xxx для числа, просто выполните:

 1.methods.grep(/to_/)

ответил(а) 2021-01-19T15:38:09+03:00 2 месяца, 3 недели назад
75

У меня был такой же вопрос, и я был не очень доволен некоторым отрывочным ответом от ream88, поэтому я решил взломать его.


# Allows you to filter output to the console using grep
# Ex:
# def foo
# puts "Some debugging output here"
# puts "The value of x is y"
# puts "The value of foo is bar"
# end
#
# grep_stdout(/value/) { foo }
# # => The value of x is y
# # => The value of foo is bar
# # => nil
def grep_stdout(expression)
# First we need to create a ruby "pipe" which is two sets of IO subclasses
# the first is read only (which represents a fake $stdin) and the second is
# write only (which represents a fake $stdout).
placeholder_in, placeholder_out = IO.pipe

# This child process handles the grep'ing. Its done in a child process so that
# it can operate in parallel with the main process.
pid = fork {
# sync $stdout so we can report any matches asap
$stdout.sync

# replace $stdout with placeholder_out
$stdin.reopen(placeholder_in)

# we have to close both placeholder_out and placeholder_in because all instances
# of an IO stream must be closed in order for it to ever reach EOF. There two
# in this method; one in the child process and one in the main process.
placeholder_in.close
placeholder_out.close

# loop continuously until we reach EOF (which happens when all
# instances of placeholder_out have closed)
read_buffer = ''
loop do
begin
read_buffer << $stdin.readpartial(4096)
if line_match = read_buffer.match(/(.*\n)(.*)/)
print line_match[1].grep(expression) # grep complete lines
read_buffer = line_match[2] # save remaining partial line for the next iteration
end
rescue EOFError
print read_buffer.grep(expression) # grep any remaining partial line at EOF
break
end
end
}

# Save the original stdout out to a variable so we can use it again after this
# method is done
original_stdout = $stdout

# Redirect stdout to our pipe
$stdout = placeholder_out

# sync $stdout so that we can start operating on it as soon as possible
$stdout.sync

# allow the block to execute and save its return value
return_value = yield

# Set stdout back to the original so output will flow again
$stdout = original_stdout

# close the main instances of placeholder_in and placeholder_out
placeholder_in.close
placeholder_out.close

# Wait for the child processes to finish
Process.wait pid

# Because the connection to the database has a tendency to go away when calling this, reconnect here
# if we're using ActiveRecord
if defined?(ActiveRecord)
suppress_stdout { ActiveRecord::Base.verify_active_connections! }
end

# return the value of the block
return_value
end


Очевидным недостатком моего решения является то, что выход потерян. Я не уверен, как обойти это без двойного вызова yield.

EDIT Я изменил свой ответ, чтобы вызвать только вызов fork один раз, что позволяет мне сохранять вывод блока и возвращать его в конце. Win.


EDIT 2 Теперь вы можете получить всю эту функциональность (и многое другое!) в этом камне https://github.com/FutureAdvisor/console_util

ответил(а) 2021-01-19T15:38:09+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема