Why am I not getting same output in Ruby - ruby

I'm not getting the consistent output in two cases:
Scenario 1:
humen = {"hand" => 1, "eye" => 2, "head" => 3, "hair"=>4}
puts "enter any body part name"
internal = gets.chomp.downcase.to_s
body = humen[internal]
puts body
#if input is "eye", it comes out 2
Scenario 2:
humen = {hand:1, eye:2, head:3, hair:4}
puts "enter any body part name"
internal = gets.chomp.downcase.to_s
body = humen[internal]
puts body
I see nothing in irb console. Can anyone please explain why that's the case?

keys are symbol in second case -
{:hand=>1, :eye=>2, :head=>3, :hair=>4}
whereas internal is a string.
humen[internal] is expecting the string assigned to internal to be present in hash humen which is not the case.
:hand != 'hand'
You should convert the string to symbol by:
humen[internal.to_sym]
String#to_sym converts a string into a symbol.

Related

How to find the body and the subject in a mailto link?

I have this mailto link :
mailto:email#address.com?&subject=test&body=type%20your&body=message%20here
I would like to find to, subject, body.
Actually I use :
uri = URI('mailto:email#address.com?&subject=test&body=type%20your&body=message%20here')
<URI::MailTo mailto:email#address.com?&subject=test&body=type%20your&body=message%20here>
I have :to with that :
uri.to
but I can not extract subject and body.
Do you know how to do it ?
You can use URI::MailTo#headers which returns an array of arrays:
uri.headers
#=> [[], ["subject", "test"], ["body", "type%20your"], ["body", "message%20here"]]
However, your mailto link is slightly broken. It should look like this:
uri = URI('mailto:email#address.com?subject=test&body=type%20your%0D%0Amessage%20here')
# ^ ^
# no '&' here newline as %0D%0A
That gives:
uri.headers
#=> [["subject", "test"], ["body", "type%20your%0D%0Amessage%20here"]]
Which can be accessed via assoc:
uri.headers.assoc('subject').last
#=> "test"
Or be converted to a hash:
headers = uri.headers.to_h
#=> {"subject"=>"test", "body"=>"type%20your%0D%0Amessage%20here"}
To get decoded values:
URI.decode_www_form_component(headers['body'])
#=> "type your\r\nmessage here"

