Module vs methods outside module - ruby

I would like to know what the difference is between using a module with methods inside it and using a simple file with many methods without creating a module, like the example below:
def doStuff
puts 'test';
end
module Example
def self.doStuff
puts 'test';
end
end
I could require both files and use the methods inside one. I want to know why I should create a module instead of having just a bunch of methods inside a .rb file.

Let's find out.
module M
def a; end
end
File.write("temp.rb", "def b\nputs 'hi'\nend") #=> 19
require_relative 'temp.rb'
class C
include M
end
C.instance_methods & [:a, :b] #=> [:a]
C.private_instance_methods & [:a, :b] #=> [:b]
C.instance_method(:b).owner #=> Object
Object.instance_methods.include? :b #=> false
Object.private_instance_methods.include? :b #=> true
Object.send(:public, :b) #=> Object
Object.instance_methods.include? :b #=> true
Object.private_instance_methods.include? :b #=> false
C.instance_methods & [:a, :b] #=> [:a, :b]
C.private_instance_methods & [:a, :b] #=> []
C.new.b #=> hi
The results are the same if we write:
class C
include M
require_relative 'temp.rb'
end

Modules allow you group your methods and you can include them in other modules and classes. You can include module methods into the module/class itself or its eigenclass. So, with modules you have more flexibility. Not to mention that you are not cluttering up the "global" namespace.
Also, when you define method in a file, you are defining it in the current context. Since, everything in Ruby is an object, you are actually defining it within a main object (an instance of Object class).
2.3.0 :001 > self
=> main
2.3.0 :002 > self.class
=> Object
2.3.0 :003 > self.object_id
=> 70123533022000
2.3.0 :004 > def test; end;
2.3.0 :005 > self.public_methods.include? :test
=> true

Related

Chaining & to_proc on symbol

