Dynamically creating/recalling/linking nameless objects - ruby

New to Ruby-land via The Odin Project. I'm writing an algorithm to generate binary search trees from a sorted array of random numbers.
class Node
attr_accessor :value, :child_left, :child_right, :parent
def initialize (value, child_left = nil, child_right = nil, parent = nil)
#value = value
#child_left = child_left
#child_right = child_right
#parent = parent
#Checker to verify object and link creation
#puts "value: #{value}, self: #{self}, parent: #{parent}, child_left: #{child_left}, child_right: #{child_right}"
end
end
def build_tree(arry, parent = nil)
if arry.length > 2
child_left = build_tree(arry[0...arry.length/2], arry[arry.length/2])
child_right = build_tree(arry[(arry.length/2)+1..-1], arry[arry.length/2])
Node.new(arry[arry.length/2], child_left, child_right, parent)
#Can't link parent object until parent is created, but can't create child object until parent can be linked
elsif arry.length == 2
child_left = build_tree(arry[0...1], arry[1])
Node.new(arry[1], child_left, nil, parent)
elsif arry.length == 1
Node.new(arry[0], nil, nil, parent)
end
end
This results in properly generated node objects linked to their child objects, but only with the same fixnum value as the parent objects' value and not the actual parent object. It seems like a chicken/egg scenario. Either I'm committing some Object/Class creation sin here, or I simply lack the vocabulary to successfully search for a solution to my problem. Please advise.
EDIT: Maybe just a hint on some term(s) to search to point me in the right direction?

First at all, you have an issue in the constructor:
def initialize (value, childL = nil, childR = nil, parent = nil)
#value = :value
#childL = :childL
#childR = :childR
#parent = :parent
end
:something in Ruby is a Symbol, the build-in object, which is quite similar to String, but not modifiable. So, whatever you pass to Node.new, your variables will be set to :value, :childL and so on.
You probably wanted to set your class variables like this:
def initialize (value, childL = nil, childR = nil, parent = nil)
#value = value
#childL = childL
#childR = childR
#parent = parent
end
Learn more on String and Symbols in Ruby here.

Related

Stripping a string to build a new S3 path

In my project I am assigning individual UUIDs to every upload that gets moved between two folders in my S3 Bucket, for the purposes of individualising their links later on.
However, while attempting to format the Object Key as displayed in the method below, all the code below
parts = old_key.split('/') greys out/ no longer functions, indicating a Syntax error that I can't see.
def move_and_rename(target_folder, prefix_generator: nil)
prefix_generator ||= -> { SecureRandom.uuid }
s3_objects.each do |obj|
prefix = prefix_generator.call
old_key = obj.key
parts = old_key.split('/')
new_last_part = "#{prefix}-#{parts.last}”
new_key = (parts[0..-2] + [new_last_part]).join('/')
new_key = s3_folder ? obj.key.sub(s3_folder, target_folder) : (parts[0..-2] + [new_last_part]).join('/')
obj.move_to(bucket: bucket_name, key: new_key)
yield(old_key: old_key, new_key: new_key, obj: obj, prefix: prefix) if block_given?
end
self
end
Or perhaps I have this structured completely wrong within the method? Any pointers would be appreciated.

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.

How do I mass-assign unique instance variable names when iterating and parsing over an array of hashes?