`[]': can't convert String into Integer (TypeError) Ruby

I am trying to iterate over a JSON parsed hash table (that has nested Array's of hashes) and insert into a Text Table . The JSON parsed code that I am trying to iterate over is:
{"server"=>{"security_groups"=>[{"name"=>"default"}], "adminPass"=>"LhXEPMkYmqF7", "id"=>"82b7e32b-f62b-4106-b499-e0046250229f", "links"=>[{"href"=>"http://10.30.1.49:8774/v2/89fc0b9d984d49fba5328766e923958f/servers/82b7e32b-f62b-4106-b499-e0046250229f", "rel"=>"self"}, {"href"=>"http://10.30.1.49:8774/89fc0b9d984d49fba5328766e923958f/servers/82b7e32b-f62b-4106-b499-e0046250229f", "rel"=>"bookmark"}], "OS-DCF:diskConfig"=>"MANUAL"}}
The code I am using to iterate over the top is:
server_table = Text::Table.new do | t |
t.head = ['Server ID', 'Server URL', 'Admin Password']
end
response = JSON.parse(r)
response['server'].each do | serv_info |
server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
end
puts server_table
I am getting the error:
/lib/get_token.rb:166:in `[]': can't convert String into Integer (TypeError)
from ./lib/get_token.rb:166:in `create_server'
from ./lib/get_token.rb:165:in `each'
from ./lib/get_token.rb:165:in `create_server'
If I individually use puts to print out each command they work fine, but the iteration does not. The commands that pull the correct info are:
puts response['server']['links'][0]['href']
puts response['server']['id']
puts response['server']['adminPass']
All 3 of those work, but if I try and iterate over them I get the string error. I know it has something to do with .each returning an Array of hashes but I do not fully understand why the PUTS command is working without issue in the script and also in IRB.
Any thoughts?
Each serv_info is a pair of a map represented as an array of 2 elements. Therefore everything after << in your code is just wrong.
The secret to avoid such mistakes is to stop trying to obfuscate your own code.
server_table.rows should contain all possible triples of server ID, link and a password.
response = # { "server" => ...}
server = response['server']
server_id = server['id']
link_infos = server['links']
admin_pass = server['adminPass']
link_infos.each do |link_info|
link = link_info['href']
server_table.rows << [server_id, link, admin_pass]
end
Update
We can easily use this code to process multiple servers
response = # [ {"server" => ...}, ...]
response.each do |server|
... # above code snippet goes here
# or you may extract it into a method and call it here
end
Also I want to mention that irb is really great for dealing with this kind of problems. It is a command line Ruby interpreter and it's great for prototyping. It prints out result of each statement you type and has an autocompletion to help you find required classes/methods. Instead of waiting several hours to get an SO answer to simple question you will get it using irb in a couple of minutes.
Perhaps you mean just
serv_info = response['server']
server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
Since response['server'] is a hash not an array.
Instead of using:
server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
Try:
server_table.rows += [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
Or:
server_table.rows << ["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]

Accepting Command-Line Arguments into a Ruby Script

I'm trying to use the following code to accept in a file as an argument in Terminal which will then be read and update the body variable with its contents. If the file is not passed in then I want to have the prompt where the user can enter their own body copy.
require 'posterous'
Posterous.config = {
'username' => 'name',
'password' => 'pass',
'api_token' => 'token'
}
include Posterous
#site = Site.primary
#GETS POST TITLE
puts "Post title: "
title = STDIN.gets.chomp()
if defined?(ARGV)
filename = ARGV.first
end
if (defined?(filename))
body = File.open(filename)
body = body.read()
else
puts "Post body: "
body = STDIN.gets.chomp()
end
puts body
When I run the program without passing in a file I get this returned:
Post title:
Hello
posterous.rb:21:in `initialize': can't convert nil into String (TypeError)
from posterous.rb:21:in `open'
from posterous.rb:21:in `'
I'm rather new to ruby and thus am not the best at it. I've tried swapping a lot of things around and changing things but to no avail. What am I doing wrong?
defined?(ARGV) won't return a boolean false, but rather "constant". Since that doesn't evaluate to false, filename gets defined as ARGV[0], which is nil.
>> ARGV
=> []
>> defined?(ARGV)
=> "constant"
?> ARGV.first
=> nil
Instead you might check the length of ARGV:
if ARGV.length > 0
filename = ARGV.first.chomp
end
From the docs:
defined? expression tests whether or not expression refers to anything recognizable (literal object, local variable that has been initialized, method name visible from the current scope, etc.). The return value is nil if the expression cannot be resolved. Otherwise, the return value provides information about the expression.
Michael gave you the basic answer to your question. A slightly more Rubyish way of doing that would be to use ARGF to do the reading; then the conditional is only needed to decide whether or not to print the prompt:
puts "Post title: "
title = gets.chomp
puts "Post body: " if ARGV.length == 0
body = ARGF.gets.chomp
puts body
..of course, if you don't need to anything else with body, you can skip storing the contents of the file(s) and just do
puts ARGF.gets.chomp

How do I handle the wrong number of method arguments?

