Advice about using a little Ruby script with / without Rails

People,

I just read some more of the comments on the "Are we dying?" thread and I realised I, too, am happy with a ML environment and low volume means it is easier to make sure I don't miss interesting stuff when I am scanning Subjects! Anyway, I thought of another Q that people might have good suggestions / advice about:

I have a Java chatbot on my server and this Ruby script to chat with it:

#!/usr/bin/ruby

require 'socket'
require 'json'

session = "SESSION_philip_rhoades_"
session = session + `echo $LOGNAME`.chomp
session = session + "@pricom.com.au"

session_init = "@" + session

host = "localhost"

dfname = nil

if dfname == nil
   dfname = 'Unknown Unknown'
end

dname = dfname.split[0]

while true
   print "> "
   input = gets.chomp

   if (input == "quit") then
     break
   end

   xmit = {
     :commands => {
     :users_name => "Philip",
     :users_fullname => "Philip Rhoades",
     :name => "Phil"
     },

     :topic_slug => "phirhodev",
     :session_id => session_init,
     :message => input
   }

   # Send it and get the client response
   s = TCPSocket.open(host, 9192)
   s.puts xmit.to_json

   while true
     response = s.gets.chomp

     if response == "@@END_OF_REPLY"
       break
     end
   puts response
   end

   s.close
end

This works fine for myself in an xterm but I also want be able to plug this functionality into a Rails web page on various Rails sites - what is the best way of dealing with this? - a gem? What I would like is a setup that will work in a script (like above) but will also work in a Rails environment.

Thanks!

Phil.

···

--
Philip Rhoades

PO Box 896
Cowra NSW 2794
Australia
E-mail: phil@pricom.com.au

Philip Rhoades <phil@pricom.com.au> writes:

What I would like is a setup that will work in a script (like above)
but will also work in a Rails environment.

Don’t tie it specifically to Rails. Rails is just Ruby after all, so
what you want is not “it works in Rails”, but “it works if used from
another Ruby program”. This is what one usually calls a library.

RubyGems gives you the possibility to include both executable scripts
and libraries (the “coderay” gem for example comes with both); see [1]
for the docs for this. If you package your script like that, both will
work. You’ll have to write a reasonable API, though, otherwise it’s not
really usable as a library. If you take this approach, you’ll usually
use that library from within the additionally supplied executable in
bin/ in order to prevent duplicate code.

A more leightweight and gem-less approach is the classic:

    if __FILE__ == $0
      # Script has been run directly
    end

This condition will evaluate to true when your script has been invoked
directly, and false if it was required by another one. It’s been a while
since I last saw a script making use of this, but there is no reason why
it shouldn’t still work. $0 is the path to the program the user invoked
originally, and __FILE__ is the path to the currently evaluated file. If
both match, then this file was the file executed first. Note the
condition might expose some unexpected behaviour in edge cases, though.

Thanks!

Phil.

Greetings
Marvin

[1]: Specification Reference - RubyGems Guides

···

--
#!/sbin/quintus
Blog: http://www.guelkerdev.de

GnuPG key: F1D8799FBCC8BC4F

session = "SESSION_philip_rhoades_"
session = session + `echo $LOGNAME`.chomp
session = session + "@pricom.com.au"

Minor nit: use ENV['LOGNAME'] to access the variable directly
to avoid fork+exec for echo. This probably reads more easily:

  session = "SESSION_philip_rhoades_#{ENV['LOGNAME']}@pircom.com.au"

The big difference between standalone and web app is below:

while true

When you write a web application or service, it already implies the
existence of an infinite loop around your program (provided by your web
server). So you should not code your own; and instead define
callback/entry points.

I recommend Sinatra as a good way to learn HTTP and build services
around it. It's lighter than Rails, doesn't require a JavaScript
engine, and very AWK-like in it's API.

  print "> "
  input = gets.chomp

And your input handling would be handled as HTTP request parameters.
And the rest is the meat of your code which can be shared between
your standalone script and web app.

  # Send it and get the client response
  s = TCPSocket.open(host, 9192)
  s.puts xmit.to_json

  while true
    response = s.gets.chomp