Here is the big hash that I start with (actually its been refined a step or two but this is what I'm starting with at this point.
angel_hash = {"follower_count"=>1369, "name"=>"AngelList", "markets"=>
[{"display_name"=>"Startups", "name"=>"startups", "id"=>448, "tag_type"=>"MarketTag",
"angellist_url"=>"http://angel.co/startups-1"}, {"display_name"=>"Venture Capital",
"name"=>"venture capital", "id"=>856, "tag_type"=>"MarketTag",
"angellist_url"=>"http://angel.co/venture-capital"}], "video_url"=>"",
"created_at"=>"2011-03-18T00:24:29Z", "updated_at"=>"2012-07-09T14:12:28Z",
"product_desc"=>"AngelList is a platform for startups to meet investors and talent. ",
"blog_url"=>"http://blog.angel.co",
"thumb_url"=>"https://s3.amazonaws.com/photos.angel.co/startups/i/6702-
766d1ce00c99ce9a5cbc19d0c87a436e-thumb_jpg.jpg", "id"=>6702,
"company_url"=>"http://angel.co", "locations"=>[{"display_name"=>"San Francisco",
"name"=>"san francisco", "id"=>1692, "tag_type"=>"LocationTag",
"angellist_url"=>"http://angel.co/san-francisco"}], "community_profile"=>false, "status"=>
{"message"=>"Done Deal: #volunteerspot raises $1.5M
http://techcrunch.com/2012/06/27/targeting-power-moms-volunteerspot-secures-1-5m-in-
series-a-from-ff-venture-capital-and-more/ \316\207 20 intros on AngelList \316\207 Funded
by #ff-venture-capital", "created_at"=>"2012-06-28T20:37:58Z", "id"=>63110},
"twitter_url"=>"http://twitter.com/angellist", "high_concept"=>"A platform for startups",
"logo_url"=>"https://s3.amazonaws.com/photos.angel.co/startups/i/6702
-766d1ce00c99ce9a5cbc19d0c87a436e-medium_jpg.jpg",
"angellist_url"=>"http://angel.co/angellist", "screenshots"=>
[{"thumb"=>"https://s3.amazonaws.com/screenshots.angel.co/98/6702/009cff275fb96709c915c4d4abc9
43d6-thumb_jpg.jpg",
"original"=>"https://s3.amazonaws.com/screenshots.angel.co/98/6702/009cff275fb96709c915c4d4abc
943d6-original.jpg"}], "hidden"=>false}
Out of this hash I parsed out some elements, and am doing just fine until I run into the embedded arrays
module SimpleAngel
class Company
attr_accessor :followers, :company_name, :markets_array, :date_joined, :locations_array
attr_accessor :high_concept, :high_concept_long, :thumbnail_logo, :full_size_logo
attr_accessor :angel_url, :twitter_url, :company_url, :blog_url
def initialize(angel_hash)
#followers = angel_hash['follower_count']
#company_name = angel_hash['name']
#markets_array = angel_hash['markets']
#markets_array.each_with_index do |market, i|
###This is where I'm stuck. I want to pull out individual elements
# from each array AND dynamically assign unique instance variable names for
# each separate market in the markets array. Something like #market1_name,
# #market1_id, etc.
end
#date_joined = angel_hash['created_at']
#locations_array = angel_hash['locations']
#high_concept = angel_hash['high_concept']
#high_concept_long = angel_hash['product_desc']
#thumbnail_logo = angel_hash['thumb_url']
#full_size_logo = angel_hash['logo_url']
#angel_url = angel_hash['angellist_url']
#twitter_url = angel_hash['twitter_url']
#company_url = angel_hash['company_url']
#blog_url = angel_hash['blog_url']
end
end
end
Here's a direct answer to your question: you can define arbitrary instance variable by calling instance_variable_set.
#markets_array.each_with_index do |market, i|
market.each do |k, v|
instance_variable_set "market#{i}_#{k}", v
# this will define #market0_id = 448
end
end

How to return a particular value from a method?

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).

How to make a control invisible?

I've made several TextCtrls and Button, but currently users of my application don't want to see them. So I have to hide them temporary (for current build).
Here they are:
class MainFrame < Wx::Frame
def initialize (parent = nil)
super nil,:title=>"sometitle",:size=>[600,600]
set_sizer Wx::BoxSizer.new Wx::VERTICAL
#tag1 = Wx::TextCtrl.new self
sizer.add_item #tag1,:flag=>Wx::RIGHT|Wx::EXPAND
#tag1.set_value 'property'
#tag1title = Wx::TextCtrl.new self
sizer.add_item #tag1title,:flag=>Wx::RIGHT|Wx::EXPAND
#tag1title.set_value 'title'
#tag2 = Wx::TextCtrl.new self
sizer.add_item #tag2,:flag=>Wx::RIGHT|Wx::EXPAND
#tag2.set_value 'description'
#tag2title = Wx::TextCtrl.new self
sizer.add_item #tag2title,:flag=>Wx::RIGHT|Wx::EXPAND
#tag2title.set_value ''
#button_parse = Wx::Button.new self
sizer.add_item #button_parse
#button_parse.label = "Parse XML"
evt_button #button_parse, :click_parse
# ......
end
# ......
end
I see nothing about it in docs and Google is also not a friend for me today.
Since they are in a sizer, then you'll be able to use Sizer#show.
Boolean show(Sizer sizer,
Boolean show = false,
Boolean recursive = false)
This works for BoxSizer and FlexGridSizer.

Resources