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

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

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.

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 do I make a Ruby method that lasts for the lifetime of a block?

Inside the body of a class, I'd like to pass a block to a method called with. For the lifetime of the block, I would like a with_value method to be available.
Otherwise, everything inside the block should behave as if it were outside the block.
Here's an example:
class C
extend M
with "some value" do
do_something_complicated
do_something_complicated
do_something_complicated
end
end
We can almost get this with:
module M
def with(str, &block)
Object.new.tap do |wrapper|
wrapper.define_singleton_method :with_value do # Here's our with_value
str # method.
end
end.instance_eval &block
end
def do_something_complicated # Push a value onto an
(#foo ||= []).push with_value # array.
end
end
but there's a problem: since we're evaluating the block passed to with inside the context of a different object, do_something_complicated isn't available.
What's the right way to pull this off?
This will make with_value available only within the block. However, _with_value will be defined within or outside of the block.
module M
def _with_value
...
end
def with(str, &block)
alias with_value _with_value
block.call
undef with_value
end
...
end
I cannot tell from the question whether this is a problem. If it is a problem, you need to further describe what you are trying to do.
Basically, the idea is to use method_missing to forward method calls from the dummy class to the calling class. If you also need to access instance variables, you can copy them from the calling class to your dummy class, and then back again after the block returns.
The Ruby gem docile is a very simple implementation of such a system. I suggest you read the source code in that repository (don't worry, it's a very small codebase) for a good example of how DSL methods like the one in your example work.
Here is a way that is closer to your attempt:
module M
def with(str, &block)
dup.tap do |wrapper|
wrapper.define_singleton_method :with_value do
...
end
end.instance_eval &block
end
...
end
dup will duplicate the class from where with is called as a class method.

Copy all methods from one class to another on the fly

I have two classes and I want to copy all of the methods from one class to another. Some methods will have no arguments, some will have arguments, and some will have hashes as arguments. And I never know in advance which ones will. So I created this code, until I figured out that it didn't take into account arguments. Is there any way to get a list of methods from a Class, and then clone them exactly to another class?
def partial(cls)
cls.instance_methods(false).each do |method_name|
define_method(method_name) do
cls.new.method(method_name.to_sym).call
end
end
end
The methods are created on the fly using define_method in the first class, so I can't just use an include. The code above has cls being passed in, then it finds all of the instance methods that are actually written in that Class, not ones it inherits, and then creates a new method with the same name. When that method is called, it actually calls the other Class with its method of the same name. This works wonderfully, unless I have args. I had condition check to see if it had arguments, and then had it call a method with arguments, but it did not handle hashes very well. It made the hash as an array for an argument, which is not what I wanted.
I was wondering if there was a simple way to literally say "Hey you know this method, whatever it is, literally make the same thing for this other Class."
you could also try DelegateClass:
class NamedArray < DelegateClass(Array)
def initialize n
#name = n
super(Array.new)
end
def sayName
"My name is #{#name}"
end
end
You could try SimpleDelegator: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/delegate/rdoc/SimpleDelegator.html
If all the methods are identical, why not just define them in a common module which you include in both classes? You mention not using include because the methods are dynamically defined, but that doesn't mean they won't be found when you mixin the module:
module Foo
def self.make_an_example_method(name)
define_method(name) do |*args|
puts "I am #{name} called with (#{args.inspect})"
end
end
end
class A
include Foo
end
class B
include Foo
end
Foo.make_an_example_method(:example)
Foo.make_an_example_method(:dynamic)
A.new.example # => I am example called with ([])
B.new.dynamic(1,2,3) # => I am dynamic called with ([1, 2, 3])

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