I'm working on a URL shortener and attemtping to convert the URL ID, which is a number, into a string, using base 36.
I'm receiving the error listed below the code:
def self.create_link(original)
url = Url.create(:original => original)
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
link = Link.new(:identifier => url.id.to_s(36))
link.url = url
link.save
return link
else
create_link(original)
end
end
I'm receiving the following error:
wrong number of arguments(1 for 0) file: tinyclone.rb location: to_s line: 91
When I researched the error, I found someone who mentioned that this error is common when you attempt to pass in parameter values when a method doesn't accept them. The error is specifically referring the following line.
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
What's the type of url.id?
I think your expecting it to be a FixNum whose to_s method accepts a radix, but you're getting something else instead... maybe a string containing a number? (e.g. "1234")
Anyway, the method seems to require no arguments and you are passing 36 nevertheless
EDIT:
Can't find the reference to the class you pointed out (Serial), but this might be worth a try:
url.id.to_i.to_s(36)
One thing I see right away is:
if Link.first(:indentifier => url.id.to_s(36)).nil? or !DIRTY_WORDS.include? url.id.to_s(36)
link = Link.new(:identifier => url.id.to_s(36))
Notice that in the first line you have :indentifier and in the second it's :identifier.
Otherwise, I agree with #Pablo Fernandez's answer that it's probably tied to the type of id.
you have 2 models, but take full responsibility on the one of them only. please take a look at code separated logic:
# Link model
def self.create_link(original)
url = Url.create(:original => original)
url_id = url.encoded_id
find_or_create_by_identifier!(:identifier => url_id)
end
# Url model
def before_validate_on_create
if url.id.to_s.include? DIRTY_WORDS
self.errors.add(:base, 'the url is invalid')
end
end
def encoded_id
url.id.to_s(36)
end

JSON object for just an integer

Silly question, but I'm unable to figure out..
I tried the following in Ruby:
irb(main):020:0> JSON.load('[1,2,3]').class
=> Array
This seems to work. While neither
JSON.load('1').class
nor this
JSON.load('{1}').class
works. Any ideas?
I'd ask the guys who programmed the library. AFAIK, 1 isn't a valid JSON object, and neither is {1} but 1 is what the library itself generates for the fixnum 1.
You'd need to do: {"number" : 1} to be valid json. The bug is that
a != JSON.parse(JSON.generate(a))
I'd say it's a bug:
>> JSON.parse(1.to_json)
JSON::ParserError: A JSON text must at least contain two octets!
from /opt/local/lib/ruby/gems/1.8/gems/json-1.1.3/lib/json/common.rb:122:in `initialize'
from /opt/local/lib/ruby/gems/1.8/gems/json-1.1.3/lib/json/common.rb:122:in `new'
from /opt/local/lib/ruby/gems/1.8/gems/json-1.1.3/lib/json/common.rb:122:in `parse'
from (irb):7
I assume you're using this: (http://json.rubyforge.org/)
JSON only supporting objects is simply not true -- json.org also does not suggest this imo. it was derived from javascript and thus especially strings and numbers are also valid JSON:
var json_string = "1";
var p = eval('(' + json_string + ')');
console.log(p);
// => 1
typeof p
// => "number"
ActiveSupport::JSON properly understands raw value JSON:
require 'active_support/json'
p = ActiveSupport::JSON.decode '1'
# => 1
p.class
# => Fixnum
and so does MultiJson:
require 'multi_json'
p = MultiJson.load '1'
# => 1
p.class
# => Fixnum
so, as a2800276 mentioned, this must be a bug.
but as of this writing, ruby 2's JSON has quirks_mode enabled by default when using the load method.
require 'json'
p = JSON.load '1'
# => 1
p.class
# => Fixnum
The first example is valid. The second two are not valid JSON data. go to json.org for details.
As said only arrays and objects are allowed at the top level of JSON.
Maybe wrapping your values in an array will solve your problem.
def set( value ); #data = [value].to_json; end
def get; JSON.parse( #data )[0]; end
From the very basics of what JSON is:
Data types in JSON can be:
Number
String
Json Object ... (and some more)
Reference to see complete list of Json data types
Now any Json data has to be encapsulated in 'Json Object' at the top level.
To understand why is this so, you can see that without a Json Object at the top level, everything would be loose and you could only have only one of the data type in the whole of Json. i.e. Either a number, a string, a array, a null value etc... but only one.
'Json Object' type has a fixed format of 'key' : 'value' pair.
You cannot store just the value. Thus you cannot have something like {1}.
You need to put in the correct format, i.e. 'key' : 'value' pair.

Resources