It's well known to Rubyist & will call to_proc on a symbol, so
[:a, :b, :c].map(&:to_s)
is equivalent to
[:a, :b, :c].map { |e| e.to_s } # => ["a", "b", "c"]
Say I want to call another method right after to_s, these two implementations will work:
[:a, :b, :c].map { |e| e.to_s.upcase }
[:a, :b, :c].map(&:to_s).map(&:upcase)
My question is, is there a way to chain the & Symbol#to_proc call in one parameter? Something like:
[:a, :b, :c].map(&:to_s:upcase)
Thanks!
If you're only doing:
%i[a b c].map { |e| e.to_s.upcase }
then just use the block and get on with more important things. If you're really doing a chain of Enumerable calls and find the blocks too visually noisy:
%i[a b c].map { |e| e.to_s.upcase }.some_chain_of_enumerable_calls...
then you could toss your logic into a lambda to help clean up the appearance:
to_s_upcase = lambda { |e| e.to_s.upcase }
%i[a b c].map(&to_s_upcase).some_chain_of_enumerable_calls...
or throw it in a method and say:
%i[a b c].map(&method(:to_s_upcase)).some_chain_of_enumerable_calls...
Either way, you're giving your little bit of logic a name (which is pretty much all &:symbol is doing for you) to make the code more readable and easier to understand. In the specific case of to_s.upcase, this is all a bit pointless but these approaches are quite useful when the block gets bigger.
You will need to define some method in advance, but this will have generality. You can do like this:
class Symbol
def * other
->x{x.send(self).send(other)}
end
end
[:a, :b, :c].map(&:to_s * :upcase)
[:a, :b, :c].map(&:to_s * :capitalize)
...
I chose * as a method for functional composition.
And if you think you might use a third symbol, you can define like:
class Proc
def * other
->x{call(x).send(other)}
end
end
So just for fun (and to prove that almost anything is possible in ruby if one puts in a bit of effort) we could define a method on Symbol (we'll call it Symbol#chain) to provide this functionality and a little more
class Symbol
def proc_chain(*args)
args.inject(self.to_proc) do |memo,meth|
meth, *passable_args = [meth].flatten
passable_block = passable_args.pop if passable_args.last.is_a?(Proc)
Proc.new do |obj|
memo.call(obj).__send__(meth,*passable_args,&passable_block)
end
end
end
alias_method :chain, :proc_chain
end
This can then be called like so
[:a, :b, :c].map(&:to_s.chain(:upcase))
#=> ["A","B","C"]
# Or with Arguments & blocks
[1,2,3,4,5].map(&:itself.chain([:to_s,2],:chars,[:map,->(e){ "#{e}!!!!"}]))
#=> => [["1!!!!"], ["1!!!!", "0!!!!"], ["1!!!!", "1!!!!"],
# ["1!!!!","0!!!!", "0!!!!"], ["1!!!!", "0!!!!", "1!!!!"]]
Can even be used as a standalone
p = :to_s.chain([:split,'.'])
p.call(123.45)
#=> ["123","45"]
# Or even
[123.45,76.75].map(&p)
#=> => [["123", "45"], ["76", "75"]]
While we're playing with syntax, how about monkey-patching Array with a to_proc method?
class Array
def to_proc
return :itself.to_proc if empty?
->(obj) { drop(1).to_proc.call(first.to_proc.call(obj)) }
end
end
["foo", "bar", "baz"].map(&[:capitalize, :swapcase, :chars, ->a{ a.join("-") }])
# => ["f-O-O", "b-A-R", "b-A-Z"]
See it on repl.it: https://repl.it/JS4B/1
There is no way to chain using the symbol to proc.
However, you could monkey patch a method to the class you are mapping over that will do both, then call that.
class Symbol
def to_upcase_str
self.to_s.upcase
end
end
[:a, :b, :c].map(&:to_upcase_str)
I am surprised no body mentioned about Proc#<< and Proc#>>:
[:a, :b, :c].map(&(:to_s.to_proc << :upcase.to_proc))
# => ["A", "B", "C"]
[:a, :b, :c].map(&(:upcase.to_proc >> :to_s.to_proc))
# => ["A", "B", "C"]
ref: https://ruby-doc.org/core-2.7.2/Proc.html#method-i-3C-3C

I have a complicated ruby object, how can I display all its methods and variables?

I have a complicated ruby object, how can I display all its methods and variables?
Is there some kind of meta call to pretty print all its values, methods and variables?
Doing as below :
object.class.instance_methods # => [:meth1, :meth2,...]
object.instance_variables # => [:#var1, :#var2,..]
Now below will give you values of all variables of an object.
object.instance_variables.map { |var| object.instance_variable_get(var) }
Docs are :-
instance_variables
instance_variable_get
instance_methods
To elaborate on what #Arup said:
To obtain all constants defined for a class or module, use MyClass.constants.
To get all class variables (e.g., ##a), use my_class.class_variables.
To get all class instance_variables (e.g., #a), use my_class.instance_variables.
To get all class methods, use my_class.singleton_class.instance_methods.
Sometimes you want just the constants, instance methods, class methods, class variables, class instance variables or instance variables that you have defined for a particular class (or, for methods, a particular module). To retrieve only those (that is, to exclude ones defined by a classes' or module's ancestors), use my_class.instance_methods(false), my_object.instance_variables(false), etc.
Example
module M
M_constant = "M constant"
def m_method
puts "M#m_instance_method"
end
end
class C
include M
attr_accessor :c_instance_variable
C_constant = "C constant"
##c_class_variable = 4
def self.c_class_method1
puts "c_class_method1"
end
def c_method
#c_instance_variable = 0
puts "c_instance_method"
end
class << self
attr_accessor :c_class_instance_variable
#c_class_instance_variable = 5
def c_class_method1
puts "c_class_method1"
end
end
end
class D < C
end
Objects
M.constants
#=> [:M_constant]
C.constants
#=> [:A, :C_constant, :M_constant]
C.constants(false)
#=> [:A, :C_constant]
D.constants
#=> [:A, :C_constant, :M_constant]
D.constants(false)
#=> []
C.class_variables
#=> [:##c_class_variable]
C.class_variables(false)
#=> [:##c_class_variable]
D.class_variables
#=> [:##c_class_variable]
D.class_variables(false)
#=> []
C.new.instance_variables
#=> [:#c_instance_variable]
D.new.instance_variables
#=> []
M.instance_methods
#=> [:m_instance_method]
C.instance_methods.size
#=> 57
C.instance_methods(false)
#=> [:c_instance_variable, :c_instance_variable=, :c_method]
D.instance_methods.size
#=> 57
D.instance_methods(false)
#=> []
C.singleton_class.instance_methods.size
#=> 102
C.singleton_class.instance_methods(false)
#=> [:c_class_method1, :c_class_instance_variable,
# :c_class_instance_variable=]
D.singleton_class.instance_methods.size
#=> 102
D.singleton_class.instance_methods(false)
#=> []

Overriding method by another defined in module

I want to define an instance method Date#next which returns the next day. So I made a DateExtension module, like this:
module DateExtension
def next(symb=:day)
dt = DateTime.now
{:day => Date.new(dt.year, dt.month, dt.day + 1),
:week => Date.new(dt.year, dt.month, dt.day + 7),
:month => Date.new(dt.year, dt.month + 1, dt.day),
:year => Date.new(dt.year + 1, dt.month, dt.day)}[symb]
end
end
Using it:
class Date
include DateExtension
end
Calling the method d.next(:week) makes Ruby throw an error ArgumentError: wrong number of arguments (1 for 0).
How can I override the default next method from Date class with the one declared in DateExtension module?
In Ruby 2.0 and later you can use Module#prepend:
class Date
prepend DateExtension
end
Original answer for older Ruby versions is below.
The problem with include (as shown in the following diagram) is that methods of a class cannot be overridden by modules included in that class (solutions follow the diagram):
Solutions
Subclass Date just for this one method:
irb(main):001:0> require 'date'; module Foo; def next(a=:hi); a; end; end
#=> nil
irb(main):002:0> class MyDate < Date; include Foo; end
#=> MyDate
irb(main):003:0> MyDate.today.next(:world)
#=> :world
Extend just the instances you need with your own method:
irb(main):001:0> require 'date'; module Foo; def next(a=:hi); a; end; end
#=> nil
irb(main):002:0> d = Date.today; d.extend(Foo); d.next(:world)
#=> :world
When including your module, perform a gross hack and reach inside the class and destroy the old 'next' so that yours gets called:
irb(main):001:0> require 'date'
#=> true
irb(main):002:0> module Foo
irb(main):003:1> def self.included(klass)
irb(main):004:2> klass.class_eval do
irb(main):005:3* remove_method :next
irb(main):006:3> end
irb(main):007:2> end
irb(main):008:1> def next(a=:hi); a; end
irb(main):009:1> end
#=> nil
irb(main):010:0> class Date; include Foo; end
#=> Date
irb(main):011:0> Date.today.next(:world)
#=> :world
This method is far more invasive than just including a module, but the only way (of the techniques shown so far) to make it so that new Date instances returned by system methods will automatically use methods from your own module.
But if you're going to do that, you might as well skip the module altogether and just go straight to monkeypatch land:
irb(main):001:0> require 'date'
#=> true
irb(main):002:0> class Date
irb(main):003:1> alias_method :_real_next, :next
irb(main):004:1> def next(a=:hi); a; end
irb(main):005:1> end
#=> nil
irb(main):006:0> Date.today.next(:world)
#=> :world
If you really need this functionality in your own environment, note that the Prepend library by banisterfiend can give you the ability to cause lookup to occur in a module before the class into which it is mixed.
Note that Module#prepend looks to be coming in Ruby 2.0.
The next method for Date is defined in the Date class and methods defined in a class take precedence over those defined in an included module. So, when you do this:
class Date
include DateExtension
end
You're pulling in your version of next but the next defined in Date still takes precedence. You'll have to put your next right in Date:
class Date
def next(symb=:day)
dt = DateTime.now
{:day => Date.new(dt.year, dt.month, dt.day + 1),
:week => Date.new(dt.year, dt.month, dt.day + 7),
:month => Date.new(dt.year, dt.month + 1, dt.day),
:year => Date.new(dt.year + 1, dt.month, dt.day)}[symb]
end
end
From the the Programming Ruby chapter on Classes and Objects:
When a class includes a module, that module's instance methods become available as instance methods of the class. It's almost as if the module becomes a superclass of the class that uses it. Not surprisingly, that's about how it works. When you include a module, Ruby creates an anonymous proxy class that references that module, and inserts that proxy as the direct superclass of the class that did the including.

How do I dynamically add an attr_reader

I expect the following code to work as expected but it gives me a NoMethodError (private method `foo' called for #<MyClass...)
class MyClass
end
my_object = MyClass.new
my_object.instance_variable_set(:#foo, "bar")
MyClass.send("attr_reader", :foo)
puts my_object.foo
The problem is I'm using literally identical code in a larger application and it works exactly as I expect, but when I simplify it to this most basic example it fails.
(I understand there are many other ways to do what I'm doing in Ruby)
Use Module#class_eval:
By doing this, the block puts you in the context of MyClass, thus allowing you to call attr_reader
ruby-1.9.2-p136 :028 > my_object.instance_variable_set(:#foo, "bar")
=> "bar"
ruby-1.9.2-p136 :029 > MyClass.class_eval{attr_reader :foo}
=> nil
ruby-1.9.2-p136 :030 > my_object.foo
=> "bar"
Let's assume for an instant that you want to create an accessor for that particular instance of the class (which I assume is the case since you are operating on the instance.
You can simply open up the instance's singleton class and use instance_eval to add the accessor
class MyClass
end
my_instance = MyClass.new
my_instance.singleton_class.instance_eval { attr_accessor :foo }
my_instance.foo = :bar
my_instance.foo # => :bar
Interesting problem, I found this solution works fine:
MyClass.class_eval("attr_reader :foo")
The answer by #MikeLewis is nice, but why not just re-open the class?
irb(main):001:0> class MyClass; end
#=> nil
irb(main):002:0> m = MyClass.new
#=> #<MyClass:0x2d43ae0>
irb(main):003:0> class MyClass; attr_accessor :foo; end
#=> nil
irb(main):004:0> m.foo = 42
#=> 42
Just force the method to become public:
MyClass.send("public", :foo)
I have no idea why it is private in some cases.
I'm puzzled at this, but one solution that works is to make the attribute_reader explicitly public using MyClass.send(:public, :foo), i.e.
class MyClass
end
my_object = MyClass.new
my_object.instance_variable_set(:#foo, "bar")
MyClass.send(:attr_reader, :foo)
MyClass.send(:public, :foo)
puts my_object.foo

What happend here? (nil in Ruby)

p parent.class #=> NilClass # ok.
p !!parent # => false # as expected.
p parent.object_id # => 17006820 # should be 4
p parent && parent.foo # => NoMethodError foo # should be nil-guarded
Where does this object come from?
Possibly something like this:
class BlankSlate
instance_methods.each do |m|
# Undefine all but a few methods. Various implementations leave different
# methods behind.
undef_method(m) unless m.to_s == "object_id"
end
end
class Foo < BlankSlate
def method_missing(*args)
delegate.send(*args)
end
def delegate
# This probably contains an error and returns nil accidentally.
nil
end
end
parent = Foo.new
p parent.class
#=> NilClass
p !!parent
#=> false
p parent.object_id
#=> 2157246780
p parent && parent.foo
#=> NoMethodError: undefined method `foo' for nil:NilClass
Creating BlankSlate or BasicObject is a common pattern (before it was added to core Ruby as of version 1.9). It serves to create objects that will do something special with any method they are sent, or heavily delegate their behaviour to a different class. The downside is that it may introduce strange behaviour like this.

Resources