Verify version of a gem with bundler from inside Ruby - ruby

Is there a way to verify that I have the latest version of a gem from inside a Ruby program? That is, is there a way to do bundle outdated #{gemname} programmatically?
I tried looking at bundler's source code but I couldn't find a straight-forward way. Currently I'm doing this, which is fragile, slow and so inelegant:
IO.popen(%w{/usr/bin/env bundle outdated gemname}) do |proc|
output = proc.readlines.join("\n")
return output.include?("Your bundle is up to date!")
end

A way to avoid external execution:
For bundler 1.2.x
require 'bundler/cli'
# intercepting $stdout into a StringIO
old_stdout, $stdout = $stdout, StringIO.new
# running the same code run in the 'bundler outdated' utility
Bundler::CLI.new.outdated('rails')
# storing the output
output = $stdout.string
# restoring $stdout
$stdout = old_stdout
For bundler 1.3.x
require 'bundler/cli'
require 'bundler/friendly_errors'
# let's cheat the CLI class with fake exit method
module Bundler
class CLI
desc 'exit', 'fake exit' # this is required by Thor
def exit(*); end # simply do nothing
end
end
# intercepting $stdout into a StringIO
old_stdout, $stdout = $stdout, StringIO.new
# running the same code run in the 'bundler outdated' utility
Bundler.with_friendly_errors { Bundler::CLI.start(['outdated', 'rails']) }
# storing the output
output = $stdout.string
# restoring $stdout
$stdout = old_stdout

There is no programmatic way to use outdated command in bundler, because the code is in a Thor CLI file which prints output to the user. Bundler's tests are also issuing the command to the system and checking the output (Link to outdated tests).
It should be fairly simple to write your own method to mirror what the outdated method in cli.rb is doing, though. See the highlighted code here : Link to outdated method in Bundler source. Remove lines with Bundler.ui and return true/false based on the value of out_count
Update: I've extracted 'bundle outdated' into a reusable method without the console output and the exits. You can find the gist here : link to gist. I have tested this on bundler 1.3 and it seems to work.

bundle check list the gems that are out to date, you might want to use it.

Hmmm, sounds like you might want bundle show or gem env

Disappointing, this looks surprisingly difficult.
There are a couple of open issues in bundler where the official line appears to be:
At this point in time, there isn't a documented ruby API.
It's something that's on our list, though.
Looking through the bundler source code cli.rb, it's fairly clear that it's going to be tricky to call from ruby, or reproduce the code in a sensible manner.
Calling methods from CLI will be difficult because they're sprinkled with calls to exit.
Reproducing the code doesn't look fun either because there is quite a lot of bundler logic in there.
Good luck!

checking the source code of latest bundler source code
I could come up with this
https://github.com/carlhuda/bundler/blob/master/lib/bundler/cli.rb#L398
$ irb
1.9.3p327 :001 > require 'bundler'
=> true
1.9.3p327 :002 > def outdated_gems(gem_name,options={})
1.9.3p327 :003?> options[:source] ||= 'https://rubygems.org'
1.9.3p327 :004?> sources = Array(options[:source])
1.9.3p327 :005?> current_spec= Bundler.load.specs[gem_name].first
1.9.3p327 :006?> raise "not found in Gemfile" if current_spec.nil?
1.9.3p327 :007?> definition = Bundler.definition(:gems => [gem_name], :sources => sources)
1.9.3p327 :008?> options["local"] ? definition.resolve_with_cache! : definition.resolve_remotely!
1.9.3p327 :009?> active_spec = definition.index[gem_name].sort_by { |b| b.version }
1.9.3p327 :010?> if !current_spec.version.prerelease? && !options[:pre] && active_spec.size > 1
1.9.3p327 :011?> active_spec = active_spec.delete_if { |b| b.respond_to?(:version) && b.version.prerelease? }
1.9.3p327 :012?> end
1.9.3p327 :013?> active_spec = active_spec.last
1.9.3p327 :014?> raise "Error" if active_spec.nil?
1.9.3p327 :015?> outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version)
1.9.3p327 :016?> {:outdated=>outdated,:current_spec_version=>current_spec.version.to_s,:latest_version=>active_spec.version.to_s}
1.9.3p327 :017?> end
=> nil
1.9.3p327 :018 >
1.9.3p327 :019 >
1.9.3p327 :020 >
1.9.3p327 :021 >
1.9.3p327 :022 > outdated_gems('rake')
=> {:outdated=>true, :current_spec_version=>"10.0.3", :latest_version=>"10.0.4"}
This may not work with earlier version of bundler.

