How to return a particular value from a method? - ruby

I have this code that tries to return a value from a method:
temp = "123"
return temp
and I have this line that calls the method and assigns the return value:
person_connections = #client.get_person_connections(:id => current_user_id )
but when I try to inspect person_connections, it shows some different object string. Any idea how to return the actual value of the temp variable?
def get_person_connections(options = {})
person_id = options[:id]
path = "/people/id=" + person_id + ":(num-connections)"
query_connections(path, options)
self
end
and
private
def query_connections(path, options={})
fields = options.delete(:fields) || LinkedIn.default_profile_fields
if options.delete(:public)
path +=":public"
elsif fields
path +=":(#{fields.map{ |f| f.to_s.gsub("_","-") }.join(',')})"
end
headers = options.delete(:headers) || {}
params = options.map { |k,v| v.is_a?(Array) ? v.map{|i| "#{k}=#{i}"}.join("&") : "#{k}=#{v}" }.join("&")
path += "?#{params}" if not params.empty?
temp_var = get(path, headers)
hash = JSON.parse(temp_var)
conn = hash["numConnections"]
end

As Samy said in a comment:
In Ruby, the last statement will be returned.
So if we take a look at get_person_connections, we see that the last line is self. What it means is that it returns the instance on which the method was called, #client in this case.
Additional notes: the solution would be to remove self, although if the method is used elsewhere be careful as returning self is often used to allow chaining of methods (though it hardly makes sense to do that on a get method).

Related

How to pass method arguments use as Hash path?

