How to implement string.codepoints for pre ruby 1.9.1 - ruby

For backward compatibility reasons I want to implement the String#codepoints ruby method (introduced in 1.9.1).
I am thinking
def codepoints(str)
str.split('').map(&:ord)
end
but I am concerned that #ord will not work properly with earlier versions of ruby.

ord was introduced in Ruby 1.9.1, see APIDock.
For ASCII strings you can use #bytes, for Unicode it won't behave in the same way as #codepoints.
In Ruby 1.8.x you can use ? to get char numeric value, I don't know what to use for 1.9.0.
Btw rubies older than 2.3 are not supported any more, consider upgrading.

Related

Can I write ruby 2.3.7 scripts that are backward compatible with 1.8.7?

Up till now, I've been writing all my scripts in POSIX shell so that I can run them on all the machines I use (macOS, various Linuxes, FreeBSD). I like to have a unified experience where I can pull down my dotfiles from git, and have all my settings and scripts ready to go.
However, POSIX shell is a really irritating language, and I've been considering switching to Ruby for my scripting needs. Unfortunately before I even got started, I realized that macOS ships with Ruby 2.3.7, and one of the machines I often need to use only has Ruby 1.8.7. It's a school machine for which I do not have sudo access, so I can't install a later version of Ruby.
TL;DR
Is it possible to write Ruby scripts that will run on both 1.8.7 and 2.3.7 (and hopefully everything in between)? Is there a set of guidelines I can follow that will help me avoid incompatible language features?
Yes, it is possible, provided you restrict yourself to the intersection of the language and library features of Ruby 1.8.7, Ruby 2.3.7, and everything in between.
The last big break of backwards-compatibility was the jump from Ruby 1.8 to Ruby 1.9. String handling was completely changed, so anything to do with text processing, you need to be very careful.
Of the top of my head:
In Ruby 1.8, strings are considered to be a sequence of bytes. In Ruby 1.9. strings are a factory for different iterators, iterating in terms of code points, characters, or bytes.
Therefore, in Ruby 1.9, strings are no longer Enumerable.
Indexing into a string will return an Integer in Ruby 1.8 and a single-character String in Ruby 1.9.
Character literals (e.g. ?a) will evaluate to an Integer in Ruby 1.8 and a single-character String in Ruby 1.9.
In Ruby 1.8, all strings are assumed to be in the same encoding (usually ASCII, but can be changed to a very limited set, namely UTF-8 and a couple of Asian encodings). Ruby 1.9 is fully encoding-aware, each string has its own separate encoding, each I/O stream has two encodings (an internal one and an external one) and each source file has a separate encoding.
Your best bet might be to restrict yourself to use only what is specified in the ISO Ruby Language Specification. The spec was specifically written so that all existing Ruby implementations at the time (MRI, YARV, IronRuby, JRuby, MacRuby, Rubinius) would automatically be compliant, which basically means that the spec only specifies the minimal required subset of the intersection of Ruby 1.8.6, Ruby 1.8.7, and Ruby 1.9.0.
Since there haven't been any backwards-incompatible changes since then, you can be assured that your code will work on all versions from Ruby 1.8.6 up to (but excluding) 3.0, and on all ISO-compliant Ruby implementations, which are as far as I know MRI, YARV, JRuby, IronRuby, Rubinius, MacRuby, MRuby, MagLev, and TruffleRuby.

Equivalent of String#setbyte and String#getbyte in ruby 1.8

Trying to get the aerospike ruby client to work under 1.8
What is the equivalent of these calls in ruby 1.8 ?
https://github.com/aerospike/aerospike-client-ruby/blob/master/lib/aerospike/utils/buffer.rb#L65
https://github.com/aerospike/aerospike-client-ruby/blob/master/lib/aerospike/utils/buffer.rb#L95
IIRC, Ruby 1.8 strings are, for all intents and purposes, what 1.9 would treat as ASCII-8BIT. As such, String#[] and String#[]= are the way to proceed as already suggested in the comments. (The same functions in 1.9 will target a potentially multibyte character at a certain offset, rather than a byte.)
For a more complete discussion on Ruby M17N and how strings changed in Ruby 1.9, see:
http://yokolet.blogspot.com/2009/07/design-and-implementation-of-ruby-m17n.html
http://yehudakatz.com/2010/05/05/ruby-1-9-encodings-a-primer-and-the-solution-for-rails/
Rather than rely on how a particular version of Ruby processes bytes/chars/strings, instead use the pack and unpack methods. They are always available and behave consistently.
For your use, unpack the data into an array, then you can use normal Array slicing to change the bytes in question, then pack everything back into the byte-stream.

