PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.ruby > [n00b] Reading a class-file and calling it at runtime.
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
[n00b] Reading a class-file and calling it at runtime.

Réponse
 
LinkBack Outils de la discussion
Vieux 05/11/2007, 01h47   #1
Miss Elaine Eos
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut [n00b] Reading a class-file and calling it at runtime.

I'm trying to read-in a folder full of "plug-ins" and call each of them,
in turn. Once I get the class-name, I do something like:

require "#{PLUG_IN_DIR}/#{one_plugin}"
plugin_class=Object.const_get(plugin_class_name).n ew
plugin_class.some_method

I *thought* that require worked a bit like the C pre-processor
"include", in that it would read and execute the named file at that
point, thereby defining my class and its methods. However, when I get
to the middle line, I get

uninitialized constant PluginClassName

Since rails is mistaking my class-name for a constant, I'm guessing that
require didn't execute the way I think it does, so my class-name isn't
initialized.

....Or maybe I've completely mis-diagnosed the problem.

At any rate, can someone offer a suggestion for how to read a folder
full of class-definition-files and, once at a time,

* Execute the class definition, so that my app knows about it
* Instantiate an instance of the class (I think we have this part,
above)
* Call a method on that class (should just be able to say
"a_class.a_method", right?)

Thanks!

--
Please take off your pants or I won't read your e-mail.
I will not, no matter how "good" the deal, patronise any business which sends
unsolicited commercial e-mail or that advertises in discussion newsgroups.
  Réponse avec citation
Vieux 05/11/2007, 03h19   #2
oga_emmanuel_oga@yahoo.com.ar
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

I'm not sure what you are trying to acomplish... but here is a trick i
use when rails mess with my requires.

def require_relative *args
path= File.dirname(args.shift)
args.each { |arg| path= File.join(path, arg) }
require path
end

This will require the file with full file name. Now you can do

Dir[File.join(File.dirname(__FILE__), '/plugins/*.rb')].each do |file|
require_relative __FILE__, file
end

That loads every file of directory plugins. Now, if you named the files
according to rails convetions, ie:

my_class_name.rb for MyClassName class, you can do something like:

plugin_classes= []

Dir[File.join(File.dirname(__FILE__), '/plugins/*.rb')].each do |file|
require_relative __FILE__, file
name= File.basename(file)
plugin_classes << $1.camelize.constantize if name =~ /(.*)\.rb$/i
end

There... it sounds easy, no?
--
Posted via http://www.ruby-forum.com/.

  Réponse avec citation
Vieux 05/11/2007, 03h22   #3
oga_emmanuel_oga@yahoo.com.ar
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

mmm i believe i messed up the things a bit, this should be the right
thing to do, if complex, anyway:

plugin_classes= []

Dir[File.join(File.dirname(__FILE__), '/plugins/*.rb')].each do |file|

file_name= File.basename(file)

require_relative __FILE__, 'plugins', file_name

plugin_classes << $1.camelize.constantize if file_name =~ /(.*)\.rb$/i
end

There, now it should work!


>
> plugin_classes= []
>
> Dir[File.join(File.dirname(__FILE__), '/plugins/*.rb')].each do |file|
> require_relative __FILE__, file
> name= File.basename(file)
> plugin_classes << $1.camelize.constantize if name =~ /(.*)\.rb$/i
> end
>
> There... it sounds easy, no?


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

  Réponse avec citation
Vieux 05/11/2007, 07h49   #4
sean.ohalpin@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: [n00b] Reading a class-file and calling it at runtime.

On 11/5/07, Miss Elaine Eos <Misc@your-pants.playnaked.com> wrote:
> I'm trying to read-in a folder full of "plug-ins" and call each of them,
> in turn. Once I get the class-name, I do something like:
>
> require "#{PLUG_IN_DIR}/#{one_plugin}"
> plugin_class=Object.const_get(plugin_class_name).n ew
> plugin_class.some_method
>
> I *thought* that require worked a bit like the C pre-processor
> "include", in that it would read and execute the named file at that
> point, thereby defining my class and its methods. However, when I get
> to the middle line, I get
>
> uninitialized constant PluginClassName
>
> Since rails is mistaking my class-name for a constant, I'm guessing that
> require didn't execute the way I think it does, so my class-name isn't
> initialized.
>
> ...Or maybe I've completely mis-diagnosed the problem.
>
> At any rate, can someone offer a suggestion for how to read a folder
> full of class-definition-files and, once at a time,
>
> * Execute the class definition, so that my app knows about it
> * Instantiate an instance of the class (I think we have this part,
> above)
> * Call a method on that class (should just be able to say
> "a_class.a_method", right?)
>
> Thanks!
>
> --
> Please take off your pants or I won't read your e-mail.
> I will not, no matter how "good" the deal, patronise any business which sends
> unsolicited commercial e-mail or that advertises in discussion newsgroups.
>
>

