ruby - using include method in a case statement - ruby-on-rails

I'm using something like this:
case referer
when (referer.include? "some_string")
redirect_link = edit_product_path
when (referer.include? "some_other_string")
redirect_link = other_product_path
end
Unfortunately, this returns nil even if the string some_string is present in the variable referer.
Here's what i tried in Ruby Console:
ruby-1.8.7-p334 :006 > jasdeep = "RAILS"
ruby-1.8.7-p334 :026 > case jasdeep
ruby-1.8.7-p334 :027?> when (jasdeep.include? "AI")
ruby-1.8.7-p334 :028?> puts "Hello"
ruby-1.8.7-p334 :029?> end
=> nil
Any inputs will be appreciated.

Try this
jasdeep = "RAILS"
case jasdeep
when /IL/
puts "Hello"
end

jasdeep = "RAILS"
case
when jasdeep.include?("AI")
puts "Hello"
end

That nil is the returned value from the puts statement, not from .include?. Try to run the following two statements separately from the console and observe the returned value:
jasdeep.include? "AI"
puts "hello"

case true
when referer.include? "some_string"
redirect_link = edit_product_path
when referer.include? "some_other_string"
redirect_link = other_product_path
end

Related

Rails - good way to convert string to array if not array rails

I receive a param and want it to be either a string like this :
"abc,efg"
or an Array like this
["abc","efg"]
In the first case I want to convert it into an Array, what would be the good way ?
Here is what I thought
if params[:ids] && params[:ids].is_a? Array
ids = params[:ids]
else if params[:ids]
ids = params[:ids].split(",")
I'd use a ternary for this to keep it simple and on one line:
ids = params[:ids].is_a?(String) ? params[:ids].split(',') : params[:ids]
I've reversed the order so you don't get an undefined method error if you try calling split on nil should params[:ids] be missing.
Array.wrap(params[:ids]).map{|x| x.split(',')}.flatten
Apologies for piling on. But I thought I would offer a slight tweak to the answer proposed by SickLickWill (which doesn't quite handle the Array case correctly):
ids = params[:id].split(',').flatten
This will handle the String case just fine:
:001 > params = {id: "abc,efg"}
:002 > ids = params[:id].split(',').flatten
=> ["abc", "efg"]
As well as the Array case:
:003 > params = {id: ["abc","efg"]}
:004 > ids = params[:id].split(',').flatten
=> ["abc", "efg"]
If there's any chance the id param will be nil, then this barfs:
:005 > params = {}
=> {}
:006 > ids = params[:id].split(',').flatten
NoMethodError: undefined method `split' for nil:NilClass
So, you could put in a conditional test:
:007 > ids = params[:id].split(',').flatten if params[:id]
=> nil
Or, use try:
:008 > ids = params[:id].try(:split, ',').try(:flatten)
=> nil
You miss end tag and you have wrong else if and you can delete the check of params[:ids] because if :ids key do not exist is_a? return NilClass
I think you can do this
ids = if params[:ids].is_a? Array
params[:ids]
elsif params[:ids]
params[:ids].split(",")
end
I think the shortest way would be to use .try. It saves you from writing out an if-then-else.
params_id = params[:id].try(:split, ',')

OpenStruct issue with Ruby 2.3.1

In Ruby 2.1.5 and 2.2.4, creating a new Collector returns the correct result.
require 'ostruct'
module ResourceResponses
class Collector < OpenStruct
def initialize
super
#table = Hash.new {|h,k| h[k] = Response.new }
end
end
class Response
attr_reader :publish_formats, :publish_block, :blocks, :block_order
def initialize
#publish_formats = []
#blocks = {}
#block_order = []
end
end
end
> Collector.new
=> #<ResourceResponses::Collector>
Collector.new.responses
=> #<ResourceResponses::Response:0x007fb3f409ae98 #block_order=[], #blocks= {}, #publish_formats=[]>
When I upgrade to Ruby 2.3.1, it starts returning back nil instead.
> Collector.new
=> #<ResourceResponses::Collector>
> Collector.new.responses
=> nil
I've done a lot of reading around how OpenStruct is now 10x faster in 2.3 but I'm not seeing what change was made that would break the relationship between Collector and Response. Any help is very appreciated. Rails is at version 4.2.7.1.
Let's have a look at the implementation of method_missing in the current implementation:
def method_missing(mid, *args) # :nodoc:
len = args.length
if mname = mid[/.*(?==\z)/m]
if len != 1
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
end
modifiable?[new_ostruct_member!(mname)] = args[0]
elsif len == 0
if #table.key?(mid)
new_ostruct_member!(mid) unless frozen?
#table[mid]
end
else
err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
err.set_backtrace caller(1)
raise err
end
end
The interesting part is the block in the middle that runs when the method name didn't end with an = and when there are no addition arguments:
if #table.key?(mid)
new_ostruct_member!(mid) unless frozen?
#table[mid]
end
As you can see the implementation first checks if the key exists, before actually reading the value.
This breaks your implementation with the hash that returns a new Response.new when a key/value is not set. Because just calling key? doesn't trigger the setting of the default value:
hash = Hash.new { |h,k| h[k] = :bar }
hash.has_key?(:foo)
#=> false
hash
#=> {}
hash[:foo]
#=> :bar
hash
#=> { :foo => :bar }
Ruby 2.2 didn't have this optimization. It just returned #table[mid] without checking #table.key? first.

In a method, how to use a default argument in abscence of second parameter in ruby?

def alphabetize(arr,rev=false)
if rev
arr.sort!{|a,b| b<=>a}
else
arr.sort!
end
puts arr
end
alphabetize([5,3,8,1],false)
This is a code which I am supposed to submit on a codecademy exercise, but upon submission I get the following error:
It looks like your method doesn't default to alphabetizing an array when it doesn't receive a second parameter.
Remove the false argument so you have on your last line:
alphabetize([5,3,8,1])
or this worked for me:
def alphabetize(arr, rev=false)
arr.sort!
if rev
arr.reverse!
else
arr
end
end
numbers = [5,7,2,3]
alphabetize(numbers)
puts numbers
You should puts return value from this method outside
def alphabetize(arr,rev=false)
if rev
arr.sort!{|a,b| b<=>a}
else
arr.sort!
end
arr
end
puts alphabetize(['d', 'c', 'a', 'b'])
If you puts the arr inside the method, the method will return nil, not arr itself. For example:
irb(main):001:0> def test()
irb(main):002:1> puts "hello"
irb(main):003:1> end
=> :test
irb(main):004:0> a = test()
hello
=> nil
irb(main):005:0> a
=> nil
irb(main):006:0> def test()
irb(main):007:1> "hello"
irb(main):008:1> end
=> :test
irb(main):009:0> a = test()
=> "hello"

In ruby, how do you write item.nil? ? nil : item.id.to_s

There has to be better way to write item.nil? ? nil : item.id.to_s. Anyone know it?
Yes it is possible :
item && item.id.to_s
Example :
a = 23
a && a.to_s # => "23"
a = nil
a && a.to_s # => nil
I would use unless:
item.id.to_s unless item.nil?
I case the condition is false, this expression evaluates to nil.
You could also do something like:
item.id.to_s if item
Since you have "ruby-on-rails tag", on rails you can do item.try(:id).try(:to_s)
Here's an example
require 'active_support/core_ext/object/try'
class Item
attr_accessor :id
end
item= Item.new
item.id= 42
p item.try(:id).try(:to_s)
item= nil
p item.try(:id).try(:to_s)
"42"
nil
EDIT: Not the best way by far, see below comments.
After the below monkey patch nil.id.to_s will start to return nil.
class NilClass
def id
self
end
def to_s
self
end
end

Inspect in Ruby

When I use this code:
x = []
x << 1
if (x[0].inspect == 1)
puts "OLLAAA"
end
It outputs nothing, but it should because x[0].inspect is == to 1. But if I change == to != I get output "OLLAAA", or when if is changed to unless. Any ideas?
Fixnum#inspect is an alias for to_s - you need to compare against "1"
Why are you so sure x[0].inspect == 1? Object::inspect returns a string.
$ irb
2.0.0-p247 :001 > x = []
=> []
2.0.0-p247 :002 > x << 1
=> [1]
2.0.0-p247 :003 > x[0].inspect == 1
=> false
If you change == to !=, obviously you flip the logic, so it prints. The exact same thing is happening for if to unless.
Because of below :
x[0].inspect # => "1"
x[0].inspect gives string instance,which is not equal to Fixnum instance 1. Thus x[0].inspect == 1 evaluates to false,and you didn't get the output. Now when you use !=,hope you got the point why you did get the output.
Fixnum#inpect call actually does Fixnum#to_s. See below :
12.method(:inspect) # => #<Method: Fixnum#to_s>
as mentioned above, inspect return a string. You can solve your problem with
if (x[0].inspect.to_i == 1)
puts "Hey I am an integer :)"
end

Resources