Ruby method chaining - `tap` with replacement [duplicate] - ruby

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is there a `pipe` equivalent in ruby?
I'm looking at the tap method in Ruby - but unfortunately the object returned from the passed block is not passed on. What method do I use to have the object passed on?
Here's what I'm trying to (unsuccessfully) do:
obj.tap{ |o| first_transform(o) }.tap{ |o| second_transform(o)}
This is, of course, equivalent to second_transform(first_transform(o)). I'm just asking how to do it the first way.
Doing this is trivial with lists:
list.map{ |item| first_transform(item) }.map{ |item| second_transform(item)}
Why isn't it as easy with objects?

class Object
def as
yield self
end
end
With this, you can do [1,2,3].as{|l| l << 4}.as{|l| l << 5}

You could also consider to make #first_transform and #second_transform instance methods of the item's class (and return the transformed item of course).
These methods definitions should look like this:
class ItemClass
# If you want your method to modify the object you should
# add a bang at the end of the method name: first_transform!
def first_transform
# ... Manipulate the item (self) then return it
transformed_item
end
end
This way you could simply chain the methods calls this way:
list.map {|item| item.first_transform.second_transform }
It even reads better in my humble opinion ;)

The simple answer is tap doesn't do what you think it does.
tap is called on an object and will always return that same object.
As a simple example of taps use
"foo".tap do |foo|
bar(foo)
end
This still returns "foo"
In your example you have an object, and you want to apply two functions to it in succession.
second_transform(first_transform(obj))
UPDATED:
So I guess I'd ask why you want to chain in this way.
obj.do{|o| first_transform(o)}.do{|o| second_transform(o)}
Is that really more clear than
second_transform(first_transform(obj))
Lets take an example I often use
markdown(truncate(#post.content))
or
truncated_post = truncate(#post.content)
markdown(truncated_post)
I guess it depends on the nature of your transform

Related

Loop method until it returns falsey

I was trying to make my bubble sort shorter and I came up with this
class Array
def bubble_sort!(&block)
block = Proc.new { |a, b| a <=> b } unless block_given?
sorted = each_index.each_cons(2).none? do |i, next_i|
if block.call(self[i], self[next_i]) == 1
self[i], self[next_i] = self[next_i], self[i]
end
end until sorted
self
end
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
end
I don't particularly like the thing with sorted = --sort code-- until sorted.
I just want to run the each_index.each_cons(s).none? code until it returns true. It's a weird situation that I use until, but the condition is a code I want to run. Any way, my try seems awkward, and ruby usually has a nice concise way of putting things. Is there a better way to do this?
This is just my opinion
have you ever read the ruby source code of each and map to understand what they do?
No, because they have a clear task expressed from the method name and if you test them, they will take an object, some parameters and then return a value to you.
For example if I want to test the String method split()
s = "a new string"
s.split("new")
=> ["a ", " string"]
Do you know if .split() takes a block?
It is one of the core ruby methods, but to call it I don't pass a block 90% of the times, I can understand what it does from the name .split() and from the return value
Focus on the objects you are using, the task the methods should accomplish and their return values.
I read your code and I can not refactor it, I hardly can understand what the code does.
I decided to write down some points, with possibility to follow up:
1) do not use the proc for now, first get the Object Oriented code clean.
2) split bubble_sort! into several methods, each one with a clear task
def ordered_inverted! (bubble_sort!), def invert_values, maybe perform a invert_values until sorted, check if existing methods already perform this sorting functionality
3) write specs for those methods, tdd will push you to keep methods simple and easy to test
4) If those methods do not belong to the Array class, include them in the appropriate class, sometimes overly complicated methods are just performing simple String operations.
5) Reading books about refactoring may actually help more then trying to force the usage of proc and functional programming when not necessary.
After looking into it further I'm fairly sure the best solution is
loop do
break if condition
end
Either that or the way I have it in the question, but I think the loop do version is clearer.
Edit:
Ha, a couple weeks later after I settled for the loop do solution, I stumbled into a better one. You can just use a while or until loop with an empty block like this:
while condition; end
until condition; end
So the bubble sort example in the question can be written like this
class Array
def bubble_sort!(&block)
block = Proc.new { |a, b| a <=> b } unless block_given?
until (each_index.each_cons(2).none? do |i, next_i|
if block.call(self[i], self[next_i]) == 1
self[i], self[next_i] = self[next_i], self[i]
end
end); end
self
end
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
end

What about implicit yield in Ruby? [duplicate]

