Confusion with Hashes and Arrays when using steam-condenser Ruby gem - ruby

I'm trying to use the steam-condenser gem to pull a list of games for a particular user (myself). So far I have the following:
require 'steam-condenser'
id = SteamId.new 'tamachan87'
games_owned = id.games
games_owned is now a hash, containing keys and arrays.
If I call games_owned.values in IRB I will get a result that contains all the information of those games, from it's ID number to the name to its logo hash.
However, when I use the following:
games_owned.each do |key, array|
puts "==== #{key} ===="
puts array
end
I get just the first value of the array such as:
==== 200260 ====
#<SteamGame:0x00000100beb0a8>
Each value/array thing has an #name variable which is the only thing I want to pull.
Could someone please help me to better understand these hashes and how I can pull specific data (#name) from them?
Thanks in advance.

The return value of SteamId#games is not a hash of arrays, it's a hash of SteamGame objects.
Your example code could be written like that:
games_owned.each do |app_id, game|
puts "==== #{app_id} ===="
puts game.name
end
See the documentation of SteamId for more information.

The reason you get an unfriendly class name and memory value is that the SteamGame class does not define an inspect method. However if all you're interested is printing the names of the games, use puts key.name

If you want to print your Steamgame object in a pretty way by using "puts"
you should overwrite "to_s" in your Steamgame class.
The reason you are getting different results is puts uses to_s method to print its argument (which is
steamgame object itself in your case with specific id).
If you use "p" or "puts array.inspect" instead of "puts", it will debug your object and you will see irb like results.
If you have an attribute like #name in your Steamgame class, you should be able to get it just by saying:
games_owned.values[i].name or puts array.name.
did you try that?

Related

Is there a way to convert an object to json or other printable format?

I have an object, and I want to dump all its information.
For debugging purpose, can I convert it to json or other suitable format?
I know using p object, sometimes can print out all its information; but not always. So I am asking is there other ways when p object becomes invalid
Try pry
It is excellent for exploring objects. Especially large objects because it has paging. The objects are also color coded to make it more readable.
Steps:
install pry
Add require 'pry' to the script file you want to debug
Add binding.pry below the object declaration of anywhere the object is in scope
Run your script
This will pop open the pry console with access to your object
Type in the object name
'ls object' will list all the instance variables of the object
There's couple ways you can go. Using json from the standard lib is one way to convert an object to json.
this converts an object in ruby to a json string:
require "json"
h = Hash.new(name: "example")
JSON.dump(h)
But you seem to be wanting to inspect an object in detail. The best solution is probably the "Pry" gem that others have suggested if you really need a lot of detail.
so after installing pry you can "cd" into objects and inspect instance variables public/private methods and the source code of methods/classes, etc. its really great stuff.
require "pry"
cd SomeObject
ls # this shows you everything defined in the object.
The problem with object.inspect that others have suggested is that it can be overriden, often is, and thus will oft not show you enough information. So it depends on what you want to find out.
puts o.instance_variables #=> shows all an objects instance variable names
puts o.instance_variable_get :#some_var #=> returns the value held by #some_var
puts o.methods - Object.methods #=> roughly speaking, shows you the methods defined on an object itself and not inheritted from parent objects
Unfortunately there's not a perfect answer here, but for debugging purposes I personally think nothing beats out pry especially with the pry debugger addon gem (forgot actual name) that allows you to step through the call stack.
You can use "inspect" : "Returns a string containing a human-readable representation of obj. By default, show the class name and the list of the instance variables and their values (by calling inspect on each of them). "
Example:
puts object.inspect
you can try puts my_object.as_json.to_json

Ruby initialization idiom using symbols

I'm doing some work in an existing Ruby code base, and I'm quite new to Ruby. I see this initialization idiom pretty often:
def initialize(input)
#number = input[:number]
#color = input[:color]
end
I guess I have two questions. One is whether this is a common idiom and if so, what's good about it? The second is, what is actually happening here? Is the implication that input is an array? A hash? The underlying mechanics aren't clear to me.
Yes, it's common. Generally when you see code like this, it means that input is a Hash. Occasionally someone might pass in an object that acts like a hash, though, and we can still expect this code to work. We can tell that input is definitely not an array, because arrays require Integers to be used as their index, but :number and :color are Symbols.
Whenever you see something starting with a colon like :number, that is a Ruby symbol.
Whenever you see something starting with a # like #number, that is the name of an instance variable. Instance variables are used to store data inside objects for later use.
Suppose we have a class Foo defined like this:
class Foo
def initialize(input)
#number = input[:number]
#color = input[:color]
end
end
In this case, we can create a new object like this:
Foo.new(number: 4, color: 'red')
The code above is equivalent to:
input_hash = { :number => 4, :color => 'red' }
Foo.new(input_hash)
One nice thing about this pattern is that you can tell exactly what each input variable is being used for because it will be written next to a descriptive symbol, and also it doesn't matter what order you put the input variables in.
Improvements
If you want to improve this code, you might consider using a new feature of Ruby called keyword arguments. Alternatively, you might also consider Hash#fetch so you can have more control over what happens when one of the keys is missing, instead of just storing a nil value in your object. I would also recommend that you check the input hash for any unexpected keys and raise an exception if they are found.
Is this a common idiom and if so, what's good about it?
It's not common, but it's acceptable. When there are more than n parameters being passed in, where "n" is often > 3, we should use a hash.
What's good about it? Look at the code. Is it simple and readable? Does it make sense that an input parameter of :number is being assigned to an instance variable of the same name?
what is actually happening here? Is the implication that input is an array? A hash? The underlying mechanics aren't clear to me.
It's a hash where :number and :color are keys.

ruby cast method input variable as string in ruby irb

How would I coerce the behavior of irb to treat variable identifiers as strings when used in method signatures?
I am trying to create a irb based calculation tool and I want to reduce the typing of users who use this tool in the irb shell. Assume my users are not ruby programmers or know much about the syntax of ruby. The may have some facility with the command line.
I have a file
calculator.rb
inside this file is
def calculate(value, units)
... some logic
end
I instruct the user to fire up irb like so
irb -r path/to/calculator.rb
I instruct the user to type
calculate(10, inches)
get return value in irb
how can I do this without requiring the user to understand that they have to wrap the second parameter in quotation marks. In other words I don't want the user to have to type
calculate(10, "inches")
is it possible to cast the user input as a string instead of a variable identifier before it is passed to my method inside my script? Maybe what I want to do is not possible without fundamentally breaking irb shell?
If this is for non-programmers how about using puts and gets?
def calculate
puts "Which number would you like to convert?"
number = gets.to_i
puts "What do you want to convert it to?"
type = gets
# your conversion logic
puts result
end
You can actually do it the way you requested using method_missing. Any matching units will get converted to strings instead of raising exceptions.
SO_CALC_UNITS = %w[inches feet yards meters parsecs]
def method_missing(method)
if SO_CALC_UNITS.include?(method.to_s)
method.to_s
else
super(method)
end
end

ruby Array.inspect vs. Array[element].to_s

I'm working with an array, which we'll call books, of complex objects, which we'll call Book. The problem is when I call puts "#{books.inspect}", ruby outputs a stream of binary (unreadable utf8 characters). However, when I call puts #{books[0].to_str}", I get a brief, pretty output that describes the book in question. Not sure if it is relevant, but Book is a subclass (we can call it's parent class Item), and books.length=1
Ruby implies that .to_s and .inspect are synonymous, but they are clearly providing different results in practice. Does anyone know why this is happening and can you provide a suggestion for how to get the nice output I want out of the whole books collection?
Misc info:
[chk ~ ]$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
class Myclass
def to_s
'my string representation'
end
def inspect
'my inspection'
end
end
a= [Myclass.new]
p a
puts a
outputs ::
[my inspection]
my string representation
The inspect method is called for each element inside the array. If that method is not defined you get the default class representation. You will just need to define inspect.
You could always just do :
def inspect
self.to_s
end
books.inspect and books[0].to_s are absolutely NOT the same.
The first is a call to inspect method of book object, which is an array. The second is a call to to_s method of books[0] object, whatever it is that is contained inside the array.
As you didn't specify what exactly is books[0], I'm afraid I can't tell anything more.
books is an array so calling books.inspect is calling Array#inspect. That method works by calling .inspect on the elements, so in this case Book#inspect.
Doing string-interpolation "Here's some info #{value}" calls .to_s on the value object whatever its class may be.
Putting these together as an example "Books #{books}" would call Array#to_s (which is an alias for Array#inspect) that calls Book#inspect to produce the output string.
When you want things to work consistently, you should define inspect and make to_s an alias of inspect as is done in the Array class as an example. e.g.
class MyClass
def inspect
'my string representation'
end
alias_method :to_s, :inspect
end
There may be times when you want them to be different where .inspect is useful for debugging and .to_s for more usual output. In that case you would define each of them with different code.

