I have searched several questions/answers/blogs without success. How to remove/delete duplicate commands from irb history?
Ideally I want to have the same behavior I configured for my bash. That is: after I execute a command every other entry in the history with the exactly same command is deleted.
But it would already be good to eliminate duplicates when I close irb.
My current .irbrc:
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
IRB.conf[:AUTO_INDENT] = true
Note: Ruby 2.4.1 (or newer!)
An AT_EXIT hook is a perfectly acceptable way to do this. Though monkey patching is not needed. IRB provides facilities for doing this by creating your own input method.
IRB gets its input from an InputMethod. History is provided by the
ReadlineInputMethod, which is a subclass.
InputMethods are attached to a Context. Entering conf in an irb session will give you access to the current context.
irb will read input according to the current context's io. For example:
irb [2.4.0] (screenstaring.com)$ conf.io
=> #<HistoryInputMethod:0x007fdc3403e180 #file_name="(line)", #line_no=3, #line=[nil, "4317.02 - 250 \n", "conf.id\n", "conf.io\n"], #eof=false, #stdin=#<IO:fd 0>, #stdout=#<IO:fd 1>, #prompt="irb [2.4.0] (screenstaring.com)$ ", #ignore_settings=[], #ignore_patterns=[]>
Uses my Bash-like history control class (for more info see below).
You can set conf.io to anything that conforms to the InputMethod interface:
conf.io = MyInputMethod.new
Whatever MyInputMethod#gets returns will be evaluated by IRB. Typically it reads from stdin.
To tell IRB to use your InputMethod at startup you can set the :SCRIPT config option:
# .irbrc
IRB.conf[:SCRIPT] = MyInputMethod.new
IRB will use :SCRIPT's value as input method when creating a Context. This can be set to a file to use its contents as the input method.
By default it's nil, which results in stdin being used (via Readline, if it's available).
To create an input method that ignores duplicates override ReadlineInputMethod#gets:
class MyInputMethod < IRB::ReadlineInputMethod
def gets
line = super # super adds line to HISTORY
HISTORY.pop if HISTORY[-1] == HISTORY[-2]
line
end
end
The InputMethod defined in my .irbrc allows one to set IRB_HISTCONTROL or IRB_HISTIGNORE like you would (more or less) for Bash:
IRB_HISTIGNORE=ignoreboth IRB_HISTCONTROL='\Aq!:foo' irb
This does the following:
Entries beginning with a space or duplicate (back-to-back) entries will not be added to the history
Entries beginning with q! (a custom method of mine) or containing foo will not be added to history
This will eliminate duplicates after closing IRB console. But it works only for IRBs using Readline (mac users warned).
# ~/.irbrc
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
deduplicate_history = Proc.new do
history = Readline::HISTORY.to_a
Readline::HISTORY.clear
history.reverse!.uniq!
history.reverse!.each{|entry| Readline::HISTORY << entry}
end
IRB.conf[:AT_EXIT].unshift(deduplicate_history)
And this monkey patch will eliminate duplicates on the fly if your IRB is using Readline:
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
class IRB::ReadlineInputMethod
alias :default_gets :gets
def gets
if result = default_gets
line = result.chomp
history = HISTORY.to_a
HISTORY.clear
history.each{|entry| HISTORY << entry unless entry == line}
HISTORY << line
end
result
end
end
Any suggestion on how to improve it?
Related
I would like to know whether I can get source code a method on the fly, and whether I can get which file is this method in.
like
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Use source_location:
class A
def foo
end
end
file, line = A.instance_method(:foo).source_location
# or
file, line = A.new.method(:foo).source_location
puts "Method foo is defined in #{file}, line #{line}"
# => "Method foo is defined in temp.rb, line 2"
Note that for builtin methods, source_location returns nil. If want to check out the C source code (have fun!), you'll have to look for the right C file (they're more or less organized by class) and find the rb_define_method for the method (towards the end of the file).
In Ruby 1.8 this method does not exist, but you can use this gem.
None of the answers so far show how to display the source code of a method on the fly...
It's actually very easy if you use the awesome 'method_source' gem by John Mair (the maker of Pry):
The method has to be implemented in Ruby (not C), and has to be loaded from a file (not irb).
Here's an example displaying the method source code in the Rails console with method_source:
$ rails console
> require 'method_source'
> I18n::Backend::Simple.instance_method(:lookup).source.display
def lookup(locale, key, scope = [], options = {})
init_translations unless initialized?
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
keys.inject(translations) do |result, _key|
_key = _key.to_sym
return nil unless result.is_a?(Hash) && result.has_key?(_key)
result = result[_key]
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
result
end
end
=> nil
See also:
https://rubygems.org/gems/method_source
https://github.com/banister/method_source
http://banisterfiend.wordpress.com/
Here is how to print out the source code from ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Without dependencies
method = SomeConstant.method(:some_method_name)
file_path, line = method.source_location
# puts 10 lines start from the method define
IO.readlines(file_path)[line-1, 10]
If you want use this more conveniently, your can open the Method class:
# ~/.irbrc
class Method
def source(limit=10)
file, line = source_location
if file && line
IO.readlines(file)[line-1,limit]
else
nil
end
end
end
And then just call method.source
With Pry you can use the show-method to view a method source, and you can even see some ruby c source code with pry-doc installed, according pry's doc in codde-browing
Note that we can also view C methods (from Ruby Core) using the
pry-doc plugin; we also show off the alternate syntax for show-method:
pry(main)> show-method Array#select
From: array.c in Ruby Core (C Method):
Number of lines: 15
static VALUE
rb_ary_select(VALUE ary)
{
VALUE result;
long i;
RETURN_ENUMERATOR(ary, 0, 0);
result = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
rb_ary_push(result, rb_ary_elt(ary, i));
}
}
return result;
}
I created the "ri_for" gem for this purpose
>> require 'ri_for'
>> A.ri_for :foo
... outputs the source (and location, if you're on 1.9).
GL.
-r
Internal methods don't have source or source location (e.g. Integer#to_s)
require 'method_source'
User.method(:last).source
User.method(:last).source_location
I had to implement a similar feature (grab the source of a block) as part of Wrong and you can see how (and maybe even reuse the code) in chunk.rb (which relies on Ryan Davis' RubyParser as well as some pretty funny source file glomming code). You'd have to modify it to use Method#source_location and maybe tweak some other things so it does or doesn't include the def.
BTW I think Rubinius has this feature built in. For some reason it's been left out of MRI (the standard Ruby implementation), hence this hack.
Oooh, I like some of the stuff in method_source! Like using eval to tell if an expression is valid (and keep glomming source lines until you stop getting parse errors, like Chunk does)...
This question already has answers here:
What will give me something like ruby readline with a default value?
(6 answers)
Closed 6 years ago.
I am using to Ruby to write a small command line utility to search Pubmed. Right now, I prompt the user for a query and display the results, and the user has the option of appending to the query or entering an entirely new query. I would like to add the ability to edit the current query; i.e. the prompt should come pre-filled with an editable version of the previous query, like so:
Enter query: <PREVIOUS QUERY HERE>
It's easy enough to print out the previous query next to the prompt, but how do I make this output editable, as if the user had typed it herself?
#casper:
Thank you for the response Casper. I tried the code that you supplied below, and it does indeed work on its own. Strangely enough, it doesn't seem to work when I try to use it in a gem. My gem is called db_hippo. I added rb-readline as a dependency in my gemspec, and I put the extension to RbReadline in lib/db_hippo/rb-readline.rb
module DbHippo
module RbReadline
<CASPER'S EXTENSION HERE>
end
end
I wish to use the functionality in another submodule of DbHippo, DbHippo::Source. In DbHippo::Source I added at the top:
require 'rb-readline'
require 'db_hippo/rb-readline'
Then in one of the methods of DbHippo::Source, I have:
RbReadline.prefill_prompt(query)
query = Readline.readline("Query: ", true)
The query variable is definitely not empty, but for some reason in this context the prompt doesn't get prefilled. I also notice that if I put the extension in the same file (lib/db_hippo/rb-readline) without making it a submodule of DbHippo, I get the error: uninitialized constant DbHippo::Source::Readline (NameError) on the line:
query = Readline.readline("Query: ", true)
This all seems to have something to do with proper naming of modules, require statements, and gems. This is the first gem I've tried to build. Any idea what's going wrong here?
Maybe googlers will find this useful.
With plain Readline on Ruby 2.1 you could use:
def ask(prompt, default=nil)
if default
Readline.pre_input_hook = -> {
Readline.insert_text(default)
Readline.redisplay
# prevent re-trigger on every `readline`
Readline.pre_input_hook = nil
}
end
data = Readline.readline("#{prompt}: ")
return data.chomp
end
ask("MOAR...?", "COMPUTARS!") # displays: MOAR...? COMPUTARS!
At the prompt the text COMPUTARS! will be editable
You can do it with RbReadline:
require 'rubygems'
require 'rb-readline'
module RbReadline
def self.prefill_prompt(str)
#rl_prefill = str
#rl_startup_hook = :rl_prefill_hook
end
def self.rl_prefill_hook
rl_insert_text #rl_prefill if #rl_prefill
#rl_startup_hook = nil
end
end
RbReadline.prefill_prompt("Previous query")
str = Readline.readline("Enter query: ", true)
puts "You entered: #{str}"
I am trying to execute rspec from ruby, and get the status or number of failures from a method or something like that. Actually I am running something like this:
system("rspec 'myfilepath'")
but I only can get the string returned by the function. Is there any way to do this directly using objects?
I think the best way would be using RSpec's configuration and Formatter. This would not involve parsing the IO stream, also gives much richer result customisation programmatically.
RSpec 2:
require 'rspec'
config = RSpec.configuration
# optionally set the console output to colourful
# equivalent to set --color in .rspec file
config.color = true
# using the output to create a formatter
# documentation formatter is one of the default rspec formatter options
json_formatter = RSpec::Core::Formatters::JsonFormatter.new(config.output)
# set up the reporter with this formatter
reporter = RSpec::Core::Reporter.new(json_formatter)
config.instance_variable_set(:#reporter, reporter)
# run the test with rspec runner
# 'my_spec.rb' is the location of the spec file
RSpec::Core::Runner.run(['my_spec.rb'])
Now you can use the json_formatter object to get result and summary of a spec test.
# gets an array of examples executed in this test run
json_formatter.output_hash
An example of output_hash value can be found here:
RSpec 3
require 'rspec'
require 'rspec/core/formatters/json_formatter'
config = RSpec.configuration
formatter = RSpec::Core::Formatters::JsonFormatter.new(config.output_stream)
# create reporter with json formatter
reporter = RSpec::Core::Reporter.new(config)
config.instance_variable_set(:#reporter, reporter)
# internal hack
# api may not be stable, make sure lock down Rspec version
loader = config.send(:formatter_loader)
notifications = loader.send(:notifications_for, RSpec::Core::Formatters::JsonFormatter)
reporter.register_listener(formatter, *notifications)
RSpec::Core::Runner.run(['spec.rb'])
# here's your json hash
p formatter.output_hash
Other Resources
Detailed work through
Gist example
I suggest you to take a look into rspec source code to find out the answer. I think you can start with example_group_runner
Edit: Ok here is the way:
RSpec::Core::Runner::run(options, err, out)
Options - array of directories, err & out - streams. For example
RSpec::Core::Runner.run(['spec', 'another_specs'], $stderr, $stdout)
Your problem is that you're using the Kernel#system method to execute your command, which only returns true or false based on whether or not it can find the command and run it successfully. Instead you want to capture the output of the rspec command. Essentially you want to capture everything that rspec outputs to STDOUT. You can then iterate through the output to find and parse the line which will tell you how many examples were run and how many failures there were.
Something along the following lines:
require 'open3'
stdin, stdout, stderr = Open3.popen3('rspec spec/models/my_crazy_spec.rb')
total_examples = 0
total_failures = 0
stdout.readlines.each do |line|
if line =~ /(\d*) examples, (\d*) failures/
total_examples = $1
total_failures = $2
end
end
puts total_examples
puts total_failures
This should output the number of total examples and number of failures - adapt as needed.
This one prints to console and at the same time captures the message. The formatter.stop is just a stub function, I don't know what it is for normally, I had to include it to use DocumentationFormatter. Also the formatter output contains console coloring codes.
formatter = RSpec::Core::Formatters::DocumentationFormatter.new(StringIO.new)
def formatter.stop(arg1)
end
RSpec.configuration.reporter.register_listener(formatter, :message, :dump_summary, :dump_profile, :stop, :seed, :close, :start, :example_group_started)
RSpec::Core::Runner.run(['test.rb','-fdocumentation'])
puts formatter.output.string
I would like to know whether I can get source code a method on the fly, and whether I can get which file is this method in.
like
A.new.method(:a).SOURCE_CODE
A.new.method(:a).FILE
Use source_location:
class A
def foo
end
end
file, line = A.instance_method(:foo).source_location
# or
file, line = A.new.method(:foo).source_location
puts "Method foo is defined in #{file}, line #{line}"
# => "Method foo is defined in temp.rb, line 2"
Note that for builtin methods, source_location returns nil. If want to check out the C source code (have fun!), you'll have to look for the right C file (they're more or less organized by class) and find the rb_define_method for the method (towards the end of the file).
In Ruby 1.8 this method does not exist, but you can use this gem.
None of the answers so far show how to display the source code of a method on the fly...
It's actually very easy if you use the awesome 'method_source' gem by John Mair (the maker of Pry):
The method has to be implemented in Ruby (not C), and has to be loaded from a file (not irb).
Here's an example displaying the method source code in the Rails console with method_source:
$ rails console
> require 'method_source'
> I18n::Backend::Simple.instance_method(:lookup).source.display
def lookup(locale, key, scope = [], options = {})
init_translations unless initialized?
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
keys.inject(translations) do |result, _key|
_key = _key.to_sym
return nil unless result.is_a?(Hash) && result.has_key?(_key)
result = result[_key]
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
result
end
end
=> nil
See also:
https://rubygems.org/gems/method_source
https://github.com/banister/method_source
http://banisterfiend.wordpress.com/
Here is how to print out the source code from ruby:
puts File.read(OBJECT_TO_GET.method(:METHOD_FROM).source_location[0])
Without dependencies
method = SomeConstant.method(:some_method_name)
file_path, line = method.source_location
# puts 10 lines start from the method define
IO.readlines(file_path)[line-1, 10]
If you want use this more conveniently, your can open the Method class:
# ~/.irbrc
class Method
def source(limit=10)
file, line = source_location
if file && line
IO.readlines(file)[line-1,limit]
else
nil
end
end
end
And then just call method.source
With Pry you can use the show-method to view a method source, and you can even see some ruby c source code with pry-doc installed, according pry's doc in codde-browing
Note that we can also view C methods (from Ruby Core) using the
pry-doc plugin; we also show off the alternate syntax for show-method:
pry(main)> show-method Array#select
From: array.c in Ruby Core (C Method):
Number of lines: 15
static VALUE
rb_ary_select(VALUE ary)
{
VALUE result;
long i;
RETURN_ENUMERATOR(ary, 0, 0);
result = rb_ary_new2(RARRAY_LEN(ary));
for (i = 0; i < RARRAY_LEN(ary); i++) {
if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
rb_ary_push(result, rb_ary_elt(ary, i));
}
}
return result;
}
I created the "ri_for" gem for this purpose
>> require 'ri_for'
>> A.ri_for :foo
... outputs the source (and location, if you're on 1.9).
GL.
-r
Internal methods don't have source or source location (e.g. Integer#to_s)
require 'method_source'
User.method(:last).source
User.method(:last).source_location
I had to implement a similar feature (grab the source of a block) as part of Wrong and you can see how (and maybe even reuse the code) in chunk.rb (which relies on Ryan Davis' RubyParser as well as some pretty funny source file glomming code). You'd have to modify it to use Method#source_location and maybe tweak some other things so it does or doesn't include the def.
BTW I think Rubinius has this feature built in. For some reason it's been left out of MRI (the standard Ruby implementation), hence this hack.
Oooh, I like some of the stuff in method_source! Like using eval to tell if an expression is valid (and keep glomming source lines until you stop getting parse errors, like Chunk does)...
I'm trying to use optparse to parse command line arguments. I would like my program to accept arguments like that:
$ ./myscript.rb [options] filename
I can easily manage the [options] part:
require 'optparse'
options = { :verbose => false, :type => :html }
opts = OptionParser.new do |opts|
opts.on('-v', '--verbose') do
options[:verbose] = true
end
opts.on('-t', '--type', [:html, :css]) do |type|
options[:type] = type
end
end
opts.parse!(ARGV)
But how do I get the filename?
I could extract it manually from ARGV, but there has to be a better solution, just can't figure out how
The "parse" method returns the unprocessed ARGV. So in your example, it will return a one element array with the filename in it.
I can't just use ARGV.pop. For example
when the last argument is "css" it
could either be a file or belong to
--type switch.
But if your script requires the last argument to be a filename (which is what your usage output inquires) this case should never happen the script should exit with a non-zero and the user should get a usage report or error.
Now if you want to make a default filename or not require a filename as the last argument but leave it optional then you could just test to see if the last argument is a valid file. If so use it as expected otherwise continue without etc.
Hope this answer can still be useful.
Ruby has one built-in variable __FILE__ can do this type of work.
puts __FILE__
it will print out your file's name.
I don't think extracting it before sending it to OptionParser is bad, I think it makes sense. I probably say this because I have never used OptionParser before, but oh well.
require 'optparse'
file = ARGV.pop
opts = OptionParser.new do |opts|
# ...
end