Rails 3.1 urllib2.quote(json.dumps(var)) Equivalent - ruby-on-rails-3.1

In Python I can convert JSON into a useable encoded string eg:
cmd2 = [{'cmd': 'inlinepush',
'params': {'raw': 'score'
}
}]
url = urllib2.quote(json.dumps(cmd2))
print url
This produces:
%5B%7B%22cmd%22%3A%20%22inlinepush%22%2C%20%22params%22%3A%20%7B%22raw%22%3A%20%22score%22%7D%7D%5D
I have searched and searched but not found a Ruby or Rails equivalent, particularly in the NET::HTTP library.
I really have spent a lot of time thrashing to no end and would be grateful of any pointers.

Try this:
require 'cgi'
require 'json'
cmd2 = [{
'cmd' => 'inlinepush',
'params' => {
'raw' => 'score'
}
}]
puts CGI.escape(JSON.dump(cmd2))

Related

Ruby equivalent of perl's "Data::Dumper" for printing deep nested hashes/arrays

This is not a duplicate of Ruby equivalent of Perl Data::Dumper. That question is more than 3.5 years old and hence want to check are there any new options available in Ruby since then.
I am looking for perl's Dumper equivalent in ruby. I don't care what Dumper does behind the curtains. I have used it extensively for printing deep nested hashes and array in perl. So far I haven't found an alternative in ruby (Or I may not have find a way to make good use of available alternatives in Ruby).
This is my perl code and its Output:
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
my $hash;
$hash->{what}->{where} = "me";
$hash->{what}->{who} = "you";
$hash->{which}->{whom} = "she";
$hash->{which}->{why} = "him";
print Dumper($hash);
OUTPUT:
$VAR1 = {
'what' => {
'who' => 'you',
'where' => 'me'
},
'which' => {
'why' => 'him',
'whom' => 'she'
}
};
Just Love the Dumper. :)
In ruby, I tried pp, p, inspect and yaml. here is my same code in ruby and its output:
#!/usr/bin/ruby
require "pp"
require "yaml"
hash = Hash.new{ |h,k| h[k] = Hash.new(&h.default_proc) }
hash[:what][:where] = "me"
hash[:what][:who] = "you"
hash[:which][:whom] = "she"
hash[:which][:why] = "him"
pp(hash)
puts "Double p did not help. Lets try single p"
p(hash)
puts "Single p did not help either...lets do an inspect"
puts hash.inspect
puts "inspect was no better...what about yaml...check it out"
y hash
puts "yaml is good for this test code but not for really deep nested structures"
OUTPUT:
{:what=>{:where=>"me", :who=>"you"}, :which=>{:whom=>"she", :why=>"him"}}
Double p did not help. Lets try single p
{:what=>{:where=>"me", :who=>"you"}, :which=>{:whom=>"she", :why=>"him"}}
Single p did not help either...lets do an inspect
{:what=>{:where=>"me", :who=>"you"}, :which=>{:whom=>"she", :why=>"him"}}
inspect was no better...what about yaml...check it out
---
:what:
:where: me
:who: you
:which:
:whom: she
:why: him
yaml is good for this test code but not for really deep nested structures
Thanks.
What about Awesome Print:
require 'awesome_print'
hash = {what: {where: "me", who: "you"}, which: { whom: "she", why: "him"}}
ap hash
Output (actually with syntax highlighting):
{
:what => {
:where => "me",
:who => "you"
},
:which => {
:whom => "she",
:why => "him"
}
}

Case-sensitive XML parser for Ruby

