Global_variable_set (like instance_variable_set)

Hello,

how can a function global_variable_set(gvarname, value) be
implemented? It should be similiar to the already existing method
Object#instance_variable_set, but set global variables rather than
instance variables.

Regards
  Thomas

Thomas Hafner <thomas@hafner.NL.EU.ORG> wrote/schrieb <ap11p4-9nm.ln1@faun.hafner.nl.eu.org>:

how can a function global_variable_set(gvarname, value) be
implemented?

The function should behave like the following one, but not use
``eval'' if possible.

def global_variable_set(gvarname, value)
  eval("#{gvarname.id2name}=value")
end

Regards
  Thomas

What problem do you need this for... it sounds like you could get by
with a different (and better) approach, but we'd need to know a little
more about what you're trying to do.

···

On 8/11/07, Thomas Hafner <thomas@hafner.nl.eu.org> wrote:

Hello,

how can a function global_variable_set(gvarname, value) be
implemented? It should be similiar to the already existing method
Object#instance_variable_set, but set global variables rather than
instance variables.

What problem do you need this for... it sounds like you could get by
with a different (and better) approach, but we'd need to know a little
more about what you're trying to do.

I believe for the record, a non-eval solution will be interesting to see
either way, even if he would use another (better) approach :slight_smile:

···

--
Posted via http://www.ruby-forum.com/\.

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708111035o2af744e1g2411e061054095ee@mail.gmail.com>:

What problem do you need this for... it sounds like you could get by
with a different (and better) approach, but we'd need to know a little
more about what you're trying to do.

Agreed that that there might be a better solution for the original
problem, but sometimes an intermediate problem becomes interesting per
se. Anyway, the original question is how to find a single, more
abstract function replacing these ones:

def with_output_to_string
  $stdout, tmp = StringIO.new, $stdout
  yield
  $stdout, tmp = tmp, $stdout
  tmp.rewind
  tmp.read
end

def with_error_to_string
  $stderr, tmp = StringIO.new, $stderr
  yield
  $stderr, tmp = tmp, $stderr
  tmp.rewind
  tmp.read
end

The only difference is $stdout vs. $stderr, so the idea was to pass
:$stdout resp. :$stderr as parameter.

Regards
  Thomas

$ ruby
require 'rubygems'
require 'inline'

module Kernel
inline :C do |builder|
   builder.include '"ruby.h"'

   builder.c <<-'EOF'
     static VALUE
     global_variable_set(char * varname, VALUE object) {
       return rb_gv_set(varname, object);
     }
   EOF
end

p global_variable_set 'foo', 5
-:17: warning: parenthesize argument(s) for future version
p $foo
# I hit ^D here
5D
5

···

On Aug 11, 2007, at 23:29, Marc Heiler wrote:

What problem do you need this for... it sounds like you could get by
with a different (and better) approach, but we'd need to know a little
more about what you're trying to do.

I believe for the record, a non-eval solution will be interesting to see
either way, even if he would use another (better) approach :slight_smile:

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars

Interesting. Perhaps this is a direct translation of how you might do
this without an eval (untested):

module Kernel
  def set_stdout(obj)
     $stdout = obj
  end

  def set_stderr(obj)
    $stderr = obj
  end
end

def with_helper(msg)
   temp = (msg == :stdout ? $stdout : $stderr)
   send("set_#{msg}", StringIO.new)
   yield
   send("set_#{msg}",temp)
   temp.rewind
   temp.read
end

def with_output_to_string
   with_helper(:stdout) { yield }
end

def with_error_to_string
  with_helper(:stderr) { yield }
end

Of course, this doesn't sound like a great idea, as unless the real
problem is actually a whole lot more interesting, this is just
unnecessary generalization and doesn't clean things up any.

Are you looking to do this to test a codebase that writes to $stdout / $stderr?

It's perfectly reasonable to have a class or method definition like this:

