How to freeze ruby standard library? - ruby

Ruby allows to re-open any class and re-implement or override methods.
Gems under supply chain attack can re-open standard library classes or core classes, re-implement frequently used methods and start recording or logging important data (say Net:HTTP library's GET/POST calls).
How do we freeze standard library classes such that the process crashes or throws warning when a rogue gem tries to re-open/re-implement them?
ActiveSupport is a popular library that does quite a lot of this. Outside ActiveSupport and gems that are too popular where its hard to not detect a supply chain attack, other gems need to cross some sort of fencing before they are allowed to override ruby std library or std/core classes.
Does ruby (or) rails community address this concern in any way today?

Related

What makes a gem incompatible with JRuby?

I ran bundle install and to my surprise, most of the gems that ship with Rails 4 installed just fine. byebug was one that did not, but no big deal.
What makes a gem incompatible with JRuby exactly?
In this particular case, the gem is written as a C extension for YARV, so it works only with YARV, not any other Ruby implementation, including, but not limited to, JRuby, Rubinius, MagLev, MRuby, IronRuby, etc.
The sad part is: as far as I can see, it only uses public Ruby APIs, it doesn't actually use any private internal information of the YARV VM, so it could just as well have been written in portable Ruby.
In general, there are several reasons why a gem may work only on one particular Ruby implementation:
It uses some particular feature of the host platform that is not available to all Ruby implementations. For example, a gem written in Java which uses Java platform libraries, will most likely not work with YARV, only with JRuby.
It accesses private internal implementation details of a particular Ruby implementation. This is obvious, I think. What's not so obvious is that there is no portable C API even amongst C-based Ruby implementations. What is usually called the "Ruby C extension API" is really just YARV laying bare its internals. Both Rubinius and JRuby have put in an enormous amount of work developing emulation layers for YARV so that at least some C extensions work, but it's hard. For example: YARV's garbage collector is extremely simple, it never moves objects in memory. Many C extensions rely on that, but this is simply not true for modern GCs such as Rubinius's or the JVM's. YARV doesn't allow multiple Ruby threads to run at the same time, many C extensions rely on that, but this is not true for pretty much all other Ruby implementations. And so on … Plus, those emulation layers are slow. Really slow. It is perfectly possible for a gem that has been "re-written in C for performance" to run slower than its pure-Ruby counterpart on JRuby or Rubinius. (After all, Rubinius can, in some cases, already compete with C. E.g. the Hash class in Rubinius is written in Ruby, and performs comparable to YARV's Hash class which is written in C.)
It uses a Ruby feature that is missing from a particular implementation. For example, Refinements have been widely criticized for being un-implementable in implementations that perform aggressive optimization of method lookup (or more precisely: Refinements, the way they are currently specified, make it impossible to apply those optimizations). The designers of Refinements all happen to be YARV developers, where it doesn't matter, because YARV doesn't optimize method lookup anyway, but e.g. the JRuby developers have decided to simply not implement Refinements. (10 years ago, they did the same thing with continuations.) So, if a gem uses Refinements, it won't work on JRuby.
The Rubinius and JRuby developers have developed an FFI API that can be used to make C APIs available from Ruby in a manner that is portable across many Ruby implementations. Rubinius, JRuby, MacRuby, and (I believe) MagLev support FFI natively, and for YARV, there is a gem which adds FFI support to it. Gems that use the implementation-independent FFI API instead of the YARV API should work on pretty much all implementations. However, the FFI API doesn't give access to the implementation internals (obviously), so for some gems it is not usable. For example, there are gems which try to give you access to the source code of a Proc, that's highly implementation-specific (and may not even work, e.g. when you ahead-of-time compile to a Java .class file with jrubyc, the source code doesn't even exist at runtime), so there has to be a different version of that gem for every Ruby implementation.

Rubinius in RubySL

I use Ruby from a user level and really don't deal with the internals. I have know Rubinius as 'Ruby in Ruby' which I assumed was a generalization. Recently, I got an error with Rubinius in the RubySL (no, I don't have error msg).
I started looking at RubySL and was a little surprised to see Rubinius everywhere. I really like Ruby and was just curious why Rubinius is in most of the RubySL? It seems to be used with things like locks / unlocks (such as https://github.com/rubysl/rubysl-thread/blob/2.0/lib/rubysl/thread/thread.rb ). Definitely not questioning it, just curious.
RubySL is short for Ruby Standard Library. It is a basic part of the shipped code bundle which forms what is generally known as Ruby. The standards library provides rather basic stuff you often need but which doesn't need to be part of the core language.
For example, the implementation of the Hash or Array, the language keywords, how assignment works, ... are part of the core language. These are often implemented in a language other than Ruby. MRI (the common C-Ruby) implements this mostly in C, JRuby implements this in Java. Rubinius implements this patly in C++ but mostly in Ruby itself. It can do this by bootstrapping itself from a very simple base VM and gradually adding more stuff with Ruby.
The standards library however is mostly implemented in Ruby in all implementations (with some exceptions mostly for performance reasons). Now, all Ruby implementations right now have their own implementation of the Ruby standards library which can thus differ in minor details.
Rubinius' approach to implementing a standards library was to implement it as separate gems. The idea was to one day provide a common standards library which could be used by other implementations (including MRI). This is in line with the efforts of esp. the Rubinius community to drive the RubySpec project in order to provide a common language specification and test suite for all Ruby implementations.
The RubySpec project was eventually abandoned and right now, it doesn't seem as if other Ruby implementations seem to be moving to the RubySL gems for implementing their standards library.
Thus, (and this is the TL;DR), the RubySL gems implement the Ruby Standard Library for the Rubinius project. Thus, it is expected to see the Rubinius project all over the place there: it is their code which is generally not used by other Ruby implementations.

jRuby and Rubinius support parallel computing, but what about gems that don't support this?

What I'm trying to understand is, practically speaking, how much benefit do I get from the parallel computing support in jRuby / Rubinius? A lot of ruby libraries keep track of global internal state. Is there any way to deal with these libraries, or do they just become unusable if I decide to parallelize my Ruby script? Maybe Rubinius automatically puts a mutex in front of all usage of unsafe libraries?
Whenever you want to use jruby or rubinius, you'll be forced to use gems that are compatible.
Many gems has been implemented using C extensions and you can not use them along jruby e.g.
Regarding others, mostly they clearly states their thread safety status.
So choosing jruby or rubinius will narrow down your options regarding the gems.
but a huge opportunity will be exposed, you'd be able to use many mature Java Libraries(in jruby case).

Using Iron Ruby classes in native Ruby class

I'm wondering if an Iron Ruby class/object can be used in a native ruby interpreter(irb) driven class(using a gem sort of a thing) ? The main problem is that I have a ruby class that is using some gems(Ex: nokogiri) which are not compatible with Iron Ruby and Iron Ruby class is using .Net libraries. So in short, I want to know if there are any ways to communicate with iron ruby classes in native ruby. If there are any alternatives to solve this, please do mention them.
No other way than having two different processes for each ruby interpreter running with some kind of communication. You could use distributed ruby for that. Anyway, the best thing to do is to not use .Net libraries and replace them with something else from ruby world.

Ruby C Bindings vs. Ruby Wrapper for System Calls

What are the major differences between the execution of Ruby C bindings vs. Ruby wrapper for system calls?
To my question into context, I am looking into incorporating Git version control functionality heavily into a Ruby on Rails application. In approaching this task I do not understand the how to think about the execution pipeline of a Ruby program which incorporates a library implemented with Ruby C bindings such as yajl-ruby vs. a Ruby wrapper for system calls such as the git Ruby Gem.
Bindings interface directly with the library's API, while wrappers use system calls to invoke the end-user application from the command line.
Wrappers are similar to UNIX pipes – programs have no knowledge about each other's internals and communicate through a textual interface. Loose coupling comes with a price, though. System calls are expensive operations and will dramatically slow down your application.
This is why bindings are great. Since they use the library's programming interface, the overhead is significantly reduced. GitHub had its own git wrapper, and speed was issue that led them to implement git in Ruby.
They did it themselves because it is kind of hard to make bindings for git. It wasn't designed to be used as a library. It's really awkward to call its functions directly since it calls die() on pretty much any error.
The demand for a proper git library led to the development of libgit2. It even comes with Ruby bindings! Since you want to integrate git functionality with your application, you should check it out.

Resources