I'm new to Ruby and trying to learn the ropes. I have an object returned from a call to the Twitter API. I'd like to loop through the :users below and be able to print out their different attributes... like :id, :screenname, etc.
BTW, these are all followers on twitter. So the object is called "Followers" and this is what I'm calling to get the inspect... "followers.inspect"
The gist of the followers.inspect is here:
https://gist.github.com/anonymous/7966898/raw/938a0048d08f44415229b98a1adef96c4946ce8d/gistfile1.txt
My problem is that I'm having a hard time figuring out how this .inspect print out matches up to what I should be looking for.
So the code I've written to try to work through this is...
followers.users.each do |i|
puts "#{i.name} has user id #{i.id_str}"
end
The error I'm getting is that there is no method called users.
Sorry, I'm sure this is a very simple question but have just gotten stuck!
As far as I can quickly see, the object you have contains a hash #attrs with a key :users.
So, it should be something like:
followers.attrs[:users].each do |i|
puts "#{i.name} has user id #{i.id_str}"
end
Maybe you'll also need to use i[:name] since all those users are also hashes, not objects with methods, but my Ruby is a bit rusty, so I don't know if those methods are automatically available when a key is present in a hash.
Anyway: {:key => "value"} in inspect means that it's a hash with keys and values, that you access like: nameofhash[:key]
[{:key => "value"},{:key => "value"}] means it's a array with two seperate hashes.
Related
I'm still new(ish), to POM, but I've found the syntax and general structure quite strong, so now I'm looking to advanced techniques.
I have a dynamic page, and for each of the sections I am running the following code/psuedo code
if has_SECTVAR1?
$LOG.info("Stuff")
end
if has_SECTVAR2?
$LOG.info("Stuff")
end
What I want to do is something like this.
ALLSECTIONARRAYS.each do |var|
if has_var?
$LOG.info("Stuff")
end
end
Any thoughts?
You can get an array of element names using #mapped_items. The more interesting part is checking if those exist on the page by calling #has_element?.
The abstract version of what you want to do is call a method on an object given its name as a string. To do this, use #send:
MyObject.send("method_name", *args)
Or in your case:
MyPage.send("has_element?")
Finally, to iterate over all elements:
MyPage.mapped_items.each do |item|
if MyPage.send("has_#{item}?")
$LOG.info("Stuff")
end
end
Unfortunately I'm needing to interact with a Soap API. If that's not bad enough, the API has parameter ordering turned on which means, regardless of the fact it's XML, it must be structured in the correct element order.
I'm using Savon so I'm building an ordered hash. However after some refactoring, the real calls stopped working whilst all my tests continued to pass. A typical test looks like this:
it 'should receive correctly ordered hash' do
example_id = 12345789
our_api = Example::ApiGateway.new()
params = {:message=>{'ApiKey' => api_key, 'ExampleId' => example_id}}
Savon::Client.any_instance.should_receive(:call).with(:get_user_details, params).and_return(mocked_response())
our_api.get_user(example_id: example_id)
end
The hash compare totally does not care about the order of the keys so this test passes regardless of the actual hash order received. I'd like the just grab the parameters that the call method receives and then I could compare the ordered keys of each hash but I con't find how to do this.
How do I make sure that the Savon call receives the message hash in the correct order?
So in the next google I found the answer. should_receive can take a block, so I can rebuild my test as
it 'should receive correctly ordered hash' do
example_id = 12345789
our_api = Example::ApiGateway.new()
params = {:message=>{'ApiKey' => api_key, 'ExampleId' => example_id}}
Savon::Client.any_instance.should_receive(:call){ |arg1, arg2|
arg1.should eq(:get_user_details)
#Ensure order here manually
arg2[:message].keys.should eq(params[:message].keys)
mocked_response()
}
our_api.get_user(example_id: example_id)
end
Now my tests will break as expected when the keys get messed with and I can rack up yet more hours to working around other peoples's fragile code...
I am new to Ruby and had a quick question.
I am trying to get all of the posts from a user's timeline, so I figured I would need to do a user_timeline api call to twitter and then filter out the posts manually. Then, while reading the Ruby Twitter documentation, I found this:
puts Twitter.user_timeline("twitter_handle").first.text
...and that will return the post already parsed out.
Is there a way to get more than just the first post automatically parsed out like that, or is that just an array method for the first and last object in the array?
Thanks
It looks like user_timeline just returns an array, so you ought to be able to use Ruby's normal array methods with it.
Twitter.user_timeline("twitter_handle").each do |tweet|
puts tweet
end
You need to iterate over each object.
Twitter.user_timeline("twitter_handle").each do |tweet|
puts tweet.text
end
The first and last methods are just convenience methods on arrays.
As you can see from source, Twitter::Client#user_timeline returns array from 20 most recent Twitter::Status, so that you can use up to 20 parsed records.
def partial(template, *args)
options = args.extract_options!
options.merge!(:layout => false)
if collection = options.delete(:collection) then
collection.inject([]) do |buffer, member|
buffer << erb(template, options.merge(:layout =>
false, :locals => {template.to_sym => member}))
end.join("\n")
else
erb(template, options)
end
end
This method has no docs. It seems to be some way of letting you add additional features to partial rendering in an erb template.
How does this Ruby code work?
I don't care as much about the role this plays in a web framework. I just would like to understand what's going on in terms of Ruby syntax.
It works much like doing render :partial in Rails — it takes a partial and a list of options (e.g. a collection of objects to render using the partial) and renders the partial with those options. Except this method appears to have ERb hardcoded in. If this is from Rails, I think this must be a very old method that isn't meant for use but hasn't yet been removed (maybe for compatibility with something or another).
The options.merge!(:layout => false) is effectively like doing options[:layout] = false.
options.delete(:collection) deletes the entry for ":collection" from the options hash and returns it if it exists. If there wasn't a collection entry, it returns nil, so the associated if-block won't run. If there is a collection, it renders the partial for each element of the collection and returns the accumulated result of rendering all of them. If there is not a collection, it just renders the partial with the options specified.
To understand this, you need to understand the docs on these methods:
extract_options!
Enumerable/Array: merge, merge!, inject, join, delete
Once you understand those, there's nothing tricky about the syntax here. You should be able to read it straight through.
Something in particular?
So I need to access this service from my rails app. I'm using soap4r to read the WSDL and dynamically generate methods for accessing the service.
From what I've read, I should be able to chain methods to access the nested XML nodes, but I can't get it to work. I tried using the wsdl2ruby command and read through the generated code. From what I can tell, the soap library is not generating these accessor methods. I'm pretty new to ruby, so I don't know if I'm just missing something?
I know when I inspect the element, I can see the data I want. I just can't get to it.
For instance if I use the following code:
require "soap/wsdlDriver"
wsdl = "http://frontdoor.ctn5.org/CablecastWS/CablecastWS.asmx?WSDL"
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
response = driver.getChannels('nill')
puts response.inspect
I get the following output:
ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}binding
ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}operation
ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}body
ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}address
#<SOAP::Mapping::Object:0x80b96394 {http://www.trms.com/CablecastWS/}GetChannelsResult=#<SOAP::Mapping::Object:0x80b96178 {http://www.trms.com/CablecastWS/}Channel=[#<SOAP::Mapping::Object:0x80b95f5c {http://www.trms.com/CablecastWS/}ChannelID="1" {http://www.trms.com/CablecastWS/}Name="CTN 5">, #<SOAP::Mapping::Object:0x80b9519c {http://www.trms.com/CablecastWS/}ChannelID="2" {http://www.trms.com/CablecastWS/}Name="PPAC 2">, #<SOAP::Mapping::Object:0x80b94620 {http://www.trms.com/CablecastWS/}ChannelID="14" {http://www.trms.com/CablecastWS/}Name="Test Channel">]>>
So the data is definitely there!
Here is the code generated by wsdl2ruby for the method being used above:
# {http://www.trms.com/CablecastWS/}GetChannels
class GetChannels
def initialize
end
end
# {http://www.trms.com/CablecastWS/}GetChannelsResponse
# getChannelsResult - ArrayOfChannel
class GetChannelsResponse
attr_accessor :getChannelsResult
def initialize(getChannelsResult = nil)
#getChannelsResult = getChannelsResult
end
end
Sorry for the long post, I figured the more info the more likely someone can point me in the right direction.
Thanks
-ray
Answer
require "soap/wsdlDriver"
wsdl = "http://frontdoor.ctn5.org/CablecastWS/CablecastWS.asmx?WSDL"
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
response = driver.getChannels('nill')
for item in response.getChannelsResult.channel
puts item.name
puts item.channelID
end
How I got the Answer
You can figure out the methods of response via
response.methods
This will get you a long list of methods that are hard to sort through, so I like to subtract out the generic methods. Ruby lets you subtract arrays.
response.methods - Object.new.methods
Using this technique, I found the getChannelsResult method for response. I repeated the process
resonse.getChannelsResult.methods - Object.new.methods
I found the channel method for its result. Again!
response.getChannelsResult.channel.methods - Object.new.methods
This returned a bunch of methods including: sort, min, max etc. So I guessed Array. A simple confirmation was in order
response.getChannelsResult.channel.class
Sure enough it returned Array. To make life simple, I just worked with the first item of the array to get its methods
response.getChannelsResult.channel.first.methods - Object.new.methods
Whoalla, I found two more methods "name" and "channelID"