Accessing Variables from Within a Module

I have the following Ruby script:

#!/usr/bin/ruby
class MyClass
  def initialize()
    @fname='doug'
  end
  attr_accessor(:fname)
end
my_instance=MyClass.new()
module MyModule
  def MyModule.test1()
    puts(my_instance.fname())
  end
end
MyModule.test1()

The purpose of the above script is to determine how I can access the
@fname instance variable from within the module. The script as shown
does not work. I'm not too surprised about that. However, I thought
the problem could be cured by changing the local variable, "my_instance"
to an instance variable (i.e., @my_instance). That didn't work either.
That did surprise me. Can anyone tell me how I can skin this cat?
Thanks.

      ... doug

···

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

Hi,

This doesn't make sense. The module and the top level are two completely
different contexts. They simply cannot share variables (unless they're
global).

Well, you *could* somehow "inject" the instance of MyClass into the
module, but this seems like very bad design to me. What are you trying
to do?

···

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

What are you trying
to do?

In the actual configuration that I am contemplating, the code that I
showed would be bifurcated into two separate files so that the class
would be in one file while the module would be in another. The objective
would be to have the accessor methods of the class available in the
module. The reason that I want two separate files is that I want to
allow others to modify the code in the module while I want the code of
the class to remain pristine. I was drawn to the use of a module
because I would like the code that is in the file that is to be editable
by others to have its own name space.

Suggestions? I'm wide open. Thanks for the input.

     ... doug

···

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

Doug Jolley wrote in post #1063908:

Suggestions? I'm wide open. Thanks for the input.

From the description I'm guessing you want to use the module as a mixin
to add methods to the class. In this case you don't even need the
accessor methods. If you include the module in the class, the methods of
the module have direct access to the instance variables -- just like
they were defined in the class.

As an example:

···

#------
module M

  def mod_show
    puts "Value of @x: #{@x}"
  end

end

class C

  include M

  def initialize
    @x = 123
  end

end

c = C.new
c.mod_show
#------

However, letting others edit parts of the code is a pretty odd way of
extending functionalities. In object oriented languages (like Ruby), the
standard way to do this is via inheritance: You derive a new class from
an old one and extend it to your needs.

Some languages like Java also let the programmer prevent methods from
being changed in subclasses (what you want to do). But Ruby is very
dynamic and not so much aimed at making code unchangeable.

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

From the description I'm guessing you want to use the module as a mixin
to add methods to the class. In this case you don't even need the
accessor methods. If you include the module in the class, the methods of
the module have direct access to the instance variables -- just like
they were defined in the class.

I don't think that I want to use a mixin. My understanding of a mixin
is that it would cause me to loose the name space separation that I was
seeking. Using a mixin would be pretty much identical to using the
inheritance that you also suggested. What I sorely need is a block that
would allow me to access the accessor methods that are outside the block
but would otherwise enforce its own namespace. I'm going to have to
reflect on this one.

Thanks so much for your patience and input.

     ... doug

···

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

Doug Jolley wrote in post #1063913:

What I sorely need is a block that
would allow me to access the accessor methods that are outside the block
but would otherwise enforce its own namespace.

You could wrap the mixin module into another module. Then you'll have
namespace separation.

But you should use a mixin or inheritance or a wrapper in any case, even
if you stick to your approach of letting others edit the code. Because
binding a module to a certain variable created at top level (like in
your first example) really makes no sense. It breaks the principle of
scopes and creates obscure dependencies. While you can do it with some
hacks, it is just bad design. A module should not depend on outer
values, except for constants and maybe global variables.

So this is how you could create a template for others to edit:

# -- file 1: --

class MyFixedClass
  # don't edit this
end

# -- file 1. --

# -- file 2: --

module EditorNamespace

  # variant 1: using inheritance
  class EditorClass < MyFixedClass
    # you may edit this
  end

  # variant 2: using a mixin (has to be included in MyFixedClass)
  module EditorMixin
    # you may edit this
  end

  # variant 3: using a wrapper
  class EditorWrapper
    def initialize
      @my_fixed = ::MyFixedClass.new
    end
    # you may edit this (the original instance is in @my_fixed)
  end

end

# -- file 2. --

···

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

Please do. From what I have read so far in the thread it is totally
unclear to me what you are trying to achieve. It seems to me that
this may be the case for you as well. :slight_smile:

Since accessors are public you can access them from anywhere - but you
need an instance to invoke them on. In your example this will work:

module MyModule
def MyModule.test1(obj)
   puts(obj.fname())
end
end

MyModule.test1(my_instance)

I am suspecting though that you might not have made your mind up
completely on where the _state_ should reside. In your original
example you create a single instance and want to make that accessible
from a global function ("global" in the sense that it is not
associated with a particular instance of a class although it is of
course associated with the module instance).

If you want to do that then you need to store the instance somewhere
presumably as instance variable of the module:

module MyModule
  @my_instance=MyClass.new()

  def MyModule.test1()
    puts(@my_instance.fname())
  end
end

An alternative would be to make MyClass a singleton but that would
just change the place where you store the state.

Can you give a more realistic example of what you want to achieve?
Please explain what the role of MyClass and MyModule is supposed to be
in your application. That would help us tremendously to understand
what you are trying to achieve and come up with better feedback.

Kind regards

robert

···

On Sun, Jun 10, 2012 at 4:15 AM, Doug Jolley <lists@ruby-forum.com> wrote:

From the description I'm guessing you want to use the module as a mixin
to add methods to the class. In this case you don't even need the
accessor methods. If you include the module in the class, the methods of
the module have direct access to the instance variables -- just like
they were defined in the class.

I don't think that I want to use a mixin. My understanding of a mixin
is that it would cause me to loose the name space separation that I was
seeking. Using a mixin would be pretty much identical to using the
inheritance that you also suggested. What I sorely need is a block that
would allow me to access the accessor methods that are outside the block
but would otherwise enforce its own namespace. I'm going to have to
reflect on this one.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

module MyModule
def MyModule.test1(obj)
   puts(obj.fname())
end
end

YES!!! This is the solution to my problem! Strangely, I came up with the
same thing as I reflected on the issue over last evening.

When I post a question here I generally try to present an illustrative
code fragment that removes all the fluff from the real code and just
focuses on the precise issue. Regardless of how careful I am, it seems
that something always gets lost in the translation. I think that is what
has happened. It would take a lot of bytes for me to explain WHY this is
the solution; but, trust me, IT IS THE SOLUTION. This provides the
precise amount of coupling that I was seeking. I'm a happy camper.
Thanks to all who contributed.

     ... doug

···

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

module MyModule
def MyModule.test1(obj)
puts(obj.fname())
end
end

YES!!! This is the solution to my problem! Strangely, I came up with the
same thing as I reflected on the issue over last evening.

Good.

When I post a question here I generally try to present an illustrative
code fragment that removes all the fluff from the real code and just
focuses on the precise issue. Regardless of how careful I am, it seems
that something always gets lost in the translation.

I guess it's just normal in the course of communication - especially
with text only media. One often needs a few rounds back and forth to
come to a common understanding. Nothing to worry about.

Thanks to all who contributed.

You're welcome!

Kind regards

robert

PS: One remark: I prefer to use "self" over the module name when
defining methods of the module. That reduces redundancy and makes it
easier to change the module's name.

···

On Sun, Jun 10, 2012 at 8:13 PM, Doug Jolley <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/