Safely extending functionality of a standard library class - ruby

Is there a simple way to extend a functionality of a standard library class like String inside a module without affecting anything outside of it? Example (won't work):
module Foo
class String
def hello
"hello #{self}!"
end
end
class Bar
def greet name
name.hello
end
end
end
Result I'm looking for:
Foo::Bar.new.greet 'Tom' #=> hello Tom!
'Tom'.hello #=> NoMethodError
I'm aware of solutions like creating MyString < String with desired functionality, but I would rather not call MyString.new('foo') every time I want to use a string inside the module.
I realise this may not be considered good practice, I'm just looking to expand my understanding of the language.

What you're looking for is Refinement:
Refinements are designed to reduce the impact of monkey patching on
other users of the monkey-patched class. Refinements provide a way to
extend a class locally.
module Foo
refine String do
def hello
"hello #{self}!"
end
end
end
puts 'Tom'.hello
#=> undefined method `hello' for "Tom":String
using Foo
puts 'Tom'.hello
#=> hello Tom!
Using refinement inside Bar class:
# Without refinement
class Bar
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> undefined method `hello' for "Tom":String
# With refinement
class Bar
using Foo
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> hello Tom!
For the complete info about scoping, method lookup and stuff look into docs link I've provided :)
P.S. Be aware, that Rubinius developers are philosophically opposed to Refinements and thus will never implement them (c) Jörg W Mittag.

Write a class of the same name then use require_relative (or similar method) to include it.
class Date
def itis
puts "It is " + self.to_s
end
Example:
[1] pry(main)> require_relative 'date.rb'
=> true
[2] pry(main)> require 'date'
=> true
[3] pry(main)> Date.new(2018, 10, 9).itis
It is 2018-10-09
=> nil

Related

NoMethodError: undefined method `meow?' for # - ruby mixin failing?

I'm playing with some of the very basics of ruby mixins, and for some reason can't access behavior from my module.
Running this on Ruby Fiddle:
module Cats
MEOW = "meow meow meow"
def Cats.meow?
return Cats::MEOW
end
end
class Example
include Cats
def sample
return "it's a sample"
end
end
e = Example.new
puts e.sample
puts e.meow?
This keeps returning NoMethodError: undefined method 'meow?' for #
My understanding of how mixins should work from tutorialspoint makes me feel like I should be able to validly call e.meow?, and get back the same result I would get from calling Cats.meow?.
Here's the code in RubyFiddle.
Incredibly basic, but any ideas where I'm falling down here?
As it turns out, I was being overly specific when defining Cats.meow?. If you want to use a module as a mixin you'll want to define your methods more generally, not with respect to their specific module namespace.
So instead of
def Cats.meow?
...
end
it should have been
def meow?
...
end
This lets you call e.meow?, since the method definition no longer limits it just to the Cats namespace.
Whoops.
As a general rule to using include and extend in Ruby:
If you want to use your module as a namespace
module Outer
module Inner
def self.my_method
"namespaced method!"
end
end
end
You use it like this Outer::Inner::my_method or Outer::Inner.my_method.
And if you want to use the module as a mixin:
# In some cases it makes sense to use names ending in -able, since it expreses
# what kind of messages you can send to an instance or class that mixes
# this module in.
# Like Devise's Recoverable module: https://github.com/plataformatec/devise/blob/f39c6fd92774cb66f96f546d8d5e8281542b4e78/lib/devise/models/recoverable.rb#L24
module Fooable
def foo
"#{self} has been foo'ed!"
end
end
Then you can include it (instances of Something obtain #foo):
class Something
include Fooable # Now Something.new can receive the #foo message.
end
Something.new.foo
=> "#<Something:0x0055c2dc104650> has been foo'ed!"
Or you can extend it (Something itself obtains #foo as a class message):
class Something
extend Fooable # Now Something can receive the #foo message.
end
Something.foo
=> "Something has been foo'ed!"

how to get source code text in ruby?

inspired by some lisp magic of runtime edit sourcecode,
I want to do it in ruby. looks like I cannot get sourcecode from method/class,
is there a way to do it?
I write a sample sourcecode here:
def helloworld n
"hello #{n}"
end
o = Kernel.method :helloword
Kernel.define_singleton_method o.name do |n|
eval o.source_code.sub('hello', 'hello world')
end
helloworld 'halida' #=> 'hello world halida'
You can't get the string representation of a part of the code, edit it and expect Ruby to reevaluate your changes. The only way to do something near to what you want is using ParseTree to get s-expressions of the source, edit and use Ruby2Ruby to generate a string of ruby code. Them add def ... and end to the string and call eval with it.
It's too hard and error-prone to be useful in a real-world situation. But I don't know any other way.
Note: ParseTree only works on Ruby 1.8.
Have a look at method_source gem. It's used by pry REPL for show-method command.
Looks like this gem utilizes standard Method#source_location (available in Ruby 1.9) to locate method and get its source code. Obviously, it doesn't work for dynamically defined methods and C methods. See docs for more information.
You can easily get source code for a method in Ruby.
Imagine the following hypothetical class:
class Klass
def self.foo
:foo
end
def bar
:bar
end
end
As you can see, this class has two methods:
a class method .foo
an instance method #bar
Use .method and .instance_method to access them programmatically:
m1 = Klass.method :foo
=> #<Method: Klass.foo>
m2 = Klass.instance_method :bar
=> #<UnboundMethod: Klass#bar>
You can use the .source method to view their source code:
puts m1.source
def self.foo
:foo
end
=> nil
puts m2.source
def self.bar
:bar
end
=> nil
Because Ruby has open classes and dynamic loading, you can also add or
change methods at run time. Just re-open the class and redefine the method:
Klass.foo
=> :foo
class Klass
def self.foo
:foobar
end
end
Klass.foo
=> :footer
The other methods previously defined in the class will remain unaffected:
Klass.bar
=> :bar
WARNING: Redefining class behavior during runtime (also called "Monkey Patching")
is a very powerful tool, it can also be somewhat dangerous. Current versions of Ruby
support a much more controlled way of going about this called 'refinements'.
You can learn more about using refinements here

Ruby: Is there a way to get the enclosing Module const of a Class?

I'm doing some metaprogramming in Ruby, and I need to dynamically generate a sibling class inside of a module. In doing so, I want to call const_set on the module, but I don't know which Module constant to call that on until runtime. An example:
Given classes
Foo::Bar::Baz
Foo::Quox::Quack
I want to be able to call a function like this (oversimplified here):
def generate_from klass
mod = klass.enclosing_module # <- THIS LINE is the one I need to figure out
mod.const_set("GeneratedClassName", Class.new)
end
and what I want to end up with, when calling with Baz, is a new class defined as
Foo::Bar::GeneratedClassName
and with a Quack, I want
Foo::Quox::GeneratedClassName
The only way I know of is to split up klass.name, then repeatedly call const_get on those strings, constantized. Does anyone know of a more elegant way?
This should get you on track:
module Foo
module Bar
class Baz
def initialize
#nesting = Module.nesting
end
def enclosing_module
#nesting.last
end
end
end
end
puts Foo::Bar::Baz.new.enclosing_module #=> Foo
Relevant documentation:
http://ruby-doc.org/core/classes/Module.html#M000441
Got it.
ActiveSupport has this Ruby extension, Module#parent. It's good enough for my use.
In Rails you can use a combination of deconstantize and constantize.
'Foo::Bar::Baz'.deconstantize.constantize # => Foo::Bar
so in a method of the class it can be used like this:
self.class.name.deconstantize.constantize
In case anyone is looking for a pure ruby version:
def get_parent_type
#Note: This will break for base types (lacking '::' in the name)
parent_type=self.class.name.split('::')[0...-1]
begin
Object.const_get(parent_type.join('::'))
rescue NameError => e
nil
end
end

Kernel#__method__ doesn't seem to work correctly in dynamically defined methods

I've been trying to dynamically define some instance methods in Ruby 1.9. Here's the code I've been using to try this out:
class Testing
[:one, :two].each do |name|
define_method(name) do
puts __method__
end
end
end
And here's the output:
ruby-1.9.2-p180 :008 > t = Testing.new
=> #<Testing:0x00000100961878>
ruby-1.9.2-p180 :009 > t.one
two
=> nil
ruby-1.9.2-p180 :010 > t.two
two
=> nil
ruby-1.9.2-p180 :011 >
I would expect the result to be one and two respectively. If I call define_method of each one outside of the iteration it works as expected. What am I not understanding here?
Here is one of many examples I saw around online of define_method being called in an iteration. Dynamically defined setter methods using define_method?
What's missing?
Also: Using __method__ isn't critical for me, but it was the best way I could show, that it seems like only the last block sent to define_method is being used for the defined methods. Maybe that is starting to explain the problem to me, but I still don't understand..
Nice find on the weird behavior. Of all the Rubies I tested, only MRI 1.9.2 demonstrates this.
Ryan Davis has reported the bug on the ruby-core list (referencing this question).
You can use something like this instead of define_method:
class Testing
[:one, :two].each do |name|
eval <<-EOM
def #{name}
puts __method__
end
EOM
end
end
t = Testing.new
t.one #=> "one"
t.two #=> "two"
The reason this happens is that define_method defines a method in a slightly different way than def does. It has to do with creating anonymous procs and lambdas. What I would suggest is to simply use the method name since you already have it. This should avoid having to search the stack trace for the method name as well, so it should perform better:
class Testing
[:one, :two].each do |name|
define_method name do
"This method's name is #{name}."
end
end
end
Testing.new.one
=> This method's name is one.
Testing.new.two
=> This method's name is two.
To clarify, notice what is returned by the following two statements:
class Testing
define_method :one do
__method__
end
end
=> #<Proc:0x000001009ebfc8#(irb):54 (lambda)>
class Testing
def one
__method__
end
end
=> nil
P.S: There's also a performance difference between using the two formats. You can verify yourself that def is faster than define_method using Benchmark.

Problem with accessing superclass methods in method redefinitions

I am having a bit trouble to understand when "super" can be called and when not. In the below example the super method leads to a no superclass error.
class Bacterium
def eats
puts "Nam"
end
end
class Bacterium
def eats
super # -> no superclass error
puts "Yam"
end
end
b = Bacterium.new
b.eats
But this works:
class Fixnum
def times
super # -> works
puts "done"
end
end
5.times { |i| puts i.to_s }
Is 5 not just also an instance of Fixnum. And am I not redefining an existing method like in the Bacterium example above?
No, not really. Fixnum inherits from Integer class, and you are in fact overriding Integer#times, so super works, as it calls implementation from the parent.
In order to achieve something similar when monkeypatching, you should alias method before redefining it, and there call it by alias.
class Bacterium
alias_method :eats_original, :eats
def eats
eats_original # -> "Nam"
puts "Yam"
end
end
Class reopening is not a form of inheritance and super is of no use there.
Just as Mladen said, and you can check that with Class#superclass:
irb> Fixnum.superclass
=> Integer
And does Integer implement #times?:
irb> Integer.instance_methods.grep /times/
=> [:times]
Yes it does.
So, in a simplified way, we can say, that super invokes the method you are in of a superclass. In your case the superclass of a Bacterium is Object, which doesn't implement #eats.
I said this is very simplified, because look at this example:
module One
def hi
" World" << super()
end
end
module Two
def hi
"Hello" << super()
end
end
class SayHi
def hi
"!!!"
end
end
h = SayHi.new
h.extend(One)
h.extend(Two)
puts h.hi
#=> Hello World!!
Don't take to serious what I wrote here, it is actually tip of the iceberg of the Ruby object model, which is important to understand (I am still learning it) - then you will get most, or all of those concepts.
Use some Google-fu for "Ruby object model"...

Resources