Problem extending (adding methods) to class

N

Nit Khair

I am trying to extend a class developed by someone else (its from the
ncurses-ruby lib). I need to add some fields and methods to it.

1. I tried directly extending it the usual way.
class MyForm < FORM

However, all attempts to access my methods would give a NoMethodError
on the base class Ncurses::FORM.

2. I then looked up the source and copied the following *on top* of my
class MyForm.

module Form
class FORM
attr_reader :user_object

def user_object=(obj)
@user_object = obj
end
end
end

I changed user_object to "my_fields". This approach works, but means i
cannot actually extend the class. I need a heirarchy below this each
adding its methods and data.


Now I am wondering whether my approach is wrong. Is the class
locked/final in some way?

I am aware of an alternative appoach: create an instance of FORM in a
class (no more inheritance). Use method_missing to call methods of
original class. However, before i make changes, would like to understand
if I am doing something wrong here.

Thanks.
 
N

Nit Khair

Nit said:
I am trying to extend a class developed by someone else (its from the
ncurses-ruby lib). I need to add some fields and methods to it.

On further thought I am wondering if being inside a module makes that
class different. Like some sort of static or factory class. Nothing
coming up on google on "module classes" or classes within modules.

Could someone explain this or point me to a link. I read that modules
cannot be instantiated or subclasses - fine. What of classes declared in
them ?
 
L

Lex Williams

Nit said:
On further thought I am wondering if being inside a module makes that
class different. Like some sort of static or factory class. Nothing
coming up on google on "module classes" or classes within modules.

Could someone explain this or point me to a link. I read that modules
cannot be instantiated or subclasses - fine. What of classes declared in
them ?

why don't you take advantage of open classes ?

you can write this :

class MyClass
attr_accessor :myfield
end

and then you can access myfield using any instance of that class . The
same goes with methods .

If you write :

class MyClass
def my_new_method
#some logic here
end
end

then , all your objects will have that method .
 
N

Nit Khair

Lex said:
why don't you take advantage of open classes ?

you can write this :

class MyClass
attr_accessor :myfield
end

and then you can access myfield using any instance of that class . The
same goes with methods .

If you write :

class MyClass
def my_new_method
#some logic here
end
end

then , all your objects will have that method .

Are you by any chance saying the same thing i have done above, when i
copied the Module Class thing from the original source and added my
method and data to it ?

However, this much is working, but i need a heirarchy. I am unable to
extend this and add methods to it.

If the original class was declared as:
Module MyClass
class MYCLASS
attr_accessor :myfield
end
end

I can copy this, and add:
attr_accessor :newfield
This is okay.

But when i do:

class AnotherClass < MYCLASS
attr_accessor :anotherfield
end

then i get a NoMethodError pointing to MyClass::MYCLASS. I get no error
when instantiating AnotherClass, only when i access the method added.

I need a heirarchy of classes under Ncurses::FORM.
 
J

Jakub Pavlík jn.

Class defined inside a module behaves exactly the same as if she was defined
'outside' - it isn't 'static' in any way.

(Following notes may either help you or not - I haven't understood
totally where exactly your problem is.)

If you want to extend class ClassC defined inside module ModuleM , you can
either write

module ModuleM
class ClassC
# add new methods here
end
end

or

class ModuleM::ClassC
# add new methods here
end

Similarly if you want to subclass ClassC, you can do it inside ModuleM

module ModuleM
class ClassD < ClassC
# blah blah
end
end

or outside:

class ClassD < ModuleM::ClassC
# blah blah
end

Sorry if I didn't understand you at all...
 
D

David A. Black

Hi --

I am trying to extend a class developed by someone else (its from the
ncurses-ruby lib). I need to add some fields and methods to it.

1. I tried directly extending it the usual way.
class MyForm < FORM

However, all attempts to access my methods would give a NoMethodError
on the base class Ncurses::FORM.

Methods you add to a subclass are not visible to instances of the
original class.
2. I then looked up the source and copied the following *on top* of my
class MyForm.

module Form
class FORM
attr_reader :user_object

def user_object=(obj)
@user_object = obj
end
end
end

I changed user_object to "my_fields". This approach works, but means i
cannot actually extend the class. I need a heirarchy below this each
adding its methods and data.

Now I am wondering whether my approach is wrong. Is the class
locked/final in some way?

No. If you want to add methods to it, you can just open it up and add
them:

require 'rubygems'
require 'ncurses'

class Ncurses::Form::FORM
def my_method
puts "Hello"
end
end

n = Ncurses::Form::FORM.new
n.my_method # Hello


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL *
* Co-taught with Patrick Ewing!
See http://www.rubypal.com for details and updates!
 
N

Nit Khair

No. If you want to add methods to it, you can just open it up and add
them:

require 'rubygems'
require 'ncurses'

class Ncurses::Form::FORM
def my_method
puts "Hello"
end
end

