How to pass a block as the parameter of an if statement? - ruby

I'm currently ripping my hairs off to find a solution. I need to parse some Json but the json gem don't allow me to parse more than 2 levels deep, so I have to do a lot of each block. And to eliminate some datas that I don't want I need to do an if/else.
So here is what I'd like to do:
result['person']['participation'].each do |participation|
if participation['movie']['release'] { |release| release['releaseState']['code'] == 3011 || release['releaseState']['code'] == nil }
next
else
puts title = participation['movie']['originalTitle']
end
end
I tried with 'unless' too, but I fear that I can't pass block in statement. If not, do you have a way to do what I need ?
Many thanks !
Here is the JSON http://api.allocine.fr/rest/v3/filmography?partner=YW5kcm9pZC12M3M&profile=medium&code=5568&filter=movie&format=json

I need to see your document structure... but if participation['movie']['release'] is an Array, you can use Array#any?
result['person']['participation'].each do |participation|
if participation['movie']['release'].any? { |release| release['releaseState']['code'] == 3011 || release['releaseState']['code'] == nil }
next
else
puts title = participation['movie']['originalTitle']
end
end
If it's not an Array, please post a document example.

Related

Shopify Shipping Script Discount on Customer Tag

I have a Shopify Plus account in which I am attempting to add a new condition to my Shipping Script that controls what shipping methods are displayed to customers. Specifically, I want to give customers with a specific tag access to free shipping. To control that
def freeItUp
index = -1
if Input.cart.customer != nil and Input.cart.customer.tags != nil
Input.cart.customer.tags.index do |tag|
return tag.upcase == "ALWAYSFREE"
end
end
return index > -1
end
shippingMethodToDelete = (condition1 or condition2 or freeItUp) ? "UPS" : "FREE"
Output.shipping_rates = Input.shipping_rates.delete_if do |shipping_rate|
puts shipping_rate.name
shipping_rate.name.upcase.start_with?(shippingMethodToDelete)
end
However, I keep getting the following error
fiber required for enumerator (Your Cart)
fiber required for enumerator (Empty Cart)
I'm not terribly familiar with Ruby, but I'm using the same code block (above) in Line Item scripts with no issues. According to the documentation I believe I'm not trying to access properties that don't exist. Any thoughts/help would be greatly appreciated.
Can you try:
def always_free_tag?
return false if Input.cart.customer.nil? || Input.cart.customer.tags.empty?
Input.cart.customer.tags.any? do |tag|
tag.upcase == "ALWAYSFREE"
end
end
shippingMethodToDelete = (condition1 or condition2 or always_free_tag?) ? "UPS" : "FREE"
Output.shipping_rates = Input.shipping_rates.delete_if do |shipping_rate|
puts shipping_rate.name
shipping_rate.name.upcase.start_with?(shippingMethodToDelete)
end
Also, can you share more of the stack trace and what line it points to?
Edit: Great! Glad that worked. I think your issue is you were using Array#index which yields an index (integer) to the block (this line: Input.cart.customer.tags.index). You're then calling #upcase on Numeric which isn't a method. If you instead did this it would work as expected:
Input.cart.customer.tags.index do |i|
return true if Input.cart.customer.tags[i].upcase == "ALWAYSFREE"
end
The other issue is that in ruby only nil and false are falsy in ruby, so your condition in shippingMethodToDelete likely wasn't returning the correct value. Instead, I changed it so it always returns a boolean that way we can be sure ALWAYSFREE is searched for and evaluated correctly. I think you were really close but take a look at Enumerable#any for more examples.

Using code block in ruby's if statement

is there a way to pass a code block as a ruby if condition?
I have a list of regular expressions and I want to check if a message matches any of them and then do something accordingly or else do something different.
Here is an example snippet for how I think it should be written:
msg_values.each do |msg|
if (SKIP_MSG_ARRAY.each { |regular_exp| return true if msg.match(regular_exp)})
# do something
else
# do something else
end
end
is it possible? or else what is the best way of writing something like this?
Use Enumerable#any?. See the reference docs: http://ruby-doc.org/core-2.0/Enumerable.html. This method (as well as Enumerable#all?) will return true or false.
Example:
msg_values.each do |msg|
if (SKIP_MSG_ARRAY.any? { |regular_exp| msg.match(regular_exp)})
# do something
else
# do something else
end
end

trouble with this case statement Ruby

