JSON in Ruby
-
All right, I wasn't aware Yajl isn't able to work with arbitrary objects. I was only using it to encode/decode hashes with simple values and arrays.
-
Hi guys,
I need some help. I have run into problems creating a json encoding where a string contains a single quote char. e.g. "Betty's pie shop"
somehow ruby creates a new char which replaces the y and the '. You can see this by executing the following command:
puts "Betty's pie shop"
and I get
Betts pie shops pie shop
if you past this into an editor that supports UTF8 you see that a special char has been added into where the y and ' was. Also note that the last bit of the string is now duplicated.
I can escape it, but this is then not a valid json string as json does not allow you to escape the ' char.
-
May be your encoding... only fails with single quotes here
> puts "Betty's pie shop" Betty's pie shop nil > p "Betty's pie shop" "Betty's pie shop" nil > print "Betty's pie shop\n" Betty's pie shop nil > print 'Betty's pie shop\n' Error; #<SyntaxError; (eval); compile error (eval); parse error, unexpected tIDENTIFIER, expecting $ print 'Betty's pie shop\n' ^> (eval)
john
-
@myhand said:
... somehow ruby creates a new char which replaces the y and the '. You can see this by executing the following command:
puts "Betty's pie shop"
and I get:
%(#008000)[>> Betts pie shops pie shop]
At the SketchUp Ruby Console:
` puts "Betty's pie shop"
>> Betty's pie shopputs "Betty's pie shop".inspect()
>> "Betty's pie shop"puts "Betty's pie shop".inspect().inspect()
>> ""Betty's pie shop""` -
s = %q(Dan's friggin' advice, "Hey, use Ruby's % lowercase 'q' interpretive delimiter. It's a great help when your bleepin' strings have "'" and '"' characters in them!")
%Q
and%
is a double-quoted string. You can choose any 2 delimeters you want.name = %$MyHand$
str = %q{I want some quotes right "HERE"! Let's go.}
-
@driven said:
May be your encoding... only fails with single quotes here
johnThought so too initially. But I got the same results by typing straight into the Sketchup Ruby console... Can you set encoding at the Sketchup level?
-
@dan rathbun said:
At the SketchUp Ruby Console:
` puts "Betty's pie shop"
>> Betty's pie shopputs "Betty's pie shop".inspect()
>> "Betty's pie shop"puts "Betty's pie shop".inspect().inspect()
>> ""Betty's pie shop""`This works for me today on my work PC. So must be something specific with my Sketchup installation/version at home. Both are Version 8 out of the box installations on Windows. The one that corrupts the "'" char is the Pro addition, while the one at work is the Standard edition.
-
@dan rathbun said:
s = %q(Dan's friggin' advice, "Hey, use Ruby's % lowercase 'q' interpretive delimiter. It's a great help when your bleepin' strings have "'" and '"' characters in them!")
%Q
and%
is a double-quoted string. You can choose any 2 delimeters you want.name = %$MyHand$
str = %q{I want some quotes right "HERE"! Let's go.}
Thank you Dan, I will give this a go tonight. As you might have guessed though the actual string I am having problems with (not the pie shop one ) is ComponentDefinition name field. Something like "Bath 6'x34"x54"". So I never actually input the string, I am just reading it. So I am not sure how I will use the above technique to step around the problem. Will have to give it some thought.
-
Disable ALL plugins and libraries, (Sketchup::plugins_disabled=true, close SketchUp and restart,) then try again ...
If it works, then you've installed a plugin that changes the
String
base class. A very big no-no, in a shared Ruby environment, such as SketchUp embedded Ruby (or DoubleCAD XT embedded Ruby, etc.)In a normal "system" Ruby script, changing a base class doesn't matter because (99% of the time,) a script runs in it's own temporary Ruby process, finishes, and the Ruby process exits.
So.. the most likely culprit would be a library that is written to run temporarily in "system" Ruby, such as
Yajl
, or the standardJSON
library, that changes theString
class, or the global methods in mixin moduleKernel
(such asputs
,) or even stream classes, likeIO
.Encoding. It is set to UTF-8 by SketchUp just after it loads the interpreter. It should stay that way. Changing it via
$KCODE
is not a good idea as that (editable) feature has been removed in newer Ruby versions. (You'd just set your code up to fail in a newer SketchUp version if it distro's with Ruby v1.9.x) -
@myhand said:
This works for me today on my work PC. So must be something specific with my Sketchup installation/version at home. Both are Version 8 out of the box installations on Windows. The one that corrupts the "'" char is the Pro addition, while the one at work is the Standard edition.
Do you have the SketchUp Developer Tools installed? (https://github.com/thomthom/sketchup-developer-tools) Might be that it's interfering.
Try with just your plugin installed.
-
Thanks guys, I will give this a go tonight. Yes I do have the SketchUp Developer Tools installed.
-
@myhand said:
... is
ComponentDefinition
name field. Something like "Bath 6'x34"x54"".OK.. yea that reminds me. We have similar problems with SketchUp's formatted Length strings when saving things into the registry with
Sketchup::write_default()
andSketchup::read_default()
methods.There are some topics on that and using
gsub()
andtr()
before writing values.
The situation is similar because we also get these values with embedded single quotes from the application. -
@thomthom said:
@myhand said:
This works for me today on my work PC. So must be something specific with my Sketchup installation/version at home. Both are Version 8 out of the box installations on Windows. The one that corrupts the "'" char is the Pro addition, while the one at work is the Standard edition.
Do you have the SketchUp Developer Tools installed? (https://github.com/thomthom/sketchup-developer-tools) Might be that it's interfering.
Try with just your plugin installed.
Yup it was the SketchUp Developer Tools. Disabling that fixed the problem thanks.
-
OK, with the single quote now working, I have run into the next (and hopefully the last) problem. It appears as if the
WebDialog.execute_script
method strips all \ characters from its arguments as it passes it into JavaScript. I think it is because it does a eval() call on the JS.
e.g.
js_command = "material_maintenance.Sketchup.callUI(\"a string >\\< with a \\\" in the middle\")"; puts "js_command = #{js_command}";
produces this in the Ruby console:
js_command = material_maintenance.Sketchup.callUI("a string >\< with a \" in the middle")
and this when you print the parameter to the callUI function as it hits JS.
a string >< with a " in the middle
replacing js_command with
js_command = "material_maintenance.Sketchup.callUI(\"a string >\\u005c\\u0022< with a \\u005c\\u0022 in the middle\")"
works and produces the desired output in JS
a string >\"< with a \" in the middle
but this feels a bit clunky. Any other ideas?
-
- You need to escape \ characters in the double-quoted javascript code that you want to bring into the webdialog (this first escaping is what makes a valid Ruby string).
%(#000000)["alert('C:\users')"] # bad Ruby string
%(#000000)["alert('C:\\users')"] # good Ruby string
- In the webdialog, the string arrives written in a script element. As always, the same escaping rules apply again:
%(#000000)[alert('C:\users')] // bad JavaScript code
%(#000000)[alert('C:\\users')] // good JavaScript code
=> So finally this means we need double escaping on the Ruby side!
%(#000000)["alert('C:\\\\users')"] # Ruby string
P.S: SketchUp does not offer error handling for syntax errors in the Ruby-to-JavaScript string. Assuming my js contains user generated data with unknown characters, or is broken (truncated), we will definitely get a popup about "Syntax Error" that we cannot suppress and handle in other ways. In order to get control of such errors, we could send the code as a JavaScript string and eval() it:
%(#000000)[webdialog.execute_script("try{eval(\"}bad_$yn7aX{\")}catch(e){}")]
All of this is an old story and to many people have suffered, discovered, solved this and re-invented the wheel. For an all-in-one solution that covers this and many other WebDialog issues (for example you will discovered that when sending \\\ from JS to Ruby, it randomly drops some ), please take a look and make use of the WebDialogX project.
- You need to escape \ characters in the double-quoted javascript code that you want to bring into the webdialog (this first escaping is what makes a valid Ruby string).
-
@myhand said:
method strips all \ characters from its arguments as it passes it into JavaScript. I think it is because it does a eval() call on the JS.
Almost - it injects a SCRIPT element in the webdialog - does pretty much the same thing.
So when you pass data to the WebDialog and something is amiss - check the string you're sending to the WebDialog - is it valid? What throws people off is that you have the quoting needed to create the Ruby string with the JS - and within the JS string you need to follow JS's own quoting and escaping rules.(Because execute_script adds a SCRIPT element for every call I prefer to remove the SCRIPT element on the JS side afterwards - as I don't like the idea of the DOM tree flooded with SCRIPT elements. I've yet to experience problems with it - but there's something about it that makes my OCD-nerve tingle.)
-
@aerilius said:
=> So finally this means we need double escaping on the Ruby side!
%(#000000)["alert('C:\\\\users')"] # Ruby string
I am sure I tried this last night, but will do some further tests again tonight.
@aerilius said:
In order to get control of such errors, we could send the code as a JavaScript string and eval() it:
%(#000000)[webdialog.execute_script("try{eval(\"}bad_$yn7aX{\")}catch(e){}")]
[/size]Nice idea, I might use this going forward.
@aerilius said:
please take a look and make use of the WebDialogX project.
I cannot access the content. I get "You do not have access to the wiki." message, even after I have registered.
-
@myhand said:
@aerilius said:
please take a look and make use of the WebDialogX project.
I cannot access the content. I get "You do not have access to the wiki." message, even after I have registered.
Sorry, it is a 5-slot private repository at this time, and we really need very experienced Rubyists for the slots.
And you are kinda re-inventing the wheel. Js has
%(#8000BF)[escape()]
and%(#8000BF)[unescape()]
, and Ruby has them in theURI
library.See topic: http://sketchucation.com/forums/viewtopic.php?f=180&t=49183#p442102
In fact I would vote for Ruby's
URI::Escape
module to be mixed into the SketchUp APIUI::WebDialog
class. -
@dan rathbun said:
Sorry, it is a 5-slot private repository at this time, and we really need very experienced Rubyists for the slots.
No problem Dan, I only looked there as Aerilius recommended I do so.
@dan rathbun said:
And you are kinda re-inventing the wheel. Js has
%(#8000BF)[escape()]
and%(#8000BF)[unescape()]
, and Ruby has them in theURI
library.See topic: http://sketchucation.com/forums/viewtopic.php?f=180&t=49183#p442102
In fact I would vote for Ruby's
URI::Escape
module to be mixed into the SketchUp APIUI::WebDialog
class.Thank you, I will try the URI library (I already use escape() in my latest JS code). I do not really want to reinvent the wheel, hence me asking the question here.
-
@aerilius said:
- You need to escape \ characters in the double-quoted javascript code that you want to bring into the webdialog (this first escaping is what makes a valid Ruby string).
%(#000000)["alert('C:\users')"] # bad Ruby string
%(#000000)["alert('C:\\users')"] # good Ruby string
- In the webdialog, the string arrives written in a script element. As always, the same escaping rules apply again:
%(#000000)[alert('C:\users')] // bad JavaScript code
%(#000000)[alert('C:\\users')] // good JavaScript code
=> So finally this means we need double escaping on the Ruby side!
%(#000000)["alert('C:\\\\users')"] # Ruby string
Thanks for a very clear explanation. I tried this last night and it worked. Need 7 '''s for a "!
- You need to escape \ characters in the double-quoted javascript code that you want to bring into the webdialog (this first escaping is what makes a valid Ruby string).
Advertisement