n = Ncurses::Form::FORM.new
n.my_method # Hello


David

That is precisely what i did. It worked. But I am unable to further
subclass it. Methods I am adding to the subclass are giving
NoMethodErrors.
 
D

David A. Black

Hi --

That is precisely what i did. It worked. But I am unable to further
subclass it. Methods I am adding to the subclass are giving
NoMethodErrors.

Can you try this and tell me what you get?

class MyForm < Ncurses::Form::FORM
def a_new_method
puts "Hi"
end
end

MyForm.new.a_new_method


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL *
* Co-taught with Patrick Ewing!
See http://www.rubypal.com for details and updates!
 
N

Nit Khair

Jakub said:
module ModuleM
class ClassC
# add new methods here
end
end
Thanks, this worked fine.
Similarly if you want to subclass ClassC, you can do it inside ModuleM

module ModuleM
class ClassD < ClassC
# blah blah
end
end

Not tried this.
or outside:

class ClassD < ModuleM::ClassC
# blah blah
end

THIS did not work. I got NoMethodErrors trying this out. I spent many
hours checking and trying to see if some other error was happening.

I needed:
class AForm < Ncurses::FORM

class BForm < AForm
and so on.

So finally, i removed the < clause abd created an instance in the
initializer. And used "method_missing" to call methods of that instance.
This is working perfectly, i can keep subclassing ... However, i still
want to understand what i did wrong. or what i am not understanding
about classes within modules.
---
Why create classes within modules ? Is it only a namespace issue - to
avoid clashes with other classes. Is it like java's package?

Should we always create modules and packages inside them in a project
with many classes ? Currently I have only one module with common stuff
and a heriarchy of classes under no module.
 
N

Nit Khair

David said:
Hi --


I don't think it was exactly this, because there is no Ncurses::FORM.
Try the code in my previous post and see if it works for you. If not,
please post some actual code that triggers the error you're talking
about. I can't duplicate it.


David

Maybe we are onto something. Your code works fine. But doesn't FORM.new
require a fields object ? I tried many variations so i cant remember
what it was but here is the last one I have before i rewrote.


include Ncurses
include Ncurses::Form

class RBForm < FORM
attr_accessor :ffields
def initialize(fields)
super(fields)
@ffields = fields
end
def set_ffields(fields)
@ffields = fields
end
def get_ffields
@ffields
end
end


get_ffields throws a NoMethodError.
If i access ffields, that too gives an error.

It is instantiated thus:
f=RBQueryForm.new(fields);

RBQueryForm is subclassed from RBForm.

See if you can spot the error here itself. Otherwise I will try to cut
and make a tiny version that you can run and see.
 
D

David A. Black

Hi --

Maybe we are onto something. Your code works fine. But doesn't FORM.new
require a fields object ? I tried many variations so i cant remember
what it was but here is the last one I have before i rewrote.


include Ncurses
include Ncurses::Form

class RBForm < FORM
attr_accessor :ffields
def initialize(fields)
super(fields)
@ffields = fields
end
def set_ffields(fields)
@ffields = fields
end
def get_ffields
@ffields
end
end


get_ffields throws a NoMethodError.
If i access ffields, that too gives an error.

It is instantiated thus:
f=RBQueryForm.new(fields);

RBQueryForm is subclassed from RBForm.

See if you can spot the error here itself. Otherwise I will try to cut
and make a tiny version that you can run and see.

*Please* post some real code that contains the error. Otherwise it
just goes back and forth.

This code runs. I've changed super(fields) to super() because with an
argument I got an error (it expected zero arguments). I don't know
exactly what the fields are supposed to consist of so I've used a
placeholder ("abc").

require 'rubygems'
require 'ncurses'
include Ncurses
include Ncurses::Form

class RBForm < FORM
attr_accessor :ffields
def initialize(fields)
super()
@ffields = fields
end
def set_ffields(fields)
@ffields = fields
end
def get_ffields
@ffields
end
end

RBForm.new("abc").set_ffields("abc")


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL *
* Co-taught with Patrick Ewing!
See http://www.rubypal.com for details and updates!
 
N

Nit Khair

David said:
Hi --



*Please* post some real code that contains the error. Otherwise it
just goes back and forth.

This code runs. I've changed super(fields) to super() because with an
argument I got an error (it expected zero arguments). I don't know
exactly what the fields are supposed to consist of so I've used a
placeholder ("abc").

RBForm.new("abc").set_ffields("abc")


David
Sorry about not posting reeal code. I tried the same thing -- to bring
it down to one file, but it won't let me pass a parameter. When i say
only super() the sample is working. The original program goes ahead with
the field array - no error at that point. There are too many modules and
classes involved for me to put it all here. Still trying to post some
real code.

I thought you may straight away spot the error considering that I am
passing a param, and you are not. wait ...
 
N

Nit Khair

OK David, I will attach a file that comes with ncurses-ruby.
I have subclassed FORM with MyForm and tried to call a method.

