Mass assignment on construction from within ruby [duplicate] - ruby

This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Idiomatic object creation in ruby
Sometimes it's useful to assign numerous of a constructed arguments to instance variables on construction. Other than the obvious method:
def initialize(arg1, arg2, arg3)
#arg1, #arg2, #arg3 = arg1, arg2, arg3
end
Is there a more concise idiom for achieving the same result? Something like that found in scala for instance:
class FancyGreeter(greeting: String) {
def greet() = println(greeting)
}
Where in this case the object FancyGreeter has a default constructor that provides assignment for it's passed arguments.

In Ruby 1.8, block arguments and method arguments have different semantics: method arguments have binding semantics, block arguments have assignment semantics.
What that means is that when you call a method, the method arguments get bound to the values that you pass in. When you call a block, the values get assigned to the arguments.
So, you can create some pretty crazy looking blocks that way, that seemingly don't do anything:
lambda {|#a|}.call(42)
The block body is empty, but because of the argument assignment semantics, the instance variable #a will be assigned the value 42. It works even crazier:
lambda {|foo.bar|}.call(42)
Yes, attr_writer methods work too. Or what about
foo = {}
lambda {|foo[:bar]|}.call(42)
p foo # => {:bar => 42}
Yup, those too.
And since you can define methods using blocks, you can do this:
class FancyGreeter
define_method(:initialize) {|#greeting|}
def greet; puts #greeting end
end
or even
class FancyGreeter
attr_accessor :greeting
define_method(:initialize) {|self.greeting|}
def greet; puts greeting end
end
However, I wouldn't recommend this for two reasons:
Not many Rubyists know this, be kind to the people who have to maintain the code after you.
In Ruby 1.9 and onwards, block argument semantics are gone, blocks also use method argument semantics, therefore this does no longer work.

I suppose you could do....
def initialize *e
#a, #b, #c = e
end

I don't know about "better" but there are varying levels of 'clever':
def initialize args={}
args.each do |key, value|
instance_variable_set "##{key}", value
end
end
But "clever" is usually dangerous when you program :-)
Edit: Given the edited question, I'll add this:
Class PickMe
def initialize say="what?"
#say = say
end
end
Just because I don't know if you're aware of default options. Otherwise, think of the value of self-documenting code. A cleanly-written 'initialize' method is priceless.

It was either Andy Hunt or Dave Thomas who proposed that Ruby should be able to handle this syntax for initializing member variables from constructor arguments:
def initialize(#a, #b, #c)
...
end
Matz did not accept their proposal; I don't remember why.

Related

How do write two methods with different number of arguments in Ruby

I am trying to write this inside my class:
class << self
def steps
#steps.call
end
def transitions
#transitions.call
end
def steps(&steps)
#steps = steps
end
def transitions(&transitions)
#transitions = transitions
end
end
That won't work since in Ruby, I can't do this kind of method overloading. Is there a way around this?
You can kind of do this with method aliasing and mixins, but the way you handle methods with different signatures in Ruby is with optional arguments:
def steps(&block)
block.present? ? #steps = block : #steps.call
end
This sort of delegation is a code smell, though. It usually means there's something awkward about the interface you've designed. In this case, something like this is probably better:
def steps
#steps.call
end
def steps=(&block)
#steps = block
end
This makes it clear to other objects in the system how to use this interface since it follows convention. It also allows for other cases, like passing a block into the steps method for some other use:
def steps(&block)
#steps.call(&block)
end
Ruby does not support method overloading (see "Why doesn't ruby support method overloading?" for the reason). You can, however, do something like:
def run(args*)
puts args
end
args will then be an array of the arguments passed in.
You can also pass in a hash of options to handle arguments, or you can pass in nil when you don't want to supply arguments and handle nil in your method body.

In Ruby, how do I define a class constructor method with the same name as the class?

I'm not sure where I have seen this, or if I just think I have seen it, but I would like to be able to call a method that creates an instance of a class with the same name. So, instead of:
# The class is called 'Vector3', for example:
Vector3.new(x,y,z)
I would like to have an eponymous method that instantiates the class, like so:
Vector3(x,y,z) #<- returns instance of Vector3 class
How would you define that in Ruby?
As #Eli mentioned, you can define a method in the kernel:
def Kernel.Vector3(*args)
Vector3.new(*args)
end
Ruby does this for Array, Complex, Float, Hash, Integer, Rational and String where you probably saw it.
The reason it works is that Object includes Kernel, hence all objects in your program (except ones directly inheriting from BasicObject) will have that method.
However, doing so is unidiomatic, unnecessary (you clutter all objects with an additional method), confusing (capitalized identifiers should be constants) and generally looked down upon.
AFAIK you can't. You can do something similar, Vector3[x, y, z].
class Vector3
def initialize(x, y, z)
# ...
end
def self.[](*args)
self.new(*args)
end
end
Note that the Ruby library uses this device as well. There's Hash.new(...) and Hash[...] , but no Hash(...). This parallels how Proc objects are invoked:
greet = Proc.new { |name| puts "Hello, #{name}" }
greet["Amadan"]
EDIT: I stand corrected:
module Kernel
def Vector3(*args)
Vector3.new(*args)
end
end
But, as Eli Sadoff said, it is impractical, violates encapsulation, and Ruby style (functions and methods should be lowercase).
This answers what I understood the question to be from the title. (Somehow I overlooked the example that contradicts that.) I will leave my answer because I think it includes some interesting elements.
class MyClass
def hi
"hi"
end
my_alias = to_s
singleton_class.class_eval { alias_method(my_alias, :new) }
end
MyClass.methods(false)
#=> [:MyClass]
my_instance = MyClass.MyClass
#=> #<MyClass:0x007fadc2092320>
my_instance.hi
#=> "hi"
Note that this works when the alias of new is passed arguments and/or a block.
See Object#singleton_class and Module#class_eval.

Metaprogramming in Ruby with derived classes

I'm trying to write a method that prints class variable names and their values. As an example:
class A
def printvars
???
end
end
class <<A
def varlist(*args)
???
end
end
class B < A
varlist :c
def initialize(c)
#c = c
end
b = B.new(10)
b.printvars()
And I would like the output to be c => 10. But I don't know what goes in the ???. I've tried using a self.class_eval in the body of varlist, but that won't let me store args. I've also tried keeping a hash in the class A and just printing it out in printvars, but the singleton class is a superclass of A and so has no access to this hash. So far everything I've tried doesn't work.
I think something similar must be possible, since Rails does something related with its validates_* methods. Ideally I could make this work exactly as expected, but even a pointer to how to print just the variable names (so just c as output) would be most appreciated.
You might like this answer: What is attr_accessor in Ruby?
Basically, as you surmised, varlist needs to be a class method which takes a variable list of arguments (*args). Once you have those arguments you could try any number of things using send, respond_to?, or maybe even instance_variable_get. Note, none of those are really recommended, but I wanted to answer your question a bit.
The other half is that you should probably look into method_missing in order to understand how things like validates_* are working. The * part necessitates that you do something like method_missing because you can't actually do module_eval until you know what you're looking for. In the case of the magic rails methods, you don't necessarily ever know what you're looking for! So we rely on the built in method_missing to let us know what got called.
For funzies, try this in IRB:
class A
def method_missing(method, *args, &block)
puts method, args.inspect
end
end
A.new.banana(13, 'snakes')
A.new.validates_serenity_of('Scooters', :within => [:calm, :uncalm])
Does that help?
Just use Module#class_variables
As far as I can tell, you're vastly over-complicating this. All you need is the pre-defined Module#class_variables method. You can call this directly on the class, or invoke it through self if you want to bind it to an instance of the class. For example:
class Foo
##bar = "baz"
def show_class_variables
self.class.class_variables
end
end
Foo.class_variables
#=> [:##bar]
foo = Foo.new
foo.show_class_variables
#=> [:##bar]

How does the "#map(&proc)" idiom work when introspecting module classes?

Presenting the Idiom
I found an interesting but unexplained alternative to an accepted answer. The code clearly works in the REPL. For example:
module Foo
class Bar
def baz
end
end
end
Foo.constants.map(&Foo.method(:const_get)).grep(Class)
=> [Foo::Bar]
However, I don't fully understand the idiom in use here. In particular, I don't understand the use of &Foo, which seems to be some sort of closure, or how this specific invocation of #grep operates on the result.
Parsing the Idiom
So far, I've been able to parse bits and pieces of this, but I'm not really seeing how it all fits together. Here's what I think I understand about the sample code.
Foo.constants returns an array of module constants as symbols.
method(:const_get) uses Object#method to perform a method lookup and return a closure.
Foo.method(:const_get).call :Bar is a closure that returns a qualified path to a constant within the class.
&Foo seems to be some sort of special lambda. The docs say:
The & argument preserves the tricks if a Proc object is given by & argument.
I'm not sure I fully understand what that means in this specific context, either. Why a Proc? What "tricks," and why are they necessary here?
grep(Class) is operating on the value of the #map method, but its features are not obvious.
Why is this #map construct returning a greppable Array instead of an Enumerator?
Foo.constants.map(&Foo.method(:const_get)).class
=> Array
How does grepping for a class named Class actually work, and why is that particular construction necessary here?
[Foo::Bar].grep Class
=> [Foo::Bar]
The Question, Restated
I'd really like to understand this idiom in its entirety. Can anyone fill in the gaps here, and explain how the pieces all fit together?
&Foo.method(:const_get) is the method const_get of the Foo object. Here's another example:
m = 1.method(:+)
#=> #<Method: Fixnum#+>
m.call(1)
#=> 2
(1..3).map(&m)
#=> [2, 3, 4]
So in the end this is just a pointfree way of saying Foo.constants.map { |c| Foo.const_get(c) }. grep uses === to select elements, so it would only get constants that refer to classes, not other values. This can be verified by adding another constant to Foo, e.g. Baz = 1, which will not get grepped.
If you have further questions please add them as comments and I'll try to clarify them.
Your parse of the idiom is pretty spot on, but I'll go through it and try to clear up any questions you mentioned.
1. Foo.constants
As you mentioned, this returns an array of module constant names as symbols.
2. Array#map
You obviously know what this does, but I want to include it for completeness. Map takes a block and calls that block with each element as an argument. It returns an Array of the results of these block calls.
3. Object#method
Also as you mentioned, this does a method lookup. This is important because a method without parentheses in Ruby is a method call of that method without any arguments.
4. &
This operator is for converting things to blocks. We need this because blocks are not first-class objects in Ruby. Because of this second-class status, we have no way to create blocks which stand alone, but we can convert Procs into blocks (but only when we are passing them to a function)! The & operator is our way of doing this conversion. Whenever we want to pass a Proc object as if it were a block, we can prepend it with the & operator and pass it as the last argument to our function. But & can actually convert more than just Proc objects, it can convert anything that has a to_proc method!
In our case, we have a Method object, which does have a to_proc method. The difference between a Proc object and a Method object lies in their context. A Method object is bound to a class instance and has access to the variables which belong to that class. A Proc is bound to the context in which it is created; that is, it has access to the scope in which it was created. Method#to_proc bundles up the context of the method so that the resulting Proc has access to the same variables. You can find more about the & operator here.
5. grep(Class)
The way Enumerable#grep works is that it runs argument === x for all x in the enumerable. The ordering of the arguments to === is very important in this case, since it's calling Class.=== rather than Foo::Bar.===. We can see the difference between these two by running:
irb(main):043:0> Class === Foo::Bar
=> true
irb(main):044:0> Foo::Bar === Class
=> false
Module#=== (Class inherits its === method from Method) returns True when the argument is an instance of Module or one of its descendants (like Class!), which will filter out constants which are not of type Module or Class.
You can find the documentation for Module#=== here.
The first thing to know is that:
& calls to_proc on the object succeeding it and uses the proc produced as the methods' block.
Now you have to drill down to how exactly the to_proc method is implemented in a specific class.
1. Symbol
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Or something like this. From the above code you clearly see that the proc produced calls the method (with name == the symbol) on the object and passes the arguments to the method. For a quick example:
[1,2,3].reduce(&:+)
#=> 6
which does exactly that. It executes like this:
Calls :+.to_proc and gets a proc object back => #<Proc:0x007fea74028238>
It takes the proc and passes it as the block to the reduce method, thus instead of calling [1,2,3].reduce { |el1, el2| el1 + el2 } it calls
[1,2,3].reduce { |el1, el2| el1.send(:+, el2) }.
2. Method
class Method
def to_proc
Proc.new do |*args|
self.call(*args)
end
end
end
Which as you can see it has a different implementation of Symbol#to_proc. To illustrate this consider again the reduce example, but now let as see how it uses a method instead:
def add(x, y); x + y end
my_proc = method(:add)
[1,2,3].reduce(&my_proc)
#=> 6
In the above example is calling [1,2,3].reduce { |el1, el2| my_proc(el1, el2) }.
Now on why the map method returns an Array instead of an Enumerator is because you are passing it a block, try this instead:
[1,2,3].map.class
#=> Enumerator
Last but not least the grep on an Array is selecting the elements that are === to its argument. Hope this clarifies your concerns.
Your sequence is equivalent to:
c_names = Foo.constants #=> ["Bar"]
cs = c_names.map { |c_name| Foo.__send__(:const_get, c_name) } #=> [Foo::Bar]
cs.select{ |c| Class === c } #=> [Foo::Bar]
You can consider Object#method as (roughly):
class Object
def method(m)
lambda{ |*args| self.__send__(m, *args) }
end
end
grep is described here http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-grep
=== for Class (which is subclass of Module) is described here http://ruby-doc.org/core-1.9.3/Module.html#method-i-3D-3D-3D
UPDATE: And you need to grep because there can be other constants:
module Foo
PI = 3.14
...
end
and you probably don't need them.

Ruby: Boolean attribute naming convention and use

Learning ruby. I'm under the impression that boolean attributes should be named as follows:
my_boolean_attribute?
However, I get syntax errors when attempting to do the following:
class MyClass
attr_accessor :my_boolean_attribute?
def initialize
:my_boolean_attribute? = false
end
end
Apparently ruby is hating the "?". Is this the convention? What am I doing wrong?
Edit: three-years later; the times, they are a-changin'…
Julik's answer is the simplest and best way to tackle the problem these days:
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
My answer to the original question follows, for posterity…
The short version:
You can't use a question mark in the name of an instance variable.
The longer version:
Take, for example, attr_accessor :foo — it's simply conceptually a bit of syntactic sugar for the following:
def foo
#foo
end
def foo=(newfoo)
#foo = newfoo
end
Furthermore, the question-mark suffix is mostly just a convention to indicate that the return value of a method is a boolean.
The best approximation I can make of what you're going for here…
class MyClass
def initialize
#awesome = true
end
def awesome?
#awesome
end
end
In this case, there may be a case to be made for using attr_accessor — after all, it may be explicit that you're working directly with a boolean attribute. Generally, I save the question-mark suffix for when I am implementing a method whose boolean return value is based on slightly more complex conditions than just the value of an attribute.
Cheers!
Edit, two years later, after a recent comment:
Ruby enforces certain naming conventions. Symbols in Ruby can't have question marks. Thus invocations of :my_boolean_attribute? both will fail with a NameError. Edit: not correct, just use the quoted syntax for a symbol, e.g., :"my_attribute?"
Symbols are immutable, attempting to assign to one will throw a SyntaxError.
The easiest way to quickly add a "question method" is to use aliasing for your reader method
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
The attr_accessor symbol implies that the variable name is #my_boolean_attribute, so that's what you should be setting (not the symbol).
Also, you can't use ? for variables, just method names.
? is convention for methodnames, not variables. You can't use an instance variable named #foo?, however you could use a variable named #foo and name the (manually created) getter method foo? if you wanted to.
Monkey-patching metaprogramming - maybe it can be made more elegant, this is only a quick draft, and I haven't done metaprogramming for a little while...
# inject the convenience method into the definition of the Object class
class Object
def Object::bool_attr(attrname)
class_eval { define_method(attrname.to_s,
lambda { instance_variable_get('#' + attrname.to_s.chop) }) }
class_eval { define_method(attrname.to_s.chop+"=",
lambda { |x| instance_variable_set('#'+attrname.to_s.chop, x) }) }
end
end
### somewhere later
class MyClass
bool_attr :my_boolean_attribute?
def initialize
#my_boolean_attribute = true
end
end
# yet even more later
foo = MyClass.new
bar = MyClass.new
foo.my_boolean_attribute = 1
puts foo.my_boolean_attribute?
puts bar.my_boolean_attribute?
With this approach, you can be DRY and get the nice questionmark too. You just might need to pick a better name than "bool_attr", like, "bool_attr_accessor" or something similar.
The definitions that I made are a bit cranky, in a sense that the question mark is present in the original symbol. Probably a cleaner approach would be to avoid the questionmark in the symbol name and append it during the definition of the method - should be less confusing.
Oh, and almost forgot to include the obligatory link: Seeing metaclasses clearly
I looked through the answers, and while the accepted answer is on-target, it introduces "extra" noise in the class. The way I'd suggest solving this issue is:
class Animal
attr_writer :can_swim
def initialize(animal_type_name)
#can_swim = true
#animal_type_name = animal_type_name
end
def can_swim?
#can_swim
end
def to_s
#animal_type_name
end
end
dog = Animal.new('Dog in a bag')
dog.can_swim = false
puts "Can this #{dog} Swim? --- [#{dog_without_legs.can_swim? ? 'YEP!' : 'NOPE!'}]"

Resources