Hello, I'm Java developer and now explore Ruby for increasing
programming knowledge. I want to understand runtime class loading
I have an application:
/lib/parser_factory.rb
class ParserFactory
end
/lib/parser_format_x.rb
class ParserFormatA
end
/lib/parser_format_y.rb
class ParserFormatB
end
/lib/parser_format_z.rb
class ParserFormatC
end
ParserFactory gets file and decides which parser to initialize and use.
I have such code in ParserFactory:
clz = "ParserFormat#{@version}"
parser_impl = Kernel.const_get(clz)
and I get an error:
Test-unit version : 2.0.1 loaded
1) Error:
test_parsing(ParserTest):
NameError: uninitialized constant Kernel::ParserPlanFormat1_0
D:/Ruby_1_86_27/lib/ruby/gems/1.8/gems/rake-0.8.1/lib/rake.rb:2237:in
`const_missing'
I don't get how I have to specify path to class. I've tried it as in
Java: "parsers/SomeClass", but it didn't help 
Also i'm exploring Ruby on Rails and
Kernel.const_get("MyFavouriteModelClass") works there.
Please explain or give guide to read.
···
--
Posted via http://www.ruby-forum.com/.
Ruby needs to interpret the file where the class is defined before you
can use it. Interpreting the file has the side-effect of defining the
constant, which is in turn a side-effect of the class keyword.
As you surely know that is typically done with require, and if the
parsers are unknown beforehand you can just use Dir[] with a glob to
require whatever has some filename pattern in a loop or something. I
mean, require is a method you can call it wherever you want.
Rails does not need that because it offers class/module autoloading:
if the filename is named after the class using some common sense
conventions, and lives in some of the standard directories,
app/something, lib, etc., then the dependencies mechanism goes and
loads it for you the first time the constant is used. That is
accomplished basically via a Ruby hook called const_missing that is
triggered when that initial failure happens.
Xavier Noria wrote:
Ruby needs to interpret the file where the class is defined before you
can use it.
I understand it.
Interpreting the file has the side-effect of defining the
constant, which is in turn a side-effect of the class keyword.
don't get idea with side-effects
As you surely know that is typically done with require, and if the
parsers are unknown beforehand you can just use Dir with a glob to
require whatever has some filename pattern in a loop or something. I
mean, require is a method you can call it wherever you want.
Something like:
require "parsers/parser_format#{@format_version.gsub(/\./, '_')}"
clz = "ParserFormat#{@format_version.gsub(/\./, '_')}"
parser_impl = Kernel.const_get(clz)
works nicely!
Rails does not need that because it offers class/module autoloading:
if the filename is named after the class using some common sense
conventions, and lives in some of the standard directories,
app/something, lib, etc., then the dependencies mechanism goes and
loads it for you the first time the constant is used. That is
accomplished basically via a Ruby hook called const_missing that is
triggered when that initial failure happens.
Thanks!
···
--
Posted via http://www.ruby-forum.com/\.
Interpreting the file has the side-effect of defining the
constant, which is in turn a side-effect of the class keyword.
don't get idea with side-effects
Ah yes let me explain a bit more. Doing
class C
end
as far as constants and class names is concerned is similar to doing this
C = Class.new
By the way, top-level constants are stored in Object. Your code works
with Kernel because it is mixed in Object and constant lookup goes up,
but Object would be the natural place to invoke const_get on.
Something like:
require "parsers/parser_format#{@format_version.gsub(/\./, '_')}"
clz = "ParserFormat#{@format_version.gsub(/\./, '_')}"
parser_impl = Kernel.const_get(clz)
works nicely!
That's right.
···
On Thu, Feb 11, 2010 at 10:32 AM, Sergey Sheypak <serega.sheypak@gmail.com> wrote:
Xavier Noria wrote:
as far as constants and class names is concerned is similar to doing
this
C = Class.new
Nice opportunity to make silly mistakes, especially if you work in group
with low communication.
Thank you for explaining me the material.
···
--
Posted via http://www.ruby-forum.com/\.
Xavier Noria wrote:
Excuse me for disturbing you again.
I have pretty close question.
I don't get how to locate files inside ruby-project. In Rails I've used
'RAILS_ROOT' and it was clear to me how does it work.
And what about usual ruby app?
1. NetBeans generated TestUnit gets this string:
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
What for?
2. My project structure:
project:
\lib
\lib\main.rb
\lib\some_file.rb
\lib\parsers\yaml_parser.rb
\data
\data\yaml_parser_config.yml
\data\source.scv
\data\Format_1.0.yml
I keep config files in 'data' catalog.
Is it good way to ref these resources in this way:
#Some TestUnit
def test_read
@conf = YAML.load_file( 'data/Format_1.0.yml' ) #Good or bad?
assert_equal(Hash, @conf.class)
assert_equal("Dates",@conf['Dates']['class'])
assert_equal(["id", "descr", "rough_est", "accurate_est", "spent",
"left", "resource_id", "begin", "end"],@conf['Tasks']['fields_ordered'])
end
or in some Parser class:
@parser_config = YAML.load_file('data/Format_1.0.yml' ) )
Or I have to use some 'magic' ruby variables?
···
--
Posted via http://www.ruby-forum.com/\.
Yes you have the __FILE__ keyword. That evaluates to the filename of
the file that contains it. So, its value is per file.
In a case like yours it is normal to rely on __FILE__ and a known
project structure to go for stuff thus avoiding config files.