Where is SimpleDelegator in Ruby 2.7? - ruby

I have been using the SimpleDelegator class for various things. But I noticed, Ruby 2.7 (ArchLinux x86_64) doesn't come with the SimpleDelegator class (no Delegator either).
My program:
#!/usr/bin/ruby -w
class OutputDecorator < SimpleDelegator
def puts(*args)
STDOUT.write "Hello #{args.join}... It's Ruby #{RUBY_VERSION} #{RUBY_PLATFORM}\n"
end
end
$stdout = OutputDecorator.new($stdout)
$stdout.puts('Sourav')
$stdout = $stdout.__getobj__
$stdout.puts('Sourav')
Running with:
Ruby 2.4.6:
> ~/.rvm/rubies/ruby-2.4.6/bin/ruby p.rb
Hello Sourav... It's Ruby 2.4.6 x86_64-linux
Sourav
Ruby 2.5.5:
> ~/.rvm/rubies/ruby-2.5.5/bin/ruby p.rb
Hello Sourav... It's Ruby 2.5.5 x86_64-linux
Sourav
Ruby 2.6.3:
> ~/.rvm/rubies/ruby-2.6.3/bin/ruby p.rb
Hello Sourav... It's Ruby 2.6.3 x86_64-linux
Sourav
Ruby 2.7.0:
> ruby p.rb
Traceback (most recent call last):
p.rb:2:in `<main>': uninitialized constant SimpleDelegator (NameError)
Is there any new alternatives to SimpleDelegator in Ruby 2.7?

The Delegator and SimpleDelegator classes aren't core classes like Array or Mutex. They're part of the delegate standard library which needs to be loaded first: require 'delegate'.
It happened to work in older Ruby versions as they came with an older RubyGems version by default. RubyGems is automatically loaded since Ruby 1.9 and until 3.1.0 that meant delegate was loaded indirectly. Updating RubyGems or running ruby with --disable=gems should cause the exact same issue with Ruby <= 2.6 too. irb also loads several standard libraries: delegate but also timeout and many more.
Programming languages with a similar mechanism like C++ also have this issue: instead of load/require there's #include, including a standard library header might include another one, then a newer version might not include the other header anymore and user code relying on the old behavior fails to compile.

Related

Which libraries are loaded by default in pry?

When I use Tempfile class in pry, I don't use require it.
% pry -f
pry(main)> Tempfile
Tempfile < #<Class:0x00007fb5121149b8>
But when in irb I must to require tempfile first.
% irb
irb(main):001:0> Tempfile
NameError: uninitialized constant Tempfile
from (irb):1
from /Users/ironsand/.rbenv/versions/2.4.3/bin/irb:11:in `<main>'
irb(main):002:0> require 'tempfile'
=> true
So it seems pry load some libraries by default.
Which libraries are actually loaded?
This is my environment
% ruby -v
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin17]
% irb --version
pirb 0.9.6(09/06/30)
% pry --version
Pry version 0.11.3 on Ruby 2.4.3
You can compare $LOADED_FEATURES to see everything that's loaded in a default pry session vs an irb session (or a plain ruby script).
The short answer is that Pry loads whichever libraries it needs to provide its own behaviour. The long answer is too long (and too likely to get out of date, or differ between versions) to list here -- better to ask your current environment.
It's good practice not to rely on other libraries to load their dependencies for you, because those dependencies can change. (Though in cases like this, it can be hard to notice you're missing a require, because everything still works.)
As an alternative to $LOADED_FEATURES, which can be a bit excessive, consider:
Gem.loaded_specs.values.each {|s| puts s.name}
which only lists gems with specs
[20] pry(main)> Gem.loaded_specs.values.each {|s| puts s.name};nil
did_you_mean
coderay
method_source
pry
io-console
vls
=> nil
BTW, in this example, I had loaded the vls gem manually.

Ruby not finding rubygems or wx modules

I'm running the default Ruby installation (ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10]) on my Intel iMac. I updated RubyGems and installed the wxruby gem. I'm trying to run the following sample program:
#!/usr/bin/ruby
require "rubygems"
require "wx"
class MyApp < Wx::App
def on_init
#frame = Wx::Frame.new(nil, -1, "The Bare Minimum")
#frame.show()
end
end
app = MyApp.new()
app.main_loop()
And I get the following error:
==> wxruby-test.rb
/Library/Ruby/Gems/1.8/gems/wxruby-1.9.3-universal-darwin/lib/wxruby2.bundle: dlopen(/Library/Ruby/Gems/1.8/gems/wxruby-1.9.3-universal-darwin/lib/wxruby2.bundle, 9): no suitable image found. Did find: (LoadError)
/Library/Ruby/Gems/1.8/gems/wxruby-1.9.3-universal-darwin/lib/wxruby2.bundle: no matching architecture in universal wrapper - /Library/Ruby/Gems/1.8/gems/wxruby-1.9.3-universal-darwin/lib/wxruby2.bundle
from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:36:in `require'
from /Library/Ruby/Gems/1.8/gems/wxruby-1.9.3-universal-darwin/lib/wx.rb:12
from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:60:in `gem_original_require'
from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:60:in `require'
from wxruby-test.rb:3
If I comment out the require rubygems statement, I get the following error:
==> wxruby-test.rb
wxruby-test.rb:3:in `require': no such file to load -- wx (LoadError)
from wxruby-test.rb:3
I'm new to Ruby on the Mac, and I'm sure this is some basic error probably related to paths, but most explanations about the environment variables are aimed at experienced users. If you need more output from other commands, please let me know. I'm running Ruby from the tcsh shell. I'm sure I'm doing something basic wrong, but I'm just stumped.
If you're running Ruby 1.8.7 you should leave in the require statement:
require "rubygems"
Ruby 1.8 didn't know about gems by default, so we had to tell Ruby to require the gems loader. Ruby 1.9+ bundles it so we no longer have to do the require.
This has nothing to do with the Mac (or Windows or Linux) OS, it's about Ruby's default load paths.
And, as a safety tip, don't mess with Ruby installed by Apple. They installed it for their own use, and it's used for some podcast-creation tools. And, at some future point they might want to add something to the system that takes advantage of an expected configuration of Ruby (or Python or Perl). Changing (or worse, deleting it) can mess you up. So, I recommend you leave it alone and use either rbenv or RVM to install Ruby in a sandbox, where you can poke, prod and mess with it safely.
What version of OS X? If it's one of the Lions, then you're out of luck. The wxwidgets library (and things based on it, like wxruby) is still only 32-bit and based on Carbon. The Lions are 64-bit-only and Carbon is deprecated.