Related

Run unit test with Ruby 2.0 and minitest 5.5 without Gemfile

I was learning Ruby by reading Programming Ruby and there is this example code:
require_relative 'count_frequency'
require_relative 'words_from_string'
require 'test/unit'
class TestWordsFromString < Test::Unit::TestCase
def test_empty_string
assert_equal([], words_from_string(''))
assert_equal [], words_from_string(' ')
end
def test_single_word
assert_equal ['cat'], words_from_string('cat')
assert_equal ['cat'], words_from_string(' cat ')
end
def test_many_words
assert_equal ['the', 'cat', 'sat', 'on', 'the', 'cat'], words_from_string('the cat sat on the mat')
end
def test_ignore_punctuation
assert_equal ['the', "cat's", 'mat'], words_from_string("the cat's mat")
end
end
When I tried to run it, an error occured:
MiniTest::Unit::TestCase is now Minitest::Test.
More detailed error message:
I'm using ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin14] and minitest (5.5.0, 5.4.3, 5.3.5, 4.3.2). I did some search and found that since minitest5.0, MiniTest::Unit::TestCase has changed to Minitest::Test. But I cannot do anything since it's in the source file of the gem. Some suggests that require minitest 4.** in Gemfile, but i'm just running a few scripts. There is no need for Gemfile I suppose. And I certainly don't want to uninstalling minitest5.**. So is there a way I could run this script with minitest5.5 and ruby 2.0?
The tests should still run. I have the same set up and even though I get that error, the tests are executed.
→ ruby --verbose etl_test.rb
MiniTest::Unit::TestCase is now Minitest::Test. From etl_test.rb:4:in `<main>'
Run options: --seed 61653
# Running:
....
Finished in 0.001316s, 3039.5137 runs/s, 3039.5137 assertions/s.
4 runs, 4 assertions, 0 failures, 0 errors, 0 skips
classyhacker:~/dev/github/exercism/ruby/etl
→ rbenv versions
system
1.9.3-p448
2.0.0-p451
2.1.0
2.1.1
2.1.2
* 2.1.3 (set by RBENV_VERSION environment variable)
jruby-1.7.8
classyhacker:~/dev/github/exercism/ruby/etl
→ gem list | grep minitest
minitest (5.5.1, 5.4.3, 4.7.5)
My test looks like
require 'minitest/autorun'
require_relative 'etl'
class TransformTest < MiniTest::Unit::TestCase
def test_transform_one_value
old = { 1 => ['A'] }
expected = { 'a' => 1 }
assert_equal expected, ETL.transform(old)
end
require minitest/autorun is also the suggested way in rubydoc http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html

Ruby: End of file reached with gem serialport

Using gem serialport in ruby i'm having the error code EOFError: end of file reached
irb
2.0.0-p451 :001 > require 'serialport'
=> true
2.0.0-p451 :002 > serial_port = SerialPort.new "/dev/ttyUSB0", 115200
=> #<SerialPort:fd 7>
2.0.0-p451 :009 > serial_port.write "#00RD0000020054*\r"
=> 17
2.0.0-p451 :010 > r = serial_port.readline("\r")
EOFError: end of file reached
from (irb):10:in `readline'
from (irb):10
from /home/user/.rvm/rubies/ruby-2.0.0-p451/bin/irb:12:in `<main>'
any suggestion?
Try crate separate SerialPort objects for reading and writing. It seems to be an issue with Ruby - see here: http://www.rngtng.com/2009/11/27/if-your-ruby-serial-port-doesnt-read-what-youre-sending/
Attempt the following
serial_port.readlines
Instead of the
serial_port.readline("\r")
I might also suggest
serial_port.readlines("\r")

How do I test Digest::SHA2.hexdigest in online irb?

I want to see the hash created by the function Digest::SHA2.hexdigest. I do not have Ruby installed, so I went for the online irb. Typing
Digest::SH­A2.hexdige­st("hello"­)
gives
=> #<NameError: uninitialized constant Digest>
Is it possible to add the needed library in any online irb?
You need to do as below :
2.0.0-p0 :003 > require 'digest'
=> true
2.0.0-p0 :004 > Digest::SHA2.hexdigest("hello")
=> "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
2.0.0-p0 :005 >
So do first require 'digest'.
Try in tutorialspoint

How do I use an ActionView::Helper in a Ruby script, outside of Rails?

I am looking to use ActionView::Helpers::NumberHelper from a Ruby script.
What all do I need to require etc.?
~> irb
ruby-1.9.2-p180 :001 > require 'action_view'
=> true
ruby-1.9.2-p180 :002 > ActionView::Base.new.number_to_currency 43
=> "$43.00"
As of Rails 3.2.13, you can do the following:
class MyClass
include ActionView::Helpers::NumberHelper
def my_method
...
number_with_precision(number, precision: 2)
...
end
end
You might need to require 'action_view' too.
Edit: This answer is still valid in Rails 4.2.3.

Printing the source code of a Ruby block

I have a method that takes a block.
Obviously I don't know what is going to be passed in and for bizarre reasons that I won't go into here I want to print the contents of the block.
Is there a way to do this?
You can do this with Ruby2Ruby which implements a to_ruby method.
require 'rubygems'
require 'parse_tree'
require 'parse_tree_extensions'
require 'ruby2ruby'
def meth &block
puts block.to_ruby
end
meth { some code }
will output:
"proc { some(code) }"
I would also check out this awesome talk by Chris Wanstrath of Github http://goruco2008.confreaks.com/03_wanstrath.html He shows some interesting ruby2ruby and parsetree usage examples.
In Ruby 1.9+ (tested with 2.1.2), you can use https://github.com/banister/method_source
Print out the source via block#source:
#! /usr/bin/ruby
require 'rubygems'
require 'method_source'
def wait &block
puts "Running the following code: #{block.source}"
puts "Result: #{yield}"
puts "Done"
end
def run!
x = 6
wait { x == 5 }
wait { x == 6 }
end
run!
Note that in order for the source to be read you need to use a file and execute the file (testing it out from irb will result in the following error: MethodSource::SourceNotFoundError: Could not load source for : No such file or directory # rb_sysopen - (irb)
Building on Evangenieur's answer, here's Corban's answer if you had Ruby 1.9:
# Works with Ruby 1.9
require 'sourcify'
def meth &block
# Note it's to_source, not to_ruby
puts block.to_source
end
meth { some code }
My company uses this to display the Ruby code used to make carbon calculations... we used ParseTree with Ruby 1.8 and now sourcify with Ruby 1.9.
In Ruby 1.9, you can try this gem which extract the code from source file.
https://github.com/ngty/sourcify
In Ruby 2.5 the following works
puts block.source
In ruby 2.7, using the method_source gem (pry depends on it)
Set.instance_method(:merge).source.display
# =>
def merge(enum)
if enum.instance_of?(self.class)
#hash.update(enum.instance_variable_get(:#hash))
else
do_with_enum(enum) { |o| add(o) }
end
self
end
The repo says it works for procs, but I haven't tested it.

Resources