class Foo
  def initialize(out=$stdout,err=$stderr)
     @out = out
     @err = err
  end

  def print_to_stdout
     @out.puts "something"
  end

  def print_to_stderr
    @err.puts "something"
  end
end

Now if you wanted to test that, you could pass in your StringIO
objects. Maybe you can draw some ideas from that, if not, it'd be
interesting to see what you're using this helper for.

···

On 8/12/07, Thomas Hafner <thomas@hafner.nl.eu.org> wrote:

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708111035o2af744e1g2411e061054095ee@mail.gmail.com>:

> What problem do you need this for... it sounds like you could get by
> with a different (and better) approach, but we'd need to know a little
> more about what you're trying to do.

Agreed that that there might be a better solution for the original
problem, but sometimes an intermediate problem becomes interesting per
se. Anyway, the original question is how to find a single, more
abstract function replacing these ones:

def with_output_to_string
  $stdout, tmp = StringIO.new, $stdout
  yield
  $stdout, tmp = tmp, $stdout
  tmp.rewind
  tmp.read
end

def with_error_to_string
  $stderr, tmp = StringIO.new, $stderr
  yield
  $stderr, tmp = tmp, $stderr
  tmp.rewind
  tmp.read
end

The only difference is $stdout vs. $stderr, so the idea was to pass
:$stdout resp. :$stderr as parameter.

Write one method that does both and returns both. Use only the one you need. See #util_capture in lib/test/zentest_assertions.rb in ZenTest.

···

On Aug 12, 2007, at 14:20, Thomas Hafner wrote:

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708111035o2af744e1g2411e061054095ee@mail.gmail.com>:

What problem do you need this for... it sounds like you could get by
with a different (and better) approach, but we'd need to know a little
more about what you're trying to do.

Agreed that that there might be a better solution for the original
problem, but sometimes an intermediate problem becomes interesting per
se. Anyway, the original question is how to find a single, more
abstract function replacing these ones:

def with_output_to_string
  $stdout, tmp = StringIO.new, $stdout
  yield
  $stdout, tmp = tmp, $stdout
  tmp.rewind
  tmp.read
end

def with_error_to_string
  $stderr, tmp = StringIO.new, $stderr
  yield
  $stderr, tmp = tmp, $stderr
  tmp.rewind
  tmp.read
end

The only difference is $stdout vs. $stderr, so the idea was to pass
:$stdout resp. :$stderr as parameter.

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121440j4e26fd21g4048d05057615b5e@mail.gmail.com>:

Are you looking to do this to test a codebase that writes to $stdout
/ $stderr?

It's rather about using someone else's code. I'd prefer not to modify
it, because otherwise I had to merge every update.

  def print_to_stdout
     @out.puts "something"
  end

  def print_to_stderr
    @err.puts "something"
  end

Replacing ``puts'' by ``@out.puts'' is such a modification of foreign
code that I'd like to avoid.

Regards
  Thomas

Gotcha. IMO, there is no need for the abstraction if it's limited to
these two functions.
You're only talking about a couple lines of code, and your need for
this won't expand much over time, it seems.

The helper is certainly useful though and I'd say if you wanted to use
eval to shorten it up, go for it, as long as it's not exposed to user
input.

If you've got a C compiler, the ruby-inline solution is likely safer.

That having been said, you don't want to create a Rube Goldberg machine. :slight_smile:

-greg

···

On 8/12/07, Thomas Hafner <thomas@hafner.nl.eu.org> wrote:

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121440j4e26fd21g4048d05057615b5e@mail.gmail.com>:

> Are you looking to do this to test a codebase that writes to $stdout
> / $stderr?

It's rather about using someone else's code. I'd prefer not to modify
it, because otherwise I had to merge every update.

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121526j299f1ed3t3b7e45851d9ec0e9@mail.gmail.com>:

Gotcha. IMO, there is no need for the abstraction if it's limited to
these two functions.
You're only talking about a couple lines of code, and your need for
this won't expand much over time, it seems.

Nevertheless, if Ruby had explicit references (does it?), it would be
simple enough to have just one function instead of the original both
ones, e.g. with ``()'' as a placeholder for a hypothetical
dereferencing operator:

def with_stream_to_string(stream)
  ()stream, tmp = StringIO.new, ()stream
  yield
  ()stream, tmp = tmp, ()stream
  tmp.rewind
  tmp.read
end

Regards
  Thomas

You'll want to catch up on this thread:
http://rubyurl.com/FrJ

Basically, variables in ruby are just containers for references to
objects. So you can't change their bindings, which would be what
you'd need to do the kind of assignment you've shown there.

···

On 8/12/07, Thomas Hafner <thomas@hafner.nl.eu.org> wrote:

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121526j299f1ed3t3b7e45851d9ec0e9@mail.gmail.com>:

> Gotcha. IMO, there is no need for the abstraction if it's limited to
> these two functions.
> You're only talking about a couple lines of code, and your need for
> this won't expand much over time, it seems.

Nevertheless, if Ruby had explicit references (does it?), it would be
simple enough to have just one function instead of the original both
ones

Container is a bad word, sorry. Label might be better. A ruby
variable is a label for a reference, nothing more. (Please correct me
if I'm wrong, anyone).

···

On 8/12/07, Gregory Brown <gregory.t.brown@gmail.com> wrote:

Basically, variables in ruby are just containers for references to
objects. So you can't change their bindings, which would be what
you'd need to do the kind of assignment you've shown there.

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121715x1d92719fjd0311d10e10bc24a@mail.gmail.com>:

> "Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121526j299f1ed3t3b7e45851d9ec0e9@mail.gmail.com>:
>
> Nevertheless, if Ruby had explicit references (does it?), it would be
> simple enough to have just one function instead of the original both
> ones

You'll want to catch up on this thread:
http://rubyurl.com/FrJ

This thread treats ``pass by reference'' which is like aliasing. With
``explicit references'' I rather mean explicitly referencing (by
operator ``&'' in C resp. ``\'' in Perl) and dereferencing (by
operator ``*'' in C resp. ``$'' in Perl). Here's a Perl example:

sub foo {
     my ($ref) = @_; # consume argument array
     ${$ref}++; # dereference and increment
}
my $bar = 3;
foo(\$bar); # make a reference to $bar and pass it to the function
print $bar; # => 4

Regards
  Thomas

···

On 8/12/07, Thomas Hafner <thomas@hafner.nl.eu.org> wrote:

Sure, but it's the same idea. You're trying to change the binding of
$bar from a different scope

-greg

···

On 8/13/07, Thomas Hafner <thomas@hafner.nl.eu.org> wrote:

"Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121715x1d92719fjd0311d10e10bc24a@mail.gmail.com>:

> On 8/12/07, Thomas Hafner <thomas@hafner.nl.eu.org> wrote:
> > "Gregory Brown" <gregory.t.brown@gmail.com> wrote/schrieb <b37300880708121526j299f1ed3t3b7e45851d9ec0e9@mail.gmail.com>:
> >
> > Nevertheless, if Ruby had explicit references (does it?), it would be
> > simple enough to have just one function instead of the original both
> > ones
>
> You'll want to catch up on this thread:
> http://rubyurl.com/FrJ

This thread treats ``pass by reference'' which is like aliasing. With
``explicit references'' I rather mean explicitly referencing (by
operator ``&'' in C resp. ``\'' in Perl) and dereferencing (by
operator ``*'' in C resp. ``$'' in Perl). Here's a Perl example:

sub foo {
     my ($ref) = @_; # consume argument array
     ${$ref}++; # dereference and increment
}
my $bar = 3;
foo(\$bar); # make a reference to $bar and pass it to the function
print $bar; # => 4