Concatenating instance methods i.e. var.method1.method2 - ruby

I am trying to write two instance methods, where method2 could process the output of method1.
For example, something like this:
puts Numbers::new(2,2).sum.sqrt
>16
I thought that the code would look something like this:
class Numbers
def initialize(x,y)
#x=x
#y=y
end
def sum
#z=#x+#y
end
def sqrt
#z**2
end
end
That is not the case and I get a NoMethodError when I try to call sqrt.
I know I am missing something easy and fundamental here, but I couldn't find a straight answer.
Thank you!

The sum method returns the value of #z which is a Fixnum. Ruby is trying to execute the sqrt method on the Fixnum instance and hence the exception.
May be this is what you want:
class Fixnum
def square
self**2
end
end
class Array
def sum
reduce(0, &:+)
end
end
Now you can:
[1,2].sum.square # 9

In order to call an instance method, you need an instance--your sum method needs to return the instance to allow chaining (same with sqrt).
Method chaining is common, but IMO a bit counter-intuitive in this case.

Related

Delegate methods to the result of a method

First of all, this is really just a golf question. My code works fine as it is. But I feel like there is probably a better (i.e. cooler) way to do this.
So I've got a class that acts a lot like a hash. However, it really internally generates a hash for each call to its hash-ish methods. The private method for generating that hash is calculated(). So my code currently has a lot of method definitions like this:
def each(&block)
return calculated.each(&block)
end
def length()
return calculated.length
end
Is there a concise way to delegate all those method calls to the calculated method?
I figured it out and it's incredibly simple. Just delegate to the name of the method. Here's a working example:
class MyClass
extend Forwardable
delegate %w([] []=) => :build_hash
def build_hash
return {'a'=>1}
end
end
edit: don't do this; I forgot Forwardable existed
You can write a "macro" for this. Well, Ruby doesn't technically have actual "macros" but it's a fairly common pattern nonetheless. Rails in particular uses it extensively - stuff like belongs_to, validates, etc are all class methods which are being used to generate instance-level functionality.
module DelegateToFunc
def delegate_to_func(delegate, delegators)
delegators.each do |func_name|
# Note: in Ruby 2.7 you can use |...| instead of |*args, &blk|
define_method(func_name) do |*args, &blk|
send(delegate).send(func_name, *args, &blk)
end
end
end
end
class SequenceBuilder
extend DelegateToFunc
delegate_to_func(:calculated, [:length, :each])
attr_accessor :min, :max
def initialize(min:, max:)
#min, #max = min, max
end
def calculated
min.upto(max).to_a
end
end
SequenceBuilder.new(min: 5, max: 10).length # => 6
SequenceBuilder.new(min: 1, max: 4).each { |num| print num } # => 1234
I will say, though, that methods generated by metaprogramming can sometimes be hard to track down and can make a program confusing, so try and use them tastefully ...
For example, do you really need your object to expose these hash-like methods? Why not just let the caller read the hash via calculated, and then call the hash methods directly on that?

Can I pass the minus (-) or plus (+) sign as params into a method and use them in the method?

I have a class, that has an attribute that's an integer. When I calculate the sum/difference of two instances of that class I actually want to calculate the sum/difference of their attribute. So my class looks like this:
class A
attr_reader :a
def initialize(a)
#a = a
end
def +(instance_of_a)
A.new(self.a + instance_of_a.a)
end
def -(instance_of_a)
A.new(self.a - instance_of_a.a)
end
end
Is there a way I could write a method to take the logic out of those 2 (- and +) methods and store them into the new method? I would like to write something like this:
def operation(sign, instance_of_a)
A.new(self.a sign instance_of_a.a)
end
def +(instance_of_a)
operation(+, instance_of_a)
end
def -(instance_of_a)
operation(-, instance_of_a)
end
Obviously this doesn't work like this, but I can't figure a way to implement something like this. That's probably because I don't really understand what the + and - are. I can't do something like -.class.name and I can't do something like this either:
def -
10 __method__ 5
end
Any clarification on this matter is more than welcome, thanks.
Yes. When your are calling a method on a object, your are sending a message to the object. In ruby send using you can send messages(call that method) to that object. For example to 1.+2 would give me three.
Now You could implement your operation method like
def operation(operation,instance_of_a)
a.send(operation,instance_of_a.a)
end
Your + method would be
operation("+",instance_of_a)

