Rubyist way to test for a hash key in an array - json

I am parsing some JSON which has been converted to Ruby data structures. I have records that look either like this:
"uros"=>[{"ure"=>"zip*less", "prs"=>[{"mw"=>"ˈzip-ləs", "sound"=>{"audio"=>"ziples01", "ref"=>"c", "stat"=>"1"}}]
or like this:
"uros"=>[{"ure"=>"gas chromatographic", "fl"=>"adjective"}]
I want to pull out the hash value for the key audio when it appears.
What is the clean way to test for the presence of said key in Ruby? Here are my attempts thus far. The variable entry represents the enclosing data structure:
if entry["uros"] != nil # Nope
#if entry["uros"]["prs"] != nil # Nope
#if not entry["uros"]["prs"]["sound"]["audio"].first.instance_of? nil # Nope
#if ! entry["uros"]["prs"].instance_of? nil # Nope
puts entry["uros"].first["prs"].first["sound"]["audio"]
end
The error message I get is either:
undefined method `first' for nil:NilClass (NoMethodError)
or conversely:
undefined method `[]' for nil:NilClass (NoMethodError)
How would you do this?

Hash has a method for checking presence of a key-value pair
if entry.key?('uros')
But problem with your code is you don't check for existence of the nested keys. You check for "uros", but then "prs" might not exist.
Here's a better version that allows nils at every step
audio = entry.dig('uros', 0, 'prs', 0, 'sound', 'audio')

You can use the safe navigation operator to search around the the data structure without getting a bunch of NoMethodErrors. The safe navigation operator will call the method, or return nil if called on nil.
audio = entry["uros"]
&.first
&.[]("prs")
&.first
&.dig("sound", "audio")
This might look funny, but remember that [] is just another method. If any part of that method chain returns nil, the whole thing will return nil.
entry["uros"]&.first is roughly equivalent to...
entry["uros"].first if entry["uros"] != nil

Related

Unable to unmarshal json into protobuf message

My problem is pretty much the opposite of this one: Unable to unmarshal json to protobuf struct field
I have a message with several nested messages of the following form:
message MyMsg {
uint32 id = 1;
message Attribute {
...
}
repeated Attribute attrs = 2;
message OtherAttribute {
...
}
OtherAttribute oAttr = 3;
...
}
Some external dependencies will send this message JSON form, which needs to then be unmarshalled into a go struct. When trying to use jsonpb like so, where resp is a *http.Response:
msg := &MyMsg{}
jsonpb.Unmarshal(resp.Body, msg)
The message is not fully decoded into the struct, i.e. some of the nested structs are missing. When the message is however decoded simply using encoding/json like so:
msg := &MyMsg{}
json.NewDecoder(resp.Body).Decode(msg)
All attributes are successfully decoded into the struct.
As jsonpb is the official package to (un)marshall between protobuf/json, I was wondering whether anyone has any idea as to why this type of behaviour could occur. Do the default behaviours for jsonpb and encoding/json differ in a way that would explain one being able to unmarshall and the other not? If so where would one configure the behaviour of jsonpb accordingly?
The default behaviour of encoding/json is the following:
Unknown fields are allowed, i.e. in case of a field not matching it is simply ignored without an error being raised.
Before it is ignored, the Decoder attempts to match the field without case sensitivity
The behaviour in point 1 can be replicated in jsonpb by using the Unmarshaller struct and setting the property AllowUnknownFields to true
var umrsh = jsonpb.Unmarshaler{}
umrsh.AllowUnknownFields = true
msg := &MyMsg{}
umrsh.Unmarshal(resp.Body, msg)
It does not seem to be possible to replicate the behaviour from point 2 within jsonpb.

How to process null value inside json string using lua?

I am using lua in asterisk pbx. I encounter following problem while processing json string.
json "null" value converted to function type in lua. why?
how to handle this scenario? because i am expecting nil because no value means null in json and nil means nothing in lua.
local json = require( "json" )
local inspect = require("inspect")
local myjson_str='{"Sms":{"key":"xxxxxxxxxxxxxxxxxxxxx","to":"{caller}","senderid":null,"type":"Simple","content":"Your request has been accepted in Previous Miss call. We get back to you very soon."}}'
local myjson_table = json.decode(myjson_str)
print(type(myjson_table["Sms"]["senderid"]))
print(myjson_table)
print(inspect(myjson_table))
print(json.encode(myjson_table))
out put for above is
function
table: 0xf5e770
{
Sms = {
content = "Your request has been accepted in Previous Miss call. We get back to you very soon.",
key = "xxxxxxxxxxxxxxxxxxxxx",
senderid = <function 1>,
to = "{caller}",
type = "Simple"
}
}
{"Sms":{"type":"Simple","key":"xxxxxxxxxxxxxxxxxxxxx","senderid":null,"content":"Your request has been accepted in Previous Miss call. We get back to you very soon.","to":"{caller}"}}
It is up to specific library to decide how to represent null value.
Using nil has its own problem because its not possible find either
original JSON has key with null value or there no such key at all.
So some libraries just return some unique value. Some provide
a way to pass this value like json.deconde(str, NULL_VALUE).
So answer is just read the doc/source of library you use.
Most likely it provide something like json.null value to check
either value is null. But function is really strange choice because
they have some undetermined rules of uniqueness.
Or try another library.
First of all, #moteus is right:
It is up to specific library to decide how to represent null value
If you're using the JSON library by Jeffrey Friedl the solution is to use a placeholder instead of null and serializing the table structure to a json string using designated encode options:
-- define a placeholder
NullPlaceholder = "\0"
-- use it in an internal table
tableStructure = {}
tableStructure['someNullValue'] = NullPlaceholder
-- pass the placeholder to the encode methode
encode_options = { null = NullPlaceholder }
jsonString = JSON:encode(tableStructure, nil, encode_options)
which leads to
{"someNullValue": null}

Why isn't exception handling built into the "dict get" command?

When dictionaries were first implemented and added to Tcl, why was the dict get command implemented in a way that allows an error to occur if an attempt is made to retrieve a value for a key that is not present in the dictionary?
This requires you to wrap the command in a catch statement every time you use it if you want to ensure that it is completely safe. It always seemed to me that a frequently used command like this would have some sort of exception handling built in.
It's a common design choice in Tcl (as well as some other languages). When a command like dict get (or, more commonly, open) fails, the program has to deal with it, which means it has to be alerted to the failure in some way.
The most common options is to have the failing command either
Return an out-of-domain value (such as null in languages that have it), or
Raise an exception.
(E.g. the lsearch command either returns an index value if successful and -1 if it fails (the first option). The dict get command either returns a value if successful and raises an exception if it fails (the second option).)
The first option isn't really practicable for dict get command, since there is no out-of-domain value. Any Tcl value could possibly be stored in a dictionary, so you can't look at the result of dict get and know that it has failed to find a value. The empty string is often used as a pseudo-null value in Tcl, but it's quite likely that empty strings are actual values in a dictionary.
So dict get raises an exception when it fails. It's not so bad. Exceptions have a lot of neat properties, such as taking control directly to the nearest enclosing handler regardless of how many stack levels it has to unwind.
(It's not really possible to handle all exceptions inside the command: a handler must know how to deal with the error, and dict get can't know that.)
Either way, a command that can fail needs to be wrapped in some kind of check. If the foo command is used to get a resource that might not be available and there is no sensible default, the code calling it must look either like this:
if {[set x [foo]] ne {BAD_RETURN_VALUE}} {
# use the resource
} else {
# deal with failure
}
or like this:
try {
foo
} on ok x {
# use the resource
} on error {} {
# deal with failure
}
or like this (if a predicate function predicting if foo will succeed exists):
if {[foo-will-succeed]} {
set x [foo]
# use the resource
} else {
# deal with failure
}
Which is about as much bother in each of the cases. Since out-of-domain values are rare in Tcl and error handling is so versatile, the predicate or exception strategies are usually favored.
patthoyts has already showed one way to add a error-suppressing getter function to the dict ensemble. Another relatively lightweight invocation is
set foo [try {dict get $bar xyzzy} on error {} {}]
which returns the result of the dict get call if successful and the empty string if not, and squashes any errors raised.
set foo [try {dict get $bar xyzzy} on error {} {return 42}]
This invocation sets a default return value to use on failure.
If the invocation is still bothersome, it can be made into a command:
proc dictget args {
set default {}
if {[lindex $args 0] eq {-default}} {
set args [lassign $args - default]
}
try {
dict get {*}$args
} on error {} {
set default
}
}
The synopsis for this is
dictget ?-default value? ?dictionaryValue? ?key ...?
Documentation: dict, if, proc, return, set, try
The dict command is implemented as an ensemble. This means you can very easily extend it yourself to achieve this. I like to call this dict get? and have it return an empty value if the key does not exist. We can add this new subcommand as follows:
proc ::tcl::dict::get? {dict key} {
if {[dict exists $dict $key]} {
return [dict get $dict $key]
}
return
}
namespace ensemble configure dict \
-map [linsert [namespace ensemble configure dict -map] end get? ::tcl::dict::get?]
As you can see this trivially wraps up the dict exists call with the dict get call but presents it as a builtin part of the dict command due to the ensemble update. In use it looks like this:
if {[dict get? $meta x-check-query] eq "yes"} {
... do stuff ...
}
(This can be seen in action in the Tcl test suite httpd test server code.)
I guess that is why we are provided with the dict exists command.
You might be expecting dict get to return empty string of that key element doesn't exists. But, having implementation like them will cause problem if the actual value of any key itself is an empty string.
% set demo {id {} name Dinesh}
id {} name Dinesh
% dict get $demo id
% dict get $demo age
key "age" not known in dictionary
%
Use dict exists if you want to skip catch.

Runtime error handling in Swift

I am fully aware that Swift doesn't have a try/catch mechanism to catch exceptions (OK, Swift 2.0 now supports them). I also understand that many API methods return a NSError that will be filled with an error object if something goes wrong. So please don't point me to this question: Error-Handling in Swift-Language
But this still doesn't explain how to react to runtime errors in your own code, like array-out-of-bounds accesses or force-unwrapping an optional value that is nil. For example:
var test: String?
test = nil
println(test!) //oops!
or
var arr = [0,1,2]
for i = 0...3 {
println(arr[i]) //oops!
}
Every programmer makes such mistakes occasionally and there should be a way to at least log them for later analysis. While debugging, Xcode can show us those, but what if this happens to an end-user or beta-tester? In pure C there is signal handling and it could be used in Objective-C as well. Is there something like this in Swift? A centralized callback entered just before the app dies?
Update:
Let me rephrase the question: in a large project, it is not feasible to manually check for the above errors on every loop and force-unwrapping. When a runtime error does happen eventually, is there a callback like Objective C's segfault handling or NSSetUncaughtExceptionHandler that will get called so that the error can be logged/e-mailed together with a stacktrace of the crash?
Edit: This answer is not updated with swift 2.0. As swift now has error handling I have not updated the below answer. Some aspect of error handling will be updated in future with swift 3.0. You can follow this answer Error-Handling in Swift-Language
Swift is made to be typeSafe language.It get error at compile time rather than waiting to cause at runtime.
In first example you are using Optional.
var test: String?
First understand meaning of optional.When you specifying optional you are saying it could be nil or have no value.Now when you unwrapping test you are saying i know this value is not nil.Please unwrap it i am sure about that.So its your responsibility to see where it nil.If you are not sure about that than you should use optional binding here.When you are unsure about value always use if condition while unwrrapping
if let notNilTest = test {
//use notNilTest
}
else{
//handle error
}
In second example it should make sense to have the runtime exception handling but you can easily get this with if condition having count.So in second example as developer you should use if condition to get count of array.
From swift guide:
If you try to use subscript syntax to retrieve or set a value for an
index that is outside of an array’s existing bounds, you will trigger
a runtime error. However, you can check that an index is valid before
using it, by comparing it to the array’s count property. Except when
count is 0 (meaning the array is empty), the largest valid index in an
array will always be count - 1, because arrays are indexed from zero.
They clearly mention about this and you should take care of these things to make your code less buggy.Some things they have provided and we should know about how to use these things.
Consider using a guard statement instead of multiple if lets.
var arr = [0,1,2]
for i = 0...3 {
Guard arr[i] != nil else {
Continue
}
println(arr[i]) //oops!
}
Or instead of
if let x = some value {
If let y = someOtherVal {
If let z = yetanotherVal {
Product = x * y* z
}
}
}
Is not nearly as neat as:
Let x = someVal
Let y = someOtherVal
Let z = yetAnotherVal
Guard x != nil,
y != nil,
z != nil
Else {
Return
}
Product = x * y * z

A JSON text must at least contain two octets

I received this error, and I couldn't find any reasonable answer to this question, so I thought I'd write a summary of the problem.
If you run this snippet in irb:
JSON.parse( nil )
You'll see the following error:
TypeError: can't convert nil into String
I was kind of expecting the function to return nil, and not a TypeError. If you convert all input using to_s, then you'll see the octet error:
JSON::ParserError: A JSON text must at least contain two octets!
That's just fine and well. If you don't know what an octet is, read this post for a summary and solution:
What is a JSON octet and why are two required?
Solution
The variable you're passing in is an empty string. Don't attempt to use an empty string in the JSON.parse method.
Question
So, now I know the cause of the error, what pattern should I use to handle this? I'm a bit loathe to monkey patch the JSON library to allow nil values. Any suggestions would be greatly appreciated.
parsed = json && json.length >= 2 ? JSON.parse(json) : nil
But really the library should be able to handle this case and return nil. Web browsers with built-in JSON support seem to work just like you expect after all.
Or to do it with a only slightly intrusive mini patch:
module JSON
def self.parse_nil(json)
JSON.parse(json) if json && json.length >= 2
end
end
parsed = JSON.parse_nil(json)
data.presence && JSON.parse(data)
JSON.parse(data.presence || '{}')
According to json.org
JSON is built on two structures:
A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.
So, minimum two octets(8 bits) required at the top level would be {} or []
IMO, the best solution would be to make sure the argument to JSON.parse is either an strigified object or a strigified array. :-)
hash = JSON.parse(json) rescue {}
array = JSON.parse(json) rescue []
string = JSON.parse(json) rescue ''