I'm currently using XmlSimple in Ruby to convert XML to a hash using the xml_in method. Everything is really nice, except for the fact that the resulting hash keys are all lowercase, whereas the XML element names were mixed-case.
Here's an example:
hash = XmlSimple.xml_in( xml_string, { 'KeyAttr' => 'name',
'ForceArray' => false,
'NoAttr' => true,
'KeyToSymbol' => true,
'SuppressEmpty' => "" } )
So, for example, this xml:
<aclEntry>
<aclEntryId>Stuff here</aclEntryId>
<principalName>Stuff here</principalName>
</aclEntry>
results in this hash:
{ :aclentryid => "Stuff Here", :principalname => "Stuff here" }
I've looked over the documentation for XmlSimple, and didn't see any option that indicated it could maintain mixed-case in the document-to-hash conversion.
Is there any way to use XmlSimple to maintain case sensitivity in the resulting hash? If not, is there an alternative Ruby XML parser that can generate a hash that maintains case-sensitivity like this?
Combination of Nokogiri and Activesupport will help.
require 'active_support/core_ext/hash/conversions'
require 'nokogiri'
require 'pp'
xml_doc = Nokogiri::XML("<aclEntry><aclEntryId>Stuff here</aclEntryId><principalName>Stuff here</principalName></aclEntry>")
h = Hash.from_xml(xml_doc.to_s).symbolize_keys
pp h #=> {:aclEntry=>{"aclEntryId"=>"Stuff here", "principalName"=>"Stuff here"}}
You can also do the same with ReXML and Activesupport
require 'rexml/document'
require 'pp'
include REXML
require 'active_support/core_ext/hash/conversions'
xmldoc = Document.new("<aclEntry><aclEntryId>Stuff here</aclEntryId><principalName>Stuff here</principalName></aclEntry>")
h = Hash.from_xml(xmldoc.to_s).symbolize_keys
pp h #=> {:aclEntry=>{"aclEntryId"=>"Stuff here", "principalName"=>"Stuff here"}}
EDIT : Having done a bit of reading it turns out that passing some options to SimpleXML produces the result you want, except that it doesn't symbolize the hash keys but that's a different issue.
require 'xmlsimple'
require 'pp'
xml_str = <<XML_STR
<aclEntry>
<aclEntryId>Stuff here</aclEntryId>
<principalName>Stuff here</principalName>
</aclEntry>
XML_STR
result = XmlSimple.xml_in xml_str, { 'ForceArray' => false, 'AttrPrefix' => true, 'KeyToSymbol' => true }
pp result # =>{:principalName=>"Stuff here", :aclEntryId=>"Stuff here"}

Passing BSON directly to MongoDB using the mong-ruby-driver?

Is there a way to pass a BSON object directly into the .find() in the mongo-ruby-driver?
At the moment I have a basic sinatra app that takes URL encoded JSON and parses it into the .find() but I would ideally like to give it straight BSON:
require 'sinatra'
require 'mongo'
require 'json'
include Mongo
db = MongoClient.new().db('test')
get '/' do
if request[:query]
query = JSON.parse(CGI::unescape(request[:query]))
db.collection('test_collection').find(query).to_a.to_json
end
end
So essentially have something along the lines of BSON.parse(url-encoded-query) and be able to pass that into a .find() returning the result.
Example URL: http://localhost:4567/?query=%7B%20%22name%22%20%3A%20%22john%20doe%22%20%7D
Current query: { "name" : "john doe" }
BSON query: { name: /.*john.*/, interests: [ 'fishing', 'golf' ]} that I'd like to work
The following test script demonstrates how to use the $elemMatch operator as a projection. Please note that the Collection#find method takes arbitrary documents for both the "selector" formal parameter and for the "opts" :fields option.
MongoDB documents are mapped to/from Ruby Hash objects, and these documents can fully incorporate MongoDB operators.
elemmatch_projection.rb
#!/usr/bin/env ruby
# Ruby translation of example from http://docs.mongodb.org/manual/reference/projection/elemMatch/
require 'mongo'
coll = Mongo::MongoClient.new['test']['students']
coll.remove
coll.insert({
zipcode: 63109,
dependents: [
{ name: "john", school: 102, age: 10 },
{ name: "jess", school: 102, age: 11 },
{ name: "jeff", school: 108, age: 15 }
]
})
p coll.find( { zipcode: 63109 }, :fields => { dependents: { '$elemMatch' => { school: 102 } } } ).to_a
ruby elemmatch_projection.rb
[{"_id"=>BSON::ObjectId('50eab29929daeb05ae000001'), "dependents"=>[{"name"=>"john", "school"=>102, "age"=>10}]}]
This is another answer because the question has been significantly clarified by the OP.
Hope that this helps you understand how to use MongoDB documents and operators in Ruby.
Your issue has more to do with parsing JSON or Ruby (Regexp) than with BSON. Your original question causes confusion by jumping directly to BSON. With the current Ruby driver, BSON is not directly exposed to the application writer, but mapped as naturally as possible from and to Ruby objects.
JSON is strictly limited and safe for parsing. Adding parsing for Regexp moves beyond this.
You can do what you want unsafely using Kernel#eval. This will parse your Regexp, but it will also parse exec, system, backticks, etc. For a public application with arbitrary user input, you will have to do something safer.
Also note, the differences between the following lines, which highlights semantics with both Ruby and MongoDB:
{ interests: [ 'fishing', 'golf' ] }
The above exactly matches interests iff they are exactly [ 'fishing', 'golf' ]. no more, no less, no other order.
{ interests: { '$in' => [ 'fishing', 'golf' ] } }
The above matches interests if interests have either 'fishing' or 'golf', any order, any position, any extras. Note that the string key '$in' requires the original => syntax.
Hope that this helps your understanding, and please feel free to followup with clarifying questions.
The following is a working example.
myapp.rb
require 'sinatra'
require 'mongo'
require 'json'
include Mongo
db = MongoClient.new().db('test')
get '/' do
if request[:query]
query = eval CGI::unescape(request[:query])
docs = db.collection('test_collection').find(query).to_a.to_json
"docs=#{docs}"
end
end
myapp_test.rb
require 'myapp'
require 'test/unit'
require 'rack/test'
require 'open-uri'
ENV['RACK_ENV'] = 'test'
class MyAppTest < Test::Unit::TestCase
include Rack::Test::Methods
def setup
#db ||= Mongo::MongoClient.new['test']
#coll ||= #db['test_collection']
#coll.remove
#coll.insert({name: 'john doe', interests: [ 'fishing', 'golf' ]})
end
def app
Sinatra::Application
end
def query_test(query)
uri = "http://localhost:4567/?query=#{URI::encode(query)}"
puts "uri=#{uri}"
get uri
puts last_response.body
assert_match(/^docs=/, last_response.body)
end
def test_john_doe
query_test("{ name: 'john doe'}")
end
def test_regexp
query_test("{ name: /.*john.*/, interests: [ 'fishing', 'golf' ]}")
end
end
ruby -I. myapp_test.rb
Run options:
# Running tests:
uri=http://localhost:4567/?query=%7B%20name:%20/.*john.*/,%20interests:%20[%20'fishing',%20'golf'%20]%7D
docs=[{"_id":{"$oid": "50e9e60029daeb0be1000001"},"name":"john doe","interests":["fishing","golf"]}]
.uri=http://localhost:4567/?query=%7B%20name:%20'john%20doe'%7D
docs=[{"_id":{"$oid": "50e9e60129daeb0be1000002"},"name":"john doe","interests":["fishing","golf"]}]
.
Finished tests in 0.065822s, 30.3850 tests/s, 60.7700 assertions/s.
2 tests, 4 assertions, 0 failures, 0 errors, 0 skips