Hi,

What you're doing here is right in principle. For example, in this code:

# ./myplugin.rb
class MyPlugin
def some_method
puts "Hi from #{self}!"
end
end

module Plugins
class AnotherPlugin
def some_method
puts "Hi from #{self}!"
end
end
end
__END__

# test-require-plugin.rb
one_plugin = "myplugin"
PLUG_IN_DIR = '.'
plugin_class_name = "MyPlugin"

require "#{PLUG_IN_DIR}/#{one_plugin}"
plugin_class = Object.const_get(plugin_class_name).new
plugin_class.some_method

plugin_class_name = "AnotherPlugin"
plugin_class = Plugins.const_get(plugin_class_name).new
plugin_class.some_method

# this will fail
plugin_class = Object.const_get(plugin_class_name).new
plugin_class.some_method

__END__
# output
Hi from #<MyPlugin:0xb7c25594>!
Hi from #<Plugins::AnotherPlugin:0xb7c23dfc>!
test-require-plugin.rb:14:in `const_get': uninitialized constant
AnotherPlugin (NameError)
from test-require-plugin.rb:14

only the last call to some_method fails. Have you checked that the
name of the class is correct or if you are defining your plugin class
within a module?

Regards,
Sean

  Réponse avec citation
Vieux 05/11/2007, 15h12   #5
Miss Elaine Eos
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: [n00b] Reading a class-file and calling it at runtime.

In article
<3736dd30711042349n7225229dw4af74110f2a52048@mail. gmail.com>,
sean.ohalpin@gmail.com wrote:

> only the last call to some_method fails. Have you checked that the
> name of the class is correct or if you are defining your plugin class
> within a module?


I am NOT using "module." I guess I need to go read-up on modules --
Thanks!

--
Please take off your pants or I won't read your e-mail.
I will not, no matter how "good" the deal, patronise any business which sends
unsolicited commercial e-mail or that advertises in discussion newsgroups.
  Réponse avec citation
Vieux 05/11/2007, 18h29   #6
bbxx789_05ss@yahoo.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

Miss Elaine Eos wrote:
> In article
> <3736dd30711042349n7225229dw4af74110f2a52048@mail. gmail.com>,
> sean.ohalpin@gmail.com wrote:
>
>> only the last call to some_method fails. Have you checked that the
>> name of the class is correct or if you are defining your plugin class
>> within a module?

>
> I am NOT using "module." I guess I need to go read-up on modules --
> Thanks!


Maybe you should post a simplified version of one of the files you are
requiring, e.g.

class Dog
def speak
puts "Woof woof"
end
end


As this example shows:

>Sean O'halpin wrote:
>
> # ./myplugin.rb
>
> class MyPlugin
> def some_method
> puts "Hi from #{self}!"
> end
> end
>
>---------------
>
> # test-require-plugin.rb
>
> one_plugin = "myplugin"
> PLUG_IN_DIR = '.'
> plugin_class_name = "MyPlugin"
>
> require "#{PLUG_IN_DIR}/#{one_plugin}"
> plugin_class = Object.const_get(plugin_class_name).new
> plugin_class.some_method
>
> # output
> Hi from #<MyPlugin:0xb7c25594>!


...you don't need to have your class inside a module to get your code to
work. But the rest of the example showed that IF your class definition
is inside a module, then you have to alter your syntax a little to
retrieve the class with const_get.

Here is another example if it s (all files are in the current
directory):

#plugin.rb:

class Dog
def speak
puts "Woof woof"
end
end



#my_program.rb:

require 'plugin'

dog_class = Object.const_get("Dog")
dog = dog_class.new
dog.speak


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

  Réponse avec citation
Vieux 05/11/2007, 18h43   #7
bbxx789_05ss@yahoo.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

Sean O'halpin wrote:
>
> plugin_class = Object.const_get(plugin_class_name).new
>


I have a question about using Object as the receiver in the above line.
Is there any specific reason you are using Object? I find calling
const_get with Object very confusing because the Object class does not
define a const_get method--it's only tracking const_get through ruby's
extremely confusing circular inheritance:

Object <------+
| |
V |
Module |
--const_get |
|
| |
V |
Class ---------+

that const_get lands in Object. Since calling const_get with any of the
class names Object, Module, or Class seems to work, why not just use
Module or Class to call const_get? If no Modules are involved, which
seems to be the op's case, then Class would seem like the least
confusing name to call const_get with.

#plugin.rb:

class Dog
def speak
puts "Woof woof"
end
end

-----------

#my_program.rb:

require 'plugin'

dog_class = Class.const_get("Dog")
dog = dog_class.new
dog.speak

Of course calling const_get with Class might still result in some
confusion--looking up the methods for Class will not reveal a const_get
method.
--
Posted via http://www.ruby-forum.com/.

  Réponse avec citation
Vieux 05/11/2007, 18h57   #8
bbxx789_05ss@yahoo.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

7stud -- wrote:
>it's only tracking const_get through ruby's
> extremely confusing circular inheritance:
>
> Object <------+
> | |
> V |
> Module |
> --const_get |
> |
> | |
> V |
> Class ---------+
>


This might be a clearer diagram:

Object
|
V
Module
--const_get

|
V
Class
|
V
Object (Object is a subclass of Class)


puts Class.kind_of?(Object)
-->true

puts Object.kind_of?(Class)
-->true

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

  Réponse avec citation
Vieux 05/11/2007, 19h42   #9
Phrogz
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

On Nov 5, 11:43 am, bbxx789_0...@yahoo.com wrote:
> Sean O'halpin wrote:
>
> > plugin_class = Object.const_get(plugin_class_name).new

>
> I have a question about using Object as the receiver in the above line.
> Is there any specific reason you are using Object?



> dog_class = Class.const_get("Dog")
> dog = dog_class.new
> dog.speak
>
> Of course calling const_get with Class might still result in some
> confusion--looking up the methods for Class will not reveal a const_get
> method.


For me personally, having someone write Module.const_get versus
Class.const_get implies that the former will only return a Module
instance, and the latter would only return a Class instance. By using
Object.const_get you are clearly stating that there is no guarantee as
to what type of object the supplied constant points to.

  Réponse avec citation
Vieux 05/11/2007, 21h20   #10
ara.t.howard@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.


On Nov 5, 2007, at 12:45 PM, Phrogz wrote:

> For me personally, having someone write Module.const_get versus
> Class.const_get implies that the former will only return a Module
> instance, and the latter would only return a Class instance. By using
> Object.const_get you are clearly stating that there is no guarantee as
> to what type of object the supplied constant points to.
>


i prefer Object.const_get too, although for different reasons: it
*should* be well known by ruby programmers that the 'top' context is
the Object instances called 'main'. another approach, suitable for
some limited situations is simply

object = eval name, Binding::Top

BEGIN{
Binding::Top = binding
}

which is less safe, of course, but works with effort for cases like

object = eval 'File::Stat', Binding::Top

which, for some reason, routinely confounds people on the list...

2 cts.

a @ http://codeforpeople.com/
--
it is not enough to be compassionate. you must act.
h.h. the 14th dalai lama




  Réponse avec citation
Vieux 05/11/2007, 22h36   #11
sean.ohalpin@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

On 11/5/07, 7stud -- <bbxx789_05ss@yahoo.com> wrote:
> Sean O'halpin wrote:
> >
> > plugin_class = Object.const_get(plugin_class_name).new
> >

>
> I have a question about using Object as the receiver in the above line.
> Is there any specific reason you are using Object?


It's a way of looking up constants in the scope of the top level
binding (the special Object known as 'main').

Regards,
Sean

P.S. Thanks for clarifying my other post

  Réponse avec citation
Vieux 05/11/2007, 22h39   #12
sean.ohalpin@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

On 11/5/07, ara.t.howard <ara.t.howard@gmail.com> wrote:

> another approach, suitable for
> some limited situations is simply
>
> object = eval name, Binding::Top
>
> BEGIN{
> Binding::Top = binding
> }
>
> which is less safe, of course, but works with effort for cases like
>
> object = eval 'File::Stat', Binding::Top
>


You can also use the predefined constant TOPLEVEL_BINDING, e.g.

object = eval 'File::Stat', TOPLEVEL_BINDING

Regards,
Sean

  Réponse avec citation
Vieux 05/11/2007, 22h50   #13
m_goldberg@ameritech.net
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

On Nov 5, 2007, at 4:20 PM, ara.t.howard wrote:

> object = eval name, Binding::Top
>
> BEGIN {
> Binding::Top = binding
> }
>
> which is less safe, of course, but works with effort for cases like
>
> object = eval 'File::Stat', Binding::Top
>
> which, for some reason, routinely confounds people on the list...
>
> 2 cts.


You probably have a good reason for writing the above rather than the
simpler

eval('File::Stat', TOPLEVEL_BINDING) # => File::Stat

but I can't figure out what it is. So please explain.

Regards, Morton

  Réponse avec citation
Vieux 05/11/2007, 23h26   #14
ara.t.howard@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.


On Nov 5, 2007, at 3:50 PM, Morton Goldberg wrote:

> You probably have a good reason for writing the above rather than
> the simpler
>
> eval('File::Stat', TOPLEVEL_BINDING) # => File::Stat
>
> but I can't figure out what it is. So please explain.
>


a) always forgetting what the constant is named
b) begin too lazy to look it when i was posting

TOPLEVEL_BINDING is, of course, the better way to go! ;-)

sorry for any confusion caused by my laziness.

ps. i *do* wish the top level binding was part of the Binding class,
Binding.top, or something, because i can never remember where it
lives...

a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




  Réponse avec citation
Vieux 05/11/2007, 23h27   #15
ara.t.howard@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.


On Nov 5, 2007, at 3:50 PM, Morton Goldberg wrote:

> but I can't figure out what it is. So please explain.


laziness ;-) sorry.

a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being
better. simply reflect on that.
h.h. the 14th dalai lama




  Réponse avec citation
Vieux 05/11/2007, 23h48   #16
bbxx789_05ss@yahoo.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

Sean O'halpin wrote:
> On 11/5/07, 7stud -- <bbxx789_05ss@yahoo.com> wrote:
>> Sean O'halpin wrote:
>> >
>> > plugin_class = Object.const_get(plugin_class_name).new
>> >

>>
>> I have a question about using Object as the receiver in the above line.
>> Is there any specific reason you are using Object?

>
> It's a way of looking up constants in the scope of the top level
> binding (the special Object known as 'main').
>


... so are Module.const_get and Class.const_get:

class Dog
end

module Stuff
Greeting = "hello"
end


MyConst = 10

puts Module.const_get("Dog").new
puts Module.const_get("Stuff")::Greeting
puts Module.const_get("MyConst")
puts
puts Class.const_get("Dog").new
puts Class.const_get("Stuff")::Greeting
puts Class.const_get("MyConst")

--output:--
#<Dog:0x251c0>
hello
10

#<Dog:0x25148>
hello
10


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

  Réponse avec citation
Vieux 06/11/2007, 05h02   #17
Miss Elaine Eos
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: [n00b] Reading a class-file and calling it at runtime.

In article
<3736dd30711042349n7225229dw4af74110f2a52048@mail. gmail.com>,
sean.ohalpin@gmail.com wrote:

> On 11/5/07, Miss Elaine Eos <Misc@your-pants.playnaked.com> wrote:
> > I'm trying to read-in a folder full of "plug-ins" and call each of them,
> > in turn. Once I get the class-name, I do something like:
> >
> > require "#{PLUG_IN_DIR}/#{one_plugin}"
> > plugin_class=Object.const_get(plugin_class_name).n ew
> > plugin_class.some_method

[snip]

Ok, I tried your example, below, and it worked the same for me as for
you. But when I go back to my actual code, same problem. I don't
follow what's different about what your example is doing and what I'm
doing. Here are some differences:

* I'm running under rails. Can't see how that should matter -- this is
long before any of the rendering stuff, and no DB accesses. I'm just
triggering code in a controller. That's all ruby, right?

* My program works like your example, below, except that it walks a
directory and does the trick for every file in it. So, rather than call
"myplugin.rb", it walks the directory, finds my_plugin.rb, uses that as
a filename, converts to MyPlugin for class name, but the rest is the
same.

* My actual plugin is a sub-class of a master-plugin. This is how I
guarantee the interface. (There's probably a more Ruby-like way to do
this, but it's what I know...) So myplugin is mildly complicated in
that my 1st line looks more like this:

class MyPlugin < MasterPlugin

But modifying the sample (below) to replicate that doesn't seem to
impact it's working-ness.

So I'm stuck trying to figure out how & where to trim back my original
to get it to act like the example. Does Rails actually matter?! Does
it matter if my require is inside a loop and/or inside another class (a
rails controller)?

The problem: I get

uninitialized constant MyPlugin

at the line with const_get().

[Example trimmed back to the minimal case that I'm using]
> What you're doing here is right in principle. For example, in this code:
>
> # ./myplugin.rb
> class MyPlugin
> def some_method
> puts "Hi from #{self}!"
> end
> end
> __END__
>
> # test-require-plugin.rb
> one_plugin = "myplugin"
> PLUG_IN_DIR = '.'
> plugin_class_name = "MyPlugin"
>
> require "#{PLUG_IN_DIR}/#{one_plugin}"
> plugin_class = Object.const_get(plugin_class_name).new
> plugin_class.some_method
>
> plugin_class_name = "AnotherPlugin"
> plugin_class = Plugins.const_get(plugin_class_name).new
> plugin_class.some_method
> __END__
> # output
> Hi from #<MyPlugin:0xb7c25594>!
> Hi from #<Plugins::AnotherPlugin:0xb7c23dfc>!


--
Please take off your pants or I won't read your e-mail.
I will not, no matter how "good" the deal, patronise any business which sends
unsolicited commercial e-mail or that advertises in discussion newsgroups.
  Réponse avec citation
Vieux 06/11/2007, 05h37   #18
Miss Elaine Eos
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: [n00b] Reading a class-file and calling it at runtime.

In article <Misc-4BC90C.22022205112007@newsclstr03.news.prodigy.net >,
Miss Elaine Eos <Misc@your-pants.PlayNaked.com> wrote:
> Ok, I tried your example, below, and it worked the same for me as for
> you. But when I go back to my actual code, same problem. I don't
> follow what's different about what your example is doing and what I'm
> doing. Here are some differences:
>
> * I'm running under rails. Can't see how that should matter -- this is
> long before any of the rendering stuff, and no DB accesses. I'm just
> triggering code in a controller. That's all ruby, right?


It seems that my problems had to do with leaving rails (WEBrick) running
and changing my controller/plug-in files. Once I quit & restarted
WEBrick, everything started working just fine.

Not sure why -- I though in the past that redefining objects worked
correctly.

Anyway, thank you much for your !

--
Please take off your pants or I won't read your e-mail.
I will not, no matter how "good" the deal, patronise any business which sends
unsolicited commercial e-mail or that advertises in discussion newsgroups.
  Réponse avec citation
Vieux 06/11/2007, 07h17   #19
Sean O'Halpin
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Reading a class-file and calling it at runtime.

On 11/5/07, 7stud -- <bbxx789_05ss@yahoo.com> wrote:
> >> I have a question about using Object as the receiver in the above line.
> >> Is there any specific reason you are using Object?

> >
> > It's a way of looking up constants in the scope of the top level
> > binding (the special Object known as 'main').
> >

>
> ... so are Module.const_get and Class.const_get:
>
> class Dog
> end
>
> module Stuff
> Greeting = "hello"
> end
>
>
> MyConst = 10
>
> puts Module.const_get("Dog").new
> puts Module.const_get("Stuff")::Greeting
> puts Module.const_get("MyConst")
> puts
> puts Class.const_get("Dog").new
> puts Class.const_get("Stuff")::Greeting
> puts Class.const_get("MyConst")
>
> --output:--
> #<Dog:0x251c0>
> hello
> 10
>
> #<Dog:0x25148>
> hello
> 10
>

Hi,

This illustrates what I mean:

Greeting = "goodbye"

class Module
Greeting = "hello"
end

class Class
Greeting = "hi!"
end

puts Module.const_get("Greeting")
puts Class.const_get("Greeting")
puts Object.const_get("Greeting")
puts eval( "Greeting", TOPLEVEL_BINDING ) # for Ara

--output--
hello
hi!
goodbye
goodbye

Regards,
Sean

  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 03h51.


Édité par : vBulletin® version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières ©2000-2008
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 1,68087 seconds with 27 queries