For later, when you start caring about reliability:

  You should add timeouts for all your network requests (open/puts/gets).
  And avoid buffered reads with IO#gets, even; since it could block
  indefinitely (networks are unreliable).
  You will need to use IO#read_nonblock/readpartial and build your own
  line-parsing instead of IO#gets.

···

Philip Rhoades <phil@pricom.com.au> wrote:

Quintus and Eric,

Thanks for your helpful responses but I probably wasn't clear enough in my post - see inline comments:

Philip Rhoades <phil@pricom.com.au> writes:

What I would like is a setup that will work in a script (like above)
but will also work in a Rails environment.

Don’t tie it specifically to Rails. Rails is just Ruby after all, so
what you want is not “it works in Rails”, but “it works if used from
another Ruby program”. This is what one usually calls a library.

Right but I am looking for a solution where I can add a "chatting" page to a number of existing Rails sites.

RubyGems gives you the possibility to include both executable scripts
and libraries (the “coderay” gem for example comes with both); see [1]
for the docs for this. If you package your script like that, both will
work. You’ll have to write a reasonable API, though, otherwise it’s not
really usable as a library. If you take this approach, you’ll usually
use that library from within the additionally supplied executable in
bin/ in order to prevent duplicate code.

OK, thanks.

A more leightweight and gem-less approach is the classic:

    if __FILE__ == $0
      # Script has been run directly
    end

This condition will evaluate to true when your script has been invoked
directly, and false if it was required by another one. It’s been a while
since I last saw a script making use of this, but there is no reason why
it shouldn’t still work. $0 is the path to the program the user invoked
originally, and __FILE__ is the path to the currently evaluated file. If
both match, then this file was the file executed first. Note the
condition might expose some unexpected behaviour in edge cases, though.

OK, thanks, I will play around with that.

What I was trying to express in my original post was the desire to have something like a text box or something that could accept typed input from the person who is typing TO the chatbot and also display the response FROM the chatbot - in a similar looking way that it happens with the Xterm interaction. I wanted something that would work in both situations - CLI and Web page - without having to do a lot of messing around with getting things in and out of text boxes etc . . maybe I am being unrealistic about what I want . .

Thanks,

Phil.

···

On 2016-01-26 18:14, Quintus wrote:
--
Philip Rhoades

PO Box 896
Cowra NSW 2794
Australia
E-mail: phil@pricom.com.au

Quintus,

Hi Philip,

first, why don’t you send this to the list?

I DID actually . . and cc'd you two . .

Second, your email headers
are set slightly confusing. If you want to engage in a private thread
with me an Eric,

That wasn't the intention . . I cc'd you two just in case you missed the list message . .

don’t set the “Reply-To:” header to only your email
address. That causes a mail client to only reply to that one email
address; Eric wouldn’t see my answer if I hadn’t noticed the error.

Hmm . . I think this is a mail client and list software issue - I have seen over the years that there are problems and arguments about this stuff regularly - I am using RoundCubeMail as a client and the options (without manually copying and pasting anything) are (I just tried it again with the mail I replied to before):

   Single Reply button - results in ONE reply to the list
   Multiple Reply button - results in ONE reply to the list
   Multiple Reply button Pull-down "Reply All" - results in a reply to the list and a cc to you
   Multiple Reply button Pull-down "Reply List" - results in ONE reply to the list

ALL of the options result in a "Reply-To:" with MY address in it. I manage a number of lists with EZMLM and as far as I know, it is the LIST manager software's responsibility to make sure the "Reply-To" has the list address in it for mail that comes from the list (if that is what is preferred).

Philip Rhoades <phil@pricom.com.au> writes:

I wanted something that would
work in both situations - CLI and Web page - without having to do a
lot of messing

This sounds like you want to employ a method using a closure,
i.e. something that makes use of the “yield” mechanism. Hand off the
external interfacing to the user of your method and only do yourself
what is common among all uses.

  def my_method
    puts "Before yield"
    yield
    puts "After yield"
  end

The caller of this method can “inject” code into the execution by doing:

  my_method do
    puts "in yield"
  end

, so that the output will be

  Before yield
  in yield
  After yield

OK, I will play with approach and see how I go.

Thanks!

Phil.

···

On 2016-01-29 06:10, Quintus wrote:
--
Philip Rhoades

PO Box 896
Cowra NSW 2794
Australia
E-mail: phil@pricom.com.au