Ruby : how to create a .downcase! style method? - ruby

I'm learning Ruby, and I was wondering :
How to create a .downcase! style method ?
I could obviously make a method callable like downcase("CAPS LOCK")
But I want string.downcase.
Obviously that's an example, I know the downcase method exists.
How do you do that ?
Thanks !

When you define a method, it is available and called in the context of an object. That means every method call has an implicit scope. downcase really means self.downcase.
For example if you define a method directly, it's added as a private method on the main context for the script.
self
# => main
def downcase
end
# private_methods means self.private_methods
private_methods.include?(:downcase)
# => true
If you want an object instance to call a method in it's context, define the method on the class.
class String
def my_downcase
end
end
"string".methods.include?(:my_downcase)
# => true
"string".my_downcase
Adding methods to built-in types is called monkey-patching and it's sort of frowned upon. Better to subclass the object to add functionality. The String constructor takes a string which is great for subclassing, and String#replace works for modifying the string in-place.
class CoolString < String
def initialize(str)
super(str)
end
def downcase!
replace(downcase)
end
end
str = CoolString.new("STRING")
str.downcase!
str
# => "string"

You can extend core classes easily:
class String
def make_it_downcase!
replace downcase # Calls downcase on the current value and replaces it with the result.
end
end
See it in action:
$ irb
irb(main):001:0> class String
irb(main):002:1> def make_it_downcase!
irb(main):003:2> replace downcase
irb(main):004:2> end
irb(main):005:1> end
=> :make_it_downcase!
irb(main):006:0> test = "TEST"
=> "TEST"
irb(main):007:0> test.make_it_downcase!
=> "test"
irb(main):008:0> test
=> "test"

You can extend the string class like so:
class String
def downcase
#implementation
end
end

Related

What does `&method(:method_ name)` mean in ruby?

I was trying to create a class that has a private class method. I want this private class method available to be used inside an instance method.
The following was my first attempt:
class Animal
class << self
def public_class_greeter(name)
private_class_greeter(name)
end
private
def private_class_greeter(name)
puts "#{name} greets private class method"
end
end
def public_instance_greeter(name)
self.class.private_class_greeter(name)
end
end
Animal.public_class_greeter('John') works fine, printing John greets private class method.
However, Animal.new.public_instance_greeter("John") throws an error: NoMethodError: private method 'private_class_greeter' called for Animal:Class.
That is expected, as the invocation self.class.private_class_greeter is same as Animal.private_class_greeter, which obviously throws an error.
After searching on how this can be fixed, I came up with the following code, that does the job:
class Animal
class << self
def public_class_greeter(name)
private_class_greeter(name)
end
private
def private_class_greeter(name)
puts "#{name} greets private class method"
end
end
define_method :public_instance_greeter, &method(:private_class_greeter)
end
I don't exactly understand what is happening here: &method(:private_class_greeter).
Could you please explain what does this mean?
If I were to replace:
define_method :public_instance_greeter, &method(:private_class_greeter)
with:
def public_instance_greeter
XYZ
end
then, what should be the content in place of XYZ?
How does Ruby parse &method(:private_class_greeter)?
The expression &method(:private_class_greeter) is
the value of the method call method(:private_class_greeter)
prefixed with the & operator.
What does the method method do?
The method method looks up the specified method name in the current context and returns a Method object that represents it. Example in irb:
def foo
"bar"
end
my_method = method(:foo)
#=> #<Method: Object#foo>
Once you have this method, you can do various things with it:
my_method.call
#=> "bar"
my_method.source_location # gives you the file and line the method was defined on
#=> ["(irb)", 5]
# etc.
What is the & operator for?
The & operator is used to pass a Proc as a block to a method that expects a block to be passed to it. It also implicitly calls the to_proc method on the value you pass in, in order to convert values that are not Proc into a Proc.
The Method class implements to_proc — it returns the contents of the method as a Proc. Therefore, you can prefix a Method instance with & and pass it as a block to another method:
def call_block
yield
end
call_block &my_method # same as `call_block &my_method.to_proc`
#=> "bar"
The define_method method just happens to take a block with the contents of the new method that is being defined. In your example, &method(:private_class_greeter) passes in the existing private_class_greeter method as a block.
Is this how &:symbol works?
Yes. Symbol implements to_proc so that you can simplify your code like this:
["foo", "bar"].map(&:upcase)
#=> ["FOO", "BAR"]
# this is equivalent to:
["foo", "bar"].map { |item| item.upcase }
# because
:upcase.to_proc
# returns this proc:
Proc { |val| val.send(:upcase) }
How can I replicate &method(:private_class_greeter)?
You can pass in a block that calls the target method:
define_method :public_instance_greeter do |name|
self.class.send(:private_class_greeter, name)
end
Of course, then you don't need to use define_method anymore, which results in the same solution Eric mentioned in his answer:
def public_instance_greeter(name)
self.class.send(:private_class_greeter, name)
end
First, take good care with your indentation. private should be 2 spaces to the right: it gives the impression that public_instance_greeter is private otherwise.
If you don't care about encapsulation, you could simply use Kernel#send:
class Animal
class << self
def public_class_greeter(name)
private_class_greeter(name)
end
private
def private_class_greeter(name)
puts "#{name} greets private class method"
end
end
def public_instance_greeter(name)
self.class.send(:private_class_greeter, name)
end
end
Animal.public_class_greeter('John')
# John greets private class method
Animal.new.public_instance_greeter("John")
# John greets private class method