(Once it works You can exit using C-c or alt-c.)


Strangely in the samples we made, FORM and FIELD take no params. This is
outside of the ncurses environment. In the sample i sent you earlier, i
tried to create a FIELD object, but it would take no params !!!
So i had no option but to take an independent fully working sample and
add a few lines.


Attachments:
http://www.ruby-forum.com/attachment/2759/f3.rb
 
D

David A. Black

Hi --

OK David, I will attach a file that comes with ncurses-ruby.
I have subclassed FORM with MyForm and tried to call a method.

(Once it works You can exit using C-c or alt-c.)


Strangely in the samples we made, FORM and FIELD take no params. This is
outside of the ncurses environment. In the sample i sent you earlier, i
tried to create a FIELD object, but it would take no params !!!
So i had no option but to take an independent fully working sample and
add a few lines.

OK, I think what's happening here is that the FORM class is overriding
new, in such a way that it does not call initialize. So overriding
initialize doesn't do anything.

I don't have a solution worked out but I believe that's the issue.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL *
* Co-taught with Patrick Ewing!
See http://www.rubypal.com for details and updates!
 
N

Nit Khair

David said:
OK, I think what's happening here is that the FORM class is overriding
new, in such a way that it does not call initialize. So overriding
initialize doesn't do anything.

I don't have a solution worked out but I believe that's the issue.

Sorry if this sounds silly, i forgot to mention that i *had* attached
the source in my prev mail (f3.rb). Did you run it?

Thanks a lot for your time and thoughts.
 
R

ragav

Sorry if this sounds silly, i forgot to mention that i *had* attached
the source in my prev mail (f3.rb). Did you run it?

Thanks a lot for your time and thoughts.


David is right.

Before the line
raise "NULL" if my_form.get_fields().nil?

insert
raise Ncurses::Form::FORM.singleton_methods(false).join(" ") #=> new

You'll see that FORM class has a singleton "new" method which always
returns a FORM object. Class#new is shadowed so you'll never get a
descendant object

raise MyForm.new.class.inspect #=> Ncurses::Form::FORM

DelegateClass is a possible solution unless you want to muck with the
C sources.

--Cheers
--Ragav
 
N

Nit Khair

ragav said:
You'll see that FORM class has a singleton "new" method which always
returns a FORM object. Class#new is shadowed so you'll never get a
descendant object

raise MyForm.new.class.inspect #=> Ncurses::Form::FORM

DelegateClass is a possible solution unless you want to muck with the
C sources.

--Cheers
--Ragav
Ah, i get it. Thanks for the link to DelegateClass - just had a look at
it.

For the moment, (as mentioned earlier), i created an instance of FORM,
and used method_missing to "delegate" calls to it after checking
respond_to?, now i can subclass that class as required.

Changing the C source will mean others will not be able to use, unless
they move to my modified source - don't want that. Thanks for the info.

So my question again is: are classes declared within a module
typically/always factory classes like this -- i mean with singleton new
methods?

Perhaps I should look thru the source code of Facets or some other
project to jump-start my ruby. Any suggestions?
 
D

David A. Black

Hi --

Sorry if this sounds silly, i forgot to mention that i *had* attached
the source in my prev mail (f3.rb). Did you run it?

Yes; that's how I figured out that initialize wasn't being called.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL *
* Co-taught with Patrick Ewing!
See http://www.rubypal.com for details and updates!
 
D

David A. Black

Hi --

Ah, i get it. Thanks for the link to DelegateClass - just had a look at
it.

For the moment, (as mentioned earlier), i created an instance of FORM,
and used method_missing to "delegate" calls to it after checking
respond_to?, now i can subclass that class as required.

Why not use a module?

module MyForm
attr_accessor :myfields
def get_fields
@myfields
end
end

class Ncurses::Form::FORM
include MyForm
end
Changing the C source will mean others will not be able to use, unless
they move to my modified source - don't want that. Thanks for the info.

So my question again is: are classes declared within a module
typically/always factory classes like this -- i mean with singleton new
methods?

No; it's relatively unusual (though not unheard of) to override new.


David

--
Rails training from David A. Black and Ruby Power and Light:
Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
Advancing with Rails January 19-22 Fort Lauderdale, FL *
* Co-taught with Patrick Ewing!
See http://www.rubypal.com for details and updates!
 
R

ragav

So my question again is: are classes declared within a module
typically/always factory classes like this -- i mean with singleton new
methods?

Singleton new methods are rare (IO.new, Class.new, Struct.new ..) and
out of these only IO gives the expected behavior when you subclass i.e
Subclass.new.class == Subclass.
Classes defined inside modules are primarily for namespacing.
Perhaps I should look thru the source code of Facets or some other
project to jump-start my ruby. Any suggestions?

Sure Facets has plenty of code samples. RubyQuiz is another.

--Cheers
--Ragav
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top