ruby object to_s gives unexpected output - ruby

What is the correct way to view the output of the puts statements below? My apologies for such a simple question.... Im a little rusty on ruby. github repo
require 'active_support'
require 'active_support/core_ext'
require 'indicators'
my_data = Indicators::Data.new(Securities::Stock.new(:symbol => 'AAPL', :start_date => '2012-08-25', :end_date => '2012-08-30').output)
puts my_data.to_s #expected to see Open,High,Low,Close for AAPL
temp=my_data.calc(:type => :sma, :params => 3)
puts temp.to_s #expected to see an RSI value for each data point from the data above

Maybe check out the awesome_print gem.
It provides the .ai method which can be called on anything.
An example:
my_obj = { a: "b" }
my_obj_as_string = my_obj.ai
puts my_obj_as_string
# ... this will print
# {
# :a => "b"
# }
# except the result is colored.
You can shorten all this into a single step with ap(my_obj).
There's also a way to return objects as HTML. It's the my_obj.ai(html: true) option.

Just use .inspect method instead of .to_s if you want to see internal properties of objects.

Related

How to use YAML.load with handlers

irb(main):001:0> a="run: yes"
=> "run: yes"
irb(main):002:0> require 'yaml'
=> true
irb(main):003:0> YAML.load a
=> {"run"=>true}
irb(main):004:0> YAML.load(a, handlers => {'bool#yes' = identity})
SyntaxError: (irb):4: syntax error, unexpected '=', expecting =>
YAML.load(a, handlers => {'bool#yes' = identity})
^
from /usr/bin/irb:11:in `<main>
I want the yaml val is yes and i google find the handler will help.
But seems i do not use correct syntax.
I try to search related docs but fail.
The problems with the listed code are
that handlers isn't defined anywhere, you likely wanted :handlers
that identity isn't defined anywhere, maybe wanted :identity that
you are missing a > on your hash rocket (=>).
So to get this code to run it should (likely) look like
YAML.load("run: yes", :handlers => {'bool#yes' => :identity})
However, so far as I know the second parameter to YAML.load is a filename.
If you are able to change the input YAML, simply quoting the value "yes" will cause it come through as a string
YAML.load("a: 'yes'")
# => {"a"=>"yes"}
If you require the un-quoted string 'yes' in the YAML to be treated as 'yes', not true in ruby after parsing. I cobbled this together (with help from this question), using Psych::Handler and Pysch::Parser. Though I'm not sure if there's another easier/better way to do this without having to hack this all together like this.
require 'yaml'
class MyHandler < Psych::Handlers::DocumentStream
def scalar(value, anchor, tag, plain, quoted, style)
if value == 'yes'
super(value, anchor, tag, plain, true, style)
else
super(value, anchor, tag, plain, quoted, style)
end
end
end
def my_parse(yaml)
parser = Psych::Parser.new(MyHandler.new{|node| return node})
parser.parse yaml
false
end
my_parse("a: yes").to_ruby
# => {"a"=>"yes"}
my_parse("a: 'yes'").to_ruby
# => {"a"=>"yes"}
my_parse("a: no").to_ruby
# => {"a"=>false}
Sidenote in the console (and the source):
YAML
# => Psych

Ruby method calls without defining variables

I am beyond confused on where the :find is coming from line 17, as well as :findcity... is that how you call a fucntion within a predefined method call from ruby???
cities = {'CA' => 'San Francisco',
'MI' => 'Detroit',
'FL' => 'Jacksonville'}
cities['NY'] = 'New York'
cities['OR'] = 'Portland'
def find_city(map, state)
if map.include? state
return map[state]
else
return "Not found."
end
end
# ok pay attention!
cities[:find] = method(:find_city)
while true
print "State? (ENTER to quit) "
state = gets.chomp
break if state.empty?
# this line is the most important ever! study!
puts cities[:find].call(cities, state)
end
For starters if you are a beginner in Ruby just don't bother trying to understand it. This is not the usual way of doing things in Ruby.
But here are some explanations:
:find is a Symbol and it could be :search or something else in this example.
You could actually use a different variable to store the method instead of storing inside the cities Hash. Like so:
# Instead of doing this
hash = {} # => {}
hash[:puts_method] = method(:puts)
hash[:puts_method].call("Foo")
# Foo
# You can just
puts_method = method(:puts)
puts_method.call("Foo")
# Foo
The find_city is the method defined in your code. Passing the symbol :find_city to the method method returns you an object representing that method (very meta uh?) of the class Method.
So like in the example above we can have an object representing the method puts with which we can send the method call to call it.
the_puts = method(:puts)
# => #<Method: Object(Kernel)#puts>
the_puts.call("Hey!")
# Hey!
# => nil
# Which is the same as simply doing
puts("Hey!")
# Hey!
# => nil

Using Ruby CSV header converters

Say I have the following class:
class Buyer < ActiveRecord::Base
attr_accesible :first_name, :last_name
and the following in a CSV file:
First Name,Last Name
John,Doe
Jane,Doe
I want to save the contents of the CSV into the database. I have the following in a Rake file:
namespace :migration do
desc "Migrate CSV data"
task :import, [:model, :file_path] => :environment do |t, args|
require 'csv'
model = args.model.constantize
path = args.file_path
CSV.foreach(path, :headers => true,
:converters => :all,
:header_converters => lambda { |h| h.downcase.gsub(' ', '_') }
) do |row|
model.create!(row.to_hash)
end
end
end
I am getting an undefined method 'downcase' for nil:NilClass. If I exclude the header converters then I get unknown attribute 'First Name'. What's the correct syntax for converting a header from, say, First Name to first_name?
After doing some research here in my desktop, it seems to me the error is for something else.
First I put the data in my "a.txt" file as below :
First Name,Last Name
John,Doe
Jane,Doe
Now I ran the code, which is saved in my so.rb file.
so.rb
require 'csv'
CSV.foreach("C:\\Users\\arup\\a.txt",
:headers => true,
:converters => :all,
:header_converters => lambda { |h| h.downcase.gsub(' ', '_') }
) do |row|
p row
end
Now running the :
C:\Users\arup>ruby -v so.rb
ruby 1.9.3p448 (2013-06-27) [i386-mingw32]
#<CSV::Row "first_name":"John" "last_name":"Doe">
#<CSV::Row "first_name":"Jane" "last_name":"Doe">
So everything is working now. Now let me reproduce the error :
I put the data in my "a.txt" file as below ( just added a , after the last column) :
First Name,Last Name,
John,Doe
Jane,Doe
Now I ran the code, which is saved in my so.rb file, again.
C:\Users\arup>ruby -v so.rb
ruby 1.9.3p448 (2013-06-27) [i386-mingw32]
so.rb:5:in `block in <main>': undefined method `downcase' for nil:NilClass (NoMethodError)
It seems, in your header row, there is blank column value which is causing the error. Thus if you have a control to the source CSV file, check there the same. Or do some change in your code, to handle the error as below :
require 'csv'
CSV.foreach("C:\\Users\\arup\\a.txt",
:headers => true,
:converters => :all,
:header_converters => lambda { |h| h.downcase.gsub(' ', '_') unless h.nil? }
) do |row|
p row
end
A more general answer, but if you have code that you need to process as text, and sometimes you might get a nil in there, then call to_s on the object. This will turn nil into an empty string. eg
h.to_s.downcase.gsub(' ', '_')
This will never blow up, whatever h is, because every class in ruby has the to_s method, and it always returns a string (unless you've overridden it to do something else, which would be unadvisable).
Passing :symbol to :header_converters will automatically convert to strings to snake case as well.
options = {:headers => true,
:header_converters => :symbol}
CSV.foreach(filepath, options) ...
#<CSV::Row first_name:"John" last_name:"Doe">
#<CSV::Row first_name:"Jane" last_name:"Doe">

Automatically Map JSON Objects into Instance Variables in Ruby

I would like to be able to automatically parse JSON objects into instance variables. For example, with this JSON.
require 'httparty'
json = HTTParty.get('http://api.dribbble.com/players/simplebits') #=> {"shots_count":150,"twitter_screen_name":"simplebits","avatar_url":"http://dribbble.com/system/users/1/avatars/thumb/dancederholm-peek.jpg?1261060245","name":"Dan Cederholm","created_at":"2009/07/07 21:51:22 -0400","location":"Salem, MA","following_count":391,"url":"http://dribbble.com/players/simplebits","draftees_count":104,"id":1,"drafted_by_player_id":null,"followers_count":2214}
I'd like to be able to do this:
json.shots_count
And have it output:
150
How could I possibly do this?
You should definitely use something like json["shots_counts"], but if you really need objectified hash, you could create a new class for this:
class ObjectifiedHash
def initialize hash
#data = hash.inject({}) do |data, (key,value)|
value = ObjectifiedHash.new value if value.kind_of? Hash
data[key.to_s] = value
data
end
end
def method_missing key
if #data.key? key.to_s
#data[key.to_s]
else
nil
end
end
end
After that, use it:
ojson = ObjectifiedHash.new(HTTParty.get('http://api.dribbble.com/players/simplebits'))
ojson.shots_counts # => 150
Well, getting what you want is hard, but getting close is easy:
require 'json'
json = JSON.parse(your_http_body)
puts json['shots_count']
Not exactly what you are looking for, but this will get you closer:
ruby-1.9.2-head > require 'rubygems'
=> false
ruby-1.9.2-head > require 'httparty'
=> true
ruby-1.9.2-head > json = HTTParty.get('http://api.dribbble.com/players/simplebits').parsed_response
=> {"shots_count"=>150, "twitter_screen_name"=>"simplebits", "avatar_url"=>"http://dribbble.com/system/users/1/avatars/thumb/dancederholm-peek.jpg?1261060245", "name"=>"Dan Cederholm", "created_at"=>"2009/07/07 21:51:22 -0400", "location"=>"Salem, MA", "following_count"=>391, "url"=>"http://dribbble.com/players/simplebits", "draftees_count"=>104, "id"=>1, "drafted_by_player_id"=>nil, "followers_count"=>2214}
ruby-1.9.2-head > puts json["shots_count"]
150
=> nil
Hope this helps!

ruby logging convenience method

I would like a ruby method "show" which does this:
anyobject.show
the output of the call would be:
anyvar => _the_ _pp_ _string_ _of_ _the_ _object_
Something close , but not quite is :
p "any_var => #{any_var.pretty_inspect}"
Since you have to type "anyvar" out to accomplish that.
This should do what you're asking. It prints readable info about an object in YAML format:
puts YAML::dump(object)
So your show method would look like this:
def show:
puts YAML::dump(self)
end
and don't forget to:
require 'yaml'
A little enhanced version of Martin's one:
require 'pp'
def show(var,bindings)
print "#{var} => #{eval('var',bindings).pretty_inspect}"
end
a,t = 1,Time.now
show a,binding #=> a => 1
show t,binding #=> t => Mon Sep 28 13:12:34 +0300 2009
In general, this can't be done because methods are called on objects, not variables.
Edit:
If you're willing to do it with a "function" rather than a method you could add this to Kernel:
def show(var)
print "#{var} => #{eval(var).pretty_inspect}"
end
and call it via
show "anyvar"
It's a bit ugly because of the need to pass the variable name in as a string, of course.

Resources