Blog

Gem on debian moved permanently (1 comment)

Added by Christoph Kappel over 7 years ago

Debian seems to have big problems with gem and the different versions, you will notice when you see this:

1 > gem list --remote
2 
3 *** REMOTE GEMS ***
4 
5 ERROR: While executing gem ... (Gem::RemoteFetcher::FetchError)
6 bad response Moved Permanently 301 (http://gems.rubyforge.org/latest_specs.4.8)

Apparently there is an easy fix, just update the sources of gem:

 1 > gem sources
 2 *** CURRENT SOURCES ***
 3 
 4 http://gems.rubyforge.org/
 5 
 6 > gem sources -r http://gems.rubyforge.org/
 7 http://gems.rubyforge.org/ removed from sources
 8 
 9 > gem sources -a http://production.s3.rubygems.org/
10 http://production.s3.rubygems.org/ added to sources

Unknown encoding in ruby 1.9.1-p429 (4 comment)

Added by Christoph Kappel over 7 years ago

Updating Ruby is usually a task that breaks many things, therefore I avoid it if possible. Being archuser, the maintainer of the Ruby decides when I need to face new problems.

This time they just added filesystem encoding stuff in p429:

Error loading gem paths on load path in gem_prelude
unknown encoding name - filesystem
<internal:gem_prelude>:69:in `find'
<internal:gem_prelude>:69:in `set_home'
<internal:gem_prelude>:38:in `dir'
<internal:gem_prelude>:76:in `set_paths'
<internal:gem_prelude>:47:in `path'
<internal:gem_prelude>:286:in `push_all_highest_version_gems_on_load_path'
<internal:gem_prelude>:355:in `<compiled>'

There exists still now sane way to init the gem path of Ruby so we can start with our hack from Setup gems load path in embedded ruby and add the required encoding stuff. This problem is known in the ruby redmine and the changesets to this issue give at least some hints what need to be done:

Numbers: on /off 1 #include <ruby/encoding.h>
 2 
 3 VALUE encoding = Qnil;
 4 
 5 void Init_prelude(void);
 6 
 7 RUBY_INIT_STACK;
 8 ruby_init();
 9 ruby_init_loadpath();
10 ruby_script("subtle");
11 
12 /* Get encoding from file system */
13 encoding = rb_enc_from_encoding(rb_filesystem_encoding());
14 
15 /* Set internal and external encoding */
16 rb_enc_set_default_internal(encoding);
17 rb_enc_set_default_external(encoding);
18 
19 /* FIXME: Fake ruby_init_gems(Qtrue) */
20 rb_define_module("Gem");
21 Init_prelude();

Inheritance of Ruby classes defined in C

Added by Christoph Kappel over 7 years ago

Creating a Ruby class directly via C is really painless, under normal circumstances you don't even have to worry about the alloc stuff. Just supply a #initialize when needed and you are done.

Numbers: on /off1 klass = rb_define_class("Test", rb_cObject);
2 rb_define_method(klass, "initialize", TestInit, 0);

Inheritance in this case works like a charm, your initialize will be called like expected. It get's more tricky when you need to call Data_Wrap_Struct. The function itself allocates an object and returns it with your supplied data pointer attached.

First solution you will most likely come up with is defining your own .new like this:

Numbers: on /off1 klass = rb_define_class("Test", rb_cObject);
2 rb_define_singleton_method(klass, "new", TestNew, -1);

Since we overwrite the default .new we need to do the call to #initialize by ourself:

Numbers: on /off 1 VALUE
 2 TextNew(int argc,
 3   VALUE *argv,
 4   VALUE self)
 5 {
 6   VALUE instance = Qnil;
 7   void *ptr = NULL;
 8 
 9   /* Fill ptr with something reasonable */
10 
11   instance = Data_Wrap_Struct(self, NULL, NULL, ptr);
12 
13   /* Pass arguments to initialize */
14   rb_obj_call_init(instance, argc, argv);
15 
16   return instance;
17 }

This will wrap our data pointer and call #initialize with all arguments - no problems so far.

Problems start when someone wants to inherit from this class:

Numbers: on /off1 class AnotherTest < Test
2   :attr_reader = arg3
3 
4   def initialize(arg1, arg2, arg3)
5     super(arg1, arg2)
6     @var = arg3
7   end
8 end

Now rb_obj_call_init calls the default #initialize and not the one from the inherited class - this will most likely end with an ArgumentError.

Remember that the first version just worked and Data_Wrap_Struct creates a new object - so we can't call it in #initialize where self is immutable.

The solution is easy, don't create your own .new. We can use allocate to just allocate our object, let Ruby do the dirty stuff and rely on it to call our #initialize.

In C it looks like this:

Numbers: on /off 1 klass = rb_define_class("Test", rb_cObject);
 2 
 3 /* This defines our alloc function, slightly changed syntax */
 4 rb_define_alloc_func(klass, TestAlloc);
 5 
 6 rb_define_method(klass, "initialize", TestInit, 0);
 7 
 8 VALUE
 9 TestAlloc(VALUE self)
10 {
11   VALUE instance = Qnil;
12   void *ptr = NULL;
13 
14   /* Fill ptr with something reasonable */
15 
16   instance = Data_Wrap_Struct(self, NULL, NULL, ptr);
17 
18   return instance;
19 }
20 
21 VALUE
22 TestInit(VALUE self)
23 {
24   /* Do initialization here */
25 
26   return Qnil;
27 }

Installing Ruby19 on Gentoo

Added by Christoph Kappel over 7 years ago

Installing Ruby 19 isn't an easy task, the (hard)masking stuff in Gentoo is really a nightmare. The API of Ruby changed a lot from 18 to 19, therefore you can easily say it's not compatible. Until Gentoo has a better version management for slotted Ruby is basically, it's just masked and up to the user installing it if needed and live with the consequences.

There exists the fancy RUBY_TARGETS mechanism, which is intended to allow packages be build for different flavors like ruby18, ruby19, jruby and ree (Ruby Enterprise Edition). According to the manpage and the nice guys in #gentoo-ruby on Freenode you just need to add RUBY_TARGETS="ruby19" in your /etc/make.conf - it doesn't.

After a bit of talk and testing various possible solutions suggestions I found it: You need to override the mask of the flag for ruby19 which is ruby_targets_ruby19 and this can be done in /etc/portage/profile/use.mask.

To make long story short just do this:

Numbers: on /off1 mkdir -p /etc/portage/profile
2 echo "dev-lang/ruby ~x86" >> /etc/portage/package.keywords
3 echo "dev-lang/eselect-ruby ~x86" >> /etc/portage/package.keywords
4 echo "dev-lang/ruby" >> /etc/portage/package.unmask
5 echo "dev-lang/eselect-ruby" >> /etc/portage/package.unmask
6 echo "-ruby_targets_ruby19" >> /etc/portage/profile/use.mask
7 echo 'RUBY_TARGETS="ruby19"' >> /etc/make.conf

In case you also need rake:

Numbers: on /off1 echo "dev-ruby/rake ~x86" >> /etc/portage/package.keywords
2 echo "dev-ruby/rubygems ~x86" >> /etc/portage/package.keywords
3 echo "dev-ruby/rake" >> /etc/portage/package.unmask
4 echo "dev-ruby/rubygems" >> /etc/portage/package.unmask

Using xmlrpc in sinatra

Added by Christoph Kappel almost 8 years ago

During my experiments with buildbot I discovered the xmlrpc interface and think it would be a nice addition to the Sinatra based surserver - actually I don't like XML at all. Once you know how to get the XML document from a rack request the rest is trivial:

Sinatra

Numbers: on /off 1 require "rubygems" 
 2 require "sinatra" 
 3 require "xmlrpc/marshal" 
 4 
 5 helpers do
 6   def upper_case(args)
 7     XMLRPC::Marshal.dump_response(args[0].upcase)
 8   end
 9 end
10 
11 post "/xmlrpc" do
12   xml = @request.body.read
13 
14   if(xml.empty?)
15     error = 400
16     return
17   end
18 
19   # Parse xml
20   method, arguments = XMLRPC::Marshal.load_call(xml)
21   method = method.gsub(/([A-Z])/, '_ ').downcase
22 
23   # Check if method exists
24   if(respond_to?(method))
25     content_type("text/xml", :charset => "utf-8")
26     send(method, arguments)
27   else
28     error = 404
29   end
30 end

Basically we parse the incoming XML, dispatch the call to a matching handler method and send a XML response back.

Client

Numbers: on /off1 require "xmlrpc/client" 
2 
3 server = XMLRPC::Client.new("127.0.0.1", "/xmlrpc", 4567)
4 puts server.call("upper_case", ARGV[0])

The client is a mere call of the XMLRPC::Client API to get the result.

Output

1 % ruby xmlrpc.rb foobar
2 FOOBAR

Setup gems load path in embedded ruby (1 comment)

Added by Christoph Kappel almost 8 years ago

Ruby lacks a way to proper init the load path for gems without using stuff like ruby_options(), which will make things even worse. Generally this is, because Ruby wasn't developed to be embedded in the first place, that also explains the lack of docs about this topic.

Reading through the code these lines here are exactly what we are looking for:

Numbers: on /off 1 /* ruby.c:1055: */
 2 void Init_prelude(void);
 3 
 4 static void                                            
 5 ruby_init_gems(int enable)                                
 6 {
 7   if (enable) rb_define_module("Gem");                                   
 8   Init_prelude();                                             
 9 }

Looks good, but ruby_init_gems() is static and thus not accessable by third party like us. The workaround is to mimic the function in our code, this includes the forward declaration of Init_prelude() or our compiler will complain about it.

In subtle I use the following to init the vm:

Numbers: on /off 1 void Init_prelude(void);
 2 
 3 RUBY_INIT_STACK;
 4 ruby_init();
 5 ruby_init_loadpath();
 6 ruby_script("subtle");
 7 
 8 /* FIXME: Fake ruby_init_gems(Qtrue) */
 9 rb_define_module("Gem");
10 Init_prelude();

If you insist to know what Init_prelude() really does have a look at the miniprelude.c file of the Ruby tarball.

Also available in: Atom RSS