• 登入
sketchucation logo sketchucation
  • 登入
⚠️ Libfredo 15.4b | Minor release with bugfixes and improvements Update

JSON in Ruby

已排程 已置頂 已鎖定 已移動 Developers' Forum
48 貼文 7 Posters 7.0k 瀏覽 7 Watching
正在載入更多貼文
  • 從舊到新
  • 從新到舊
  • 最多點贊
回覆
  • 在新貼文中回覆
登入後回覆
此主題已被刪除。只有擁有主題管理權限的使用者可以查看。
  • J 離線
    jeemang
    最後由 編輯 2011年3月18日 下午10:02

    Quick question: what are people using to create JSON strings in Ruby? I did a little poking around and apparently even the "pure" version of the JSON implementation for ruby doesn't work within Sketchup, which my testing seems to confirm. So, I thought I'd see if anyone had any suggestions in this area.

    Thanks,

    Josh

    1 條回覆 最後回覆 回覆 引用 0
    • D 離線
      Dan Rathbun
      最後由 編輯 2011年3月19日 上午1:51

      Well if you look at a Hash using the .inspect() you will see that it looks almost like JSON, except that the "=>" symbols need to be replaced with ":" (a colon.)

      So for a quick and dirty simple JSON string you might try bulding a Hash of values:

      hash = {} hash['KeyOne']= somevalue
      .. etc ...

      jsonStr = hash.inspect.gsub('=>',':')

      I'm not here much anymore.

      1 條回覆 最後回覆 回覆 引用 0
      • D 離線
        Dan Rathbun
        最後由 編輯 2011年3月19日 上午6:06

        I guess I should cover what happens in the other direction, when you are returning a JSON string from a webdialog, and want to use the data on the Ruby side.

        You reverse the process of "=>" to ":" replacement, then eval() the string back into a Hash object.

        Ex:
        hash_obj = eval( jsonStr.inspect.gsub(':','=>') )

        💭

        Works as long as you don't have any colons embedded within any of the string datavalues. If you do, you'll need to iterate the hash_obj afterward, and replace them.

        hash_obj.each {|k,v|
          hash_obj[k]= v.gsub('=>',';') if v.is_a?(String)
        }
        

        I'm not here much anymore.

        1 條回覆 最後回覆 回覆 引用 0
        • J 離線
          jeemang
          最後由 編輯 2011年3月21日 下午6:36

          Hi Dan;

          Thanks for the response -- I'll give that a shot.

          Josh

          1 條回覆 最後回覆 回覆 引用 0
          • M 離線
            Myhand
            最後由 編輯 2012年11月26日 下午11:20

            You can also try this class wrote. It can serialise Ruby objects, including nested arrays and object graphs and escapes strings to produce valid valid Ruby. I did not need de-serialisation so have not added that yet.

            http://www.keepingmyhandin.com/Downhome/Sketchup/simplejsonserializerrubyimplementation

            http://www.keepingmyhandin.com/

            1 條回覆 最後回覆 回覆 引用 0
            • D 離線
              Dan Rathbun
              最後由 編輯 2012年11月27日 上午12:39

              Thanx for sharing.

              However it has one major drawback. You defined your class at the toplevel. This should be reserved for Ruby Core basclasses.

              Why? We all cannot be defining custom classes in the global ObjectSpace, otherwise MY class JSON will clash with YOUR class JSON !

              Custom classes should be defined within YOUR "Author" namespace, or sub-namespace, however you wish to organize it.

              For example:

              module MyHand
                module Lib
                  module JSON
                    # the code here
                  end # module JSON
                end # module Lib
              end # module MyHand
              

              Then if anyone (including you,) wishes to use it from within one of their sub-modules, they have several options.

              (1) Create a reference that aliases into your lib class:

              module Author
                module NiftyPlugin
              
                  # make sure the lib file is loaded
                  require("myhand/lib/json.rb")
              
                  # create an alias;
                  JSON = MyHand;;Lib;;JSON
              
                  # use it;
                  json = JSON.new()
              
                end # module NiftyPlugin
              end # 
              

              (2) Make your JSON a MIXIN module instead of a class.
              Users then mix it into their nested namespaces:

              module Author
                module NiftyPlugin
              
                  # make sure the lib file is loaded
                  require("myhand/lib/json.rb")
              
                  # mix in the library module, as a nested class;
                  class JSON
                    # bring in methods as instance methods;
                    include(MyHand;;Lib;;JSON)
                    # bring in methods as class methods;
                    extend(MyHand;;Lib;;JSON)
                  end # class
              
                  # use it calling a class method;
                  str = JSON.escape("\tHello World!\n")
              
                end # module NiftyPlugin
              end # 
              

              They can do similar by mixing into a nested module.

              In fact the way you wrote it, the methods never the ref to the self instance, so basically you wrote class (ie, singleton) methods, so it really IS a library module, but you mis-defined it as a class.

              If you change it to a module (within some custom modular namespace,) and then at the top of the module call module_function(), and Ruby will make a copy of each of the methods for you (one instance and one singleton.)

              💭

              I'm not here much anymore.

              1 條回覆 最後回覆 回覆 引用 0
              • A 離線
                Aerilius
                最後由 編輯 2012年11月27日 上午1:30

                Just for completion, if someone uses Dan's simple example it works well if you know what key/values you have (configurations, options...).
                In case you don't know the possible values (ie. user input that might contain colons : or =>), you have to make sure that you don't replace them within strings, only between keys and values.

                
                def from_json(json_string)
                  # split at every even number of unescaped quotes; if it's not a string then replace ; and null
                  ruby_string = json_string.split(/(\"(?;.*?[^\\])*?\")/).
                    collect{|s|
                      (s[0..0] != '"')? s.gsub(/\;/, "=>").gsub(/null/, "nil") ; s
                    }.
                    join()
                  result = eval(ruby_string)
                  return result
                rescue Exception => e
                  {}
                end
                
                
                
                def to_json(obj)
                  json_classes = [String, Symbol, Fixnum, Float, Array, Hash, TrueClass, FalseClass, NilClass]
                  # remove non-JSON objects
                  check_value = nil
                  check_array = Proc.new{|o| o.reject!{|k| !check_value.call(k) } }
                  check_hash = Proc.new{|o| o.reject!{|k,v| !k.is_a?(String) && !k.is_a?(Symbol) || !check_value.call(v) } }
                  check_value = Proc.new{|v|
                    if v.is_a?(Array)
                      check_array.call(v)
                    elsif v.is_a?(Hash)
                      check_hash.call(v)
                    end
                    json_classes.include?(v.class)
                  }
                  return "null" unless check_value.call(obj)
                  # split at every even number of unescaped quotes; if it's not a string then turn Symbols into String and replace => and nil
                  json_string = obj.inspect.split(/(\"(?;.*?[^\\])*?\")/).
                    collect{|s|
                      (s[0..0] != '"')?                        # If we are not inside a string
                      s.gsub(/\;(\S+?(?=\=>|\s))/, "\"\\1\""). # Symbols to String
                        gsub(/=>/, ";").                       # Arrow to colon
                        gsub(/\bnil\b/, "null") ;              # nil to null
                      s
                    }.join()
                  return json_string
                end
                
                
                1 條回覆 最後回覆 回覆 引用 0
                • OricAtmosO 離線
                  OricAtmos
                  最後由 編輯 2012年11月27日 下午5:02

                  Is there a reason to avoid libraries like Yajl, because that's what I'm using. I should note that our plugin isn't distributed in any way and only used internally so far and I just put all necessary Yajl files in a sub folder inside our plugin folder. So that's not too pretty I guess, but it works fine.

                  1 條回覆 最後回覆 回覆 引用 0
                  • M 離線
                    Myhand
                    最後由 編輯 2012年11月27日 下午8:40

                    @oricatmos said:

                    Is there a reason to avoid libraries like Yajl, because that's what I'm using. I should note that our plugin isn't distributed in any way and only used internally so far and I just put all necessary Yajl files in a sub folder inside our plugin folder. So that's not too pretty I guess, but it works fine.

                    Thanks! I have not seen Yajl. Will give it a try. I tried

                    http://flori.github.com/json/doc/index.html

                    before but could not get it to work within Sketchup hence me writing my own class.

                    http://www.keepingmyhandin.com/

                    1 條回覆 最後回覆 回覆 引用 0
                    • M 離線
                      Myhand
                      最後由 編輯 2012年11月27日 下午9:12

                      @dan rathbun said:

                      Thanx for sharing.

                      However it has one major drawback. You defined your class at the toplevel. This should be reserved for Ruby Core basclasses.

                      In fact the way you wrote it, the methods never the ref to the self instance, so basically you wrote class (ie, singleton) methods, so it really IS a library module, but you mis-defined it as a class.

                      Thanks Dan, this class is actually part of a module in my code, I just cut and pasted it out to show how it works. Thank you for the tips about libraries though, I have not explored this side of Ruby yet.

                      You say that my methods are class methods. But I have done some tests and they seem to behave as object methods. i.e. each has access to the object's local state variables. I can also not call them as you would call a static method, i.e. JSON.escape().

                      Why do you think my methods are static?

                      Cheers

                      http://www.keepingmyhandin.com/

                      1 條回覆 最後回覆 回覆 引用 0
                      • M 離線
                        Myhand
                        最後由 編輯 2012年11月27日 下午10:17

                        @oricatmos said:

                        Is there a reason to avoid libraries like Yajl, because that's what I'm using. I should note that our plugin isn't distributed in any way and only used internally so far and I just put all necessary Yajl files in a sub folder inside our plugin folder. So that's not too pretty I guess, but it works fine.

                        Hi OricAtmos, I tried to get this to work but keep getting errors when trying to include the library:

                        require 'yajl'

                        fails with the following error:

                        load "c:/temp/yajl_test.rb"
                        Error: #<LoadError: c:/temp/yajl.rb:1:in require': no such file to load -- yajl/yajl> c:/temp/yajl_test.rb:1 c:/temp/yajl.rb:1 c:/temp/yajl_test.rb:1:in require'
                        c:/temp/yajl_test.rb:1
                        (eval):1:in `load'
                        (eval):1

                        How did you install the library?

                        http://www.keepingmyhandin.com/

                        1 條回覆 最後回覆 回覆 引用 0
                        • OricAtmosO 離線
                          OricAtmos
                          最後由 編輯 2012年11月27日 下午11:19

                          @myhand said:

                          Hi OricAtmos, I tried to get this to work but keep getting errors when trying to include the library:
                          [...]

                          How did you install the library?

                          I think it might have to do with the library search paths or something. I'll get back to you tomorrow with the details.

                          1 條回覆 最後回覆 回覆 引用 0
                          • D 離線
                            Dan Rathbun
                            最後由 編輯 2012年11月28日 上午2:07

                            @myhand said:

                            I tried to get this to work but keep getting errors when trying to include the library:
                            require 'yajl'
                            If you do not specify some kind of filepath, then the file must be in one of the directories listed in the $LOAD_PATH array.

                            Ruby's require() first checks to see if the argument resolves to an absolute path, and if so, checks to see if the file exists, and if true, attempts to load it.

                            Secondly, it checks to see if the argument is a relative path (incl. no path at all,) and if so, require() then iterates the $LOAD_PATH array prepending the base paths in front of your relative path. If it finds match, it loads the file, IF such a path is NOT ALREADY present in the $LOADED_FEATURES (aka $") array.

                            What does the following LoadError exception message tell you?
                            Error: #<LoadError: c:/temp/yajl.rb:1:inrequire': no such file to load -- yajl/yajl>`

                            Answer: That "c:/temp/yajl.rb" on line 1, is calling require("yajl/yajl"), but no file named "yajl.rb", "yalj.so", "yalj.dll", etc., can be found, because it's a relative path, and there is no path containing a "yalj" SUB-directory in the $LOAD_PATH array, containing a file (of any valid extension that require() can load,) named "yalj".

                            IF you simply copied the "yalj" directory into the SketchUp "plugins" directory, and typed require("yajl/yajl") in the SketchUp Ruby Console, it would be found. (Not to say that it would work, because it itself may have other file dependencies, such as Standard Ruby library files, which requires you to have a full Ruby installation, AND push it's library paths into the $LOAD_PATH array.)

                            Understanding require() and load(), and how they use (or not,) the $LOAD_PATH (aka $:) and $LOADED_FEATURES (aka $") arrays, is Ruby 101 week 1.

                            Click on the link in my signature, and follow the advice to collect docs. And just below my Newbie Guide, I posted the old "Pick-Axe" book. Required reading.

                            I'm not here much anymore.

                            1 條回覆 最後回覆 回覆 引用 0
                            • D 離線
                              Dan Rathbun
                              最後由 編輯 2012年11月28日 上午6:40

                              @myhand said:

                              I can also not call them as you would call a static method, i.e. JSON.escape().

                              OK Example:

                              Assume your "plugins" dir, has sub-dir "myhand", which has a sub-dir "lib", which contains a file "json.rb"

                              I recommend having your nested dir names match your nested namespaces, so you can remember the relative paths when it comes time to type a require expression.

                              module MyHand
                                module Lib
                                  module JSON # mixin module
                              
                                    def escape(value)
                                      ret = ""
                                      value.split("").each do |c|
                                        if (/["\\\/\b\f\n\r\t]/.match( c ) )
                                          ret << '\\' << c
                                        else
                                          ret << c
                                        end
                                      end
                                      return ret
                                    end # escape()
                              
                                  end # module JSON
                                end # module Lib
                              end # module MyHand
                              

                              .. and in a plugin:

                              module Author
                                module NiftyPlugin
                               
                                  # make sure the lib file is loaded
                                  require("myhand/lib/json.rb")
                               
                                  # mix in the library module, as a nested module;
                                  module JSON
                                    #
                                    # bring in public mixin instance methods
                                    # as public module methods in THIS module;
                                    #
                                    extend(MyHand;;Lib;;JSON)
                                    #
                                  end # module
                               
                                  # use it calling a module method;
                                  str = JSON.escape("\tHello World!\n")
                              
                                  puts(str)
                               
                                end # module NiftyPlugin
                              end # module Author
                              

                              OR ... using module_function() like the Math module does ...

                              module MyHand
                                module Lib
                                  module JSON # mixin module
                              
                                    module_function()
                              
                                    def escape(value)
                                      ret = ""
                                      value.split("").each do |c|
                                        if (/["\\\/\b\f\n\r\t]/.match( c ) )
                                          ret << '\\' << c
                                        else
                                          ret << c
                                        end
                                      end
                                      return ret
                                    end # escape()
                              
                                  end # module JSON
                                end # module Lib
                              end # module MyHand
                              

                              .. and in a plugin:

                              module Author
                                module NiftyPlugin
                               
                                  # make sure the lib file is loaded
                                  require("myhand/lib/json.rb")
                               
                                  # Use a library module function, via a
                                  # local constant aliasing the library;
                                  JSON = MyHand;;Lib;;JSON
                               
                                  # use it calling a module method;
                                  str = JSON.escape("\tHello World!\n")
                              
                                  puts(str)
                               
                                end # module NiftyPlugin
                              end # module Author
                              

                              I'm not here much anymore.

                              1 條回覆 最後回覆 回覆 引用 0
                              • OricAtmosO 離線
                                OricAtmos
                                最後由 編輯 2012年11月28日 下午12:03

                                Dan already explained more than I could have. He also wrote a nice ruby script to include additional folders in $LOAD_PATH. Read all about it here: http://sketchucation.com/forums/viewtopic.php?f=180&t=29412&p=342471&hilit=!loadpaths

                                1 條回覆 最後回覆 回覆 引用 0
                                • M 離線
                                  Myhand
                                  最後由 編輯 2012年11月28日 下午1:31

                                  @dan rathbun said:

                                  @myhand said:

                                  I tried to get this to work but keep getting errors when trying to include the library:
                                  require 'yajl'
                                  If you do not specify some kind of filepath, then the file must be in one of the directories listed in the $LOAD_PATH array.

                                  Ruby's require() first checks to see if the argument resolves to an absolute path, and if so, checks to see if the file exists, and if true, attempts to load it.

                                  Secondly, it checks to see if the argument is a relative path (incl. no path at all,) and if so, require() then iterates the $LOAD_PATH array prepending the base paths in front of your relative path. If it finds match, it loads the file, IF such a path is NOT ALREADY present in the $LOADED_FEATURES (aka $") array.

                                  Thank you Dan for the detailed explanation and links to starter guides. I will review and try this when I get home tonight. One interesting point in this case though is that the only file called yajl.* is c:/temp/yajl.rb which is also the file that contains the

                                  require 'yajl/yajl'
                                  

                                  line. There is a a subdirectory called yajl, but no files named "yajl.rb", "yajl.so" or "yajl.dll" anywhere else in the yajl library distribution... So cannot see how adding the "c:/temp" path to $LOAD_PATH will find the file as it does not appear to exist.

                                  Will let you know.

                                  http://www.keepingmyhandin.com/

                                  1 條回覆 最後回覆 回覆 引用 0
                                  • OricAtmosO 離線
                                    OricAtmos
                                    最後由 編輯 2012年11月28日 下午2:36

                                    @myhand said:

                                    There is a a subdirectory called yajl, but no files named "yajl.rb", "yajl.so" or "yajl.dll" anywhere else in the yajl library distribution... So cannot see how adding the "c:/temp" path to $LOAD_PATH will find the file as it does not appear to exist.

                                    Sounds like you don't have the complete library.
                                    This is a list of files I have in my Yajl folder:

                                    
                                    [...]\rubylibs\yajl.rb
                                    [...]\rubylibs\yajl\1.8\yajl.so
                                    [...]\rubylibs\yajl\1.9\yajl.so
                                    [...]\rubylibs\yajl\bzip2.rb
                                    [...]\rubylibs\yajl\bzip2\stream_reader.rb
                                    [...]\rubylibs\yajl\bzip2\stream_writer.rb
                                    [...]\rubylibs\yajl\deflate.rb
                                    [...]\rubylibs\yajl\deflate\stream_reader.rb
                                    [...]\rubylibs\yajl\deflate\stream_writer.rb
                                    [...]\rubylibs\yajl\gzip.rb
                                    [...]\rubylibs\yajl\gzip\stream_reader.rb
                                    [...]\rubylibs\yajl\gzip\stream_writer.rb
                                    [...]\rubylibs\yajl\http_stream.rb
                                    [...]\rubylibs\yajl\json_gem.rb
                                    [...]\rubylibs\yajl\json_gem\encoding.rb
                                    [...]\rubylibs\yajl\json_gem\parsing.rb
                                    [...]\rubylibs\yajl\version.rb
                                    [...]\rubylibs\yajl\yajl.rb
                                    
                                    
                                    1 條回覆 最後回覆 回覆 引用 0
                                    • M 離線
                                      Myhand
                                      最後由 編輯 2012年11月28日 下午8:41

                                      @oricatmos said:

                                      @myhand said:

                                      There is a a subdirectory called yajl, but no files named "yajl.rb", "yajl.so" or "yajl.dll" anywhere else in the yajl library distribution... So cannot see how adding the "c:/temp" path to $LOAD_PATH will find the file as it does not appear to exist.

                                      Sounds like you don't have the complete library.
                                      This is a list of files I have in my Yajl folder:

                                      Yes OricAtmos, I think you are right. I took my version from here

                                      https://rubygems.org/gems/yajl-ruby.

                                      As I cannot install the gem in Sketchup I unzipped the gem file and took the files from the lib directory. This gives me the following files which is clearly not complete.

                                      
                                      C;\Temp\lib\yajl
                                      C;\Temp\lib\yajl.rb
                                      C;\Temp\lib\yajl\bzip2
                                      C;\Temp\lib\yajl\bzip2.rb
                                      C;\Temp\lib\yajl\deflate
                                      C;\Temp\lib\yajl\deflate.rb
                                      C;\Temp\lib\yajl\gzip
                                      C;\Temp\lib\yajl\gzip.rb
                                      C;\Temp\lib\yajl\http_stream.rb
                                      C;\Temp\lib\yajl\json_gem
                                      C;\Temp\lib\yajl\json_gem.rb
                                      C;\Temp\lib\yajl\version.rb
                                      C;\Temp\lib\yajl\bzip2\stream_reader.rb
                                      C;\Temp\lib\yajl\bzip2\stream_writer.rb
                                      C;\Temp\lib\yajl\deflate\stream_reader.rb
                                      C;\Temp\lib\yajl\deflate\stream_writer.rb
                                      C;\Temp\lib\yajl\gzip\stream_reader.rb
                                      C;\Temp\lib\yajl\gzip\stream_writer.rb
                                      C;\Temp\lib\yajl\json_gem\encoding.rb
                                      C;\Temp\lib\yajl\json_gem\parsing.rb
                                      
                                      

                                      Where did you get the library from?

                                      Cheers,

                                      myhand

                                      http://www.keepingmyhandin.com/

                                      1 條回覆 最後回覆 回覆 引用 0
                                      • OricAtmosO 離線
                                        OricAtmos
                                        最後由 編輯 2012年11月28日 下午8:57

                                        @myhand said:

                                        Where did you get the library from?

                                        I don't remember where I got the Windows binaries from. Perhaps I still have a bookmark in my web browser at work, but right now I'm at home and can't have a look. But since I have access to our project repository from home I can offer you this:

                                        Link Preview Image
                                        Dropbox - 404

                                        favicon

                                        (dl.dropbox.com)

                                        1 條回覆 最後回覆 回覆 引用 0
                                        • M 離線
                                          Myhand
                                          最後由 編輯 2012年11月28日 下午10:12

                                          @oricatmos said:

                                          @myhand said:

                                          Where did you get the library from?

                                          I don't remember where I got the Windows binaries from. Perhaps I still have a bookmark in my web browser at work, but right now I'm at home and can't have a look. But since I have access to our project repository from home I can offer you this:

                                          Link Preview Image
                                          Dropbox - 404

                                          favicon

                                          (dl.dropbox.com)

                                          Thanks OricAtmos! Will give it a try.

                                          http://www.keepingmyhandin.com/

                                          1 條回覆 最後回覆 回覆 引用 0
                                          • 1
                                          • 2
                                          • 3
                                          • 1 / 3
                                          • 第一個貼文
                                            最後的貼文
                                          Buy SketchPlus
                                          Buy SUbD
                                          Buy WrapR
                                          Buy eBook
                                          Buy Modelur
                                          Buy Vertex Tools
                                          Buy SketchCuisine
                                          Buy FormFonts

                                          Advertisement