diff options
15 files changed, 855 insertions, 697 deletions
diff --git a/Library/Homebrew/test/test_json.rb b/Library/Homebrew/test/test_json.rb new file mode 100644 index 000000000..458cfd123 --- /dev/null +++ b/Library/Homebrew/test/test_json.rb @@ -0,0 +1,16 @@ +require 'testing_env' +require 'vendor/multi_json' + +class JsonSmokeTest < Test::Unit::TestCase + def test_encode + hash = { "foo" => ["bar", "baz"], "qux" => 1 } + json = %q|{"foo":["bar","baz"],"qux":1}| + assert_equal json, MultiJson.encode(hash) + end + + def test_decode + hash = { "foo" => ["bar", "baz"], "qux" => 1 } + json = %q|{"foo":["bar","baz"],"qux":1}| + assert_equal hash, MultiJson.decode(json) + end +end diff --git a/Library/Homebrew/vendor/multi_json.rb b/Library/Homebrew/vendor/multi_json.rb index daa5ca5ac..61ce79ba5 100644 --- a/Library/Homebrew/vendor/multi_json.rb +++ b/Library/Homebrew/vendor/multi_json.rb @@ -1,62 +1,116 @@ module MultiJson - class DecodeError < StandardError; end - module_function - - @engine = nil - - # Get the current engine class. - def engine - return @engine if @engine - self.engine = self.default_engine - @engine + class DecodeError < StandardError + attr_reader :data + def initialize(message="", backtrace=[], data="") + super(message) + self.set_backtrace(backtrace) + @data = data + end end + @adapter = nil + REQUIREMENT_MAP = [ + ["oj", :oj], ["yajl", :yajl], ["json", :json_gem], ["json/pure", :json_pure] ] - # The default engine based on what you currently - # have loaded and installed. First checks to see - # if any engines are already loaded, then checks - # to see which are installed if none are loaded. - def default_engine - :ok_json - end + class << self - # Set the JSON parser utilizing a symbol, string, or class. - # Supported by default are: - # - # * <tt>:json_gem</tt> - # * <tt>:json_pure</tt> - # * <tt>:ok_json</tt> - # * <tt>:yajl</tt> - def engine=(new_engine) - case new_engine - when String, Symbol - require "vendor/multi_json/engines/#{new_engine}" - @engine = MultiJson::Engines.const_get("#{new_engine.to_s.split('_').map{|s| s.capitalize}.join('')}") - when Class - @engine = new_engine - else - raise "Did not recognize your engine specification. Please specify either a symbol or a class." + # The default adapter based on what you currently + # have loaded and installed. First checks to see + # if any adapters are already loaded, then checks + # to see which are installed if none are loaded. + def default_adapter + :ok_json end - end + # :nodoc: + alias :default_engine :default_adapter - # Decode a JSON string into Ruby. - # - # <b>Options</b> - # - # <tt>:symbolize_keys</tt> :: If true, will use symbols instead of strings for the keys. - def decode(string, options = {}) - engine.decode(string, options) - rescue engine::ParseError => exception - raise DecodeError, exception.message, exception.backtrace - end + # Get the current adapter class. + def adapter + return @adapter if @adapter + self.use self.default_adapter + @adapter + end + # :nodoc: + alias :engine :adapter + + # Set the JSON parser utilizing a symbol, string, or class. + # Supported by default are: + # + # * <tt>:oj</tt> + # * <tt>:json_gem</tt> + # * <tt>:json_pure</tt> + # * <tt>:ok_json</tt> + # * <tt>:yajl</tt> + # * <tt>:nsjsonserialization</tt> (MacRuby only) + def use(new_adapter) + @adapter = load_adapter(new_adapter) + end + alias :adapter= :use + # :nodoc: + alias :engine= :use + + def load_adapter(new_adapter) + case new_adapter + when String, Symbol + require "vendor/multi_json/adapters/#{new_adapter}" + MultiJson::Adapters.const_get(:"#{new_adapter.to_s.split('_').map{|s| s.capitalize}.join('')}") + when NilClass, FalseClass + default_adapter = self.default_adapter + require "vendor/multi_json/adapters/#{default_adapter}" + MultiJson::Adapters.const_get(:"#{default_adapter.to_s.split('_').map{|s| s.capitalize}.join('')}") + when Class + new_adapter + else + raise "Did not recognize your adapter specification. Please specify either a symbol or a class." + end + end + + # Decode a JSON string into Ruby. + # + # <b>Options</b> + # + # <tt>:symbolize_keys</tt> :: If true, will use symbols instead of strings for the keys. + # <tt>:adapter</tt> :: If set, the selected engine will be used just for the call. + def load(string, options={}) + adapter = current_adapter(options) + begin + adapter.load(string, options) + rescue adapter::ParseError => exception + raise DecodeError.new(exception.message, exception.backtrace, string) + end + end + # :nodoc: + alias :decode :load + + def current_adapter(options) + if new_adapter = (options || {}).delete(:adapter) + load_adapter(new_adapter) + else + adapter + end + end + + # Encodes a Ruby object as JSON. + def dump(object, options={}) + adapter = current_adapter(options) + adapter.dump(object, options) + end + # :nodoc: + alias :encode :dump + + def with_adapter(new_adapter) + old_adapter, self.adapter = adapter, new_adapter + yield + ensure + self.adapter = old_adapter + end + alias :with_engine :with_adapter - # Encodes a Ruby object as JSON. - def encode(object) - engine.encode(object) end + end diff --git a/Library/Homebrew/vendor/multi_json/adapters/json_common.rb b/Library/Homebrew/vendor/multi_json/adapters/json_common.rb new file mode 100644 index 000000000..992cc5ad5 --- /dev/null +++ b/Library/Homebrew/vendor/multi_json/adapters/json_common.rb @@ -0,0 +1,25 @@ +module MultiJson + module Adapters + module JsonCommon + + def load(string, options={}) + string = string.read if string.respond_to?(:read) + ::JSON.parse(string, :symbolize_names => options[:symbolize_keys], :quirks_mode => true) + end + + def dump(object, options={}) + object.to_json(process_options(options)) + end + + protected + + def process_options(options={}) + return options if options.empty? + opts = {} + opts.merge!(JSON::PRETTY_STATE_PROTOTYPE.to_h) if options.delete(:pretty) + opts.merge!(options) + end + + end + end +end diff --git a/Library/Homebrew/vendor/multi_json/adapters/json_gem.rb b/Library/Homebrew/vendor/multi_json/adapters/json_gem.rb new file mode 100644 index 000000000..7b34e91a1 --- /dev/null +++ b/Library/Homebrew/vendor/multi_json/adapters/json_gem.rb @@ -0,0 +1,12 @@ +require 'json' unless defined?(::JSON) +require 'multi_json/adapters/json_common' + +module MultiJson + module Adapters + # Use the JSON gem to dump/load. + class JsonGem + ParseError = ::JSON::ParserError + extend JsonCommon + end + end +end diff --git a/Library/Homebrew/vendor/multi_json/adapters/json_pure.rb b/Library/Homebrew/vendor/multi_json/adapters/json_pure.rb new file mode 100644 index 000000000..5d06ea665 --- /dev/null +++ b/Library/Homebrew/vendor/multi_json/adapters/json_pure.rb @@ -0,0 +1,12 @@ +require 'json/pure' unless defined?(::JSON) +require 'multi_json/adapters/json_common' + +module MultiJson + module Adapters + # Use JSON pure to dump/load. + class JsonPure + ParseError = ::JSON::ParserError + extend JsonCommon + end + end +end diff --git a/Library/Homebrew/vendor/multi_json/adapters/nsjsonserialization.rb b/Library/Homebrew/vendor/multi_json/adapters/nsjsonserialization.rb new file mode 100644 index 000000000..77ae4f15a --- /dev/null +++ b/Library/Homebrew/vendor/multi_json/adapters/nsjsonserialization.rb @@ -0,0 +1,34 @@ +framework 'Foundation' +require 'multi_json/adapters/ok_json' + +module MultiJson + module Adapters + class Nsjsonserialization < MultiJson::Adapters::OkJson + ParseError = ::MultiJson::OkJson::Error + + def self.load(string, options={}) + string = string.read if string.respond_to?(:read) + data = string.dataUsingEncoding(NSUTF8StringEncoding) + object = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves, error: nil) + if object + object = symbolize_keys(object) if options[:symbolize_keys] + object + else + super(string, options={}) + end + end + + def self.dump(object, options={}) + pretty = options[:pretty] ? NSJSONWritingPrettyPrinted : 0 + object = object.as_json if object.respond_to?(:as_json) + if NSJSONSerialization.isValidJSONObject(object) + data = NSJSONSerialization.dataWithJSONObject(object, options: pretty, error: nil) + NSMutableString.alloc.initWithData(data, encoding: NSUTF8StringEncoding) + else + super(object, options) + end + end + + end + end +end diff --git a/Library/Homebrew/vendor/multi_json/adapters/oj.rb b/Library/Homebrew/vendor/multi_json/adapters/oj.rb new file mode 100644 index 000000000..4c5e7fb8d --- /dev/null +++ b/Library/Homebrew/vendor/multi_json/adapters/oj.rb @@ -0,0 +1,26 @@ +require 'oj' unless defined?(::Oj) + +module MultiJson + module Adapters + # Use the Oj library to dump/load. + class Oj + ParseError = if defined?(::Oj::ParseError) + ::Oj::ParseError + else + SyntaxError + end + + ::Oj.default_options = {:mode => :compat} + + def self.load(string, options={}) #:nodoc: + options.merge!(:symbol_keys => options[:symbolize_keys]) + ::Oj.load(string, options) + end + + def self.dump(object, options={}) #:nodoc: + options.merge!(:indent => 2) if options[:pretty] + ::Oj.dump(object, options) + end + end + end +end diff --git a/Library/Homebrew/vendor/multi_json/engines/ok_json.rb b/Library/Homebrew/vendor/multi_json/adapters/ok_json.rb index 07a110f6f..3e36c862e 100644 --- a/Library/Homebrew/vendor/multi_json/engines/ok_json.rb +++ b/Library/Homebrew/vendor/multi_json/adapters/ok_json.rb @@ -1,18 +1,18 @@ -require "vendor/multi_json/vendor/ok_json" unless defined?(::OkJson) +require 'multi_json/vendor/okjson' module MultiJson - module Engines + module Adapters class OkJson - ParseError = ::OkJson::Error + ParseError = ::MultiJson::OkJson::Error - def self.decode(string, options = {}) #:nodoc: + def self.load(string, options={}) #:nodoc: string = string.read if string.respond_to?(:read) - result = ::OkJson.decode(string) + result = ::MultiJson::OkJson.decode("[#{string}]").first options[:symbolize_keys] ? symbolize_keys(result) : result end - def self.encode(object) #:nodoc: - ::OkJson.valenc(stringify_keys(object)) + def self.dump(object, options={}) #:nodoc: + ::MultiJson::OkJson.valenc(stringify_keys(object)) end def self.symbolize_keys(object) #:nodoc: @@ -23,7 +23,7 @@ module MultiJson def self.stringify_keys(object) #:nodoc: modify_keys(object) do |key| - key.is_a?(Symbol) ? key.to_s : key + key.respond_to?(:to_s) ? key.to_s : key end end diff --git a/Library/Homebrew/vendor/multi_json/adapters/yajl.rb b/Library/Homebrew/vendor/multi_json/adapters/yajl.rb new file mode 100644 index 000000000..3c0987dd9 --- /dev/null +++ b/Library/Homebrew/vendor/multi_json/adapters/yajl.rb @@ -0,0 +1,18 @@ +require 'yajl' unless defined?(::Yajl) + +module MultiJson + module Adapters + # Use the Yajl-Ruby library to dump/load. + class Yajl + ParseError = ::Yajl::ParseError + + def self.load(string, options={}) #:nodoc: + ::Yajl::Parser.new(:symbolize_keys => options[:symbolize_keys]).parse(string) + end + + def self.dump(object, options={}) #:nodoc: + ::Yajl::Encoder.encode(object, options) + end + end + end +end diff --git a/Library/Homebrew/vendor/multi_json/engines/json_gem.rb b/Library/Homebrew/vendor/multi_json/engines/json_gem.rb deleted file mode 100644 index dd2b1d499..000000000 --- a/Library/Homebrew/vendor/multi_json/engines/json_gem.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'json' unless defined?(::JSON) - -module MultiJson - module Engines - # Use the JSON gem to encode/decode. - class JsonGem - ParseError = ::JSON::ParserError - - def self.decode(string, options = {}) #:nodoc: - opts = {} - opts[:symbolize_names] = options[:symbolize_keys] - string = string.read if string.respond_to?(:read) - ::JSON.parse(string, opts) - end - - def self.encode(object) #:nodoc: - object.to_json - end - end - end -end diff --git a/Library/Homebrew/vendor/multi_json/engines/json_pure.rb b/Library/Homebrew/vendor/multi_json/engines/json_pure.rb deleted file mode 100644 index f89da0171..000000000 --- a/Library/Homebrew/vendor/multi_json/engines/json_pure.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'json/pure' unless defined?(::JSON) - -module MultiJson - module Engines - # Use JSON pure to encode/decode. - class JsonPure - ParseError = ::JSON::ParserError - - def self.decode(string, options = {}) #:nodoc: - opts = {} - opts[:symbolize_names] = options[:symbolize_keys] - string = string.read if string.respond_to?(:read) - ::JSON.parse(string, opts) - end - - def self.encode(object) #:nodoc: - object.to_json - end - end - end -end diff --git a/Library/Homebrew/vendor/multi_json/engines/yajl.rb b/Library/Homebrew/vendor/multi_json/engines/yajl.rb deleted file mode 100644 index 8dfe4b1aa..000000000 --- a/Library/Homebrew/vendor/multi_json/engines/yajl.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'yajl' unless defined?(Yajl) - -module MultiJson - module Engines - # Use the Yajl-Ruby library to encode/decode. - class Yajl - ParseError = ::Yajl::ParseError - - def self.decode(string, options = {}) #:nodoc: - ::Yajl::Parser.new(:symbolize_keys => options[:symbolize_keys]).parse(string) - end - - def self.encode(object) #:nodoc: - ::Yajl::Encoder.new.encode(object) - end - end - end -end diff --git a/Library/Homebrew/vendor/multi_json/vendor/ok_json.rb b/Library/Homebrew/vendor/multi_json/vendor/ok_json.rb deleted file mode 100644 index 65b607251..000000000 --- a/Library/Homebrew/vendor/multi_json/vendor/ok_json.rb +++ /dev/null @@ -1,581 +0,0 @@ -# Copyright 2011 Keith Rarick -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# See https://github.com/kr/okjson for updates. - -require 'stringio' - -# Some parts adapted from -# http://golang.org/src/pkg/json/decode.go and -# http://golang.org/src/pkg/utf8/utf8.go -module OkJson - extend self - - - # Decodes a json document in string s and - # returns the corresponding ruby value. - # String s must be valid UTF-8. If you have - # a string in some other encoding, convert - # it first. - # - # String values in the resulting structure - # will be UTF-8. - def decode(s) - ts = lex(s) - v, ts = textparse(ts) - if ts.length > 0 - raise Error, 'trailing garbage' - end - v - end - - - # Parses a "json text" in the sense of RFC 4627. - # Returns the parsed value and any trailing tokens. - # Note: this is almost the same as valparse, - # except that it does not accept atomic values. - def textparse(ts) - if ts.length < 0 - raise Error, 'empty' - end - - typ, _, val = ts[0] - case typ - when '{' then objparse(ts) - when '[' then arrparse(ts) - else - raise Error, "unexpected #{val.inspect}" - end - end - - - # Parses a "value" in the sense of RFC 4627. - # Returns the parsed value and any trailing tokens. - def valparse(ts) - if ts.length < 0 - raise Error, 'empty' - end - - typ, _, val = ts[0] - case typ - when '{' then objparse(ts) - when '[' then arrparse(ts) - when :val,:str then [val, ts[1..-1]] - else - raise Error, "unexpected #{val.inspect}" - end - end - - - # Parses an "object" in the sense of RFC 4627. - # Returns the parsed value and any trailing tokens. - def objparse(ts) - ts = eat('{', ts) - obj = {} - - if ts[0][0] == '}' - return obj, ts[1..-1] - end - - k, v, ts = pairparse(ts) - obj[k] = v - - if ts[0][0] == '}' - return obj, ts[1..-1] - end - - loop do - ts = eat(',', ts) - - k, v, ts = pairparse(ts) - obj[k] = v - - if ts[0][0] == '}' - return obj, ts[1..-1] - end - end - end - - - # Parses a "member" in the sense of RFC 4627. - # Returns the parsed values and any trailing tokens. - def pairparse(ts) - (typ, _, k), ts = ts[0], ts[1..-1] - if typ != :str - raise Error, "unexpected #{k.inspect}" - end - ts = eat(':', ts) - v, ts = valparse(ts) - [k, v, ts] - end - - - # Parses an "array" in the sense of RFC 4627. - # Returns the parsed value and any trailing tokens. - def arrparse(ts) - ts = eat('[', ts) - arr = [] - - if ts[0][0] == ']' - return arr, ts[1..-1] - end - - v, ts = valparse(ts) - arr << v - - if ts[0][0] == ']' - return arr, ts[1..-1] - end - - loop do - ts = eat(',', ts) - - v, ts = valparse(ts) - arr << v - - if ts[0][0] == ']' - return arr, ts[1..-1] - end - end - end - - - def eat(typ, ts) - if ts[0][0] != typ - raise Error, "expected #{typ} (got #{ts[0].inspect})" - end - ts[1..-1] - end - - - # Sans s and returns a list of json tokens, - # excluding white space (as defined in RFC 4627). - def lex(s) - ts = [] - while s.length > 0 - typ, lexeme, val = tok(s) - if typ == nil - raise Error, "invalid character at #{s[0,10].inspect}" - end - if typ != :space - ts << [typ, lexeme, val] - end - s = s[lexeme.length..-1] - end - ts - end - - - # Scans the first token in s and - # returns a 3-element list, or nil - # if no such token exists. - # - # The first list element is one of - # '{', '}', ':', ',', '[', ']', - # :val, :str, and :space. - # - # The second element is the lexeme. - # - # The third element is the value of the - # token for :val and :str, otherwise - # it is the lexeme. - def tok(s) - case s[0] - when ?{ then ['{', s[0,1], s[0,1]] - when ?} then ['}', s[0,1], s[0,1]] - when ?: then [':', s[0,1], s[0,1]] - when ?, then [',', s[0,1], s[0,1]] - when ?[ then ['[', s[0,1], s[0,1]] - when ?] then [']', s[0,1], s[0,1]] - when ?n then nulltok(s) - when ?t then truetok(s) - when ?f then falsetok(s) - when ?" then strtok(s) - when Spc then [:space, s[0,1], s[0,1]] - when ?\t then [:space, s[0,1], s[0,1]] - when ?\n then [:space, s[0,1], s[0,1]] - when ?\r then [:space, s[0,1], s[0,1]] - else numtok(s) - end - end - - - def nulltok(s); s[0,4] == 'null' && [:val, 'null', nil] end - def truetok(s); s[0,4] == 'true' && [:val, 'true', true] end - def falsetok(s); s[0,5] == 'false' && [:val, 'false', false] end - - - def numtok(s) - m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s) - if m && m.begin(0) == 0 - if m[3] && !m[2] - [:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))] - elsif m[2] - [:val, m[0], Float(m[0])] - else - [:val, m[0], Integer(m[0])] - end - end - end - - - def strtok(s) - m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s) - if ! m - raise Error, "invalid string literal at #{abbrev(s)}" - end - [:str, m[0], unquote(m[0])] - end - - - def abbrev(s) - t = s[0,10] - p = t['`'] - t = t[0,p] if p - t = t + '...' if t.length < s.length - '`' + t + '`' - end - - - # Converts a quoted json string literal q into a UTF-8-encoded string. - # The rules are different than for Ruby, so we cannot use eval. - # Unquote will raise an error if q contains control characters. - def unquote(q) - q = q[1...-1] - a = q.dup # allocate a big enough string - r, w = 0, 0 - while r < q.length - c = q[r] - case true - when c == ?\\ - r += 1 - if r >= q.length - raise Error, "string literal ends with a \"\\\": \"#{q}\"" - end - - case q[r] - when ?",?\\,?/,?' - a[w] = q[r] - r += 1 - w += 1 - when ?b,?f,?n,?r,?t - a[w] = Unesc[q[r]] - r += 1 - w += 1 - when ?u - r += 1 - uchar = begin - hexdec4(q[r,4]) - rescue RuntimeError => e - raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}" - end - r += 4 - if surrogate? uchar - if q.length >= r+6 - uchar1 = hexdec4(q[r+2,4]) - uchar = subst(uchar, uchar1) - if uchar != Ucharerr - # A valid pair; consume. - r += 6 - end - end - end - w += ucharenc(a, w, uchar) - else - raise Error, "invalid escape char #{q[r]} in \"#{q}\"" - end - when c == ?", c < Spc - raise Error, "invalid character in string literal \"#{q}\"" - else - # Copy anything else byte-for-byte. - # Valid UTF-8 will remain valid UTF-8. - # Invalid UTF-8 will remain invalid UTF-8. - a[w] = c - r += 1 - w += 1 - end - end - a[0,w] - end - - - # Encodes unicode character u as UTF-8 - # bytes in string a at position i. - # Returns the number of bytes written. - def ucharenc(a, i, u) - case true - when u <= Uchar1max - a[i] = (u & 0xff).chr - 1 - when u <= Uchar2max - a[i+0] = (Utag2 | ((u>>6)&0xff)).chr - a[i+1] = (Utagx | (u&Umaskx)).chr - 2 - when u <= Uchar3max - a[i+0] = (Utag3 | ((u>>12)&0xff)).chr - a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr - a[i+2] = (Utagx | (u&Umaskx)).chr - 3 - else - a[i+0] = (Utag4 | ((u>>18)&0xff)).chr - a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr - a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr - a[i+3] = (Utagx | (u&Umaskx)).chr - 4 - end - end - - - def hexdec4(s) - if s.length != 4 - raise Error, 'short' - end - (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3]) - end - - - def subst(u1, u2) - if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3 - return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself - end - return Ucharerr - end - - - def unsubst(u) - if u < Usurrself || u > Umax || surrogate?(u) - return Ucharerr, Ucharerr - end - u -= Usurrself - [Usurr1 + ((u>>10)&0x3ff), Usurr2 + (u&0x3ff)] - end - - - def surrogate?(u) - Usurr1 <= u && u < Usurr3 - end - - - def nibble(c) - case true - when ?0 <= c && c <= ?9 then c.ord - ?0.ord - when ?a <= c && c <= ?z then c.ord - ?a.ord + 10 - when ?A <= c && c <= ?Z then c.ord - ?A.ord + 10 - else - raise Error, "invalid hex code #{c}" - end - end - - - # Encodes x into a json text. It may contain only - # Array, Hash, String, Numeric, true, false, nil. - # (Note, this list excludes Symbol.) - # X itself must be an Array or a Hash. - # No other value can be encoded, and an error will - # be raised if x contains any other value, such as - # Nan, Infinity, Symbol, and Proc, or if a Hash key - # is not a String. - # Strings contained in x must be valid UTF-8. - def encode(x) - case x - when Hash then objenc(x) - when Array then arrenc(x) - else - raise Error, 'root value must be an Array or a Hash' - end - end - - - def valenc(x) - case x - when Hash then objenc(x) - when Array then arrenc(x) - when String then strenc(x) - when Numeric then numenc(x) - when true then "true" - when false then "false" - when nil then "null" - else - raise Error, "cannot encode #{x.class}: #{x.inspect}" - end - end - - - def objenc(x) - '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}' - end - - - def arrenc(a) - '[' + a.map{|x| valenc(x)}.join(',') + ']' - end - - - def keyenc(k) - case k - when String then strenc(k) - else - raise Error, "Hash key is not a string: #{k.inspect}" - end - end - - - def strenc(s) - t = StringIO.new - t.putc(?") - r = 0 - while r < s.length - case s[r] - when ?" then t.print('\\"') - when ?\\ then t.print('\\\\') - when ?\b then t.print('\\b') - when ?\f then t.print('\\f') - when ?\n then t.print('\\n') - when ?\r then t.print('\\r') - when ?\t then t.print('\\t') - else - c = s[r] - case true - when Spc <= c && c <= ?~ - t.putc(c) - when true - u, size = uchardec(s, r) - r += size - 1 # we add one more at the bottom of the loop - if u < 0x10000 - t.print('\\u') - hexenc4(t, u) - else - u1, u2 = unsubst(u) - t.print('\\u') - hexenc4(t, u1) - t.print('\\u') - hexenc4(t, u2) - end - else - # invalid byte; skip it - end - end - r += 1 - end - t.putc(?") - t.string - end - - - def hexenc4(t, u) - t.putc(Hex[(u>>12)&0xf]) - t.putc(Hex[(u>>8)&0xf]) - t.putc(Hex[(u>>4)&0xf]) - t.putc(Hex[u&0xf]) - end - - - def numenc(x) - if x.nan? || x.infinite? - return 'null' - end rescue nil - "#{x}" - end - - - # Decodes unicode character u from UTF-8 - # bytes in string s at position i. - # Returns u and the number of bytes read. - def uchardec(s, i) - n = s.length - i - return [Ucharerr, 1] if n < 1 - - c0 = s[i].ord - - # 1-byte, 7-bit sequence? - if c0 < Utagx - return [c0, 1] - end - - # unexpected continuation byte? - return [Ucharerr, 1] if c0 < Utag2 - - # need continuation byte - return [Ucharerr, 1] if n < 2 - c1 = s[i+1].ord - return [Ucharerr, 1] if c1 < Utagx || Utag2 <= c1 - - # 2-byte, 11-bit sequence? - if c0 < Utag3 - u = (c0&Umask2)<<6 | (c1&Umaskx) - return [Ucharerr, 1] if u <= Uchar1max - return [u, 2] - end - - # need second continuation byte - return [Ucharerr, 1] if n < 3 - c2 = s[i+2].ord - return [Ucharerr, 1] if c2 < Utagx || Utag2 <= c2 - - # 3-byte, 16-bit sequence? - if c0 < Utag4 - u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx) - return [Ucharerr, 1] if u <= Uchar2max - return [u, 3] - end - - # need third continuation byte - return [Ucharerr, 1] if n < 4 - c3 = s[i+3].ord - return [Ucharerr, 1] if c3 < Utagx || Utag2 <= c3 - - # 4-byte, 21-bit sequence? - if c0 < Utag5 - u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx) - return [Ucharerr, 1] if u <= Uchar3max - return [u, 4] - end - - return [Ucharerr, 1] - end - - - class Error < ::StandardError - end - - - Utagx = 0x80 # 1000 0000 - Utag2 = 0xc0 # 1100 0000 - Utag3 = 0xe0 # 1110 0000 - Utag4 = 0xf0 # 1111 0000 - Utag5 = 0xF8 # 1111 1000 - Umaskx = 0x3f # 0011 1111 - Umask2 = 0x1f # 0001 1111 - Umask3 = 0x0f # 0000 1111 - Umask4 = 0x07 # 0000 0111 - Uchar1max = (1<<7) - 1 - Uchar2max = (1<<11) - 1 - Uchar3max = (1<<16) - 1 - Ucharerr = 0xFFFD # unicode "replacement char" - Usurrself = 0x10000 - Usurr1 = 0xd800 - Usurr2 = 0xdc00 - Usurr3 = 0xe000 - Umax = 0x10ffff - - Spc = ' '[0] - Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t} - Hex = '0123456789abcdef' -end diff --git a/Library/Homebrew/vendor/multi_json/vendor/okjson.rb b/Library/Homebrew/vendor/multi_json/vendor/okjson.rb new file mode 100644 index 000000000..c18ed41c0 --- /dev/null +++ b/Library/Homebrew/vendor/multi_json/vendor/okjson.rb @@ -0,0 +1,602 @@ +# encoding: UTF-8 +# +# Copyright 2011, 2012 Keith Rarick +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# See https://github.com/kr/okjson for updates. + +require 'stringio' + +# Some parts adapted from +# http://golang.org/src/pkg/json/decode.go and +# http://golang.org/src/pkg/utf8/utf8.go +module MultiJson + module OkJson + extend self + + + # Decodes a json document in string s and + # returns the corresponding ruby value. + # String s must be valid UTF-8. If you have + # a string in some other encoding, convert + # it first. + # + # String values in the resulting structure + # will be UTF-8. + def decode(s) + ts = lex(s) + v, ts = textparse(ts) + if ts.length > 0 + raise Error, 'trailing garbage' + end + v + end + + + # Parses a "json text" in the sense of RFC 4627. + # Returns the parsed value and any trailing tokens. + # Note: this is almost the same as valparse, + # except that it does not accept atomic values. + def textparse(ts) + if ts.length < 0 + raise Error, 'empty' + end + + typ, _, val = ts[0] + case typ + when '{' then objparse(ts) + when '[' then arrparse(ts) + else + raise Error, "unexpected #{val.inspect}" + end + end + + + # Parses a "value" in the sense of RFC 4627. + # Returns the parsed value and any trailing tokens. + def valparse(ts) + if ts.length < 0 + raise Error, 'empty' + end + + typ, _, val = ts[0] + case typ + when '{' then objparse(ts) + when '[' then arrparse(ts) + when :val,:str then [val, ts[1..-1]] + else + raise Error, "unexpected #{val.inspect}" + end + end + + + # Parses an "object" in the sense of RFC 4627. + # Returns the parsed value and any trailing tokens. + def objparse(ts) + ts = eat('{', ts) + obj = {} + + if ts[0][0] == '}' + return obj, ts[1..-1] + end + + k, v, ts = pairparse(ts) + obj[k] = v + + if ts[0][0] == '}' + return obj, ts[1..-1] + end + + loop do + ts = eat(',', ts) + + k, v, ts = pairparse(ts) + obj[k] = v + + if ts[0][0] == '}' + return obj, ts[1..-1] + end + end + end + + + # Parses a "member" in the sense of RFC 4627. + # Returns the parsed values and any trailing tokens. + def pairparse(ts) + (typ, _, k), ts = ts[0], ts[1..-1] + if typ != :str + raise Error, "unexpected #{k.inspect}" + end + ts = eat(':', ts) + v, ts = valparse(ts) + [k, v, ts] + end + + + # Parses an "array" in the sense of RFC 4627. + # Returns the parsed value and any trailing tokens. + def arrparse(ts) + ts = eat('[', ts) + arr = [] + + if ts[0][0] == ']' + return arr, ts[1..-1] + end + + v, ts = valparse(ts) + arr << v + + if ts[0][0] == ']' + return arr, ts[1..-1] + end + + loop do + ts = eat(',', ts) + + v, ts = valparse(ts) + arr << v + + if ts[0][0] == ']' + return arr, ts[1..-1] + end + end + end + + + def eat(typ, ts) + if ts[0][0] != typ + raise Error, "expected #{typ} (got #{ts[0].inspect})" + end + ts[1..-1] + end + + + # Scans s and returns a list of json tokens, + # excluding white space (as defined in RFC 4627). + def lex(s) + ts = [] + while s.length > 0 + typ, lexeme, val = tok(s) + if typ == nil + raise Error, "invalid character at #{s[0,10].inspect}" + end + if typ != :space + ts << [typ, lexeme, val] + end + s = s[lexeme.length..-1] + end + ts + end + + + # Scans the first token in s and + # returns a 3-element list, or nil + # if s does not begin with a valid token. + # + # The first list element is one of + # '{', '}', ':', ',', '[', ']', + # :val, :str, and :space. + # + # The second element is the lexeme. + # + # The third element is the value of the + # token for :val and :str, otherwise + # it is the lexeme. + def tok(s) + case s[0] + when ?{ then ['{', s[0,1], s[0,1]] + when ?} then ['}', s[0,1], s[0,1]] + when ?: then [':', s[0,1], s[0,1]] + when ?, then [',', s[0,1], s[0,1]] + when ?[ then ['[', s[0,1], s[0,1]] + when ?] then [']', s[0,1], s[0,1]] + when ?n then nulltok(s) + when ?t then truetok(s) + when ?f then falsetok(s) + when ?" then strtok(s) + when Spc then [:space, s[0,1], s[0,1]] + when ?\t then [:space, s[0,1], s[0,1]] + when ?\n then [:space, s[0,1], s[0,1]] + when ?\r then [:space, s[0,1], s[0,1]] + else numtok(s) + end + end + + + def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end + def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end + def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end + + + def numtok(s) + m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s) + if m && m.begin(0) == 0 + if m[3] && !m[2] + [:val, m[0], Integer(m[1])*(10**Integer(m[3][1..-1]))] + elsif m[2] + [:val, m[0], Float(m[0])] + else + [:val, m[0], Integer(m[0])] + end + else + [] + end + end + + + def strtok(s) + m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s) + if ! m + raise Error, "invalid string literal at #{abbrev(s)}" + end + [:str, m[0], unquote(m[0])] + end + + + def abbrev(s) + t = s[0,10] + p = t['`'] + t = t[0,p] if p + t = t + '...' if t.length < s.length + '`' + t + '`' + end + + + # Converts a quoted json string literal q into a UTF-8-encoded string. + # The rules are different than for Ruby, so we cannot use eval. + # Unquote will raise an error if q contains control characters. + def unquote(q) + q = q[1...-1] + a = q.dup # allocate a big enough string + rubydoesenc = false + # In ruby >= 1.9, a[w] is a codepoint, not a byte. + if a.class.method_defined?(:force_encoding) + a.force_encoding('UTF-8') + rubydoesenc = true + end + r, w = 0, 0 + while r < q.length + c = q[r] + case true + when c == ?\\ + r += 1 + if r >= q.length + raise Error, "string literal ends with a \"\\\": \"#{q}\"" + end + + case q[r] + when ?",?\\,?/,?' + a[w] = q[r] + r += 1 + w += 1 + when ?b,?f,?n,?r,?t + a[w] = Unesc[q[r]] + r += 1 + w += 1 + when ?u + r += 1 + uchar = begin + hexdec4(q[r,4]) + rescue RuntimeError => e + raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}" + end + r += 4 + if surrogate? uchar + if q.length >= r+6 + uchar1 = hexdec4(q[r+2,4]) + uchar = subst(uchar, uchar1) + if uchar != Ucharerr + # A valid pair; consume. + r += 6 + end + end + end + if rubydoesenc + a[w] = '' << uchar + w += 1 + else + w += ucharenc(a, w, uchar) + end + else + raise Error, "invalid escape char #{q[r]} in \"#{q}\"" + end + when c == ?", c < Spc + raise Error, "invalid character in string literal \"#{q}\"" + else + # Copy anything else byte-for-byte. + # Valid UTF-8 will remain valid UTF-8. + # Invalid UTF-8 will remain invalid UTF-8. + # In ruby >= 1.9, c is a codepoint, not a byte, + # in which case this is still what we want. + a[w] = c + r += 1 + w += 1 + end + end + a[0,w] + end + + + # Encodes unicode character u as UTF-8 + # bytes in string a at position i. + # Returns the number of bytes written. + def ucharenc(a, i, u) + case true + when u <= Uchar1max + a[i] = (u & 0xff).chr + 1 + when u <= Uchar2max + a[i+0] = (Utag2 | ((u>>6)&0xff)).chr + a[i+1] = (Utagx | (u&Umaskx)).chr + 2 + when u <= Uchar3max + a[i+0] = (Utag3 | ((u>>12)&0xff)).chr + a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr + a[i+2] = (Utagx | (u&Umaskx)).chr + 3 + else + a[i+0] = (Utag4 | ((u>>18)&0xff)).chr + a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr + a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr + a[i+3] = (Utagx | (u&Umaskx)).chr + 4 + end + end + + + def hexdec4(s) + if s.length != 4 + raise Error, 'short' + end + (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3]) + end + + + def subst(u1, u2) + if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3 + return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself + end + return Ucharerr + end + + + def surrogate?(u) + Usurr1 <= u && u < Usurr3 + end + + + def nibble(c) + case true + when ?0 <= c && c <= ?9 then c.ord - ?0.ord + when ?a <= c && c <= ?z then c.ord - ?a.ord + 10 + when ?A <= c && c <= ?Z then c.ord - ?A.ord + 10 + else + raise Error, "invalid hex code #{c}" + end + end + + + # Encodes x into a json text. It may contain only + # Array, Hash, String, Numeric, true, false, nil. + # (Note, this list excludes Symbol.) + # X itself must be an Array or a Hash. + # No other value can be encoded, and an error will + # be raised if x contains any other value, such as + # Nan, Infinity, Symbol, and Proc, or if a Hash key + # is not a String. + # Strings contained in x must be valid UTF-8. + def encode(x) + case x + when Hash then objenc(x) + when Array then arrenc(x) + else + raise Error, 'root value must be an Array or a Hash' + end + end + + + def valenc(x) + case x + when Hash then objenc(x) + when Array then arrenc(x) + when String then strenc(x) + when Numeric then numenc(x) + when true then "true" + when false then "false" + when nil then "null" + else + if x.respond_to?(:to_json) + x.to_json + else + raise Error, "cannot encode #{x.class}: #{x.inspect}" + end + end + end + + + def objenc(x) + '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}' + end + + + def arrenc(a) + '[' + a.map{|x| valenc(x)}.join(',') + ']' + end + + + def keyenc(k) + case k + when String then strenc(k) + else + raise Error, "Hash key is not a string: #{k.inspect}" + end + end + + + def strenc(s) + t = StringIO.new + t.putc(?") + r = 0 + + # In ruby >= 1.9, s[r] is a codepoint, not a byte. + rubydoesenc = s.class.method_defined?(:encoding) + + while r < s.length + case s[r] + when ?" then t.print('\\"') + when ?\\ then t.print('\\\\') + when ?\b then t.print('\\b') + when ?\f then t.print('\\f') + when ?\n then t.print('\\n') + when ?\r then t.print('\\r') + when ?\t then t.print('\\t') + else + c = s[r] + case true + when rubydoesenc + begin + c.ord # will raise an error if c is invalid UTF-8 + t.write(c) + rescue + t.write(Ustrerr) + end + when Spc <= c && c <= ?~ + t.putc(c) + else + n = ucharcopy(t, s, r) # ensure valid UTF-8 output + r += n - 1 # r is incremented below + end + end + r += 1 + end + t.putc(?") + t.string + end + + + def numenc(x) + if ((x.nan? || x.infinite?) rescue false) + raise Error, "Numeric cannot be represented: #{x}" + end + "#{x}" + end + + + # Copies the valid UTF-8 bytes of a single character + # from string s at position i to I/O object t, and + # returns the number of bytes copied. + # If no valid UTF-8 char exists at position i, + # ucharcopy writes Ustrerr and returns 1. + def ucharcopy(t, s, i) + n = s.length - i + raise Utf8Error if n < 1 + + c0 = s[i].ord + + # 1-byte, 7-bit sequence? + if c0 < Utagx + t.putc(c0) + return 1 + end + + raise Utf8Error if c0 < Utag2 # unexpected continuation byte? + + raise Utf8Error if n < 2 # need continuation byte + c1 = s[i+1].ord + raise Utf8Error if c1 < Utagx || Utag2 <= c1 + + # 2-byte, 11-bit sequence? + if c0 < Utag3 + raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max + t.putc(c0) + t.putc(c1) + return 2 + end + + # need second continuation byte + raise Utf8Error if n < 3 + + c2 = s[i+2].ord + raise Utf8Error if c2 < Utagx || Utag2 <= c2 + + # 3-byte, 16-bit sequence? + if c0 < Utag4 + u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx) + raise Utf8Error if u <= Uchar2max + t.putc(c0) + t.putc(c1) + t.putc(c2) + return 3 + end + + # need third continuation byte + raise Utf8Error if n < 4 + c3 = s[i+3].ord + raise Utf8Error if c3 < Utagx || Utag2 <= c3 + + # 4-byte, 21-bit sequence? + if c0 < Utag5 + u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx) + raise Utf8Error if u <= Uchar3max + t.putc(c0) + t.putc(c1) + t.putc(c2) + t.putc(c3) + return 4 + end + + raise Utf8Error + rescue Utf8Error + t.write(Ustrerr) + return 1 + end + + + class Utf8Error < ::StandardError + end + + + class Error < ::StandardError + end + + + Utagx = 0x80 # 1000 0000 + Utag2 = 0xc0 # 1100 0000 + Utag3 = 0xe0 # 1110 0000 + Utag4 = 0xf0 # 1111 0000 + Utag5 = 0xF8 # 1111 1000 + Umaskx = 0x3f # 0011 1111 + Umask2 = 0x1f # 0001 1111 + Umask3 = 0x0f # 0000 1111 + Umask4 = 0x07 # 0000 0111 + Uchar1max = (1<<7) - 1 + Uchar2max = (1<<11) - 1 + Uchar3max = (1<<16) - 1 + Ucharerr = 0xFFFD # unicode "replacement char" + Ustrerr = "\xef\xbf\xbd" # unicode "replacement char" + Usurrself = 0x10000 + Usurr1 = 0xd800 + Usurr2 = 0xdc00 + Usurr3 = 0xe000 + + Spc = ' '[0] + Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t} + end +end diff --git a/Library/Homebrew/vendor/multi_json/version.rb b/Library/Homebrew/vendor/multi_json/version.rb index 1e7282421..a20d52a35 100644 --- a/Library/Homebrew/vendor/multi_json/version.rb +++ b/Library/Homebrew/vendor/multi_json/version.rb @@ -1,3 +1,3 @@ module MultiJson - VERSION = "1.0.3" + VERSION = "1.5.0" unless defined?(MultiJson::VERSION) end |
