When running Chef, RubyGems throws a System Stack Error - ruby

I'm running Ruby 1.9.3p392 and I've installed the latest chef gem (11.4.2). When I try to run any of the chef command line utilities, I get the following error:
bin/ruby_noexec_wrapper:14: stack level too deep (SystemStackError)
In fact, running the following also causes a similar error to be thrown:
require 'rubygems'
gem 'chef' # or gem 'chef', '11.4.2'
Digging a bit deeper, I see that the issue seems to originate from lib/ruby/site_ruby/1.9.1/rubygems/requirement.rb:
lib/ruby/site_ruby/1.9.1/rubygems/requirement.rb:24: stack level too deep (SystemStackError)
Which is odd, because that line is apart of a block that's defining a hash of lambdas that represent various requirement operations (ie; are versions =, is version1 >= version2, etc).
class Gem::Requirement
OPS = { #:nodoc:
"=" => lambda { |v, r| v == r },
"!=" => lambda { |v, r| v != r },
">" => lambda { |v, r| v > r },
"<" => lambda { |v, r| v < r },
">=" => lambda { |v, r| v >= r }, # <-- line 24
"<=" => lambda { |v, r| v <= r },
"~>" => lambda { |v, r| v >= r && v.release < r.bump }
}
#...
end
Scrolling down the file, I see that the only place OPS[">="] could be called is on line 198:
def satisfied_by? version
raise ArgumentError, "Need a Gem::Version: #{version.inspect}" unless
Gem::Version === version
# #28965: syck has a bug with unquoted '=' YAML.loading as YAML::DefaultKey
requirements.all? { |op, rv| (OPS[op] || OPS["="]).call version, rv } # <-- line 198
end
I've noticed that at the time of running requirements.all?, requirements is set to [[">=", #<Gem::Version "0">]]. It seems to be evaluating <Gem::Version "11.4.2"> >= <Gem::Version "0">.
I've been working on this all day and I have yet to get to the bottom of it. Could anybody help me understand why RubyGems is throwing this error?
Thanks.
edit: Chef seems to run fine on 1.8.7. Could it be an issue with 1.9.3?

Related

Stringifying query parameters: can we go further?

I wrote this method:
def stringify_query_params(query_parameters)
stringified_query_params = ''
query_parameters.each_with_index do |kv, i|
k, v = kv
index = i
if index == 0
stringified_query_params += "?#{k}=#{v}"
else
stringified_query_params += "&#{k}=#{v}"
end
end
return stringified_query_params
end
RubyCop is complaining in my running instance of RubyMine saying that I should instead be capturing the output of the conditional branching logic like this.
I was able to make it slightly better, using some methods in the Enumerable module
def stringify_query_parameters(query_parameters)
query_parameters.each_with_object([]).with_index do |((k, v), acc), index|
acc.push((index.positive? ? '&' : '?') + "#{k}=#{v}")
end.join('')
end
Can anyone think of a way to make it even terser?
It can be as follows:
def stringify_query_parameters(query_parameters)
'?' + query_parameters.map{ |k, v| "#{k}=#{v}" }.join('&')
end

Why does comparing frozen Gem versions fail?

