IronRuby - how to require .NET assemblies without strong name? - ironruby

This page on the IronRuby help website talks about being able to 'require' some well-known assemblies such as System.Windows.Forms without needing to crank out the entire 'ah-come-on-gimme-a-break-here-you-cannot-be-serious' strong name of the assembly.
In the docs it says this:
>>> require "System.Windows.Forms"
=> true
But when I try the same 'require', I get this:
>>> require "System.Windows.Forms"
IronRuby.Libraries:0:in 'require': no such file to load -- System.Windows.Forms (LoadError)
from :0:in 'Initialize##1'
What might I be doing wrong? Could it be a setup problem? I can't see this "libs directory on the load path" that gets mentioned in the documentation. Is the documentation wrong?
Thanks.

The way that this works is because the IronRuby guys have written a bunch of wrapper scripts.
Look in <your ironruby install path>\lib\ironruby and you'll see System.Windows.Forms.rb, System.Drawing.rb etc.
What happens when you do require 'System.Windows.Forms' is that IronRuby finds that rb file and runs it. The code inside that file just does the full strong-named require for you.
If you want to load other dll's that they haven't written wrappers for, you have 3 options:
require the full path to the dll (eg c:\program files\whatever\whatever\blah.dll)
require the strong name (this only works if it's in the GAC or somewhere else IronRuby can find dll's in)
use load_assembly - This is the most convenient, but IIRC it loads the dll into the LoadFrom context, not the Load context.
If you don't understand what that means, then basically it's fine in testing, but don't do it in production :-)

Well, it was a setup problem - there were two copies of ir.exe in the IronRuby download, and I was using the wrong one.

Related

How does require 'digest/md5' works?

require 'digest/md5' # => true
Digest::Md5.hexdigest('') # => "d41d8cd98f00b204e9800998ecf8427e"
Which file does this require use? Is an actual file being required? Or is it required programmatically?
This is (sorta) explained in the documentation for Kernel#require:
require(name) → true or false
Loads the given name, returning true if successful and false if
the feature is already loaded.
If the filename does not resolve to an absolute path, it will be
searched for in the directories listed in $LOAD_PATH ($:).
If the filename has the extension “.rb”, it is loaded as a source file; if
the extension is “.so”, “.o”, or “.dll”, or the default shared library
extension on the current platform, Ruby loads the shared library as a Ruby
extension. Otherwise, Ruby tries adding “.rb”, “.so”, and so on to the
name until found. If the file named cannot be found, a LoadError will be raised.
By default $LOAD_PATH will include the directories where Ruby's standard library lives. Directories, plural, because native (compiled binary) modules in the standard library live in a different directory than pure-Ruby modules.
Digest is actually a great example because some of its files are native and others are Ruby.
On my Mac $LOAD_PATH includes (among others) these two directories (truncated for readability):
.../usr/lib/ruby/2.0.0
.../usr/lib/ruby/2.0.0/universal-darwin15
The former is where pure-Ruby modules live and the latter is where native modules live.
So when I do require 'digest/md5' Ruby first looks in .../usr/lib/ruby/2.0.0/ for a directory named digest/, and upon finding it, for a file in it named md5.rb. It doesn't find it, so it looks for md5.bundle. Why .bundle and not .so or .o? Because that's the "default shared library extension" that Ruby was configured with when it was compiled for OS X. Go figure.
Ruby doesn't find it there, so next it looks in .../usr/lib/ruby/2.0.0/universal-darwin15/digest/. There's no md5.rb there, but there is an md5.bundle, so Ruby loads it.
It loads a C-extension that can be found in Ruby's source dir - ruby/ext/digest/md5/
It's one of Ruby's standard libraries (stdlib), which means that it's available in pretty much every implementation of Ruby. It does, in fact, load a file. But it's a file that was copied to your computer when you installed Ruby and is pretty much always going to be available to you. Another good example of a standard library is DateTime.
One thing that confused me a lot when I started learning Ruby and Rails was that Rails requires a fair number of Ruby's standard libraries for you. So it's good to be aware of what's actually going on under the hood.

Ruby Fiddle dll search Path

I am trying to load a dll using the following fiddle code: ( If there is a easier way to load a dll and call a function on it that would solve my problem I am happy to hear it )
require 'fiddle' unless defined?(Fiddle)
require 'fiddle/import' unless defined?(Fiddle::Importer)
extend Fiddle::Importer
dlload "Foo.dll"
dlload "C:/Folder/Foo.dll" works like I want. But the problem is that Foo.dll is a c++ dll that requires several other dlls in various locations.
How do I go about just calling dlload "Foo.dll" without a full path. In short how do I add a list of directories to the Ruby dll search path?
I have tried the following:
$LOAD_PATH.unshift("C:/Folder")
ENV['RUBYLIB'] = "C:/Folder"
ENV['LD_LIBRARY_PATH'] = "C:/Folder"
The ruby interpreter is running inside another program (Sketchup), so my environment is restricted.
The only solution I got to work was writing a small kernel32.dll library and calling AddDllDirectory from within it.

