Updated eJSON to use Eiffel 6.8 version.

Basically the changes are:

Replace ? by detachable
indexing by note
removing `is' from features, and in some places replaced by =
In the ecf now we need to include every gobo library, because the gobo.ecf, exclude libraries that are needed.
TODO: the test-suite is not void-safety.
This commit is contained in:
jvelilla
2011-07-07 12:03:25 +00:00
parent 94c5c90eaa
commit f4c472cb9f
26 changed files with 1009 additions and 929 deletions

View File

@@ -1,4 +1,4 @@
indexing
note
description: "Core factory class for creating JSON objects and corresponding Eiffel objects."
author: "Paul Cohen"
date: "$Date: $"
@@ -8,98 +8,73 @@ indexing
class EJSON
inherit
{NONE} KL_EXCEPTIONS
{NONE} EXCEPTIONS
feature -- Access
value (an_object: ?ANY): JSON_VALUE is
-- JSON value from Eiffel object. Raises an "eJSON exception" if
value (an_object: detachable ANY): detachable JSON_VALUE
-- JSON value from Eiffel object. Raises an "eJSON exception" if
-- unable to convert value.
local
b: BOOLEAN
i: INTEGER
i8: INTEGER_8
i16: INTEGER_16
i32: INTEGER_32
i64: INTEGER_64
n8: NATURAL_8
n16: NATURAL_16
n32: NATURAL_32
n64: NATURAL_64
r32: REAL_32
r64: REAL_64
a: ARRAY [ANY]
c: CHARACTER
s8: STRING_8
ucs: UC_STRING
ja: JSON_ARRAY
jc: JSON_CONVERTER
do
-- Try to convert from basic Eiffel types. Note that we check with
-- `conforms_to' since the client may have subclassed the base class
-- that these basic types are derived from.
if an_object = Void then
create {JSON_NULL} Result
elseif an_object.conforms_to (a_boolean) then
b ?= an_object
elseif attached {BOOLEAN} an_object as b then
create {JSON_BOOLEAN} Result.make_boolean (b)
elseif an_object.conforms_to (an_integer_8) then
i8 ?= an_object
elseif attached {INTEGER_8} an_object as i8 then
create {JSON_NUMBER} Result.make_integer (i8)
elseif an_object.conforms_to (an_integer_16) then
i16 ?= an_object
elseif attached {INTEGER_16} an_object as i16 then
create {JSON_NUMBER} Result.make_integer (i16)
elseif an_object.conforms_to (an_integer_32) then
i32 ?= an_object
elseif attached {INTEGER_32} an_object as i32 then
create {JSON_NUMBER} Result.make_integer (i32)
elseif an_object.conforms_to (an_integer_64) then
i64 ?= an_object
elseif attached {INTEGER_64} an_object as i64 then
create {JSON_NUMBER} Result.make_integer (i64)
elseif an_object.conforms_to (a_natural_8) then
n8 ?= an_object
elseif attached {NATURAL_8} an_object as n8 then
create {JSON_NUMBER} Result.make_natural (n8)
elseif an_object.conforms_to (a_natural_16) then
n16 ?= an_object
elseif attached {NATURAL_16} an_object as n16 then
create {JSON_NUMBER} Result.make_natural (n16)
elseif an_object.conforms_to (a_natural_32) then
n32 ?= an_object
elseif attached {NATURAL_32} an_object as n32 then
create {JSON_NUMBER} Result.make_natural (n32)
elseif an_object.conforms_to (a_natural_64) then
n64 ?= an_object
elseif attached {NATURAL_64} an_object as n64 then
create {JSON_NUMBER} Result.make_natural (n64)
elseif an_object.conforms_to (a_real_32) then
r32 ?= an_object
elseif attached {REAL_32} an_object as r32 then
create {JSON_NUMBER} Result.make_real (r32)
elseif an_object.conforms_to (a_real_64) then
r64 ?= an_object
elseif attached {REAL_64} an_object as r64 then
create {JSON_NUMBER} Result.make_real (r64)
elseif an_object.conforms_to (an_array) then
a ?= an_object
elseif attached {ARRAY [detachable ANY]} an_object as a then
create ja.make_array
from
i := a.lower
until
i > a.upper
loop
ja.add (value (a @ i))
if attached value (a @ i) as v then
ja.add (v)
else
check value_attached: False end
end
i := i + 1
end
Result := ja
elseif an_object.conforms_to (a_character) then
c ?= an_object
create {JSON_STRING} Result.make_json (c.out)
elseif an_object.conforms_to (a_uc_string) then
ucs ?= an_object
create {JSON_STRING} Result.make_json (ucs.to_utf8)
elseif an_object.conforms_to (a_string_8) then
s8 ?= an_object
elseif attached {CHARACTER_8} an_object as c8 then
create {JSON_STRING} Result.make_json (c8.out)
elseif attached {CHARACTER_32} an_object as c32 then
create {JSON_STRING} Result.make_json (c32.out)
elseif attached {STRING_8} an_object as s8 then
create {JSON_STRING} Result.make_json (s8)
elseif attached {STRING_32} an_object as s32 then
create {JSON_STRING} Result.make_json (s32.as_string_8) -- FIXME: need correct convertion/encoding here ...
end
if Result = Void then
-- Now check the converters
jc := converter_for (an_object)
if jc /= Void then
if an_object /= Void and then attached converter_for (an_object) as jc then
Result := jc.to_json (an_object)
else
raise (exception_failed_to_convert_to_json (an_object))
@@ -107,118 +82,108 @@ feature -- Access
end
end
object (a_value: JSON_VALUE; base_class: ?STRING): ANY is
object (a_value: detachable JSON_VALUE; base_class: detachable STRING): detachable ANY
-- Eiffel object from JSON value. If `base_class' /= Void an eiffel
-- object based on `base_class' will be returned. Raises an "eJSON
-- exception" if unable to convert value.
require
a_value_not_void: a_value /= Void
local
jc: JSON_CONVERTER
jb: JSON_BOOLEAN
jn: JSON_NUMBER
js: JSON_STRING
ja: JSON_ARRAY
jo: JSON_OBJECT
i: INTEGER
ll: LINKED_LIST [ANY]
t: HASH_TABLE [ANY, UC_STRING]
ll: LINKED_LIST [detachable ANY]
t: HASH_TABLE [detachable ANY, STRING_GENERAL]
keys: ARRAY [JSON_STRING]
ucs: UC_STRING
s32: STRING_32
s: detachable STRING_GENERAL
do
if base_class = Void then
if a_value.generator.is_equal ("JSON_NULL") then
Result := Void
elseif a_value.generator.is_equal ("JSON_BOOLEAN") then
jb ?= a_value
check jb /= Void end
Result := jb.item
elseif a_value.generator.is_equal ("JSON_NUMBER") then
jn ?= a_value
check jn /= Void end
if jn.item.is_integer_8 then
Result := jn.item.to_integer_8
elseif jn.item.is_integer_16 then
Result := jn.item.to_integer_16
elseif jn.item.is_integer_32 then
Result := jn.item.to_integer_32
elseif jn.item.is_integer_64 then
Result := jn.item.to_integer_64
elseif jn.item.is_natural_64 then
Result := jn.item.to_natural_64
elseif jn.item.is_double then
Result := jn.item.to_double
end
elseif a_value.generator.is_equal ("JSON_STRING") then
js ?= a_value
check js /= Void end
create ucs.make_from_string (js.item)
Result := ucs
elseif a_value.generator.is_equal ("JSON_ARRAY") then
ja ?= a_value
check ja /= Void end
from
create ll.make ()
i := 1
until
i > ja.count
loop
ll.extend (object (ja [i], Void))
i := i + 1
end
Result := ll
elseif a_value.generator.is_equal ("JSON_OBJECT") then
jo ?= a_value
check jo /= Void end
keys := jo.current_keys
create t.make (keys.count)
from
i := keys.lower
until
i > keys.upper
loop
ucs ?= object (keys [i], Void)
check ucs /= Void end
t.put (object (jo.item (keys [i]), Void), ucs)
i := i + 1
end
Result := t
end
else
if converters.has (base_class) then
jc := converters @ base_class
Result := jc.from_json (a_value)
else
raise (exception_failed_to_convert_to_eiffel (a_value, base_class))
end
end
if a_value = Void then
Result := Void
else
if base_class = Void then
if a_value = Void then
Result := Void
elseif attached {JSON_NULL} a_value then
Result := Void
elseif attached {JSON_BOOLEAN} a_value as jb then
Result := jb.item
elseif attached {JSON_NUMBER} a_value as jn then
if jn.item.is_integer_8 then
Result := jn.item.to_integer_8
elseif jn.item.is_integer_16 then
Result := jn.item.to_integer_16
elseif jn.item.is_integer_32 then
Result := jn.item.to_integer_32
elseif jn.item.is_integer_64 then
Result := jn.item.to_integer_64
elseif jn.item.is_natural_64 then
Result := jn.item.to_natural_64
elseif jn.item.is_double then
Result := jn.item.to_double
end
elseif attached {JSON_STRING} a_value as js then
create s32.make_from_string (js.item)
Result := s32
elseif attached {JSON_ARRAY} a_value as ja then
from
create ll.make
i := 1
until
i > ja.count
loop
ll.extend (object (ja [i], Void))
i := i + 1
end
Result := ll
elseif attached {JSON_OBJECT} a_value as jo then
keys := jo.current_keys
create t.make (keys.count)
from
i := keys.lower
until
i > keys.upper
loop
s ?= object (keys [i], Void)
check s /= Void end
t.put (object (jo.item (keys [i]), Void), s)
i := i + 1
end
Result := t
end
else
if converters.has_key (base_class) and then attached converters.found_item as jc then
Result := jc.from_json (a_value)
else
raise (exception_failed_to_convert_to_eiffel (a_value, base_class))
end
end
end
end
object_from_json (json: STRING; base_class: ?STRING): ANY is
-- Eiffel object from JSON representation. If `base_class' /= Void an
-- Eiffel object based on `base_class' will be returned. Raises an
object_from_json (json: STRING; base_class: detachable STRING): detachable ANY
-- Eiffel object from JSON representation. If `base_class' /= Void an
-- Eiffel object based on `base_class' will be returned. Raises an
-- "eJSON exception" if unable to convert value.
require
json_not_void: json /= Void
local
jv: JSON_VALUE
jv: detachable JSON_VALUE
do
json_parser.set_representation (json)
jv := json_parser.parse
Result := object (jv, base_class)
if jv /= Void then
Result := object (jv, base_class)
end
end
converter_for (an_object: ANY): JSON_CONVERTER is
converter_for (an_object: ANY): detachable JSON_CONVERTER
-- Converter for objects. Returns Void if none found.
require
an_object_not_void: an_object /= Void
do
if converters.has (an_object.generator) then
Result := converters @ an_object.generator
if converters.has_key (an_object.generator) then
Result := converters.found_item
end
end
json_reference (s: STRING): JSON_OBJECT is
json_reference (s: STRING): JSON_OBJECT
-- A JSON (Dojo style) reference object using `s' as the
-- reference value. The caller is responsable for ensuring
-- the validity of `s' as a json reference.
@@ -232,21 +197,20 @@ feature -- Access
create js_value.make_json (s)
Result.put (js_value, js_key)
end
json_references (l: DS_LIST [STRING]): JSON_ARRAY is
-- A JSON array of JSON (Dojo style) reference objects using the
-- strings in `l' as reference values. The caller is responsable
-- for ensuring the validity of all strings in `l' as json
json_references (l: LIST [STRING]): JSON_ARRAY
-- A JSON array of JSON (Dojo style) reference objects using the
-- strings in `l' as reference values. The caller is responsable
-- for ensuring the validity of all strings in `l' as json
-- references.
require
l_not_void: l /= Void
local
c: DS_LIST_CURSOR [STRING]
c: ITERATION_CURSOR [STRING]
do
create Result.make_array
from
c := l.new_cursor
c.start
until
c.after
loop
@@ -254,10 +218,10 @@ feature -- Access
c.forth
end
end
feature -- Change
add_converter (jc: JSON_CONVERTER) is
add_converter (jc: JSON_CONVERTER)
-- Add the converter `jc'.
require
jc_not_void: jc /= Void
@@ -269,7 +233,7 @@ feature -- Change
feature {NONE} -- Implementation
converters: DS_HASH_TABLE [JSON_CONVERTER, STRING] is
converters: HASH_TABLE [JSON_CONVERTER, STRING]
-- Converters hashed by generator (base class)
once
create Result.make (10)
@@ -277,9 +241,9 @@ feature {NONE} -- Implementation
feature {NONE} -- Implementation (Exceptions)
exception_prefix: STRING is "eJSON exception: "
exception_failed_to_convert_to_eiffel (a_value: JSON_VALUE; base_class: ?STRING): STRING is
exception_prefix: STRING = "eJSON exception: "
exception_failed_to_convert_to_eiffel (a_value: JSON_VALUE; base_class: detachable STRING): STRING
-- Exception message for failing to convert a JSON_VALUE to an instance of `a'.
do
Result := exception_prefix + "Failed to convert JSON_VALUE to an Eiffel object: " + a_value.generator
@@ -288,15 +252,18 @@ feature {NONE} -- Implementation (Exceptions)
end
end
exception_failed_to_convert_to_json (an_object: ?ANY): STRING is
exception_failed_to_convert_to_json (an_object: detachable ANY): STRING
-- Exception message for failing to convert `a' to a JSON_VALUE.
do
Result := exception_prefix + "Failed to convert Eiffel object to a JSON_VALUE: " + an_object.generator
Result := exception_prefix + "Failed to convert Eiffel object to a JSON_VALUE"
if an_object /= Void then
Result := ": " + an_object.generator
end
end
feature {NONE} -- Implementation (JSON parser)
json_parser: JSON_PARSER is
json_parser: JSON_PARSER
once
create Result.make_parser ("")
end
@@ -304,7 +271,7 @@ feature {NONE} -- Implementation (JSON parser)
feature {NONE} -- Implementation (Basic Eiffel objects)
a_boolean: BOOLEAN
an_integer_8: INTEGER_8
an_integer_16: INTEGER_16
@@ -320,26 +287,26 @@ feature {NONE} -- Implementation (Basic Eiffel objects)
a_natural_32: NATURAL_32
a_natural_64: NATURAL_64
a_real_32: REAL_32
a_real_64: REAL_64
an_array: ARRAY [ANY] is
an_array: ARRAY [ANY]
once
Result := <<>>
end
a_character: CHARACTER
a_string_8: STRING_8 is
a_string_8: STRING_8
once
Result := ""
end
a_uc_string: UC_STRING is
a_string_32: STRING_32
once
create Result.make_from_string ("")
Result := {STRING_32} ""
end
end -- class EJSON
end -- class EJSON