Why doesn't each_slice work?

I am trying to use the Enumerable#each_slice. It doesn't work on my computer, stating that method is not found.
I am running ruby 1.8.6 (2008-08-11 patchlevel 287) [universal-darwin9.0]
API: http://ruby-doc.org/core/classes/Enumerable.html#M003142
Example:
(1..10).each_slice(3) {|a| p a} # I get NoMethodError: undefined method `each_slice' for 1..10:Range
What am I doing wrong?
In ruby 1.8.6 you have to require 'enumerator' (which is part of stdlib and has been merged into core in 1.8.7+) before using each_slice.
Sadly the ruby-doc lists methods that are added to core classes by stdlib without mentioning where the methods are from.
just compared 1.8.6 to 1.9 and it looks like
(1..10).respond_to? :each_slice
is true in 1.9 and false in 1.8.6. So, the doc you are using is not for 1.8.6. if you can upgrade to a newer version of Ruby easily it should give you that method on the Range.

undefined method ‘bytes’ for for String in Ruby

I am working with ruby 1.8.6 (2007-03-13 patchlevel 0) [x86_64-linux] and I get
undefined method `bytes' for #<String:0x2a95ec2268> (NoMethodError)
even though my code works on ruby 1.8.7. patchlevel 249
I saw somewhere that you need to add require "jcode" for a similar method not defined error with each_byte. I tried adding that but it still does not work. Any suggestions are very appreciated.
In Ruby 1.8.6, you can use my backports gem:
require 'backports/1.8.7/string/bytes'
Ta-da, you now have access to String#bytes.
You also have all the many other changes introduced in 1.8.7. And most of 1.9.1, and all of the upcoming 1.9.2, etc...
Ruby 1.8.6 doesn't have String#bytes. That's a 1.9 addition that was backported to 1.8.7.
You can roughly implement it yourself like this:
class String
require 'enumerator'
def bytes(&block)
return to_enum(:each_byte) unless block_given?
each_byte &block
end
end unless ''.respond_to?(:bytes)
[Note: I haven't checked whether this actually fulfills the contract of String#bytes 100%, but it is close enough for my use.]

Why does 6.times.map work in ruby 1.8.7 but not 1.8.6

The following code snippet works fine in 1.8.7 on Mac OS X, but not in 1.8.6 on Ubuntu. Why? Is there a workaround?
Works in 1.8.7:
$ ruby --version
ruby 1.8.7 (2009-06-08 patchlevel 173) [universal-darwin10.0]
ltredgate15:eegl leem$ irb
>> 6.times.map {'foo'}
=> ["foo", "foo", "foo", "foo", "foo", "foo"]
>>
But not in 1.8.6:
# ruby --version
ruby 1.8.6 (2008-08-11 patchlevel 287) [i686-linux]
Ruby Enterprise Edition 20090610
# irb
irb(main):001:0> 6.times.map {'foo'}
LocalJumpError: no block given
from (irb):1:in `times'
from (irb):1
irb(main):002:0>
Why is there a difference? What's the workaround for 1.8.6?
In 1.8.7+ iterator methods like times return an enumerator if they are called without a block. In 1.8.6 you have to do
require 'enumerator'
6.enum_for(:times).map {...}
Or for this specific use case you could simply do (0...6).map {...}
In Ruby 1.9, the library was changed so functions that did iteration would return an Enumerator object if they were called without a block. A whole host of other language features were also changed, and it was widely known that compatibility would be broken between Ruby 1.8.x and Ruby 1.9 in the interests of improving the language as a whole. Most people didn't find this too distressing.
The Ruby development team decided that Ruby 1.8.7 should be a transition release adding some of the library features that Ruby 1.9 introduced. They took a lot of criticism for the decision, and many enterprise Ruby users remained (and many still remain) running Rails on Ruby 1.8.6, because they feel the changes introduced 1.8.7 are just too large, and too risky. But nevertheless, 1.8.7 remains, and having iteration functions return Enumerators is one of the features that was incorporated.
It is this migration feature that you're seeing in 1.8.7, which is not present in 1.8.6.
sepp2k's answer gives a good workaround. There's not much for me to add on that count.
Because 1.8.6 #times yields on the given block, while 1.8.7 returns an Enumerator object you can keep around and implements Enumerable.
Ruby 1.8.7 introduces many changes. If you want to use them in Ruby 1.8.6, simply
require 'backports'
That's it. This gives you many methods of 1.9.1 and the upcoming 1.9.2 as well, although it's possible to require 'backports/1.8.7' for just the changes of 1.8.7, or even just the backports you need, e.g. require 'backports/1.8.7/integer/times'

Resources