If I have the following project structure
project/
lib/
subproject/
a.rb
b.rb
lib.rb
where lib.rb looks like this :-
module Subproject
def foo
do_some_stuff
end
end
and a.rb and b.rb both need to mixin some methods within lib.rb and are both namespaced within a module like so :-
require 'subproject/lib'
module Subproject
class A
include Subproject
def initialize()
foo()
end
end
end
What does ruby do when it encounters the include statement? How does it know that I want to only include the mixin from lib.rb rather than the whole module which includes both class A and class B, is this based purely on the require of subproject/lib or am I getting it wrong and it is including the whole of the module, including the definitions of Class A and B within themselves?
It is including the whole of the module. There is only one Subproject module, you've just reopened it in a.rb and b.rb and added classes A and B to it. I don't think require is related anyhow there.
BTW, you can always try it out in irb:
>> Subproject::A
=> Subproject::A
>> Subproject::A::A
=> Subproject::A
Related
I am trying to create a LWRP to extend a supermarket cookbook 'webpshere'.
In my resource file, I am trying to extend this class with a base class found in parent cook book.
In the code below, 'WebsphereBase' is defined in the parent library 'websphere_base'. Can I get help on how to reference it?
Thanks
#require 'websphere_base'
module PIWebsphereCookBook
class WebsphereJbdc < WebsphereBase
require_relative 'helper'
In the source of the cookbook, you can see that the WebsphereBase class is defined inside the WebsphereCookbook module.
To reference this class from outside this module, you have to name the nesting so that Ruby is able to find the class you are referring to. With youur example, this can look similar to:
module PIWebsphereCookBook
class WebsphereJbdc < WebsphereCookbook::WebsphereBase
require_relative 'helper'
# ...
end
end
You don't need to require things coming from upstream cookbooks, nor can you (except for my weirdo cookbooks). All libs for cookbooks you depend on will be loaded by the time your library files run.
I'm new to writing big Ruby projects (only mods and application scripting till now). I've made a project with some files in the project root and others in subfolders, including a "Test" folder.
So far I've tried:
Adding all folders and subfolders to the load path in RubyMine.
Declaring all the files to be part of the same module.
I've thought of using require_relative for loading all files needed but it seems tiresome and very Java-esque... Is there a better way?
Here is an example of a typical folder structure, its modules and how to include everything into the library. You would then only need to require 'lib' wherever you want to pull in the library for use.
# Root folder structure of project
lib.rb
./lib/a.rb
./lib/b.rb
./lib/b/c.rb
# lib.rb
require 'lib/a'
require 'lib/b'
module Lib
end
# ./lib/a.rb
module Lib
module A
end
end
# ./lib/b.rb
require 'lib/b/c'
module Lib
module B
end
end
# ./lib/b/c.rb
module Lib
module B
module C
end
end
end
This code doesn't seem to work - it can't figure out some_func was defined. Why not?
# in file 1
def ModuleA
def some_func
"boo"
end
end
# in file 2
def ModuleB
include ModuleA
MY_CONSTANT = some_func
end
You are declaring your modules wrong and you need to extend not include
module ModuleA
def some_func
"boo"
end
end
module ModuleB
extend ModuleA
MY_CONSTANT = some_func
end
In your code example, you use the include directive.
This means that all the methods defined in ModuleA are included into ModuleB as instance methods.
However, by then invoking some_func in the module body of ModuleB, you try to invoke it as if it was defined as a class method on ModuleB (which it is not, since you have used include before).
If you actually want to define (and call) it as a class method, then you need to use extend ModuleA inside ModuleB to add the method definition.
So I've just recently started writing some Ruby and whilst I understand how modules work, the following behaviour still throws me off.
module ModuleA
def a_greet
'Hello from module A'
end
end
module ModuleB
def b_greet
'Hello from module B'
end
end
include ModuleA
include ModuleB
# WHY DOES THIS WORK !!!!!
p ModuleA.b_greet
I get that the functions from the modules can be called without specifying Module. and that I'd never write code in this way, but I cannot understand why you can call a method included from ModuleB when explicitly stating ModuleA?
Wait, there's more:
"Why does this work?".b_greet # => "Hello from module B"
You're including those modules in a top-level object main. It's a special object: all methods defined on it become available to all objects (see the line above, there's now b_greet method on a String). ModuleA is an object too, so, when you include ModuleB, ModuleA gets its methods. If you include those modules in a regular class/object, you won't get this "sharing" behaviour.
For a while I had been including an entire class inside of a Ruby module. Apparently this is not what I am supposed to do. It appears that the point of a module is to store functions which can then be included as methods in a new class.
I don't want this. I have a class that I want to keep in a separate file which I can access from other files. How can I do this?
Thanks.
Modules serve a dual purpose as a holder for functions and as a namespace. Keeping classes in modules is perfectly acceptable. To put a class in a separate file, just define the class as usual and then in the file where you wish to use the class, simply put require 'name_of_file_with_class' at the top. For instance, if I defined class Foo in foo.rb, in bar.rb I would have the line require 'foo'.
If you are using Rails, this include often happens automagically
Edit: clarification of file layout
#file: foo.rb
class Foo
def initialize
puts "foo"
end
end
...
#file: bar.rb
require 'foo'
Foo.new
If you are in Rails, put these classes in lib/ and use the naming convention for the files of lowercase underscored version of the class name, e.g. Foo -> foo.rb, FooBar -> foo_bar.rb, etc.
As of ruby version 1.9 you can use require_relative, to require files relatively to the file you are editing.
You can also use load. Also you use require relative if the file is in the same directory. Read this link for further understanding: http://rubylearning.com/satishtalim/including_other_files_in_ruby.html
When Using Require, inside the string indicate the full path name of the class you are refereing to unless its in the Root Folder of Ruby
MyApp
|_ app
|_ bin
|_ etc, etc
root_level_file.rb
You can just do:
require './root_level_file'.
RootLevelFile.new