how to break chain with yield_self - ruby

Is it possible to break yield_self (then) chain in ruby?
"a".then { |str| <break> if break_condition }.then { |str| str << "b" } # => I need "a"

You could move the whole code into another method and "break" the chain with a simple return:
def foo
"a".then { |str| return str if break_condition ; str }
.then { |str| str << "b" }
end
You could utilize catch and throw:
catch do |brk|
"a".then { |str| throw(brk, str) if break_condition ; str }
.then { |str| str << "b" }
end
Alternatively, you could not use then in the first place:
str = "a"
str << "b" unless break_condition

I don't think that you can "break" the chain without raising an exception but you can pass a tagged value from the first block to the second one:
"a".
then { |str| [str, !break_condition] }.
then { |str,do_it| do_it ? str << "b" : str }
edit: An other form that might be easier to work with:
"a".
then { |str| break [str,true] if break_condition; str }.
then { |str,broken| break str if broken; str << "b" }

You can refactor your chain with using just one then like this
result =
"a".then do |str|
next str if break_condition
str << "b"
end
or
result =
"a".then do |str|
break str if break_condition
str << "b"
end

This might be silly, but since you can't break or return, I guess raise should do it:
def broken break_condition
begin
"a"
.then { |str| break_condition ? raise(str) : str }
.then { |str| str << "b" }
rescue RuntimeError => e
str = e.message
end
end
>> broken true
=> "a"
>> broken false
=> "ab"
One liner works too:
>> "a".then { |str| true ? raise(str) : str }.then { |str| str << "b" } rescue $!.message
=> "a"
>> "a".then { |str| false ? raise(str) : str }.then { |str| str << "b" } rescue $!.message
=> "ab"
Best silly solution I could come up with:
>> "a".then{#a=_1}.then { |s| s if false }&.then { |s| s << "b" }||#a
=> "a"
>> "a".then{#a=_1}.then { |s| s if true }&.then { |s| s << "b" }||#a
=> "ab"

Related

Manipulating symbols in ruby

I am trying to take an array of symbols,
a = [:apple, :banana ,:grape, :black]
and add a string at the end of each symbol depending on the last letter. If the symbol ends with e, add "hello", otherwise "hi". I want to get:
[:applehello, :bananahi]
I did:
n = []
a.each do |b|
if (b[-1] == "e")
n.push b.to_s + "hello"
else
n.push b.to_s + "hi"
end
end
p n
I have to convert it into strings. How can I get the final output in symbols?
Did it using sub aswell-
a.each do |q|
if (q[-1]=="e")
then n.push q.to_s.sub(/e/,"ehello")
else
n.push q.to_s.sub(/\z/,"ahi")
end
end
p n
Use to_sym to have a symbol back
a = [:apple, :banana , :grape, :black]
a.map do |s|
(s.to_s + (s[-1] == 'e' ? 'hello' : 'hi')).to_sym
end
An alternative
a = [:apple, :banana , :grape, :black]
a.map do |s|
"#{s}#{s[-1] == 'e' ? 'hello' : 'hi'}".to_sym
end
Tried with following,
a.map { |x| "#{x}#{x.to_s.last == 'e' ? 'hello' : 'hi'}".to_sym }
# => [:applehello, :bananahi, :grapehello, :blackhi]
a.map{|sym| sym.to_s.sub(/.\z/) do
|c| case c; when "e" then "hello"; else "hi" end.to_sym
end}
# => [:applhello, :bananhi, :graphello, :blachi]

Why this (dead simple) ruby regex behaves like this?

Why "whatever".gsub(/.*/, "bien") outputs "bienbien" instead of just "bien"?
I'm completely lost here :S Anyone could point me in the right direction?
You can see what's happening using a block:
>> 'foo'.sub(/.*/) { |m| p m; 'bar' }
"foo"
=> "bar"
>> 'foo'.gsub(/.*/) { |m| p m; 'bar' }
"foo"
""
=> "barbar"
>> 'foo'.gsub(/^.*/) { |m| p m; 'bar' }
"foo"
=> "bar"
>> 'foo'.gsub(/^.*$/) { |m| p m; 'bar' }
"foo"
=> "bar"
>> 'foo'.gsub(/.*$/) { |m| p m; 'bar' }
"foo"
""
=> "barbar"
>> 'foo'.gsub(/.+/) { |m| p m; 'bar' }
"foo"
=> "bar"
Put another way, gsub will continue matching, and matches an empty string at the very end a line. (And that is arguably a bug.)

Difference between 2 different nested hash in Ruby 1.8.7

Consider the Following nested Hash:
data1 = {
"3"=>{"passenger_type"=>"ADT", "the_order"=>"3", "last"=>"JONES", "first"=>"ALENA", "middle"=>nil},
"2"=>{"passenger_type"=>"ADT", "the_order"=>"2", "last"=>"JONES", "first"=>"MAXIM", "middle"=>nil},
"1"=>{"passenger_type"=>"ADTT", "the_order"=>"1", "last"=>"JONES", "first"=>"TODD", "middle"=>nil}}
data2 = {
"3"=>{"first"=>"ALENA", "the_order"=>"3", "middle"=>"", "passenger_type"=>"ADTT", "last"=>"JONES"},
"2"=>{"first"=>"MAXIM", "the_order"=>"2", "middle"=>"", "passenger_type"=>"ADT", "last"=>"JONES"},
"1"=>{"first"=>"TODD", "the_order"=>"1", "middle"=>"", "passenger_type"=>"ADT", "last"=>"JONESS"}}
The Output Should be like this(difference between both hash listed values):
{"3" => {"passenger_type" => ["ADT", "ADTT"]},
"1" => {"passenger_type" => ["ADTT", "ADT"], "last" => ["JONES", "JONESS"]}
Anyone your suggestion is appreciated, thanks in advance.
You can use the form of Hash#merge that takes a block to produce the desired result in a compact manner:
data1.merge(data2) { |_,ho,hn|
ho.merge(hn) { |_,o,n| (o==n||o==''||n=='') ? nil : [o,n] }
.delete_if { |_,v| v==nil } }
.delete_if { |_,v| v.empty? }
#=> {"3"=>{"passenger_type"=>["ADT", "ADTT"]},
# "1"=>{"passenger_type"=>["ADTT", "ADT"], "last"=>["JONES", "JONESS"]}}
Here's some ugly code:
data3 = {}
data1.each do |k, v|
v2 = data2[k]
v.each do |item, val|
if v2.has_key?(item) then
if (val == nil or val == '') and (v2[item] == nil or v2[item] == '') then
next
end
if val != v2[item] then
data3[k] ||= {}
data3[k][item] = [val, v2[item]]
end
end
end
end
puts data3
prints
{"3"=>{"passenger_type"=>["ADT", "ADTT"]}, "1"=>{"passenger_type"=>["ADTT", "ADT"], "last"=>["JONES", "JONESS"]}}

Scanning an array of strings for match in Ruby

I have an array:
a = ["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
and then I want to return true if one of the elements in that array matches the string:
s = "example.com"
I tried with include? and any?.
a.include? s
a.any?{|w| s=~ /#{w}/}
I don't know how to use it here. Any suggestions?
You can use any? like:
[
"http://design.example.com",
"http://www.domcx.com",
"http://subr.com"
].any?{ |s| s['example.com'] }
Substituting your variable names:
a = [
"http://design.example.com",
"http://www.domcx.com",
"http://subr.com"
]
s = "example.com"
a.any?{ |i| i[s] }
You can do it several other ways also, but the advantage using any? is it will stop as soon as you get one hit, so it can be much faster if that hit occurs early in the list.
How is the below:
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "sus"
p a.any? { |w| w.include? s } #=> false
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "design.example"
p a.any? { |w| w.include? s } #=>true
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "desingn.example"
p a.any? { |w| w.include? s } #=>false
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "example"
p a.any? { |w| w.include? s } #=>true
a=["http://design.example.com", "http://www.domcx.com", "http://subr.com"]
s= "example.com"
p a.any? { |w| w.include? s } #=>true

comparing multiple strings character by character and outputting the overlap?

ruby
i have the following
p = 0
[s1.size,s2.size].max.times { |c| if s1[c] == s2[c]; p = c; else break; end };
matched_part = s1[0..p]
but i dont know how i can this for multiple strings (more than 2) at the same time.
Alright, how's this?
class String
def self.overlap(s1,s2,*strings)
strings += [s2]
strings.min { |s| s.size }.size.times do |n|
return s1[0,n] unless strings.all? { |string| s1[n]==string[n] }
end
s1
end
end
class String
def self.overlap(first,second,*others)
s1 = first
others = [second] + others
others.each do |s2|
p = 0
s1.length.times { |c| if s1[c] == s2[c] then p = c else break end }
s1 = s1[0..p]
end
s1
end
end
puts String.overlap "marry had a little lamb", "marry had a bug dog", "marry had a cat", "marry had a bird OUT:", "marry had something" #=> marry had
In one line:
strings[0].slice(0,(0...strings[0].size).find {|i| strings.map {|s| s[i..i]}.uniq.size > 1})

Resources