Reflection in ruby?

I am curious how this works. For example if I create a factory pattern based class where you can "register" classes for later use and then do something like
FactoryClass.register('YourClassName', [param, param, ...]);
FactoryClass.create('your_class_name').call_method_from_this_object
where 'class_name' is a key in a hash that maps to value: ClassName
is there anything like php reflection, where I can create an instance of a class based on a string name and pass in the arguments in? (in php the arguments would be an array of them that php then knows how what to do with)
So if we take a real world example:
class Foo
attr_reader :something
def initialize(input)
#something = input
end
def get_something
return #something
end
end
# In the factory class, foo is then placed in a hash: {'foo' => 'Foo'}
# This step might not be required??
FactoryClass.create('Foo', ['hello'])
# Some where in your code:
FactoryClass.create('foo').get_something # => hello
Is this possible to do in ruby? I know everything is essentially an object, but I haven't seen any API or docs on creating class instances from string names like this and also passing in objects.
As for the hash above, thinking about it now I would probably have to do something like:
{'foo' => {'class' => 'Foo', 'params' => [param, param, ...]}}
This way when you call .create on the FactoryClass it would know, ok I can instantiate Foo with the associated params.
If I am way off base, please feel free to educate me.
Check out Module#const_get (retrieving a constant from a String) and Object#send (calling a method from a String).
Here is an answer that doesn't use eval.
PHP's Reflection is called Metaprogramming in Ruby, but they are quite different. Everything in Ruby is open and could be accessed.
Consider the following code:
class Foo
attr_reader :something
def initialize(input)
#something = input
end
def get_something
return #something
end
end
#registered = { }
def register(reference_name, class_name, params=[])
#registered[reference_name] = { class_name: class_name, params: [params].flatten }
end
def create(reference_name)
h = #registered[reference_name]
Object.const_get(h[:class_name]).new(*(h[:params]))
end
register('foo', 'Foo', ['something'])
puts create('foo').get_something
You can use Object#const_get to get objects from strings. Object.const_get('Foo') will give you the object Foo.
However, you don't need to send class name as string. You can also pass around the class name as object and use that directly.
class Foo
attr_reader :something
def initialize(input)
#something = input
end
def get_something
return #something
end
end
#registered = { }
def register(reference_name, class_name, params=[])
#registered[reference_name] = { class_name: class_name, params: [params].flatten }
end
def create(reference_name)
h = #registered[reference_name]
h[:class_name].new(*(h[:params]))
end
register('foo', Foo, ['something else'])
puts create('foo').get_something
Actually one of the strong points in ruby is meta-programming. So this is really easy to do in ruby.
I am going to skip the registering part, and jump straight to the creation
A simple implementation would be this
class FactoryClass
def self.create(class_name, params)
klass = Object.const_get(class_name)
klass.new(*params)
end
end
and then you can just do:
FactoryClass.create('YourClassName', [param, param, ...]);
and this would be equivalent to calling
YourClassName.new(param, param, ...)

Method chaining in ruby

