Combinatory method like tap, but able to return a different value?
Define Object#as
:
class Object
def as
yield self
end
end
And now you can write:
def not_sure_this_is_nice_enough_method1
something_complex(a, b, c).as do |obj|
a_predicate_check? ? obj.one_more_method_call : obj
end
end
Ruby: reuse value in a block without assigning it to variable (write object method on the fly)
The method simply yields self
to the block, returning the block's result. I don't think it exists, but you can implement it yourself:
class Object
def decompose
yield self
end
end
[3, 4, 7, 8].decompose{ |array| array[2] + array[3] }
#=> 15
{:key1 => 'value', :key2 => true}.decompose{ |hash| hash[:key1] if hash[:key2] }
#=> "value"
[3, 4, 7, 8].decompose{ |array| [array.min, array.max] }
#=> [3, 8]
Difference between Kernel#yield_self, yield(self), Kernel#then and Object#tap in Ruby?
The difference between tap
and yield_self
is in what is returned by each of the two methods.
Object#tap
yields self to the block and then returns self. Kernel#yield_self
yields self to the block and then returns the result of the block.
Here are some examples of where each can be useful:
tap
Replacing the need for a result
line at the end of a method:
def my_method
result = get_some_result
call_some_method_with result
result
end
can be written as:
def my_method
get_some_result.tap do |result|
call_some_method_with result
end
end
Another example is initialisation of some object that takes several steps:
some_object = SomeClass.new.tap do |obj|
obj.field1 = some_value
obj.field2 = other_value
end
yield_self and yield(self)
If used inside one of your own methods yield_self
would have the same effect as yield(self)
. However, by having it as a method in its own right this promotes method chaining as an alternative to nested function calls.
This blog post by Michał Łomnicki has some helpful examples. e.g. this code:
CSV.parse(File.read(File.expand_path("data.csv"), __dir__))
.map { |row| row[1].to_i }
.sum
can be rewritten as:
"data.csv"
.yield_self { |name| File.expand_path(name, __dir__) }
.yield_self { |path| File.read(path) }
.yield_self { |body| CSV.parse(body) }
.map { |row| row[1].to_i }
.sum
This can aid with clarity where nested calls are being used for a series of transformations on some data. Similar features exist in other programming languages. The pipe operator in Elixir is a good one to take a look at.
then
#yield_self
might feel a bit technical and wordy. That's why Ruby 2.6 introduced an alias for #yield_self
, #then
.
"something"
.then {|str| str.chars.map {|x| x.ord + 1 }}
.then {|ords| ords.map {|x| x.chr }}
.then {|chars| chars.join }
.then {|str| str + "!" }
.then {|str| str + "!" }
# tpnfuijoh!!
Cleave a run-time computed value?
cleave
is likely not the right answer here. When Factor says cannot apply SOMETHING to a run-time computed value most often it means something can be written better. I think here you want to replace cleave
with histogram:
IN: scratchpad 100 [ { "abundant" "deficient" "perfect" } random ] replicate
histogram
--- Data stack:
H{ { "deficient" 33 } { "perfect" 30 } { "abundant" 37 } }
Is having a return type of Task enough to make a method run asynchronously?
Based on your comments you need to do something like this:
public Task<string> ComplexOperation()
{
return Task.Run(() => /* Do something complex */);
}
You can play with it like this:
public static async Task Main()
{
Console.WriteLine("Before" );
var myResultTask = ComplexOperation();
Console.WriteLine("After task creation");
var result = await myResultTask;
Console.WriteLine("After async await");
}
public Task<string> ComplexOperation()
{
Console.WriteLine("Creation");
return Task.Run(() =>
{
Console.WriteLine("In before work");
Thread.Sleep(500); //simulate work;
Console.WriteLine("In after work");
return "Done";
});
}
And compare the behavior with switching to your implementation when you just return Task.FromResult
. Also it does not makes much sense in such test example, TBH.
How to tap an observable for only the first emitted value
You could do this with combination of tap()
and map()
because map()
passes also index parameter for each next
:
this.http.post()
.pipe(
map((response, index) => [response, index]),
tap(([response, index]) => {
if (index === 0) { ... }
}),
)
.subscribe(([response] => { ... })
You could of course put everything into map((response, index => {...})
and then just return the same response
object but it's better to avoid making side-effects in map()
.
Equivalent of `std::iter::inspect` for method chains
You can define a trait for this almost exactly like that:
trait Inspect {
fn inspect(self, f: impl Fn(&Self)) -> Self;
}
impl<T> Inspect for T {
fn inspect(self, f: impl Fn(&Self)) -> Self {
f(&self);
self
}
}
I modified it a bit to pass self
by value to make it more flexible. It will work with &T
/&mut T
and return &T
/&mut T
.
Test:
#[derive(Debug)]
struct Foo {}
impl Foo {
fn a(&self) -> &Self {
self
}
fn b(&self) -> &Self {
self
}
fn c(&self) -> &Self {
self
}
}
fn main() {
Foo {}
.a()
.inspect(|x| println!("after a(): {:?}", x))
.b()
.inspect(|x| println!("after b(): {:?}", x))
.c();
}
Output:
after a(): Foo
after b(): Foo
Playground
Test for mutable value:
#[derive(Debug, Default)]
struct Foo {
value: i32,
}
impl Foo {
fn a(&mut self) -> &mut Self {
self.value += 1;
self
}
fn b(&mut self) -> &mut Self {
self.value += 2;
self
}
}
fn main() {
Foo::default()
.a()
.inspect(|x| println!("after a(): {:?}", x))
.b()
.inspect(|x| println!("after b(): {:?}", x));
}
Output:
after a(): Foo { value: 1 }
after b(): Foo { value: 3 }
Playground
Building a Rails scope using `tap`
tap
will not work for this.
all
is anActiveRecord::Relation
, a query waiting to happen.all.where(...)
returns a newActiveRecord::Relation
the new query.However checking the documentation for tap, you see that it returns the object that it was called on (in this case
all
) as opposed to the return value of the block.i.e. it is defined like this:
def tap
yield self # return from block **discarded**
self
endWhen what you wanted was just:
def apply
yield self # return from block **returned**
endOr something similar to that.
This is why you keep getting all the objects returned, as opposed to the objects resulting from the query. My suggestion is that you build up the hash you send to where
as opposed to chaining where
calls. Like so:
query = {}
query[:first_name] = options[:query] if options[:query]
query[:graduated] = options[:graduated] if options[:graduated]
# ... etc.
all.where(query)
Or a possibly nicer implementation:
all.where({
first_name: options[:query],
graduated: options[:graduated],
}.delete_if { |_, v| v.empty? })
(If intermediate variables are not to your taste.)
Related Topics
Rails Email Error - 530-5.5.1 Authentication Required
How to Run Ruby on Rails with Ruby 1.9X
How to Reference a File from Inside of a Gem
How to Debug Http of Ruby Google-Api-Client
How to Use Ruby for Shell Scripting
Rmagick Installation: Can't Find Magickwand.H
Checking If a Variable Is Not Nil and Not Zero in Ruby
Ruby Array to String Conversion
Unknown Ruby Interpreter Version (Do Not Know How to Handle): Ruby_Version
M Hartl's Ruby on Rails Tutorial Chapter 5 Custom Title on Home Page
Why 6.84 - 3.6 == 3.2399999999999998
Actioncontroller::Routingerror (No Route Matches [Put] ) for Ajax Call
Optimization for Finding Perfect-Square Algorithm