E.G.
def do_the_thing(file_to_load, hash_path)
file = File.read(file)
data = JSON.parse(file, { symbolize_names: true })
data[sections.to_sym]
end
do_the_thing(file_I_want, '[:foo][:bar][0]')
Tried a few methods but failed so far.
Thanks for any help in advance :)
Assuming you missed the parameters names...
Lets assume our file is:
// test.json
{
"foo": {
"bar": ["foobar"]
}
}
Recomended solution
Does your param really need to be a string??
If your code can be more flexible, and pass arguments as they are on ruby, you can use the Hash dig method:
require 'json'
def do_the_thing(file, *hash_path)
file = File.read(file)
data = JSON.parse(file, symbolize_names: true)
data.dig(*hash_path)
end
do_the_thing('test.json', :foo, :bar, 0)
You should get
"foobar"
It should work fine !!
Read the rest of the answer if that doesn't satisfy your question
Alternative solution (using the same argument)
If you REALLY need to use that argument as string, you can;
Treat your params to adapt to the first solution, it won't be a small or fancy code, but it will work:
require 'json'
BRACKET_REGEX = /(\[[^\[]*\])/.freeze
# Treats the literal string to it's correspondent value
def treat_type(param)
# Remove the remaining brackets from the string
# You could do this step directly on the regex if you want to
param = param[1..-2]
case param[0]
# Checks if it is a string
when '\''
param[1..-2]
# Checks if it is a symbol
when ':'
param[1..-1].to_sym
else
begin
Integer(param)
rescue ArgumentError
param
end
end
end
# Converts your param to the accepted pattern of 'dig' method
def string_to_args(param)
# Scan method will break the match results of the regex into an array
param.scan(BRACKET_REGEX).flatten.map { |match| treat_type(match) }
end
def do_the_thing(file, hash_path)
hash_path = string_to_args(hash_path)
file = File.read(file)
data = JSON.parse(file, symbolize_names: true)
data.dig(*hash_path)
end
so:
do_the_thing('test.json', '[:foo][:bar][0]')
returns
"foobar"
This solution though is open to bugs when the "hash_path" is not on an acceptable pattern, and treating it's bugs might make the code even longer
Shortest solution (Not safe)
You can use Kernel eval method which I EXTREMELY discourage to use for security reasons, read the documentation and understand its danger before using it
require 'json'
def do_the_thing(file, hash_path)
file = File.read(file)
data = JSON.parse(file, symbolize_names: true)
eval("data#{hash_path}")
end
do_the_thing('test.json', '[:foo][:bar][0]')
If the procedure you were trying to work with was just extracting the JSON data to an object, you might find yourself using either of the following scenarios:
def do_the_thing(file_to_load)
file = File.read(file)
data = JSON.parse(file, { symbolize_names: true })
data[sections.to_sym]
end
do_the_thing(file_I_want)[:foo][:bar][0]
or use the dig function of Hash :
def do_the_thing(file_to_load, sections)
file = File.read(file)
data = JSON.parse(file, { symbolize_names: true })
data.dig(*sections)
end
do_the_thing(file_I_want, [:foo, :bar, 0])

ShadowingOuterLocalVariable rubocop error

here is my code, and here is my error. I think dont need to more descriptions here:
#terminal-error (error on object "= ->(object) do "
lib/form_object/base.rb:18:30: W: Lint/ShadowingOuterLocalVariable: Shadowing outer local variable - object.
need_validation = ->(object) do
def valid?
valid_attributes = []
attributes.each do |attribute_name, _attributes|
attribute_set = self.class.attribute_set[attribute_name]
object = self[attribute_name]
need_validation = ->(object) do
(object.class < FormObject::Base || attribute_set.options[:validate]) && object.respond_to?(:valid?)
end
if need_validation.call(object)
valid_attributes << object.valid?
elsif object.is_a?(Array)
object.each do |nested|
valid_attributes << nested.valid? if need_validation.call(nested)
end
end
end
valid_attributes << super
valid_attributes.all?
end
It's a warning from a lint that you run, which detects cases where you shadow (i.e. hide) another local variable, from an outer scope.
You have:
object = self[attribute_name]
need_validation = ->(object) do
(object.class < FormObject::Base || attribute_set.options[:validate]) && object.respond_to?(:valid?)
end
So the first variable object could not be referred to inside the lambda, as the argument is also called object.
You can remove this warning by simply renaming the parameter of your lambda:
need_validation = ->(obj) do
(obj.class < FormObject::Base || attribute_set.options[:validate]) && obj.respond_to?(:valid?)
end

Using variable declared in one method to open webpage in another method

I am working on a CLI Project and trying to open up a web page by using url variable declared in another method.
def self.open_deal_page(input)
index = input.to_i - 1
#deals = PopularDeals::NewDeals.new_deals
#deals.each do |info|
d = info[index]
#product_url = "#{d.url}"
end
#product_url.to_s
puts "They got me!"
end
def self.deal_page(product_url)
#self.open_deal_page(input)
deal = {}
html = Nokogiri::HTML(open(#product_url))
doc = Nokogiri::HTML(html)
deal[:name] = doc.css(".dealTitle h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
deal[:purchase] = doc.css("div a.button").attribute("href")
deal
#binding.pry
end
but I am receiving this error.
`open': no implicit conversion of nil into String (TypeError)
any possible solution? Thank you so much in advance.
Try returning your #product_url within your open_deal_page method, because now you're returning puts "They got me!", and also note that your product_url is being created inside your each block, so, it won't be accessible then, try creating it before as an empty string and then you can return it.
def open_deal_page(input)
...
# Create the variable
product_url = ''
# Assign it the value
deals.each do |info|
product_url = "#{info[index].url}"
end
# And return it
product_url
end
In your deal_page method tell to Nokogiri to open the product_url that you're passing as argument.
def deal_page(product_url)
...
html = Nokogiri::HTML(open(product_url))
...
end

Dynamically check if a field in JSON is nil without using eval

Here's an extract of the code that I am using:
def retrieve(user_token, quote_id, check="quotes")
end_time = Time.now + 15
match = false
until Time.now > end_time || match
#response = http_request.get(quote_get_url(quote_id, user_token))
eval("match = !JSON.parse(#response.body)#{field(check)}.nil?")
end
match.eql?(false) ? nil : #response
end
private
def field (check)
hash = {"quotes" => '["quotes"][0]',
"transaction-items" => '["quotes"][0]["links"]["transactionItems"]'
}
hash[check]
end
I was informed that using eval in this manner is not good practice. Could anyone suggest a better way of dynamically checking the existence of a JSON node (field?). I want this to do:
psudo: match = !JSON.parse(#response.body) + dynamic-path + .nil?
Store paths as arrays of path elements (['quotes', 0]). With a little helper function you'll be able to avoid eval. It is, indeed, completely inappropriate here.
Something along these lines:
class Hash
def deep_get(path)
path.reduce(self) do |memo, path_element|
return unless memo
memo[path_element]
end
end
end
path = ['quotes', 0]
hash = JSON.parse(response.body)
match = !hash.deep_get(path).nil?

How to conditionally assign Ruby variables to object instances

I have a Team class that contains a find_team class method. The method returns a Team object if one is found, or nil if no object is found:
class Team
##all_teams = []
def self.find_team(name)
index = ##all_teams.find_index { |t| t.name == name }
if index.nil?
nil
else
##all_teams[index]
end
end
end
In implementing the class, I need to assign a variable to the correct Team object if it exists or create a new Team object if it doesn't. I'm struggling with finding the clearest, quickest, ruby-ist way to do it. Some options I've considered:
t1 = Team.find_team("Some Team") ? Team.find_team("Some Team") : Team.new("Some Team")
t2 = Team.find_team("Some Other Team")
t2 ||= Team.new("Some Other Team")
t3 = if Team.find_team("Another Team")
Team.find_team("Another Team")
else
Team.new("Another Team")
I favor the second example, as it's less verbose and repetitive, but I'm wondering if there's some Ruby trick I'm missing in this scenario.
t1 = Team.find_team("Some Team") || Team.new("Some Team")
is probably the most Ruby-ish version. You can also consider to enhance your custom method.
As a side note, you can refactor your find_team method to use Enumerable#find
class Team
##all_teams = []
def self.find_team(name)
##all_teams.find { |t| t.name == name }
end
end
And you can also add a new method that returns the instance if none
class Team
##all_teams = []
def self.find_team(name)
##all_teams.find { |t| t.name == name }
end
def self.find_or_build_team(name)
find_team(name) || Team.new(name)
end
end
so that you will just call
Team.find_or_build("Some Team")
How about:
t1 = Team.find_team('Some Team') || Team.new('Some Team')
This assigns a new Team instance into t1 only if find_team method returns nil.

Resources