How to target something in an object like Xpath does? - ruby

I use Xpath to get some elements of an XML. Is there a similar way to obtain it for an object/hash?
I need get the value of a JSON object using some kind of selectors, which would need to be flexible enough because this JSON won't always be structured the same way.
Something like this is xpath would have been //data/children/*/title for instance.
Is there something similar for objects? I don't want to convert my object to an XML, it would bring other problems.

Ruby 2.7 introduced pattern matching, which might solve your problem. For example:
data = {
data: {
children: [
{
title: 'Find me'
},
{
title: 'I am wrong'
}
]
}
}
case data
in {data: {children: [{title: 'Find me'}, *rest]}}
puts 'found'
else
puts 'not found'
end
In this case, Ruby checks the data structure and prints 'ok' if {title: 'Find me'} is in children key.

Related

How can i sort an arrays of hashes in ruby

this is the code i tried to sort it by name,email,country,comments.first i tried sorting by names
array_of_hashes=[
{"Name"=>"Akash","Email"=>"akash85#gmail.com","Country"=>"India",'Comments'=>"9898984523"},
{"Email"=>"rahul#hotmail.com","Country"=>"Srilanka","Name"=>"Rahul"},
{"Country"=>"India", "Comments"=>"3455358782","Email"=>"veera#gmail.com","Name"=>"Veera"},
{"Name"=>"Akash","Country"=>"India", "Email"=>"akash37#yahoo.com", "Comments"=>"8898788932"}
]
puts array_of_hashes.sort_by { |element| element.keys(&:Name)}
but the displayed output is not as i expected,it prints the same which i mentioned above.
i expected to code the final output should be like this
Name Email Country Comments
Akash akash37#live.com India 8898788932
Akash akash85#gmail.com India 9898984523
Rahul rahul#hotmail.com Srilanka
Veera veera#gmail.com India 3455358782
Help me to resolve these.Thanks in advance!
You should look at what element.keys(&:Name) evaluates to in the block that you're passing to #sort_by. All methods in Ruby can be given a block, you can pass it even if the method doesn't use it. Hash#keys doesn't use the block so element.keys(&:Name) is the same as element.keys and you end up trying to sort by the array ['Name', 'Email', 'Country', 'Comments'].
If you want to sort by the name, say so:
hash.sort_by { |element| element['Name'] }
Keep in mind that your keys are strings so you want element['Name'] rather than element[:Name]. I'd also recommend that you don't call your array of hashes hash, that's a little confusing.
not_a_hash = [
{"Name"=>"Akash","Email"=>"akash85#gmail.com","Country"=>"India",'Comments'=>"9898984523"},
{"Email"=>"rahul#hotmail.com","Country"=>"Srilanka","Name"=>"Rahul"},
{"Country"=>"India", "Comments"=>"3455358782","Email"=>"veera#gmail.com","Name"=>"Veera"},
{"Name"=>"Akash","Country"=>"India", "Email"=>"akash37#yahoo.com", "Comments"=>"8898788932"}
]
sorted_values = not_a_hash.map{|h| h.values_at("Name", "Email", "Country", "Comments")}.sort

Using a Power Automate flow, how do I convert JSON array to a delimited string?

In Power Automate I am calling an API which returns this JSON:
{
"status":"200",
"Suburbs":[
{
"ID":"1000",
"Name":"CONCORD WEST",
"Postcode":"2138"
},
{
"ID":"1001",
"Name":"LIBERTY GROVE",
"Postcode":"2138"
},
{
"ID":"1002",
"Name":"RHODES",
"Postcode":"2138"
},
{
"ID":"3891",
"Name":"UHRS POINT",
"Postcode":"2138"
},
{
"ID":"1003",
"Name":"YARALLA",
"Postcode":"2138"
}
]
}
Using PA actions, how do I convert this JSON to a String variable that looks like this?:
"CONCORD WEST, LIBERTY GROVE, RHODES, UHRS POINT, YARALLA"
I figured out how to do this. I prefer not to use complex code-style expressions in Power Automate flows as I think they are hard to understand and hard to maintain so used standard PA actions where I could.
I parsed the JSON, then used "Select" to pick out the suburb names, then used concat() within a "for each" loop through the Suburbs array. I think that Compose could probably be used in the place of the concat() but stopped investigating once I'd found this solution.

