Scripting with Ruby

Posted by Twisol on Tue 28 Jul 2009 07:06 PM — 7 posts, 21,598 views.

USA #0
I managed to get Ruby scripting running pretty easily, although it was quite a fight finding an wsh-integrated version. I finally found an ActiveRuby install (not related to the people at ActiveState unfortunately), which worked just fine when I set it up.*

I haven't gone too deep into it, but I already found some problems if I try to print to the screen without using Note or any of the other MUSHclient functions. print, p, and puts all fail (as well as gets, which waits for user input) due to a "bad file descriptor". I have no way to tell whether this is a MUSHclient problem or an ActiveRuby problem, though. I am glad to say that fun constructs like "3.times do Note 'Hi!' end" work perfectly, though. ;)

Any idea what's up with the bad file descriptor? Seems to me like STDIN/STDOUT aren't set right, or something...


* http://www.geocities.co.jp/SiliconValley-PaloAlto/9251/ruby/main.html

EDIT: Hmm... functions like Note() have to match the declared parameter amount exactly, so I can't do Note() or Note(a, b), just Note(a). (But I can do Note(a + b) fine)
Amended on Tue 28 Jul 2009 08:01 PM by Twisol
Australia Forum Administrator #1
MUSHclient is not a console application, and therefore the file descriptors stdin, stdout and stderr do not exist.

Any attempt to do things like print to stdout (or stderr) or get input from stdin will therefore fail.

In Lua, I replaced the standard "print" function with one that basically calls world.Note, thus "printing" to the output window.

You are right that "functions like Note() have to match the declared parameter amount exactly" because all the script languages that use the Windows Script Host use COM (Component Object Model) and that uses a well-defined interface (ie. a fixed number of arguments). Some script languages also check that the correct return value is present too, so that methods that specify a return code must provide one.

In the case of Lua, again since I wrote a set of "glue" routines from scratch, certain functions (eg. Note) I extended by allowing multiple arguments. Quite a few of them call concatArgs (in lua_methods.cpp) which simply gets as many arguments as it can, concatenates them together into a single string, and then calls the underlying function.
USA #2
Hmm, I see. That makes sense, I guess I'm just a bit spoiled on Lua. ^_^

New problem, though. If I define a method, for some reason I'm unable to call it. This code works fine in the Ruby interpreter (except with print instead of Note), so I'm at a loss.


Script error
World: Sol_ruby
Execution of line 5 column 1
Immediate execution
Unknown property or method : Test
Unknown name
Error context in script:
   1 : def Test
   2 :   Note "Hi."
   3 : end
   4 : 
   5*: Test()


def Test
  Note "Hi."
end

Test()



(EDIT: The code is defined in the script file, exactly as shown.)

(EDIT 2: It doesn't appear to be an ActiveRuby-specific issue, because I loaded up its specific interpreter and ran this, and it worked fine.)
Amended on Tue 28 Jul 2009 09:36 PM by Twisol
Australia Forum Administrator #3
Try wading through this thread:

http://www.gammon.com.au/forum/bbshowpost.php?id=7857
USA #4
There we go! I found a solution on page 2, I just need to add 'self.' to the method definition. It works now! :D
USA #5
I'm working on a Ruby module with "glue" functions to make accessing the MUSHclient interface more natural (like you can pass variable arguments to Note) - thought I'd mention that.

It seems to me like there really should be a way to tell a Windows Script Host object what its stdout/stdin descriptors should be, or access them during the course of the program. Could this link (*) help provide that functionality? If it could be used that way, you could easily check its StdOut property after a script has run, and print it out...

* http://msdn.microsoft.com/en-us/library/cbxxzwb5(VS.85).aspx
USA #6
It uh, it took a while, but I finally came back to try Ruby again. Here's a basic compatibility layer for Ruby/MUSHclient scripting. It's still a work-in-progress, but it'll likely only change as I try to use things that need adding, so if anyone thinks something needs to be changed, let me know!


module MUSHclient
  @sendto = {:world => 0,
             :command => 1,
             :output => 2,
             :status => 3,
             :notepad => 4,
             :notepadappend => 5,
             :logfile => 6,
             :notepadreplace => 7,
             :commandqueue => 8,
             :variable => 9,
             :execute => 10,
             :speedwalk => 11,
             :script => 12,
             :immediate => 13,
             :scriptafteromit => 14
            }

  def self.append_features(klass)
    klass.instance_eval do
      class << @world
        def Note(*text)
          super(text.join)
        end

        def Tell(*text)
          super(text.join)
        end

        def EnableGroup(name, on=true)
          super(name, on)
        end
      end

      def puts(*text)
        Note(*text)
      end

      class << STDOUT
        def puts(*text)
          Note(*text)
        end
      end
    end

    $sendto = @sendto

    super
  end
end


To use, just add a single line to the main script file:


include MUSHclient


The module will take care of the rest. If you put the MUSHclient module in its own file, though, you'll need to make sure you require that file before including the module:


require 'its_file_name.rb'
include MUSHclient