This question already has answers here:
Can you supply arguments to the map(&:method) syntax in Ruby?
(9 answers)
Closed 8 years ago.
I often write:
some_array.each { |array_element| array_element.some_method(args) }
Why not have an option for an implicit yield so you could write e.g.:
some_array.each { _.some_method(args) }
I am not sure what character _ should actually be, and I imagine it would only be used in the most boilerplate setting, where you're dealing with a one-dimensional array and just trying to yield each item to the block in succession. It would save a lot of redundant typing.
Are you familiar with #to_proc and the & syntax for method calls? They cover some cases similar to the one you show here. For example:
[1, -2, -4].map(&:abs) => [1, 2, 4]
The & is used to pass an object in place of a block. If the object isn't a Proc, #to_proc is automatically called on it to get a Proc before it is used in place of the block. Symbol#to_proc returns a Proc which behaves like: { |obj, *args| obj.symbol_name(*args) }.
In your example, you use args which are presumably captured from the surrounding lexical environment. Symbol#to_proc won't help you there. But it wouldn't be hard to make a new Proc-building method which would. For example:
class Symbol
def with_args(*args)
Proc.new { |x| x.send(self, *args) }
end
end
Then you could do:
some_array.each(&:some_method.with_args(args))
Whether that is any better than an explicit block is up to you. In any case, this is a technique you should be aware of.

Detect if something is Enumerable in Ruby

I have a method that accepts either a single object or a collection of objects. What is the proper way of detecting if what's passed in is Enumerable? I'm currently doing the following (which works but I'm not sure it's the correct way):
def foo(bar)
if bar.respond_to? :map
# loop over it
else
# single object
end
end
I would use is_a?.
bar.is_a? Enumerable
But there’s a better way to take a single object or a collection, assuming that the caller knows which one they’re passing in. Use a splat:
def foo(*args)
args.each do |arg|
…
end
end
Then you can call it as foo(single_arg), foo(arg1, arg2), and foo(*argv).
I depends on your exact needs, but it's usually not a great idea to differentiate between a single object and an Enumerable. In particular, a Hash is an Enumerable, but in most cases it should be considered as a single object.
It's usually better to distinguish between a single object and an array-like argument. That's what Ruby often does. The best way to do this is to check if arg.respond_to? :to_ary. If it does, then all methods of Array should be available to you, if not treat it as a single object.
If you really want to check for Enumerable, you could test arg.is_a? Enumerable but consider that a Hash is an Enumerable and so are Lazy enumerators (and calling map on them won't even give you an array!)
If your purpose is to loop over it, then the standard way is to ensure it is an array. You can do it like this without condition.
def foo(bar)
[*bar] # Loop over it. It is ensured to be an array.
end
What about handling single items or a collection in one shot?
[*bar].each { |item| puts item }
This will work whether bar is a single item or an array or hash or whatever. This probably isn't the best for working with hashes, but with arrays it works pretty well.
Another way to ensure that something is an Array is with the Array "function (technically still a method):
def foo(bar)
Array(bar).map { |o| … }
end
Array will leave an array an array, and convert single elements to an array:
Array(["foo"]) # => ["foo"]
Array("foo") # => ["foo"]
Array(nil) # => []

Omitting an argument for a method in a block

I wonder, is it possible to do something similar in Ruby to what I can do in Scala or other languages:
someCollection.foreach(x => println(x)) // a full version
someCollection.foreach(println) // a short version
In Ruby I can do:
some_array.each { |x| puts x }
So how can I do this?
some_array.each { puts }
UPDATE:
I'm not talking about puts in particular, it just picked it for example. There might be some_other_method which takes one parameter.
some_array.map { some_other_method }
some_array.map(some_other_method) # ???
def some_other_method a
# ... doing something with a
end
If you look up the rules for implicit η-expansion in the SLS (§6.26.5), it should be immediately obvious that it relies crucially on static type information and thus cannot possibly work in Ruby.
You can, however, explicitly obtain a Method object via reflection. Method objects respond to to_proc and like any object that responds to to_proc can thus be passed as if they were blocks using the unary prefix & operator:
some_array.each(&method(:puts))
Not quite like that, unfortunately. You can send a method name to be called on each object, e.g.:
some_array.each &:print_myself
Which is equivalent to:
some_array.each {|x| x.print_myself}
But I don't know of a clean (read: built-in) way to do what you're asking for. (Edit: #Jörg's answer does this, though it doesn't really save you any typing. There is no automatic partial function application in Ruby)

Is there a method in Ruby Object to pass itself to a block or proc?

I think it would be natural to have in Ruby something like:
class Object
def yield_self
yield(self)
end
end
Does there exist a method like this by any chance? (I haven't found.) Does anybody else think it would be nice to have it?
yield_self has been added to ruby core a month ago as of June 2017. https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/58528
It's in ruby 2.5.0 after revision number 58528, although I'm not exactly sure how to get that code yet. Perhaps if someone knows how they can edit this answer
I don't understand why you want the complexity of:
Object.new.yield_self do |foo|
...
end
When the following is almost exactly equivalent:
foo = Object.new
...
There is indeed the tap method that does almost exactly what you're asking:
x = [].tap do |array|
array << 'foo'
array << 9
end
p x
#=> ["foo", 9]
As Rob Davis points out, there's a subtle but important difference between tap and your method. The return value of tap is the receiver (i.e., the anonymous array in my example), while the return value of your method is the return value of the block.
You can see this in the source for the tap method:
VALUE
rb_obj_tap(VALUE obj)
{
rb_yield(obj);
return obj;
}
We're returning the obj that was passed into the function rather than the return value of rb_yield(obj). If this distinction is crucial, then tap is not what you need. Otherwise, it seems like a good fit.

Resources