Is there a way to properly drill down into a JSON response with random property names

I'm trying to test an API response where key values are randomized alphanumerics. This is making it difficult for me to drill down into the JSON response to get the data I want to test.
I am using SuperTest/Mocha/Chai. At this point I'm just trying to test to see if the property 'id', 'name', and 'pattern' exist, and to verify the values of those properties.
Unfortunately since the parent of those properties is a randomized value, i've been unable to access it.
I'm new to API testing in general, so I apologize if I'm not including some important information. Normally I would do something like this:
Example of expects I normally write:
end(function(err, res) {
expect(res.body).to.have.property('id');
expect(res.body.id).to.equal(0);
}
So far, the only way I've found to do it is to put response.text into a variable, then use split and splice to separate out the data I want. This is ugly and probably inefficient.
Example JSON I'm working with:
{ idTag1: 'randomValue',
idTag2:
{ 'randomValue':
{ id: 'an integer',
name: 'a basic string',
pattern: 'a basic string'
}
}
}

Is there an easier way to persist an object to db when using angular-meteor?

I really like meteor-angular, however, in the following code snippet, I think there is still friction when persisting changes back to the db. For example, in this code sample:
saveParty(name: string, description: string) {
Parties.update(this.selectedParty._id, {$set: {name: name, description: description}});
}
it is going to difficult to manually type "name: name, description: description" if there were a large number of fields.
Is it possible to do something like (kind of like what breezsjs does):
saveParty() {
Parties.save(this.selectedParty);
}
or better yet:
saveParty() {
this.selectedParty.Save();
}
Yes :)
Take a look at AngularMeteorCollection methods here - http://angular-meteor.com/api/AngularMeteorCollection#methods
AngularMeteorObject methods here - http://angular-meteor.com/api/AngularMeteorObject
and
And the examples at the bottom

Parsing JSON in Ruby (like XPATH)

I have a JSON document returned from a query to the Google Books API, e.g:
{
"items": [
{
"volumeInfo": {
"industryIdentifiers": [
{
"type": "OTHER",
"identifier": "OCLC:841804665"
}
]
}
},
{
"volumeInfo": {
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "156898118X"...
I need the ISBN number (type: ISBN_10 or ISBN_13) and I've written a simple loop that traverses the parsed JSON (parsed = json.parse(my_uri_response)). In this loop, I have a next if k['type'] = "OTHER" which sets "type" to "OTHER".
How do I best extract just one ISBN number from my JSON example? Not all of them, just one.
Something like XPath search would be helpful.
JSONPath may be just what you're looking for:
require 'jsonpath'
json = #your raw JSON above
path = JsonPath.new('$..industryIdentifiers[?(#.type == "ISBN_10")].identifier')
puts path.on(json)
Result:
156898118X
See this page for how XPath translates to JSONPath. It helped me determine the JSONPath above.
how about:
parsed['items'].map { |book|
book['volume_info']['industryIdentifiers'].find{ |prop|
['ISBN_10', 'ISBN_13'].include? prop['type']
}['identifier']
}
If you receive undefined method [] for nil:NilClass this means that you have an element within items array, which has no volume_info key, or that you have a volume with a set of industryIdentifiers without ISBN. Code below should cover all those cases (+ the case when you have volumeInfo without industry_identifiers:
parsed['items'].map { |book|
identifiers = book['volume_info'] && book['volume_info']['industryIdentifiers']
isbn_identifier = idetifiers && identifiers.find{ |prop|
['ISBN_10', 'ISBN_13'].include? prop['type']}['identifier']
}
isbn_identifier && isbn_identifier['identifier']
}.compact
If you happen to have the andand gem, this might be written as:
parsed['items'].map { |book|
book['volume_info'].andand['industryIdentifiers'].andand.find{ |prop|
['ISBN_10', 'ISBN_13'].include? prop['type']
}.andand['identifier']
}.compact
Note that this will return only one ISBN for each volume. If you have volumes with both ISBN_10 and ISBN_13 and you want to get both, instead of find you'll need to use select method and .map{|i| i[:identifier]} in place of .andand['identifier'].

Resources