I want to build an API client that has an interface similar to rails active record. I want the consumers to be able to chain methods and after the last method is chained, the client requests a url based on the methods called. So it's method chaining with some lazy evaluation. I looked into Active Record but this is very complicated (spawning proceses, etc).
Here is a toy example of the sort of thing I am talking about. You can chain as many 'bar' methods together as you like before calling 'get', like this:
puts Foo.bar.bar.get # => 'bar,bar'
puts Foo.bar.bar.bar.get # => 'bar,bar,bar'
I have successfully implemented this, but I would rather not need to call the 'get' method. So what I want is this:
puts Foo.bar.bar # => 'bar,bar'
But my current implementation does this:
puts Foo.bar.bar #=> [:bar, :bar]
I have thought of overriding array methods like each and to_s but I am sure there is a better solution.
How would I chain the methods and know which was the last one so I could return something like the string returned in the get method?
Here is my current implementation:
#!/usr/bin/env ruby
class Bar
def get(args)
# does a request to an API and returns things but this will do for now.
args.join(',')
end
end
class Foo < Array
def self.bar
#q = new
#q << :bar
#q
end
def bar
self << :bar
self
end
def get
Bar.new.get(self)
end
end
Also see: Ruby Challenge - Method chaining and Lazy Evaluation
How it works with activerecord is that the relation is a wrapper around the array, delegating any undefined method to this internal array (called target). So what you need is to start with a BasicObject instead of Object:
class Foo < BasicObject
then you need to create internal variable, to which you will delegate all the methods:
def method_missing(*args, &block)
reload! unless loaded?
#target.send(*args, &block)
end
def reload!
# your logic to populate target, e.g:
#target = #counter
#loaded = true
end
def loaded?
!!#loaded
end
To chain methods, your methods need to return new instance of your class, e.g:
def initialize(counter=0)
#counter = counter
end
def bar
_class.new(#counter + 1)
end
private
# BasicObject does not define class method. If you want to wrap your target
# completely (like ActiveRecord does before rails 4), you want to delegate it
# to #target as well. Still you need to access the instance class to create
# new instances. That's the way (if there are any suggestion how to improve it,
# please comment!)
def _class
(class << self; self end).superclass
end
Now you can check it in action:
p Foo.new.bar.bar.bar #=> 3
(f = Foo.new) && nil # '&& nil' added to prevent execution of inspect
# object in the console , as it will force #target
# to be loaded
f.loaded? #=> false
puts f #=> 0
f.loaded? #=> true
A (very simple, maybe simplistic) option would be to implement the to_s method - as it is used to "coerce" to string (for instance in a puts), you could have your specific "this is the end of the chain" code there.

How are respond_to and respond_to_missing different?

I'm confused when to use each of this methods.
From respond_to? documentation:
Returns true if obj responds to the given method. Private methods
are included in the search only if the optional second parameter
evaluates to true.
If the method is not implemented, as Process.fork on Windows,
File.lchmod on GNU/Linux, etc., false is returned.
If the method is not defined, respond_to_missing? method is called and
the result is returned.
And respond_to_missing?:
Hook method to return whether the obj can respond to id method or
not.
See #respond_to?.
Both methods takes 2 arguments.
Both methods seems to the same thing(check if some object respond to given method) so why we should use(have) both?
Defining 'resond_to_missing?` gives you ability to take methods:
class A
def method_missing name, *args, &block
if name == :meth1
puts 'YES!'
else
raise NoMethodError
end
end
def respond_to_missing? name, flag = true
if name == :meth1
true
else
false
end
end
end
[65] pry(main)> A.new.method :meth1
# => #<Method: A#meth1>
Why respond_to? couldn't do this?
What I guess:
respond_to? checks if method is in:
Current object.
Parent object.
Included modules.
respond_to_missing? checks if method is:
Defined via method_missing:
Via array of possible methods:
def method_missing name, *args, &block
arr = [:a, :b, :c]
if arr.include? name
puts name
else
raise NoMethodError
end
end
Delegating it to different object:
class A
def initialize name
#str = String name
end
def method_missing name, *args, &block
#str.send name, *args, &block
end
end
2 . Other way that I'm not aware of.
Where should both be defined/used(my guessing too):
Starting from 1.9.3(as fair I remember) define only respond_to_missing? but use only respond_to?
Last questions:
Am I right? Did I missed something? Correct everything that is bad and/or answer questions asked in this question.
respond_to_missing? is supposed to be updated when you make available additional methods using the method missing technique. This will cause the Ruby interpreter to better understand the existence of the new method.
In fact, without using respond_to_missing?, you can't get the method using method.
Marc-André posted a great article about the respond_to_missing?.
In order for respond_to? to return true, one can specialize it, as follows:
class StereoPlayer
# def method_missing ...
# ...
# end
def respond_to?(method, *)
method.to_s =~ /play_(\w+)/ || super
end
end
p.respond_to? :play_some_Beethoven # => true
This is better, but it still doesn’t make play_some_Beethoven behave exactly like a method. Indeed:
p.method :play_some_Beethoven
# => NameError: undefined method `play_some_Beethoven'
# for class `StereoPlayer'
Ruby 1.9.2 introduces respond_to_missing? that provides for a clean solution to the problem. Instead of specializing respond_to? one specializes respond_to_missing?. Here’s a full example:
class StereoPlayer
# def method_missing ...
# ...
# end
def respond_to_missing?(method, *)
method =~ /play_(\w+)/ || super
end
end
p = StereoPlayer.new
p.play_some_Beethoven # => "Here's some_Beethoven"
p.respond_to? :play_some_Beethoven # => true
m = p.method(:play_some_Beethoven) # => #<Method: StereoPlayer#play_some_Beethoven>
# m acts like any other method:
m.call # => "Here's some_Beethoven"
m == p.method(:play_some_Beethoven) # => true
m.name # => :play_some_Beethoven
StereoPlayer.send :define_method, :ludwig, m
p.ludwig # => "Here's some_Beethoven"
See also Always Define respond_to_missing? When Overriding method_missing.

Adding an instance variable to a class in Ruby

How can I add an instance variable to a defined class at runtime, and later get and set its value from outside of the class?
I'm looking for a metaprogramming solution that allows me to modify the class instance at runtime instead of modifying the source code that originally defined the class. A few of the solutions explain how to declare instance variables in the class definitions, but that is not what I am asking about.
Ruby provides methods for this, instance_variable_get and instance_variable_set. (docs)
You can create and assign a new instance variables like this:
>> foo = Object.new
=> #<Object:0x2aaaaaacc400>
>> foo.instance_variable_set(:#bar, "baz")
=> "baz"
>> foo.inspect
=> #<Object:0x2aaaaaacc400 #bar=\"baz\">
You can use attribute accessors:
class Array
attr_accessor :var
end
Now you can access it via:
array = []
array.var = 123
puts array.var
Note that you can also use attr_reader or attr_writer to define just getters or setters or you can define them manually as such:
class Array
attr_reader :getter_only_method
attr_writer :setter_only_method
# Manual definitions equivalent to using attr_reader/writer/accessor
def var
#var
end
def var=(value)
#var = value
end
end
You can also use singleton methods if you just want it defined on a single instance:
array = []
def array.var
#var
end
def array.var=(value)
#var = value
end
array.var = 123
puts array.var
FYI, in response to the comment on this answer, the singleton method works fine, and the following is proof:
irb(main):001:0> class A
irb(main):002:1> attr_accessor :b
irb(main):003:1> end
=> nil
irb(main):004:0> a = A.new
=> #<A:0x7fbb4b0efe58>
irb(main):005:0> a.b = 1
=> 1
irb(main):006:0> a.b
=> 1
irb(main):007:0> def a.setit=(value)
irb(main):008:1> #b = value
irb(main):009:1> end
=> nil
irb(main):010:0> a.setit = 2
=> 2
irb(main):011:0> a.b
=> 2
irb(main):012:0>
As you can see, the singleton method setit will set the same field, #b, as the one defined using the attr_accessor... so a singleton method is a perfectly valid approach to this question.
#Readonly
If your usage of "class MyObject" is a usage of an open class, then please note you are redefining the initialize method.
In Ruby, there is no such thing as overloading... only overriding, or redefinition... in other words there can only be 1 instance of any given method, so if you redefine it, it is redefined... and the initialize method is no different (even though it is what the new method of Class objects use).
Thus, never redefine an existing method without aliasing it first... at least if you want access to the original definition. And redefining the initialize method of an unknown class may be quite risky.
At any rate, I think I have a much simpler solution for you, which uses the actual metaclass to define singleton methods:
m = MyObject.new
metaclass = class << m; self; end
metaclass.send :attr_accessor, :first, :second
m.first = "first"
m.second = "second"
puts m.first, m.second
You can use both the metaclass and open classes to get even trickier and do something like:
class MyObject
def metaclass
class << self
self
end
end
def define_attributes(hash)
hash.each_pair { |key, value|
metaclass.send :attr_accessor, key
send "#{key}=".to_sym, value
}
end
end
m = MyObject.new
m.define_attributes({ :first => "first", :second => "second" })
The above is basically exposing the metaclass via the "metaclass" method, then using it in define_attributes to dynamically define a bunch of attributes with attr_accessor, and then invoking the attribute setter afterwards with the associated value in the hash.
With Ruby you can get creative and do the same thing many different ways ;-)
FYI, in case you didn't know, using the metaclass as I have done means you are only acting on the given instance of the object. Thus, invoking define_attributes will only define those attributes for that particular instance.
Example:
m1 = MyObject.new
m2 = MyObject.new
m1.define_attributes({:a => 123, :b => 321})
m2.define_attributes({:c => "abc", :d => "zxy"})
puts m1.a, m1.b, m2.c, m2.d # this will work
m1.c = 5 # this will fail because c= is not defined on m1!
m2.a = 5 # this will fail because a= is not defined on m2!
Mike Stone's answer is already quite comprehensive, but I'd like to add a little detail.
You can modify your class at any moment, even after some instance have been created, and get the results you desire. You can try it out in your console:
s1 = 'string 1'
s2 = 'string 2'
class String
attr_accessor :my_var
end
s1.my_var = 'comment #1'
s2.my_var = 'comment 2'
puts s1.my_var, s2.my_var
The other solutions will work perfectly too, but here is an example using define_method, if you are hell bent on not using open classes... it will define the "var" variable for the array class... but note that it is EQUIVALENT to using an open class... the benefit is you can do it for an unknown class (so any object's class, rather than opening a specific class)... also define_method will work inside a method, whereas you cannot open a class within a method.
array = []
array.class.send(:define_method, :var) { #var }
array.class.send(:define_method, :var=) { |value| #var = value }
And here is an example of it's use... note that array2, a DIFFERENT array also has the methods, so if this is not what you want, you probably want singleton methods which I explained in another post.
irb(main):001:0> array = []
=> []
irb(main):002:0> array.class.send(:define_method, :var) { #var }
=> #<Proc:0x00007f289ccb62b0#(irb):2>
irb(main):003:0> array.class.send(:define_method, :var=) { |value| #var = value }
=> #<Proc:0x00007f289cc9fa88#(irb):3>
irb(main):004:0> array.var = 123
=> 123
irb(main):005:0> array.var
=> 123
irb(main):006:0> array2 = []
=> []
irb(main):007:0> array2.var = 321
=> 321
irb(main):008:0> array2.var
=> 321
irb(main):009:0> array.var
=> 123
Readonly, in response to your edit:
Edit: It looks like I need to clarify
that I'm looking for a metaprogramming
solution that allows me to modify the
class instance at runtime instead of
modifying the source code that
originally defined the class. A few of
the solutions explain how to declare
instance variables in the class
definitions, but that is not what I am
asking about. Sorry for the confusion.
I think you don't quite understand the concept of "open classes", which means you can open up a class at any time. For example:
class A
def hello
print "hello "
end
end
class A
def world
puts "world!"
end
end
a = A.new
a.hello
a.world
The above is perfectly valid Ruby code, and the 2 class definitions can be spread across multiple Ruby files. You could use the "define_method" method in the Module object to define a new method on a class instance, but it is equivalent to using open classes.
"Open classes" in Ruby means you can redefine ANY class at ANY point in time... which means add new methods, redefine existing methods, or whatever you want really. It sounds like the "open class" solution really is what you are looking for...
I wrote a gem for this some time ago. It's called "Flexible" and not available via rubygems, but was available via github until yesterday. I deleted it because it was useless for me.
You can do
class Foo
include Flexible
end
f = Foo.new
f.bar = 1
with it without getting any error. So you can set and get instance variables from an object on the fly.
If you are interessted... I could upload the source code to github again. It needs some modification to enable
f.bar?
#=> true
as method for asking the object if a instance variable "bar" is defined or not, but anything else is running.
Kind regards, musicmatze
It looks like all of the previous answers assume that you know what the name of the class that you want to tweak is when you are writing your code. Well, that isn't always true (at least, not for me). I might be iterating over a pile of classes that I want to bestow some variable on (say, to hold some metadata or something). In that case something like this will do the job,
# example classes that we want to tweak
class Foo;end
class Bar;end
klasses = [Foo, Bar]
# iterating over a collection of klasses
klasses.each do |klass|
# #class_eval gets it done
klass.class_eval do
attr_accessor :baz
end
end
# it works
f = Foo.new
f.baz # => nil
f.baz = 'it works' # => "it works"
b = Bar.new
b.baz # => nil
b.baz = 'it still works' # => "it still works"

Resources