Can someone help me understand how to write this case statement properly its not working and as a NOOB I have no idea how to fix it:
def hide_link?(link, mailing)
case link
when 'edit' && ['sent', 'sending', 'archived'].include?(mailing.status)
return true
when 'send_schedule' && ['sent', 'sending', 'archived'].include?(mailing.status)
return true
when 'archive' && ['archived'].include?(mailing.status)
puts "I should be in here"
return true
else 'dashboard' && ['sending', 'draft'].include?(mailing.status)
return true
end
end
Basically I want to return true when the link matches certain criteria.
I believe that if link doesn't match these criterias the method should return false. Thus:
def hide_link?(link, mailing)
case link
when 'edit'
['sent', 'sending', 'archived'].include?(mailing.status)
when 'send_schedule'
['sent', 'sending', 'archived'].include?(mailing.status)
when 'archive'
puts "I should be in here"
['archived'].include?(mailing.status)
when 'dashboard'
['sending', 'draft'].include?(mailing.status)
else
false
end
end
The construction [...].include?(mailing.status) has result true or false which will be returned as a result of hide_link? method.
Remove return.
link = "fred"
case link
when "fred"
true
else
false
end
case will return the value itself which will then be passed to the method.
Refactor of megas's version:
def hide_link?(link, mailing)
statuses_to_hide = case link
when 'edit', 'send_schedule'
%w{sent sending archived}
when 'archive'
%w{archived}
when 'dashboard'
%w{sending draft}
else
[]
end
statuses_to_hide.include?(mailing.status)
end
The conditions in the case statement all follow the same form, which suggest that there is an opportunity to eliminate some repetition, and to separate policy from implementation. The policy is the set of conditions under which the link should be hidden:
WHEN_TO_HIDE_LINK = [
['edit', %w(sent sending archived)],
['send_schedule', %w(sent sending archived)],
['archive', %w(archived)],
['dashboard', %w(sending draft)],
]
The implementation is the code that applies the policy:
def hide_link?(link, mailing)
WHEN_TO_HIDE_LINK.any? do |link_value, mailing_statuses|
link_value == link && mailing_statuses.include?(mailing.status)
end
end
Explanations below the fold.
%w
%w is a way to specify a list of strings without typing all those quotes and commas. This:
%w(sent sending archived)
is equivalent to this:
['sent', 'sending', 'archived']
any?
Enumerable#any? passes each element of the array to the block (the bit between the do and the end). If the block ever returns truthy, then the result of any? is true; otherwise, the value of any? is false.
array decomposition
Did you notice that although each element of WHEN_TO_HIDE_LINK is an array, the block passed to any? does not take an array? You might expect that you'd have to do this:
WHEN_TO_HIDE_LINK.any? do |when_to_hide|
link_value = when_to_hide[0]
mailing_statuses = when_to_hide[1]
...
but Ruby will decompose array into parts for you. Here's one way to do it:
WHEN_TO_HIDE_LINK.any? do |when_to_hide|
link_value, mailing_statuses = when_to_hide
...
When there is an array on the right side of the = and comma-separated variables on the left, Ruby decomposes the array into its elements and assigns them to the variables separately.
But Ruby can make things even easier:
WHEN_TO_HIDE_LINK.any? do |link_value, mailing_statuses|
...
This is equivalent to either of the preceding two fragments.

Ruby Newbie: Confused About Boolean Logic

I have an array, if I find a value in it, I want to execute a block of code. Also, if the array is nil, I want to execute that block. So the code I tried is:
if !array.respond_to? :index || array.index(str)
#some code
So if it's nil it's true, or if str is somewhere in the array, it's true, right? But if it finds the item at index 0, it doesn't enter the block. Also, according to irb false || 0 evalueates to 0. WTF?? I thought that everything was true except false and nil. I guess || does something odd that I'm not expecting??
My questions are: What's going on? What's a nice way to write a conditional that does what I want?
Using nil? and include? with an inline if seems most idiomatic to me.
#your code if arr.nil? || arr.include?(str)
if array.nil? || array.member?(s)
# ...
false || 0 evaluates to 0 because it's an or. False isn't truthy (obviously ;) but 0 is, so the expression is truthy.
Are you checking for a nil array or an empty one? If you've already declared the array it won't be nil even if it's empty. I'd write it like:
if array.empty? || array.include(str)
or if you really want to check for a nil array:
if array.nil? || array.include(str)
I'd use .include rather than .index to avoid getting a 0.
if array.nil?­ || array­.member?(str­)
#code block
end
The || operator almost reminds you of a coalesce.
Given a = false, b = :bacon
return a || b #returns :bacon

Ruby: map tags into a boolean condition to get a true/false result

I have an array of tags per item like so:
item1 = ['new', 'expensive']
item2 = ['expensive', 'lame']
I also have a boolean expression as a string based on possible tags:
buy_it = "(new || expensive) && !lame"
How can I determine if an item matches the buying criteria based on the tags associated with it? My original thought was to do a gsub on all words in buy_it to become 'true' or 'false' based on them existing in the itemx tags array and then exec the resulting string to get a boolean result.
But since the Ruby community is usually more creative than me, is there a better solution?
EDIT:
Just to clarify, buy_it in my example is dynamic, users can change the criteria for buying something at run-time.
Along the lines of your gsub idea, instead of substituting each word for true/false every time, why not substitute each "query" into an expression that can be re-used, e.g. the example buy_it:
buy_it = "(new || expensive) && !lame"
buy_it_expr = buy_it.gsub(/(\w+)/, 'tags.include?("\1")')
puts buy_it_expr
=> (tags.include?("new") || tags.include?("expensive")) && !tags.include?("lame")
It could be evaluated into a Proc and used like this:
buy_it_proc = eval "Proc.new { |tags| #{buy_it_expr} }"
buy_it_proc.call(item1)
=> true
buy_it_proc.call(item2)
=> false
Of course, care must be taken that the expression does not contain malicious code. (One solution might be to strip all but the allowed operator characters from the string and of course be wary of exceptions during eval.)
A hash is a good candidate here.
items = {'ipad' => ['new', 'expensive'], 'kindle' => ['expensive', 'lame']}
items.each do |name,tags|
if tags.include?('new' || 'expensive') && !tags.include?('lame')
puts "buy #{name}."
else
puts "#{name} isn't worth it."
end
end

Resources