I am using the Oauth-Ruby gem, and I am able to fetch particular resources by doing stuff like:
#photos = #access_token.get('/photos.xml')
I am wondering how I can pass parameters to that get. I have tried doing:
#photos = #access_token.get('/photos.xml', :parameters => {:id => 1} )
But no luck. I can't find anything in the docs. Anyone knows?
This is source of Oauth get method
# File lib/oauth/tokens/access_token.rb, line 23
def get(path, headers = {})
request(:get, path, headers)
end
As you can see, it does not support parameters. If you are on rails, there is a method .to_query on a hash
{a: "b", c: "d"}.to_query #=> "a=b&c=d"
If not, you can use something like addressable gem
Addressable::URI.form_encode({a: "b", c: "d"}) #=> "a=b&c=d"
Related
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.
I am sending a multidimensional array using the post method given by the Rack::Test like
post "#{url}.json",:data => [["Company","Website"],["this is the dummy text, with,comma","www.technology.com"],["some company","www.url.com"]]
But in my controller when check my params params[:data] i am receiving it as a single dimensioned array ["Company", "Website", "this is the dummy text, with comma", "www.technology.com", "some company", "www.url.com"]
But i want it to retain it's property as a multi-dimensional array. I need help to do this.
The Rack::Test methods all have the same signature... and the second param is a hash of params
i.e.
post '/path', params={}, rack_env={}
This is because they're just URL params - which are typical key/value structures (i.e. a hash)
Why do you need it to be a multi-dimensional array?
EDIT: oh, I get it - you have a single hash with one key (:data)
If it's still causing you grief you could explicitly call to_param in there
ruby-1.9.2-p180 :003 > h = {:data => [["Company","Website"],["this is the dummy text, with,comma","www.technology.com"],["some company","www.url.com"]]}
=> {:data=>[["Company", "Website"], ["this is the dummy text, with,comma", "www.technology.com"], ["some company", "www.url.com"]]}
ruby-1.9.2-p180 :004 > h.to_param
=> "data[][]=Company&data[][]=Website&data[][]=this+is+the+dummy+text%2C+with%2Ccomma&data[][]=www.technology.com&data[][]=some+company&data[][]=www.url.com"
A workaround if you really need nested arrays is to change the request content type to JSON:
post url, JSON.dump([[1, 2], [3, 4]]), { "CONTENT_TYPE" => "application/json" }
This will correctly send a nested array through to the rack app.
Neither of the above worked too well for me but this did (see my original answer here).
The problem is body is sent as application/x-www-form-urlencoded by default, which doesn't handle multi-dimensional arrays too well. You can send it as application/json, but Sinatra probably won't merge the data into the request params. I use a middleware from rack-contrib which parses a json body from a POST request and merges it for you:
# Gemfile
`gem 'rack-contrib'`
then config.ru:
require 'rack/contrib'
require './app'
use Rack::PostBodyContentTypeParser
run Sinatra::Application
This won't be used in testing by default, but you can specify it:
# spec_helper.rb
OUTER_APP = Rack::Builder.parse_file("config.ru").first
module RSpecMixin
include Rack::Test::Methods
def app
OUTER_APP # typically this might just be Sinatra::Application
end
end
RSpec.configure do |config|
config.include RSpecMixin
end
And example usage:
it 'is ok' do
post '/', { key: 'value' }.to_json, { 'CONTENT_TYPE' => 'application/json' }
expect(last_response).to be_ok
end
I'd like to do some sanitization of query params.
I parse the query with CGI.parse, then I delete some params, but I can't find an opposite method to build the query.
I don't really want to do something like
params.map{|n,v| "#{CGI.escape n}=#{CGI.escape v.to_s}"}.join("&")
There's got to be a simpler way. Is there?
There is a nice method in URI module:
require 'uri'
URI.encode_www_form("q" => "ruby", "lang" => "en") #=> "q=ruby&lang=en"
If you're using Rails (or don't mind pulling in ActiveSupport), then you can use to_param (AKA to_query):
{ :a => '&', :b => 'Where is pancake house?', :c => ['an', 'array'] }.to_param
# a=%26&b=Where+is+pancake+house%3F&c%5B%5D=an&c%5B%5D=array
to_param handles arrays a little differently than your version though, it'll put out c[]=an&c[]=array rather than just c=an&c=array.
While there's no better answer, I'll put up the method which I'm using now.
def build_query(params)
params.map do |name,values|
values.map do |value|
"#{CGI.escape name}=#{CGI.escape value}"
end
end.flatten.join("&")
end
I am not sure if the following is a simplification, but it avoids expanding the (key, value) pairs of a hash.
params.map{|qq| qq.map{|q| CGI.escape(q)}.join('=')}.join('&')
I have a .cfg file with the following data:
*.*.key_val = {
key1= "value1";
key2 = "value2";
key3 = "value3";
};
I want to read this file and store the key value pairs in a hash #var[key][val].
How it can be done?
THIS cfg you may parse in such way:
read file using File#read
convert text into 2-dimentional array using String#scan and regex
convert array into hash using Hash[]
text = File.read('your.cfg')
# => "*.*.key_val = {\n key1= \"value1\";\n key2 = \"value2\";\n key3 = \"value3\";\n};"
data = text.scan(/(\S+)\s*=\s*"([^"]+)/)
# => [["key1", "value1"], ["key2", "value2"], ["key3", "value3"]]
#var = Hash[data]
# => {"key1"=>"value1", "key2"=>"value2", "key3"=>"value3"}
Or just:
#var = Hash[File.read('your.cfg').scan(/(\S+)\s*=\s*"([^"]+)/)]
I'd strongly recommend transferring the configuration to something like YAML. It's made to be easy to understand, flexible, universally implemented, well documented, both as a standard and as a part of the core library, and easy to understand. (Yes, I said it twice on purpose.)
My YAML files load into Ruby as a Hash when I do something like:
require 'yaml'
config = YAML.load_file('/path/to/config/file')
I'll create the initial template for the configuration file in Ruby, as a Hash, then serialize it and write it to disk. That way I know what's on the disk is exactly the way YAML wants it to be and helps me avoid that "it won't load because either the data is wrong or the code is wrong" quandary.
# A simple round-trip (load and dump) of an object.
require 'yaml'
test_obj = {
'foo' => 'bar',
'one_two_three' => [1, 2, 3],
'hash' => {'another' => 'hash'}
} #=> {"foo"=>"bar", "one_two_three"=>[1, 2, 3], "hash"=>{"another"=>"hash"}}
File.open('./config.yaml', 'w') { |fo| fo.puts YAML::dump( test_obj ) } #=> nil
ruby_obj = YAML::load_file( './config.yaml' ) #=> {"foo"=>"bar", "one_two_three"=>[1, 2, 3], "hash"=>{"another"=>"hash"}}
ruby_obj == test_obj #=> true
require 'pp'
pp ruby_obj
{"foo"=>"bar", "one_two_three"=>[1, 2, 3], "hash"=>{"another"=>"hash"}}
pp test_obj
{"foo"=>"bar", "one_two_three"=>[1, 2, 3], "hash"=>{"another"=>"hash"}}
You should try out the 'parseconfig' gem: https://rubygems.org/gems/parseconfig/
gem install parseconfig
Here's a sample how to use this gem:
require 'rubygems'
require 'parseconfig'
my_config = ParseConfig.new('your_file.cfg')
puts my_config.get_value('key_val')
Good luck and have fun learning Ruby. :)
EDIT
As Glenux said this is only for simple configuration files. I'll check if I can find anything else.
EDIT 2
I can't find a gem or something to parse a cfg file like in your example. I guess your only option is to write a parser yourself (like Nakilon did) or use something like YAML instead. Good luck anyway. :)
The parseconfig class is only intended for simple configuration files !
It accepts files of the format "param = value" (cf http://www.5dollarwhitebox.org/drupal/projects#rb-parseconfig ) but it will not parse the *.*.key_val = { and } thing.
Is the configuration file yours or generated/used by a third-party software? If it is yours, it may be wiser to use an other configuration file format (JSON, Ini, YAML, etc).
Wanted to mention this ruby library that can help you transfer configuration between JSON, YAML or Windows Ini file formats:
https://github.com/kigster/dupervisor
The use case is to move the configuration to YAML, but be able to generate whatever the format is needed by the software – in the case of this gem – it's supervisord's INI file format.
I'm doing a proof of concept thing here and having a bit more trouble than I thought I was going to. Here is what I want to do and how I am currently doing it.
I am sending my Sinatra app a json file which contains the simple message below.
[
{
title: "A greeting!",
message: "Hello from the Chairman of the Board"
}
]
From there I have a post which I am using to take the params and write them to sqlite database
post '/note' do
data = JSON.parse(params) #<---EDIT - added, now gives error.
#note = Note.new :title => params[:title],
:message => params[:message],
:timestamp => (params[:timestamp] || Time.now)
#note.save
end
When I send the message the timestamp and the id are saved to the database however the title and message are nil.
What am I missing?
Thanks
Edit:
Now when I run my app and send it the json file I get this error:
C:/Users/Norm/ruby/Ruby192/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread'
TypeError: can't convert Hash into String
Edit 2: Some success.
I have the above json in a file call test.json which is the way the json will be posted. In order to post the file I used HTTPClient:
require 'httpclient'
HTTPClient.post 'http://localhost:4567/note', [ :file => File.new('.\test.json') ]
After thinking about it some more, I thought posting the file was the problem so I tried sending it a different way. The example below worked once I changed n my post /note handle to this:
data = JSON.parse(request.body.read)
My new send.rb
require 'net/http'
require 'rubygems'
require 'json'
#host = 'localhost'
#port = '4567'
#post_ws = "/note"
#payload ={
"title" => "A greeting from...",
"message" => "... Sinatra!"
}.to_json
def post
req = Net::HTTP::Post.new(#post_ws, initheader = {'Content-Type' =>'application/json'})
#req.basic_auth #user, #pass
req.body = #payload
response = Net::HTTP.new(#host, #port).start {|http| http.request(req) }
puts "Response #{response.code} #{response.message}:
#{response.body}"
end
thepost = post
puts thepost
So I am getting closer. Thanks for all the help so far.
Sinatra won't parse the JSON automatically for you, but luckily parsing JSON is pretty straightforward:
Start with requiring it as usual. require 'rubygems' if you're not on Ruby 1.9+:
>> require 'json' #=> true
>> a_hash = {'a' => 1, 'b' => [0, 1]} #=> {"a"=>1, "b"=>[0, 1]}
>> a_hash.to_json #=> "{"a":1,"b":[0,1]}"
>> JSON.parse(a_hash.to_json) #=> {"a"=>1, "b"=>[0, 1]}
That's a roundtrip use to create, then parse some JSON. The IRB output shows the hash and embedded array were converted to JSON, then parsed back into the hash. You should be able to break that down for your nefarious needs.
To get the fields we'll break down the example above a bit more and pretend that we've received JSON from the remote side of your connection. So, the received_json below is the incoming data stream. Pass it to the JSON parser and you'll get back a Ruby data hash. Access the hash as you would normally and you get the values:
>> received_json = a_hash.to_json #=> "{"a":1,"b":[0,1]}"
>> received_hash = JSON.parse(received_json) #=> {"a"=>1, "b"=>[0, 1]}
>> received_hash['a'] #=> 1
>> received_hash['b'] #=> [0, 1]
The incoming JSON is probably a parameter in your params[] hash but I am not sure what key it would be hiding under, so you'll need to figure that out. It might be called 'json' or 'data' but that's app specific.
Your database code looks ok, and must be working if you're seeing some of the data written to it. It looks like you just need to retrieve the fields from the JSON.