Ruby: require vs include/extend: Using a module inside another, but not exposing to users

ruby include module from another file
ruby inheritance vs include
rails include module
ruby include class

I was having trouble understanding an error while unit testing my module, which is a mixin.

Suppose the mixin to be tested is module A:

require 'path/b'    
module A
    def methodA()
        puts methodB.attr1 
    end
end

And it depends on another mixin B which was defined in a file at path/b.rb

module B
    def methodB
       return someObject #that has property 'attr1'
    end       
end

Now, we have a class to unit test module A

require 'path/moduleA'
class TestA
    include Path::moduleA
end

describe 'test moduleA.methodA'
  it 'does something'
     testObject = TestA.new
     testObject.methodA()
     expect(....)
  end
end  

I get following error on running the rspec test

NameError:
   undefined local variable or method `methodB' for #<TestA:0x00007f77a03db9a8>

I am able to resolve it by one of following ways:

  1. including module B in module A
  2. including module B in class TestA

Questions

  1. I am not clear why include is required to get access to methodB in module A and class TestA when 'require' was already added in module A.

  2. My intention is to use methods of module B in module A, but not let users of module A access module B methods automatically.

    • resolution 1 above gives users of A, access to B's methods

    • resolution 2 forces users of A (user -> the unit test class in this example) to include A's dependency B directly, even though user is only interested in accessing A's methods.

Hence, both resolutions don't achieve what I want. Is there a way to achieve it?

I'm new to Ruby so may be it doesn't support this. I'm from Java background where I would model A and B as two classes, make an instance of B as field of A, then expose A's own public methods to users of A. But since they are mixins, I need to use modules in ruby.

Just to be very explicit: require / require_relative / load and include / extend / prepend have absolutely nothing whatsoever to do with each other.

The former three simply run a Ruby file. That's it. That is all they do. They differ in how and where they search for the file, but after they found the file, they don't do anything else than just execute it.

The latter three add a module to the ancestor chain. include essentially makes the module the superclass, extend is really the same as singleton_class.include (i.e. makes the module the superclass of the singleton class), and prepend inserts the module at the beginning of the ancestor's chain, i.e. actually before the class that it is prepended to.

Ruby Cookbook: Modules and Namespaces – O'Reilly, Explore Modules and Namespaces in Ruby with these recipes from the Ruby Cookbook. The objects may be constants, methods, classes, or other modules. require 'set' # Deals with a collection of unordered values with no class TaggableString < String include Taggable def initialize(*args) super  Each time I referenced files using a relative path in the previous examples, I wrote the path to explicitly reference the current working directory. If you’re used to using Ruby 1.8, this may come as a surprise to you. If you’ve been using Ruby 1.9.2, it may or may not appear to be the natural thing to do.

require just tells ruby to read / load the code inside the ruby file. In this case it will just define the module. However in order for code inside a module to be included inside another module or class, you must include it inside the module or class. So you should just as you mentioned do:

require 'path/b'    
module A
  include B
  def methodA()
    puts methodB.attr1 
  end
end

You should not need to change your test with this since module A already includes module B. However this is not a very good OOP design pattern here. But hopefully you understand why now.

Ruby Methods: differences between load, require, include and , Ruby Methods differences: load vs require vs include vs extend in Ruby. The load method simply reads and parses another files into your code then we can use the load 'test_module.rb' just before the class definition in won't be applied - Ruby will use the file from memory, not from the file system. You can access variables, functions, and mixins from another module by writing <namespace>.<variable>, <namespace>.<function>(), or @include <namespace>.<mixin>(). By default, the namespace is just the last component of the module’s URL. Members (variables, functions, and mixins) loaded with @use are only visible in the stylesheet that loads

After more googling, I found the answer to my 2nd question using suggestion from: https://makandracards.com/makandra/977-calling-selected-methods-of-a-module-from-another-module

so basically i did:

require 'path/b'
module A
   module B_RequiredMethods
       include Path::B
       module_function :methodB
   end

    def methodA
        puts B_RequiredMethods.methodB.attr1
    end
end

In my case, B_RequiredMethods could be named properly to represent the method of B which would be exposed by it. Ideally, I would make those methods class level methods of B, but it is managed by some other team.

Good Module, Bad Module - via @codeship, You know how to use modules in Ruby, but are you abusing them? to program with modules and why they may or may not be great ideas. module Quack def say puts "quack" end end class WaterFowl include it limits the ability to inherit from other custom classes (because Ruby require 'fileutils'  The script module takes the script name followed by a list of space-delimited arguments. Either a free form command or cmd parameter is required, see the examples. The local script at path will be transferred to the remote node and then executed. The given script will be processed through the shell environment on the remote node.

Logic Programming: 25th International Conference, ICLP 2009, , Here we use the Thea library, which exposes OWL axioms directly as Prolog predicates. Thea is being extended to handle OWL2[22]. One possible solution would be to use dot to perform the layout, and then use this to guide placement within For prolog applications, this has the advantage that the end user does not  While @extend is allowed within @media and other CSS at-rules, it’s not allowed to extend selectors that appear outside its at-rule. This is because the extending selector only applies within the given media context, and there’s no way to make sure that restriction is preserved in the generated selector without duplicating the entire style

Popular Photography, And not only that weat Cambridge D0 NOT strip cameras we do | I would like to to thank not remove batteries or charge extra for straps, you for your prompt and Send it to our store to the attention of Mr. Ruby at 7th Ave, and 13th St., New future purchases with a purchase 'I would much father buy from youthan from a  Although Android offers a variety of widgets to provide small and re-usable interactive elements, you might also need to re-use larger components that require a special layout. To efficiently re-use complete layouts, you can use the <include/> and <merge/> tags to embed another layout inside the current layout.

Technological impact, Very commonly they compete with each other for major defense and space contracts. SPACE VEHICLES VS AIRCRAFT From a financial standpoint the impact of year this would extend the manned lunar exploration of the moon into 1974 or 1975. Since there are no beds, couches, or even chairs in the lunar module,  After ` includ ing class A into each package, you wind up with two definitions of class A. Using ` include is just a shortcut for cut and pasting text in a file. Importing a name from a package does not duplicate text; it makes that name visible from another package without copying the definition. `include “A.sv"

Comments
  • I think my question is similar to stackoverflow.com/questions/322470/…
  • If i include module B in module A, all of the methods of B become methods of A due to inheritance. However, i want to use methods of B in A without exposing them to users of A. Is it acheivable? Reason for this is that module A is a different class from module B and doesn't make sense to inherit it. One way is to let users of A include B but then they become aware of what modules A depends on, thats not right either.
  • "If i include module B in module A, all of the methods of B become methods of A due to inheritance." – No, they don't. The methods of B are methods of B, period. If you include module B into module A, then the only thing that happens is that Ruby records the fact that you did this. Then, later, when you include B into some class C, Ruby will make B the new superclass of C, A the superclass of B, and the old superclass of C the superclass of A. At no point whatsoever does a method of one module or class become a method of another module or class.