How to compactly write a block that executes a method with arguments

In the following code:
def main
someArray.all? { |item| checkSomething(item) }
end
private
def checkSomething(arg)
...
end
How do I shorten the all? statement in order to ged rid of the redundant item variable?
I'm looking for something like someArray.all?(checkSomething) which gives a "wrong number of arguments" error.
You could have a slightly shorter code if checkSomething was a method on your object class. Don't know what it is, so, I'm guessing, you're working with primitives (numbers, strings, etc.). So something like this should work:
class Object
def check_something
# check self
end
end
some_array.all?(&:check_something)
But this is, of course, a horrible, horrible way of going about it. Saving a few keystrokes at the cost of such global pollution - absolutely not worth it. Moreover, even this trick will not be available as soon as you will need to pass additional parameters to the check method.
Besides, the original code is quite readable too.
You could use Object#method and Method#to_proc (i.e. &method) to get rid of the item variable, although it is slower:
def main(array)
array.all?(&method(:check_something))
end
def check_something(arg)
arg.odd?
end
main [1,3,5] #=> true
main [1,3,6] #=> false
If checkSomething is an item method (i.e. defined in the class of the 'i' object) you could do symbol to proc...
def main
someArray.all?(&:checkSomething)
end
A method only has access to passed arguments, or to selfso to bypass passing arguments you need to make the method an instance method of the object class (so it can use self)
The way you have it... where checkSomething is external to the i class... you can't do that.
Considering you want to keep your object's checkSomething private, I think this would be a good work around :
class Something
def main
someArray.all?(&checkSomething)
end
private
def checkSomething
->(item) do
# Checking part.
end
end
end
For block that executes a method with arguments, Checkout this way...
def main
someArray.all? &checkSomething(arg1, arg2, ...)
end
private
def checkSomething(arg1, arg2, ...)
Proc.new { |item| ..... }
end
could you not use a Ruby's collection method 'any?' instead?
def main
#students is an array of students
students.any?(&:passed)
end
class Student
def passed
#code to check if student passed
end
end
Ref http://ruby-doc.org/core-2.2.2/Enumerable.html#method-i-any-3F

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]

Sub-classing Fixnum in ruby

So I understand you aren't supposed to to directly subclass Fixnum, Float or Integer, as they don't have a #new method. Using DelegateClass seems to work though, but is it the best way? Anyone know what the reason behind these classes not having #new is?
I need a class which behaves like a Fixnum, but has some extra methods, and I'd like to be able to refer to its value through self from within the class, for example:
class Foo < Fixnum
def initialize value
super value
end
def increment
self + 1
end
end
Foo.new(5).increment + 4 # => 10
You can pretty easily set up a quick forwarding implementation yourself:
class MyNum
def initialize(number)
#number = number
end
def method_missing(name, *args, &blk)
ret = #number.send(name, *args, &blk)
ret.is_a?(Numeric) ? MyNum.new(ret) : ret
end
end
Then you can add whatever methods you want on MyNum, but you'll need to operate on #number in those methods, rather than being able to call super directly.
IIRC, the main implementation of Ruby stores Fixnums as immediate values, using some of the low bits of the word to tag it as a Fixnum instead of a pointer to an object on the heap. That's why, on a 32-bit machine, Fixnums are only 29-bits (or whatever it is) instead of a full word.
So because of that, you can't add methods to a single "instance" of Fixnum, and you can't subclass it.
If you're dead-set on having a "Fixnum-like" class, you'll probably have to make a class that has a Fixnum instance variable, and forward method calls appropriately.
Could you not extend FixNum itself? Like...
class Fixnum
def even?
self % 2 == 0
end
end
42.even?

Resources