I am writing something in Ruby that needs to compare versions in order to determine whether or not something needs to be updated.
But when I run current_version <=> desired_version and at least one of the versions is frozen, I get:
4: from .../ruby/2.6.0/rubygems/version.rb:344:in `<=>'
3: from .../ruby/2.6.0/rubygems/version.rb:371:in `canonical_segments'
2: from .../ruby/2.6.0/rubygems/version.rb:393:in `_split_segments'
1: from .../ruby/2.6.0/rubygems/version.rb:387:in `_segments'
FrozenError (can't modify frozen Gem::Version)
According to the docs, the source code is this:
def <=>(other)
return unless Gem::Version === other
return 0 if #version == other._version || canonical_segments == other.canonical_segments
lhsegments = _segments
rhsegments = other._segments
lhsize = lhsegments.size
rhsize = rhsegments.size
limit = (lhsize > rhsize ? lhsize : rhsize) - 1
i = 0
while i <= limit
lhs, rhs = lhsegments[i] || 0, rhsegments[i] || 0
i += 1
next if lhs == rhs
return -1 if String === lhs && Numeric === rhs
return 1 if Numeric === lhs && String === rhs
return lhs <=> rhs
end
return 0
end
I don't see why this code would be mutating the state of the Gem. Is there something that I'm missing?
The error tells you where: The <=> method calls canonical_segments, which calls _split_segments, which calls _segments. So that's where the mutation must be happening; not directly in the method you've copied in the post.
More specifically, here's the offending source code:
def canonical_segments
#canonical_segments ||=
_split_segments.map! do |segments|
segments.reverse_each.drop_while {|s| s == 0 }.reverse
end.reduce(&:concat)
end
protected
def _version
#version
end
def _segments
# segments is lazy so it can pick up version values that come from
# old marshaled versions, which don't go through marshal_load.
# since this version object is cached in ##all, its #segments should be frozen
#segments ||= #version.scan(/[0-9]+|[a-z]+/i).map do |s|
/^\d+$/ =~ s ? s.to_i : s
end.freeze
end
def _split_segments
string_start = _segments.index {|s| s.is_a?(String) }
string_segments = segments
numeric_segments = string_segments.slice!(0, string_start || string_segments.size)
return numeric_segments, string_segments
end

LetterCountI CoderByte. Raises Exception with working code

Learning programming so sorry for a beginner question! Here I have a code that works in my sublime text editor but raises an exception on Coderbyte, which from what I know uses Ruby 1.8.7. I suspect it might have to do with the different versions of Ruby. Would be helpful to understand what is going wrong. Thanks for replying!
Exception raised is:
(eval):9: undefined method `keys' for []:Array (NoMethodError) from (eval):4:in `each' from (eval):4:in `LetterCountI' from (eval):23
def LetterCountI(str)
str = str.split
repeating_letters = []
str.each do |word|
word = word.split("")
letters = Hash.new(0)
word.each { |letter| letters[letter] += 1 }
selected_letters = letters.select { |key, value| value > 1 }
repeating_letters << selected_letters.keys.length
end
if (repeating_letters.select {|l| l >= 1}).empty?
return -1
else
max = repeating_letters.max
p repeating_letters
return str[repeating_letters.index(max)]
end
end
Yes, it's the versions. In Ruby 1.8.7 hash.select returns an Array, which has no keys method. In later versions select returns a Hash.

Inconsistent printing with Ruby

I am trying to print a ruby hash:
opts = {
'one' => '1',
'two' => '1',
'three' => '0'
}
I want the output to be
one=1
two=1
three=0
This works fine with this code on one machine which runs ruby 1.8.7
print opts.map{|k,v| k + '=' + v + "\n"}.to_s
But on a different machine which runs ruby 1.9, it prints
["one=1\n", "two=1\n", "three=0\n"]
What is going wrong?
Try
print opts.map{|k,v| k + '=' + v + "\n"}.join
The explanation is easy: With ruby 1.9 Array.to_s changed its behaviour.
An alternative:
puts opts.map{|k,v| k + '=' + v }.join("\n")
or
puts opts.map{|k,v| "#{k}=#{v}" }.join("\n")
I would prefer:
opts.each{|k,v| puts "#{k}=#{v}" }
And another version, but with another look:
opts.each{|k,v| puts "%-10s= %s" % [k,v]}
The result is:
one = 1
two = 1
three = 0
(But the keys should be not longer then the length in %-10s.)
It's working as expected. Give this a try:
a={:one=>1, :two=>2, :three=>3}
a.each {|k,v| puts "#{k}=>#{v}" }
Try:
res = ""
opts.map{|k,v| res += k + '=' + v + "\n"}
puts res

Compare the Content, Not the Results, of Procs

Using Ruby 1.9.2
Problem
Compare the content, not the results, of two procs. I understand the results can't be tested because of the halting problem but that's OK; I don't want to test the results anyway.
For instance
proc {#x == "x"} == proc {#x == "x"} => false # doh!
That returns false because the objects inside the procs are not the same.
My clunky solution
I have a work around solution that kinda sorta does what I want but it doesn't really test that the proc is "equal" to what I put in it. In my specific case the format of my procs will always be boolean tests on instance variables like this:
{#x == "x" && #y != "y" || #z == String}
I wrote a method that builds classes dynamically and creates instance variables set to specified values:
def create_proc_tester(property_value_hash)
new_class = Class.new.new
new_class.class.class_eval do
define_method(:xql?) { |&block| instance_eval &block }
end
property_value_hash.each do |key, value|
new_class.instance_variable_set("##{key}", value)
end
new_class
end
Which could be used something like this:
class Foo
attr_accessor :block
end
foo = Foo.new
foo.block = proc {#x == "x" && #y != "y" || #z == String}
tester = create_proc_tester(:x => "x", :y => "y", :z => Fixnum)
puts "Test #1: #{tester.xql? &foo.block}"
tester = create_proc_tester(:x => "x", :y => "x", :z => String)
puts "Test #2: #{tester.xql? &foo.block}"
> Test #1: false
> Test #2: true
.
.
That's all great and wonderful but I want to know if there is a better, more meta, way to do this that actually tests the contents of the proc not just a work around that solves my specific problem; something that could be used to test any proc.
I was thinking there might be a way to use the Ruby parser to get something to compare but I have no idea how. I'm researching it now but thought I'd try to see if anyone here has done this before and knows how. That might be a dead-end though because of the dynamic nature of Ruby but that's where I'm looking now.
If you're using Ruby 1.9, you may be able to use the sourcify gem.
$ irb
> require 'sourcify'
=> true
> a = proc {#x == "x"}
=> #<Proc:0x9ba4240#(irb):2>
> b = proc {#x == %{x}}
=> #<Proc:0x9ba23f0#(irb):3>
> a == b
=> false
> a.to_source == b.to_source
=> true
> RUBY_VERSION
=> "1.9.2"
We also ran into the ParseTree/Ruby 1.9 incompatibility problem at my company.
$ sudo gem install ruby2ruby ParseTree
require 'parse_tree'
require 'ruby2ruby'
require 'parse_tree_extensions'
# All of these are the same:
proc { puts 'a' }.to_ruby # => "proc { puts(\"a\") }"
lambda { puts "a" }.to_ruby # => "proc { puts(\"a\") }"
Proc.new { puts %{a} }.to_ruby # => "proc { puts(\"a\") }"
# If you need to do this with classes:
class Bar; define_method(:foo) { 'a' }; end
puts Ruby2Ruby.new.process(Unifier.new.process(ParseTree.translate(Bar)))
# will print this:
# class Bar < Object
# def foo
# "a"
# end
# end

Resources