Ruby: export variable into local namespace

I want to programmatically insert a new variable into the local Ruby namespace. For example, I want to be able to write
label = 'some_name'
# some code equivalent to
# some_name = 3
# but using only 'label' to get the name.
puts some_name # returns 3
What do I put in the middle here to get this done?
I've answered another SO question similar to this. The short answer is this, if you specifically want to create a local variable with the name of it based on the value of another variable, then there is no way to do it. It you just want to make seem as though you've created a local but it is really ruby magic, then something like #mikong's answer is one way to go.
Note that if you relax your contraint and are happy to create an instance variable instead, then you can do it.
label = 'some_name'
self.instance_variable_set("#{label}", 3)
puts #some_name
You can even dynamically define an accessor and then you can get rid of the unsightly #, but once again you will simply have a method masquerading as a local rather than a real local variable.
The following is not exactly code between the 2 lines that you mentioned above:
class Example
attr_accessor :label
def method_missing(name, *args, &block)
return some_processing if name == label.to_sym
end
def some_processing
3 # of course, this can be something more complicated
end
def test
#label = 'some_name'
puts some_name
end
end
Nonetheless it seems to work with what you need. The mechanism has changed from what you gave (label is now an attribute). Also, technically, it's not a variable but a method with a dynamic name that returns what you need.
Personally, I think your requirements seem a little bit dangerous in that the "variable" name changes. I would probably not use the code in my example. I guess depending on the project requirements, I'll think of a different approach.
label = 'some_name'
eval "#{label} = 3"
puts eval "#{label}"
puts local_variables
Note that you would presumably never have an opportunity to execute...
puts some_name
...because if you knew what local variables you were going to create there would be no need to name them with run-time code. And that's good, because the interpreter will not be able to puts some_name directly because it never parsed an assignment for some_name. But it is there and it is a local, as puts local_variables is able to show.

Resources