Ruby RestClient converts XML to Hash

I need to send a POST request as an XML string but I get odd results. The code:
require 'rest_client'
response = RestClient.post "http://127.0.0.1:2000", "<tag1>text</tag1>", :content_type => "text/xml"
I expect to receive "<tag1>text</tag1>" as the parameter on the request server. Instead, I get "tag1"=>"text". It converts the XML to a hash. Why is that? Any way around this?
Try this:
response = RestClient.post "http://127.0.0.1:2000",
"<tag1>text</tag1>",
{:accept => :xml, :content_type => :xml}
I think you just needed to specify the ":accept" to let it know you wanted to receive it in the XML format. Assuming it's your own server, you can debug on the server and see the request format used is probably html.
Hope that helps.
Instead of using RestClient, use Ruby's built-in Open::URI for GET requests or something like Net::HTTP or the incredibly powerful Typhoeus:
uri = URI('http://www.example.com/search.cgi')
res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
In Typhoeus, you'd use:
res = Typhoeus::Request.post(
'http://localhost:3000/posts',
:params => {
:title => 'test post',
:content => 'this is my test'
}
)
Your resulting page, if it's in XML will be easy to parse using Nokogiri:
doc = Nokogiri::XML(res.body)
At that point you'll have a fully parsed DOM, ready to be searched, using Nokogiri's search methods, such as search and at, or any of their related methods.

An more elegant way to query MongoDB in Ruby?

I am fairly new to Ruby and MongoDB in particular. I use Mongo in a Ruby script to store and process thousands of Tweets in a collection. I would love to improve legibility and "rubyness" of the find command here:
require 'rubygems'
require 'mongo'
db = Mongo::Connection.new("localhost").db("db")
coll = db.collection("tweets")
cursor = coll.find({
'geo_enabled' => true,
'status.text' => { '$exists' => true },
'followers_count' => {
'$gte' => 10,
'$lt' => 100 }
})
cursor.each_with_index { |row,idx|
# do stuff
}
The mongodb query syntax drives me nuts! Is there a more elegant, ruby-like way to do a query?
You can use Mongoid, it has nice syntax for queries, much similar to that of ActiveRecord/ActiveRelation.

Resources