irb(main):001:0> class Fixnum
irb(main):002:1> define_method(:gimme_five) do
irb(main):003:2* 5
irb(main):004:2> end
irb(main):005:1> end
=> #<Proc:0x007ff4ed01cd10#(irb):2 (lambda)>
irb(main):006:0> class String
irb(main):007:1> define_method(:scramble) do
irb(main):008:2* new_string = self.reverse()
irb(main):009:2> new_string = new_string.upcase()
irb(main):010:2> new_string
irb(main):011:2> end
irb(main):012:1> end
=> #<Proc:0x007ff4ed02d868#(irb):7 (lambda)>
irb(main):013:0>
I'm am not sure what I am doing wrong but my methods are not being defined???
In ruby, it is much more common to define methods as follows (using your output as an example:
def gimme_five
5
end
I believe that the syntax you are using to define your methods 'works', but what it is doing is creating 'lambdas' instead of regular methods. Lambdas and Procs compose Ruby's support for functional programming, and are special Ruby objects that represent blocks of code -- think of them as mini bundled up methods you can pass around to other objects.
So yeah, just define methods normally and should be fine -- the output in your irb REPL is just returning the lambda for no reason in particular -- just like how if you were to set an array in irb, you would get that array returned back:
>> a = [5]
=> [5]
Related
What does a ruby method ending with an "=" mean?
See the available methods in this print out:
2.2.0 :066 > obj.methods(false)
=> [:label=, :label, :description=, :description, :thumbnail=, :thumbnail, :attribution=, :attribution, :license=, :license, :logo=, :logo, :see_also=, :seeAlso=, :see_also, :seeAlso, :related=, :related, :within=, :within, :metadata=, :metadata, :sequences=, :sequences, :structures=, :structures, :viewing_hint=, :viewingHint=, :viewing_hint, :viewingHint, :viewing_direction=, :viewingDirection=, :viewing_direction, :viewingDirection, :service=, :service]
For example whats this difference between label= and label?
foo= is no different than any other method, except:
it requires precisely one argument and
Ruby permits you to add spaces before the = character.
class Foo
def foo=(other)
puts 'hi'
end
end
Foo.new.foo = 7
hi
class Goo
def goo=
puts 'hi'
end
end
Goo.new.goo=
Ruby says, "I'm waiting for an argument...". So we provide one:
4
and then she complains about what she asked you to do:
#=> ArgumentError: wrong number of arguments (1 for 0)
= methods are typically used to create a setter for an instance variable (if attr_acccessor or attr_writer is not used):
class Foo
def initialize(foo)
#foo=foo
end
# getter
def foo
#foo
end
# setter
def foo=(other)
#foo = other
end
end
f = Foo.new('dog')
f.foo
#=> "dog"
f.foo = 'cat'
#=> "cat"
f.foo
#=> "cat"
the methods ending with "=" are setting the instance variable
look at the answer here: why-use-rubys-attr-accessor-attr-reader-and-attr-writer
It is equivalent of setter methods in other languages, it is just convention so it looks more natural to say
obj.description="Fun Site"
vs
obj.setDescription("Fun Site")
There is nothing special about methods that end in =
You can see this by running the code below:
def bob=
puts "bob="
end
p send('bob='.to_sym)
What is special is the '=' infix operator. When you write self.bob = "bill". It is interpreted as self.send('bob='.to_sym, "bill").
Putting a ? at the end of a method is a hint that it returns a boolean (true/false). Methods that end in ! hint that the method affects the instance. See String#chomp vs String#chomp.
You can find out more about ruby operators at http://www.tutorialspoint.com/ruby/ruby_operators.htm and more about naming conventions at https://github.com/bbatsov/ruby-style-guide#naming
I know that methods in Ruby are not objects but procs and lambdas are. Is there any difference between them other than that? Because both we can pass around. What makes the proc objects different from a method?
Method:
1.8.7-p334 :017 > def a_method(a,b)
1.8.7-p334 :018?> puts "a method with args: #{a}, #{b}"
1.8.7-p334 :019?> end
1.8.7-p334 :021 > meth_ref = Object.method("a_method")
=> #<Method: Class(Object)#a_method>
1.8.7-p334 :022 > meth_ref.call(2,3)
Proc Object:
a = lambda {|a, b| puts "#{a}, #{b}"}
a.call(2,3)
In brief:
a Method object is "bound" to an object so that self points to that object when you call the method, and a Proc doesn't have that behavior; self depends on the context in which the Proc was created/called.
However:
You said in your question that "methods are not objects," but you have to be careful to distinguish between "method" and Method.
A "method" is a defined set of expressions that is given a name and put into the method table of a particular class for easy lookup and execution later:
class Foo
def my_method
return 123
end
end
Foo.new.my_method
# => 123
A Method object (or similarly an UnboundMethod object) is an actual Ruby object created by calling method / instance_method / etc. and passing the name of a "method" as the argument:
my_Foo = Foo.new
my_Method = my_Foo.method(:my_method)
# => #<Method: Foo#my_method>
my_Method.call
# => 123
my_UnboundMethod = Foo.instance_method(:my_method)
# => #<UnboundMethod: Foo#my_method>
my_UnboundMethod.bind(my_Foo).call
# => 123
A Proc object is a set of expressions that is not given a name, which you can store for later execution:
my_proc = Proc.new { 123 }
my_proc.call
# => 123
You may find it useful to read the RDoc documentation for UnboundMethod, Method, and Proc. The RDoc pages list the different instance methods available to each type.
Differences between blocks and procs
Procs are objects, blocks are not
At most one block can appear in an argument list
Differences between procs and lambdas
Lambdas check the number of arguments, while procs do not
Lambdas and procs treat the return keyword differently
It is very well explained here (I just copied that from the link below)
http://awaxman11.github.io/blog/2013/08/05/what-is-the-difference-between-a-block/
I am looking for a way (or perhaps a best practice) to chain various methods on a string object without actually opening up the String class. This is because the transformations I want to apply to the String object are fairly project specific, and I don't see a reason to pollute the global space with it.
Is there a way to achieve this? Maybe a wrapper of some sort? I experimented with gsub! on an instance variable but gsub!, unless the gsub, throws nil on failure to match, so it halts the chaining I want to achieve.
Basically, I need to be able to do:
"my_string".transformation1.transformation2.transformation3
and get to keep all those transformations namespaced to my application. Any ideas?
If you are using Ruby >= 2.0 you can use refinements:
module MyRefinements
refine String do
def transformation1
# ...
self
end
def transformation2
# ...
self
end
def transformation3
# ...
self
end
end
end
# Either in global scope (active until the end-of-file)
# or in lexical scope (active until the lexical scope end)
# More on this in the refinements docs scope section
# global scope
using MyRefinements
"test".transformation1.transformation2.transformation3 #=> "test"
# lexical scope
begin
using MyRefinements
"test".transformation1.transformation2.transformation3 #=> "test"
end
You can add a method to an instance, but you're going to need to jump through a hoop to chain the methods:
str = 'now is the time'
def str.foo(target, replacement)
self.gsub(target, replacement)
end
def str.bar
self.reverse
end
str.singleton_methods # => [:foo, :bar]
str.foo('ow', 'ever') # => "never is the time"
str.bar # => "emit eht si won"
This won't work:
str.foo('ow', 'ever').bar
# ~> NoMethodError
# ~> undefined method `bar' for "never is the time":String
You can use "bang" type methods, that mutate the original object:
str = 'now is the time'
def str.foo(target, replacement)
self.gsub!(target, replacement)
self
end
def str.bar
self.reverse!
self
end
str.singleton_methods # => [:foo, :bar]
str.foo('ow', 'ever').bar # => "emit eht si reven"
Be careful though. This won't work on every type of object, only ones that allow mutating.
And, the fact that the added methods are only available to that particular variable is really limiting; It's messier reusing that same functionality. You can clone the variable and assign that clone to a new variable, but replacing the value with something different becomes messy:
str2 = str.clone
str.object_id # => 70259449706680
str2.object_id # => 70259449706520
str.singleton_methods # => [:foo]
str2.singleton_methods # => [:foo]
str2 = 'all good men'
str2.foo('ll', '') # =>
# ~> NoMethodError
# ~> undefined method `foo' for "all good men":String
Personally, I'd do it through a subclass:
class MyString < String
def foo(s, t)
self.gsub(s, t)
end
end
str = MyString.new('now is the time')
str.foo('ow', 'ever') # => "never is the time"
str2 = 'all good men'
str2.foo('ll', '') # =>
# ~> NoMethodError
# ~> undefined method `foo' for "all good men":String
If you're on Ruby v2+, look at #mdesantis's answer using refinements. They were introduced to solve this sort of problem. If you're < v2.0, I'd go the sub-class route or accept having to modify String.
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.
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"