What are the ruby conventions for $LOAD_PATH for non-gems?

I have some code in a ruby project. From what I understand, library code should live in the lib folder.
so I have
/lib
/mymodule.rb
/mymodule
/somefile.rb
I have been using this internal library by calling require 'relative/path/to/lib/mymodule.rb'. What is the best practice to all this library code to the $LOAD_PATH? All I want to do is say
require 'mymodule'
instead of requiring the file directly.
I have been googling around for the last 30mins, and it is not obvious to be what the best practice/convention is.
You can either use require_relative, which might be a bit messy if
you move files around and therefore slightly unstable. Or set
$LOAD_PATH in a startup/init file of your project. Just be aware of
using your own subfolder in that case to avoid name conflicts with
your gems.

How to use WinSxS manifests to redirect to an older version of a DLL?

Let's say I have an application that uses MSHTML. Installing IE9 beta would update MSHTML which breaks my application. I found that copies of IE8 dll is still present in the WinSxS folder, so maybe I can somehow use them without recompiling my program? Can WinSxS do it?
I've searched for a long time but couldn't figure out how to redirect the loader to use the IE8 MSHTML (which is in WinSXS) instead of the IE9 (which is in %SYSTEMROOT%\system32). Any ideas/examples would be appreciated.
I've since gone with a different approach to this problem. I'll share what I eventually did -- I hijack LoadLibrary and load whatever DLL I want: DLL file loaded twice with DLL redirection through manifest.
To answer the specific title of the question ("use WinSxS manifests to redirect"), I'll answer with "No, you can't" based on my long time battle with WinSxS (downvote if you disagree, I'll be happy to see how that can be done.)
You definitely can't use WinSxS manifests or policy redirection to force loading different versions of OS components. While os components are also stored in the WinSxS store, they are not bindable as sxs assemblies and so this kind of redirection is not possible.
Grovelling around to redirect LoadLibrary and force loading of an older version of mshtml (or any other OS DLL) is a very bad idea and I strongly recommend against it. Reasons include the fact that the older DLL may not be present on all installs, that you are unlikely to correctly hook all the loading paths (and hence create a strange hybrid), and of course that things like MSHTML are designed for use in a specific way and any other use could lead to problems later - especially in security sensitive stuff like HTML.
Martyn

In Ruby, what's the equivalent of Java's technique of limiting access to source in a cowork situation?

In Java when you compile a .java file which defines a class, it creates a .class file. If you provide these class files to your coworkers then they cannot modify your source. You can also bundle all of these class files into a jar file to package it up more neatly and distribute it as a single library.
Does Ruby have any features like these when you want to share your functionality with your coworkers but you don't want them to be able to modify the source (unless they ask you for the actual .rb source file and tell you that they want to change it)?
I believe the feature you are looking for is called "trust" (and a source code control repository). Ruby isn't compiled in the same way that Java is, so no you can't do this.
I have to say your are in a rough position, not wanting to share code with a coworker. However, given that this is an unassailable constraint perhaps you could change the nature of the problem.
If you have a coworker that needs access to some service provided by a library of yours, perhaps you could expose it by providing a web/rest service instead of as a .rb file.
This way you can hide your code behind a web server, and if there is a network architecture that allows for low latency making these service calls, you can effectively achive the same goal.
Trust is a lot easier though.
edit:
Just saw this on HN: http://blog.astrails.com/2009/5/12/ruby-http-require, allows a ruby file to include another file through http instead of the filesystem.
Ruby is
A dynamic, interpreted, open source programming language with a focus on simplicity and productivity.
So like all interpreted languages, you need to give the source code to anyone who want's to execute your program/script.
By the way searching "compiled ruby" on google returned quiet a few results.
I don't think there is one. Ruby is purely an interpreted language, which means ruby interprets your source code directly in order to run it. Java is compiled, so there's an intermediate bytecode (the .class). You can obfuscate your ruby if you really wish, but it's probably more trouble than it's worth.
Just to make sure you realize, however, upwards of 95% of Java can be decompiled back into source using various free utilities, so in reality, Java's compilation isn't much better than distributing Ruby source.
This is not a language specific problem and one that can be managed more effectively through source control software.
There is a library called ruby2c that compiles a subset of Ruby into C code (which you can then compile into native code, if you want).
It was actually originally written as a Ruby code obfuscator (but has since been used for lots of other stuff, including Ruby Arduino development).

Resources