How to match regexp starting from specific character index in Ruby 1.8?

In Ruby 1.9 I would use String#match(regexp,start_index). I'm sure there must be a (computationally efficient) equivalent in Ruby 1.8, but I can't find it. Do you know what it is?
You could start the regexp with ^.{start_index}
or take the substring first before performing the match.
Alternatively, if you're constrained to using Ruby 1.8, but can install your own libraries then you could use Oniguruma.
As far as I can tell, there is no efficient way to match a Regexp against a large string, starting from an arbitrary index, in pure Ruby 1.8.
This seems like a major flaw. I guess the moral of the story is: use Ruby 1.9!

Count instances of a value in an array in Ruby 1.8.6

The following line is working fine in ruby 1.8.7 and not in 1.8.6. What alternative I can use in 1.8.6
x = [3,4,5,6,7,78,4,3,2,5,5,3]
x.count(3)
=> 3
Since count is not a method in Array in version 1.8.6, I am getting this error. Is there a similar method in this version?
x = [3,4,5,6,7,78,4,3,2,5,5,3]
x.grep(3).size
#=> 3
count = x.select {|e| e == 3}.size
As a general tip: there is the really cool backports library by Marc-André Lafortune, which tries to implement as much of the new features of the Ruby 1.8.7, 1.8.8 (i.e. the tip of the 1_8 branch in the Subversion repository), 1.9.1 and 1.9.2 standard libraries as well as some select methods from ActiveSupport as possible in pure, cross-1.8-1.9-compatible Ruby.
So, if you just do
require 'backports'
it will turn your Ruby 1.8.6, 1.8.7 or 1.9.1 into as close to Ruby 1.9.2 as is possible without dropping to C or breaking backwards compatibility.
Disclaimer: I haven't actually used it myself, since I don't see the point of using an outdated version of Ruby anyway.

Do all Ruby interpreters follow the same Ruby syntax?

Do all Ruby interpreters follow the same Ruby syntax defined in www.ruby-lang.org?
MRI
YARV
Rubinius
JRuby
IronRuby
Cause it is the interpreter that defines the Ruby language. Does that mean one interpreter could add a feature/syntatic sugar that other interpreters haven't?
If that is the case, do all interpreters have their own API documentation?
Cause I'm using: http://ruby-doc.org/ruby-1.9/index.html.
Which interpreters are implementing that one?
Could someone shed a light on this topic.
Thanks!
Do all Ruby interpreters follow the same Ruby syntax defined in www.ruby-lang.org?
Yes, they all use the same syntax. In fact, they actually all use the same parser, or at least a parser that was automatically generated from the same source file.
Cause I'm using: http://ruby-doc.org/ruby-1.9/index.html.
Which interpreters are implementing that one?
At the moment, the only production-ready Ruby execution engine that implements Ruby 1.9 fully is YARV.
JRuby itself is production-ready, and it implements both Ruby 1.8.7 and Ruby 1.9.2, but the Ruby 1.9.2 implementation is not yet complete. IronRuby and Rubinius are also working on implementations of Ruby 1.9.2. MacRuby has a fairly complete Ruby 1.9 implementation, but it is still far from a 1.0 release. MRI doesn't implement Ruby 1.9 and probably never will.
But I don't understand why you are so concerned about the syntax. Syntax differences are trivial to spot: if there were a difference in the syntax, the engine would simply refuse to parse your file and you would know immediately that there is something wrong. Differences in semantics on the other hand are much more dangerous.
Which bit of "syntactic sugar" are you referring to?
Keep in mind that ruby has a very small set of keywords. A lot of stuff that seems to be a keyword at first is actually implemented by Kernel (eg require, puts, and raise).
http://apidock.com/ruby/Kernel

Resources