This commit is contained in:
2015-04-07 18:36:38 +02:00
59 changed files with 3873 additions and 2872 deletions

View File

@@ -7,3 +7,4 @@
*.ecf text
*.bat text
*.json text
*.txt text

View File

@@ -1,2 +1,2 @@
*.swp
EIFGENs
EIFGENs/

View File

@@ -1,10 +1,12 @@
History file for EJSON
History file for EJSON
======================
team: ""
date: "2011-07-06"
revision: "0.3.0"
WARNING: THIS FILE IS NOT UP TO DATE
+++++++++++++++++++++Important Changes since 0.2.0 version++++++++++++++++++++++++++++++++++++++++++++++
@@ -23,4 +25,4 @@ implementation.
*Added converters and factory classes
*Added new top level directories; library, test, build and example
*Added new top level directories; library, test, build and example

View File

@@ -1,4 +1,5 @@
Copyright (c) 2010 Javier Velilla and others, http://ejson.origo.ethz.ch
Copyright (c) 2010-2014 Javier Velilla, Jocelyn Fiat and others,
https://github.com/eiffelhub/json .
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -6,10 +7,10 @@ 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:
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.
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,
@@ -17,4 +18,4 @@ 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.
THE SOFTWARE.

View File

@@ -1,21 +1,26 @@
Readme file for eJSON
=====================
team: "Javier Velilla,Jocelyn Fiat, Paul Cohen"
date: "$Date$"
revision: "$Revision$"
team: "Javier Velilla, Jocelyn Fiat"
previous contributors: "Paul Cohen"
date: "2014-nov-17"
1. Introduction
---------------
eJSON stands for Eiffel JSON library and is a small Eiffel library for dealing
with the JSON format. The objective of the library is to provide two basic
features Eiffel2JSON and JSON2Eiffel.
with the JSON format. This library provides a JSON parser and visitors,
including a pretty printer.
The converters part is now obsolete and not recommended (remember: the
objective of converters were to provide two basic features Eiffel2JSON and
JSON2Eiffel). There will be a new design for converters as a standalone
library on top of Current json library.
2. Legal stuff
--------------
eJSON is copyrighted by the author Javier Velilla and others. It is licensed
eJSON is copyrighted by the author Javier Velilla, Jocelyn Fiat and others. It is licensed
under the MIT License. See the file license.txt in the same directory as this
readme file.
@@ -46,18 +51,18 @@ Currently the only documentation on eJSON is available at:
EJSON requires that you have:
1. Gobo 3.9 installed or later
2. One of the following compiler combinations installed:
* ISE Eiffel 6.5 or later.
1. One of the following compiler combinations installed:
* ISE Eiffel 13.11 or later.
* gec [try to test]
* tecomp [try to test]
eJSON probably works fine with other versions of the above compilers.
There are no known platform dependencies (Windows, Linux).
To install eJSON simply extract the ejson-X.Y.Z.zip file to some appropriate
place on your hard disk. There are no requirements on environment variables or
registry variables.
registry variables.
Note eJSON is also delivered within EiffelStudio release, under
$ISE_LIBRARY/contrib/library/text/parser/json
To verify that everything works you should compile the example programs and/or
the test program.
@@ -70,18 +75,18 @@ installation.
Directory Description
--------- -----------
doc Contains the eJSON.pdf documentation file.
examples Contains the two example programs.
ejson Contains the actual eJSON library classes.
test Contains a test program for eJSON.
doc Contains documentation file.
examples Contains example codes.
library Contains the actual eJSON library classes.
test Contains test suite for eJSON.
7. Contacting the Team
----------------------
Contact the team:
https://github.com/eiffelhub/json/issues
Javier Velilla «javier.hector@gmail.com»
Paul Cohen «paco@seibostudios.se»
Jocelyn Fiat «jfiat@eiffel.com»
8. Releases
@@ -92,8 +97,16 @@ history.txt.
Version Date Description
------- ---- -----------
0.6.0 2014-11-17 Fixed various issue with parsing string (such as \t and related),
Implemented escaping of slash '/' only in case of '</' to avoid
potential issue with javascript and </script>
Many feature renaming to match Eiffel style and naming convention,
kept previous feature as obsolete.
Restructured the library to make easy extraction of "converter"
classes if needed in the future.
Marked converters classes as obsolete.
0.5.0 2013-11-dd Added JSON_ITERATOR, simplified JSON_OBJECT
0.4.0 2012-12-12 Updated documentation URI
0.3.0 2011-07-06 JSON Factory Converters
0.2.0 2010-02-07 Adapted to EiffelStudio 6.4 or later, supports void-safety
0.1.0 2010-02-07 First release, Adapted to SmartEiffel 1.2r7 and EiffelStudio 6.2 or previous
0.1.0 2010-02-07 First release, Adapted to SmartEiffel 1.2r7 and EiffelStudio 6.2 or previous

View File

@@ -0,0 +1,295 @@
== Preface ==
This document is a living document! As always read and try out the code to understand what's really going on.
=== About the project ===
The eJSON project was started by Javier Velilla in 2008. The aim was simply to
provide JSON support to Eiffel programmers. A couple of other people have been
involved to various extent since the start; Berend de Boer, Jocelyn Fiat and
Manu Stapf. In 2009 Paul Cohen joined the project as an active developer and
later Jocelyn Fiat.
The current active maintainers:
- Javier Velilla
- Jocelyn Fiat
The formal name of the project is “eJSON”.
For questions regarding eJSON please contact
- <javier.hector at gmail.com>
- <jfiat at eiffel.com>
- or directly on [https://github.com/eiffelhub/json/issues]
=== Current version and status ===
The latest release is 0.6.0. eJSON has been improved and cleaned.
The converters are not obsolete.
== Introduction ==
=== What is JSON? ===
JSON (JavaScript Object Notation) is a lightweight computer data interchange format. It is a text-based, human-readable format for representing simple data structures and associative arrays (called objects). See the [http://en.wikipedia.org/wiki/JSON Wikipedia article on JSON], [http://www.json.org www.json.org] and [http://www.json.com www.json.com] for more information.
The JSON format is specified in [http://www.ietf.org/rfc/rfc4627.txt IETF RFC 4627] by Douglas Crockford. The official [http://www.iana.org/assignments/media-types Internet MIME media type] for JSON is "application/json". The recommended file name extension for JSON files is ".json".
=== Advantages ===
1. Lightweight data-interchange format.
2. Easy for humans to read and write.
3. Enables easy integration with AJAX/JavaScript web applications. See the article [http://www.developer.com/lang/jscript/article.php/3596836 Speeding Up AJAX with JSON] for a good short discussion on this subject.
4. JSON data structures translate with ease into the native data structures universal to almost all programming languages used today.
=== Use in Eiffel applications ===
JSON can be used as a general serialization format for Eiffel objects. As such it could be used as a:
* Data representation format in REST-based web service applications written in Eiffel.
* Serialization format for Eiffel objects in persistence solutions.
* File format for configuration files in Eiffel systems.
=== Prerequisites ===
eJSON works today with EiffelStudio 13.11
There is an optional extension that requires the latest snapshot of the Gobo Eiffel libraries (a working snapshot is distributed with EiffelStudio). The depencencies on Gobo are on Gobo's unicode
and regex libraries and for some of the extra features in eJSON, on Gobos structure classes DS_HASH_TABLE and DS_LINKED_LIST.
eJSON is intended to work with all ECMA compliant Eiffel compilers.
=== Installation ===
You can either download a given release and install on your machine or you can get the latest snapshot of the code.
To download go to the [http://ejson.origo.ethz.ch/download download page].
To get the latest snapshot of the code do:
: $ git clone https://github.com/eiffelhub/json.git json
*[https://github.com/eiffelhub/json/releases download page]
*[https://github.com/eiffelhub/json github project]
Note that the latest json release is also delivered with EiffelStudio installation under <code>$ISE_LIBRARY/contrib/library/text/parser/json</code>.
=== Cluster and directory layout ===
json/
library/ (Root directory for eJSON library classes)
kernel/ (All classes in this cluster should eventually only depend on ECMA Eiffel and FreeELKS).
json_array.e
json_boolean.e
json_null.e
json_number.e
json_object.e
json_string.e
json_value.e
parser/
json_parser.e
json_parser_access.e
json_reader.e
json_tokens.e
utility/
file/
json_file_reader.e
visitor/
json_visitor.e
json_iterator.e
json_pretty_string_visitor.e
print_json_visitor.e
converters/ (JSON core converter classes !OBSOLETE!)
json_converter.e
json_hash_table_converter.e
json_list_converter.e
json_linked_list_converter.e
json_arrayed_list_converter.e
support/
ejson.e
shared_ejson.e
gobo_converters/ (JSON core converter classes support for GOBO !OBSOLETE!)
converters/
json_ds_hash_table_converter.e
json_ds_linked_list_converter.e
shared_gobo_ejson.e
test/ (Contains autotest suite)
autotest/ (AutoTest based unit test).
examples/ (Example code)
=== Future development ===
Here is a list of suggestions for future development of eJSON.
* Ongoing: Provide a JSON_FACTORY class for easy conversion between arbitrary JSON and Eiffel values.
* Ongoing: Provide a mechanism for users to add custom converters between JSON values and user space Eiffel classes.
* Ongoing: Implement a full test framework for eJSON.
* Suggestion: Investigate performance and improve it if neccessary.
* Suggestion: Support JSON references. See [http://www.json.com/2007/10/19/json-referencing-proposal-and-library JSON Referencing Proposal and Library] and [http://www.sitepen.com/blog/2008/06/17/json-referencing-in-dojo JSON referencing in Dojo] for more information.
* Suggestion: Support JSON path. See [http://goessner.net/articles/JsonPath JSONPath - XPath for JSON] for more information.
* Suggestion: Support JSON schema validation. See [http://json-schema.org JSON Schema Proposal] for more information.
* Suggestion: Support RDF JSON serialization. See [http://n2.talis.com/wiki/RDF_JSON_Specification RDF JSON Specification] for more information.
* Suggestion: Add support to JSON classes for conversion from Eiffel manifest values. So one can write things like:
== A simple example ==
There are two basic approaches to using eJSON; either you use the basic JSON_VALUE classes, converting to and from JSON values to corresponding Eiffel instances or you use the high level eJSON interface class SHARED_EJSON. Of course you can use a mix of both approaches if you find it appropriate!
Here is an example of how to create a JSON number value from an INTEGER and then obtain the JSON representation for that value.
simple_example is
local
i: INTEGER
jn: JSON_NUMBER
s: STRING
do
i := 42
create jn.make_integer (i)
s := jn.representation -- s.is_equal ("42")
end
== Mapping of JSON values to Eiffel values ==
=== JSON number ===
JSON numbers are represented by the class JSON_NUMBER. JSON number values can be converted to/from NATURAL_*, INTEGER_* and REAL_64 values. For floating point values REAL_* is used. The complete mapping is as follows:
JSON number -> Eiffel:
* -128 <= n <= +127 -> INTEGER_8
* n can't be represented by INTEGER_8 and -32768 <= n <= +32767 -> INTEGER_16
* n can't be represented by INTEGER_16 and -2147483648 <= n <= +2147483647 -> INTEGER_32
* n can't be represented by INTEGER_32 and -9223372036854775808 <= n <= +9223372036854775807 -> INTEGER_64
* n can't be represented by INTEGER_64 and 9223372036854775808 <= n <= 18446744073709551615 -> NATURAL_64
* n has fractional dot '.' -> REAL_64.
* n -> eJSON exception if number can't be represented by a INTEGER_64, NATURAL_64 or REAL_64.
Eiffel -> JSON number:
* NATURAL_8, NATURAL_16, NATURAL_32, NATURAL_64, NATURAL -> JSON number
* INTEGER_8, INTEGER_16, INTEGER_32, INTEGER_64, INTEGER -> JSON number
* REAL_32, REAL_64, REAL -> JSON number
You can use the following creation routines to create JSON_NUMBER instances:
* JSON_NUMBER.make_integer
* JSON_NUMBER.make_real
* JSON_NUMBER.make_natural
eiffel_to_json_number_representation is
local
i: INTEGER
r: REAL
jn: JSON_NUMBER
do
print ("JSON representation of Eiffel INTEGER: '")
i := 123
create jn.make_integer (i)
print (jn.representation)
print ("'%N")
print ("JSON representation of Eiffel REAL: '")
r := 12.3
create jn.make_real (r)
print (jn.representation)
print ("'%N")
end
The output of the above code will be:
JSON representation of Eiffel INTEGER: '123'
JSON representation of Eiffel REAL: '12.300000190734863'
=== JSON boolean ===
JSON boolean values are represented by the class JSON_BOOLEAN. The JSON boolean value "true" is converted to/from the BOOLEAN value "True" and the JSON boolean value "false is converted to/from the BOOLEAN value "False".
eiffel_to_json_boolean_representation is
local
b: BOOLEAN
jb: JSON_BOOLEAN
do
print ("JSON representation of Eiffel BOOLEAN: '")
b := True
create jb.make (b)
print (jb.representation)
print ("'%N")
print("JSON representation of Eiffel BOOLEAN: '")
b := False
create jb.make (b)
print (jb.representation)
print ("'%N")
end
The output of the above code will be:
JSON representation of Eiffel BOOLEAN: 'true'
JSON representation of Eiffel BOOLEAN: 'false'
=== JSON string ===
JSON strings are represented by the class JSON_STRING. JSON string values can be converted to/from STRING_32, STRING and CHARACTER values. The complete mapping is as follows:
JSON string -> Eiffel:
* All JSON strings -> STRING or STRING_32
Eiffel -> JSON string:
* STRING_32 -> JSON string
* STRING -> JSON string
* CHARACTER -> JSON string
eiffel_to_json_string_representation is
local
s: STRING
js: JSON_STRING
do
print ("JSON representation of Eiffel STRING: '")
s := "JSON rocks!"
create js.make_from_string (s)
print (js.representation)
print ("'%N")
end
The output of the above code will be:
JSON representation of Eiffel STRING: '"JSON rocks!"'
Note: JSON escape unicode characters, as well a other specific characters, to get the unescaped string value, use either 'unescaped_string_8' or 'unescaped_string_32'.
=== JSON null ===
The JSON null value is represented by the class JSON_NULL. The JSON null value can be converted to/from Void.
eiffel_to_json_null_representation is
local
a: ANY
jn: JSON_NULL
do
create jn
print ("JSON representation for JSON null value: '")
print (jn.representation)
print ("'%N")
a := Void
if attached {JSON_NULL} json.value (a) as l_jn then -- json from SHARED_EJSON!
print ("JSON representation of Eiffel Void reference: '")
print (l_jn.representation)
print ("'%N")
end
end
The output of the above code will be:
JSON representation for JSON null value: 'null'
JSON representation of Eiffel Void reference: 'null'
=== JSON array ===
JSON array is represented by the class JSON_ARRAY.
=== JSON object ===
JSON object is represented by the class JSON_OBJECT.
== The eJSON visitor pattern ==
TBD. See examples.
== The eJSON file reader class ==
TBD.

View File

@@ -0,0 +1,83 @@
class
BASIC
create
make
feature {NONE} -- Initialization
make
-- Initialize `Current'.
local
parser: JSON_PARSER
printer: JSON_PRETTY_STRING_VISITOR
s: STRING_32
do
-- Create parser for content `json_content'
create parser.make_with_string (json_content)
-- Parse the content
parser.parse_content
if
parser.is_valid and then
attached parser.parsed_json_value as jv
then
-- Json content is valid, and well parser.
-- and the parsed json value is `jv'
-- Let's access the glossary/title value
if
attached {JSON_OBJECT} jv as j_object and then
attached {JSON_OBJECT} j_object.item ("glossary") as j_glossary and then
attached {JSON_STRING} j_glossary.item ("title") as j_title
then
print ("The glossary title is %"" + j_title.unescaped_string_8 + "%".%N")
else
print ("The glossary title was not found!%N")
end
-- Pretty print the parsed JSON
create s.make_empty
create printer.make (s)
jv.accept (printer)
print ("The JSON formatted using a pretty printer:%N")
print (s)
end
end
feature -- Status
feature -- Access
json_content: STRING = "[
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
]"
feature -- Change
feature {NONE} -- Implementation
invariant
-- invariant_clause: True
end

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="basic" uuid="5156B9EE-0436-42A3-BDA1-74710DF05A35">
<target name="basic">
<root class="BASIC" feature="make"/>
<setting name="console_application" value="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="json" location="..\..\library\json-safe.ecf" readonly="false"/>
<cluster name="basic" location=".\"/>
</target>
</system>

View File

@@ -5,20 +5,25 @@ note
revision: "$Revision$"
file: "$HeadURL: $"
class JSON_ARRAYED_LIST_CONVERTER
class
JSON_ARRAYED_LIST_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
JSON_LIST_CONVERTER
JSON_LIST_CONVERTER
redefine
object
end
create
make
make
feature -- Access
object: ARRAYED_LIST [detachable ANY]
object: ARRAYED_LIST [detachable ANY]
feature {NONE} -- Factory
@@ -27,4 +32,7 @@ feature {NONE} -- Factory
create Result.make (nb)
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_ARRAYED_LIST_CONVERTER

View File

@@ -0,0 +1,44 @@
note
description: "A JSON converter"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class
JSON_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
SHARED_EJSON
feature -- Access
object: ANY
-- Eiffel object
deferred
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
-- Convert from JSON value.
-- Returns Void if unable to convert
deferred
end
to_json (o: like object): detachable JSON_VALUE
-- Convert to JSON value
deferred
end
invariant
has_eiffel_object: object /= Void -- An empty object must be created at creation time!
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,88 @@
note
description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
author: "Paul Cohen"
date: "$Date: 2014-01-30 15:27:41 +0100 (jeu., 30 janv. 2014) $"
revision: "$Revision: 94128 $"
file: "$HeadURL: $"
class
JSON_HASH_TABLE_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
JSON_CONVERTER
create
make
feature {NONE} -- Initialization
make
do
create object.make (0)
end
feature -- Access
object: HASH_TABLE [ANY, HASHABLE]
feature -- Conversion
from_json (j: attached like to_json): like object
do
create Result.make (j.count)
across
j as ic
loop
if attached json.object (ic.item, Void) as l_object then
if attached {HASHABLE} json.object (ic.key, Void) as h then
Result.put (l_object, h)
else
check
key_is_hashable: False
end
end
else
check
object_attached: False
end
end
end
end
to_json (o: like object): detachable JSON_OBJECT
local
js: JSON_STRING
failed: BOOLEAN
do
create Result.make
across
o as c
loop
if attached {JSON_STRING} json.value (c.key) as l_key then
js := l_key
else
if attached {READABLE_STRING_GENERAL} c.key as s_key then
create js.make_from_string_general (s_key)
else
create js.make_from_string (c.key.out)
end
end
if attached json.value (c.item) as jv then
Result.put (jv, js)
else
failed := True
end
end
if failed then
Result := Void
end
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_HASH_TABLE_CONVERTER

View File

@@ -5,20 +5,25 @@ note
revision: "$Revision$"
file: "$HeadURL: $"
class JSON_LINKED_LIST_CONVERTER
class
JSON_LINKED_LIST_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
JSON_LIST_CONVERTER
JSON_LIST_CONVERTER
redefine
object
end
create
make
make
feature -- Access
object: LINKED_LIST [detachable ANY]
object: LINKED_LIST [detachable ANY]
feature {NONE} -- Factory
@@ -27,4 +32,7 @@ feature {NONE} -- Factory
create Result.make
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_LINKED_LIST_CONVERTER

View File

@@ -0,0 +1,80 @@
note
description: "A JSON converter for LIST [ANY]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class
JSON_LIST_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
JSON_CONVERTER
feature {NONE} -- Initialization
make
do
object := new_object (0)
end
feature -- Access
object: LIST [detachable ANY]
feature {NONE} -- Factory
new_object (nb: INTEGER): like object
deferred
ensure
Result /= Void
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
local
i: INTEGER
do
Result := new_object (j.count)
from
i := 1
until
i > j.count
loop
Result.extend (json.object (j [i], Void))
i := i + 1
end
end
to_json (o: like object): detachable JSON_ARRAY
local
c: ITERATION_CURSOR [detachable ANY]
failed: BOOLEAN
do
create Result.make (o.count)
from
c := o.new_cursor
until
c.after
loop
if attached json.value (c.item) as jv then
Result.add (jv)
else
failed := True
end
c.forth
end
if failed then
Result := Void
end
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_ARRAYED_LIST_CONVERTER

View File

@@ -5,9 +5,14 @@ note
revision: "$Revision$"
file: "$HeadURL: $"
class EJSON
class
EJSON
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
EXCEPTIONS
feature -- Access
@@ -19,13 +24,13 @@ feature -- Access
i: INTEGER
ja: JSON_ARRAY
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.
-- 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 attached {BOOLEAN} an_object as b then
create {JSON_BOOLEAN} Result.make_boolean (b)
create {JSON_BOOLEAN} Result.make (b)
elseif attached {INTEGER_8} an_object as i8 then
create {JSON_NUMBER} Result.make_integer (i8)
elseif attached {INTEGER_16} an_object as i16 then
@@ -47,7 +52,7 @@ feature -- Access
elseif attached {REAL_64} an_object as r64 then
create {JSON_NUMBER} Result.make_real (r64)
elseif attached {ARRAY [detachable ANY]} an_object as a then
create ja.make_array
create ja.make (a.count)
from
i := a.lower
until
@@ -56,24 +61,24 @@ feature -- Access
if attached value (a @ i) as v then
ja.add (v)
else
check value_attached: False end
check
value_attached: False
end
end
i := i + 1
end
Result := ja
elseif attached {CHARACTER_8} an_object as c8 then
create {JSON_STRING} Result.make_json (c8.out)
create {JSON_STRING} Result.make_from_string (c8.out)
elseif attached {CHARACTER_32} an_object as c32 then
create {JSON_STRING} Result.make_json (c32.out)
create {JSON_STRING} Result.make_from_string_32 (create {STRING_32}.make_filled (c32, 1))
elseif attached {STRING_8} an_object as s8 then
create {JSON_STRING} Result.make_json (s8)
create {JSON_STRING} Result.make_from_string (s8)
elseif attached {STRING_32} an_object as s32 then
create {JSON_STRING} Result.make_json_from_string_32 (s32)
create {JSON_STRING} Result.make_from_string_32 (s32)
end
if Result = Void then
-- Now check the converters
-- Now check the converters
if an_object /= Void and then attached converter_for (an_object) as jc then
Result := jc.to_json (an_object)
else
@@ -84,7 +89,7 @@ feature -- Access
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
-- object based on `base_class' will be returned. Raises an "eJSON
-- exception" if unable to convert value.
local
i: INTEGER
@@ -160,12 +165,10 @@ feature -- Access
-- "eJSON exception" if unable to convert value.
require
json_not_void: json /= Void
local
jv: detachable JSON_VALUE
do
json_parser.set_representation (json)
jv := json_parser.parse
if jv /= Void then
json_parser.parse_content
if json_parser.is_valid and then attached json_parser.parsed_json_value as jv then
Result := object (jv, base_class)
end
end
@@ -190,8 +193,8 @@ feature -- Access
js_key, js_value: JSON_STRING
do
create Result.make
create js_key.make_json ("$ref")
create js_value.make_json (s)
create js_key.make_from_string ("$ref")
create js_value.make_from_string (s)
Result.put (js_value, js_key)
end
@@ -205,7 +208,7 @@ feature -- Access
local
c: ITERATION_CURSOR [STRING]
do
create Result.make_array
create Result.make (l.count)
from
c := l.new_cursor
until
@@ -262,7 +265,10 @@ feature {NONE} -- Implementation (JSON parser)
json_parser: JSON_PARSER
once
create Result.make_parser ("")
create Result.make_with_string ("{}")
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class EJSON

View File

@@ -0,0 +1,43 @@
note
description: "[
Shared factory class for creating JSON objects. Maps JSON
objects to ELKS HASH_TABLEs and JSON arrays to ELKS
LINKED_LISTs. Use non-conforming inheritance from this
class to ensure that your classes share the same
JSON_FACTORY instance.
]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision: 89185 $"
file: "$HeadURL: $"
class
SHARED_EJSON
obsolete
"This JSON converter design has issues [Sept/2014]."
feature -- Access
json: EJSON
-- A shared EJSON instance with default converters for
--LINKED_LIST [ANY] and HASH_TABLE [ANY, HASHABLE]
local
jalc: JSON_ARRAYED_LIST_CONVERTER
jllc: JSON_LINKED_LIST_CONVERTER
jhtc: JSON_HASH_TABLE_CONVERTER
once
create Result
create jalc.make
Result.add_converter (jalc)
create jllc.make
Result.add_converter (jllc)
create jhtc.make
Result.add_converter (jhtc)
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class SHARED_EJSON

View File

@@ -1,37 +0,0 @@
note
description: "Objects that ..."
date: "$Date$"
revision: "$Revision$"
class
JSON_FILE_READER
feature -- Access
read_json_from (a_path: STRING): detachable STRING
local
l_file: PLAIN_TEXT_FILE
template_content: STRING
l_last_string: detachable STRING
do
create l_file.make_with_name (a_path)
-- We perform several checks until we make a real attempt to open the file.
if not l_file.exists then
print ("error: '" + a_path + "' does not exist%N")
else
if not l_file.is_readable then
print ("error: '" + a_path + "' is not readable.%N")
else
l_file.open_read
create template_content.make_empty
l_file.read_stream (l_file.count)
l_last_string := l_file.last_string
check l_last_string /= Void end -- implied by postcondition of `l_file.read_stream'
template_content.append (l_last_string.string)
Result := template_content
l_file.close
end
end
end
end

View File

@@ -9,20 +9,13 @@
</file_rule>
<option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard" namespace="EJSON.Library">
<assertions/>
<warning name="export_class_missing" enabled="false"/>
<warning name="old_verbatim_strings" enabled="false"/>
<warning name="syntax" enabled="false"/>
<warning name="vjrv" enabled="false"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/>
<cluster name="json" location=".\" recursive="true">
<file_rule>
<exclude>^/gobo$</exclude>
<exclude>^/kernel$</exclude>
<exclude>^/extras$</exclude>
</file_rule>
<cluster name="kernel" location=".\kernel\" recursive="true"/>
<cluster name="extras" location=".\extras\" recursive="true"/>
<cluster name="json" location=".\">
<cluster name="json_kernel" location=".\kernel\" recursive="true"/>
<cluster name="json_parser" location=".\parser\" recursive="true"/>
<cluster name="json_utility" location=".\utility\" recursive="true"/>
</cluster>
<cluster name="json_converter" location=".\converter\" recursive="true"/>
</target>
</system>

View File

@@ -9,20 +9,13 @@
</file_rule>
<option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" void_safety="none" syntax="standard" namespace="EJSON.Library">
<assertions/>
<warning name="export_class_missing" enabled="false"/>
<warning name="old_verbatim_strings" enabled="false"/>
<warning name="syntax" enabled="false"/>
<warning name="vjrv" enabled="false"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/>
<cluster name="json" location=".\" recursive="true">
<file_rule>
<exclude>^/gobo$</exclude>
<exclude>^/kernel$</exclude>
<exclude>^/extras$</exclude>
</file_rule>
<cluster name="kernel" location=".\kernel\" recursive="true"/>
<cluster name="extras" location=".\extras\" recursive="true"/>
<cluster name="json" location=".\" >
<cluster name="json_kernel" location=".\kernel" recursive="true"/>
<cluster name="json_parser" location=".\parser" recursive="true"/>
<cluster name="json_utility" location=".\utility" recursive="true"/>
</cluster>
<cluster name="json_converter" location=".\converter" recursive="true"/>
</target>
</system>

View File

@@ -12,6 +12,6 @@
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/>
<library name="json" location="json.ecf" readonly="true"/>
<library name="gobo_structure" location="$ISE_LIBRARY\library\gobo\gobo_structure.ecf"/>
<cluster name="json_gobo" location=".\gobo" recursive="true" />
<cluster name="json_gobo_converter" location=".\gobo_converter" recursive="true" />
</target>
</system>

View File

@@ -1,36 +0,0 @@
note
description: "A JSON converter"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class JSON_CONVERTER
inherit
SHARED_EJSON
feature -- Access
object: ANY
-- Eiffel object
deferred
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
-- Convert from JSON value.
-- Returns Void if unable to convert
deferred
end
to_json (o: like object): detachable JSON_VALUE
-- Convert to JSON value
deferred
end
invariant
has_eiffel_object: object /= Void -- An empty object must be created at creation time!
end

View File

@@ -1,76 +0,0 @@
note
description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
author: "Paul Cohen"
date: "$Date: 2014-01-30 15:27:41 +0100 (jeu., 30 janv. 2014) $"
revision: "$Revision: 94128 $"
file: "$HeadURL: $"
class JSON_HASH_TABLE_CONVERTER
inherit
JSON_CONVERTER
create
make
feature {NONE} -- Initialization
make
do
create object.make (0)
end
feature -- Access
object: HASH_TABLE [ANY, HASHABLE]
feature -- Conversion
from_json (j: attached like to_json): like object
do
create Result.make (j.count)
across
j as ic
loop
if attached json.object (ic.item, Void) as l_object then
if attached {HASHABLE} json.object (ic.key, Void) as h then
Result.put (l_object, h)
else
check key_is_hashable: False end
end
else
check object_attached: False end
end
end
end
to_json (o: like object): detachable JSON_OBJECT
local
c: HASH_TABLE_ITERATION_CURSOR [ANY, HASHABLE]
js: JSON_STRING
failed: BOOLEAN
do
create Result.make
from
c := o.new_cursor
until
c.after
loop
if attached {JSON_STRING} json.value (c.key) as l_key then
js := l_key
else
create js.make_json (c.key.out)
end
if attached json.value (c.item) as jv then
Result.put (jv, js)
else
failed := True
end
c.forth
end
if failed then
Result := Void
end
end
end -- class JSON_HASH_TABLE_CONVERTER

View File

@@ -1,74 +0,0 @@
note
description: "A JSON converter for LIST [ANY]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class JSON_LIST_CONVERTER
inherit
JSON_CONVERTER
feature {NONE} -- Initialization
make
do
object := new_object (0)
end
feature -- Access
object: LIST [detachable ANY]
feature {NONE} -- Factory
new_object (nb: INTEGER): like object
deferred
ensure
Result /= Void
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
local
i: INTEGER
do
Result := new_object (j.count)
from
i := 1
until
i > j.count
loop
Result.extend (json.object (j [i], Void))
i := i + 1
end
end
to_json (o: like object): detachable JSON_ARRAY
local
c: ITERATION_CURSOR [detachable ANY]
jv: detachable JSON_VALUE
failed: BOOLEAN
do
create Result.make_array
from
c := o.new_cursor
until
c.after
loop
jv := json.value (c.item)
if jv /= Void then
Result.add (jv)
else
failed := True
end
c.forth
end
if failed then
Result := Void
end
end
end -- class JSON_ARRAYED_LIST_CONVERTER

View File

@@ -1,178 +1,192 @@
note
description: "[
JSON_ARRAY represent an array in JSON.
An array in JSON is an ordered set of names.
Examples
array
[]
[elements]
]"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
description: "[
JSON_ARRAY represent an array in JSON.
An array in JSON is an ordered set of names.
Examples
array
[]
[elements]
]"
author: "$Author$"
date: "$date$"
revision: "$Revision$"
class
JSON_ARRAY
JSON_ARRAY
inherit
JSON_VALUE
JSON_VALUE
ITERABLE [JSON_VALUE]
DEBUG_OUTPUT
create
make_array
make, make_empty,
make_array
feature {NONE} -- Initialization
make_array
-- Initialize JSON Array
do
create values.make (10)
end
make (nb: INTEGER)
-- Initialize JSON array with capacity of `nb' items.
do
create items.make (nb)
end
make_empty
-- Initialize empty JSON array.
do
make (0)
end
make_array
-- Initialize JSON Array
obsolete
"Use `make' Sept/2014"
do
make (10)
end
feature -- Access
i_th alias "[]" (i: INTEGER): JSON_VALUE
-- Item at `i'-th position
require
is_valid_index: valid_index (i)
do
Result := values.i_th (i)
end
i_th alias "[]" (i: INTEGER): JSON_VALUE
-- Item at `i'-th position
require
is_valid_index: valid_index (i)
do
Result := items.i_th (i)
end
representation: STRING
local
i: INTEGER
do
Result := "["
from
i := 1
until
i > count
loop
Result.append (i_th (i).representation)
i := i + 1
if i <= count then
Result.append_character (',')
end
end
Result.append_character (']')
end
representation: STRING
do
Result := "["
across
items as ic
loop
if Result.count > 1 then
Result.append_character (',')
end
Result.append (ic.item.representation)
end
Result.append_character (']')
end
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_array' procedure on `a_visitor'.)
do
a_visitor.visit_json_array (Current)
end
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_array' procedure on `a_visitor'.)
do
a_visitor.visit_json_array (Current)
end
feature -- Access
new_cursor: ITERATION_CURSOR [JSON_VALUE]
-- Fresh cursor associated with current structure
do
Result := values.new_cursor
Result := items.new_cursor
end
feature -- Mesurement
count: INTEGER
-- Number of items.
do
Result := values.count
end
count: INTEGER
-- Number of items.
do
Result := items.count
end
feature -- Status report
valid_index (i: INTEGER): BOOLEAN
-- Is `i' a valid index?
do
Result := (1 <= i) and (i <= count)
end
valid_index (i: INTEGER): BOOLEAN
-- Is `i' a valid index?
do
Result := (1 <= i) and (i <= count)
end
feature -- Change Element
put_front (v: JSON_VALUE)
require
v_not_void: v /= Void
do
values.put_front (v)
ensure
has_new_value: old values.count + 1 = values.count and
values.first = v
end
require
v_not_void: v /= Void
do
items.put_front (v)
ensure
has_new_value: old items.count + 1 = items.count and items.first = v
end
add, extend (v: JSON_VALUE)
require
v_not_void: v /= Void
do
values.extend (v)
ensure
has_new_value: old values.count + 1 = values.count and
values.has (v)
end
add, extend (v: JSON_VALUE)
require
v_not_void: v /= Void
do
items.extend (v)
ensure
has_new_value: old items.count + 1 = items.count and items.has (v)
end
prune_all (v: JSON_VALUE)
-- Remove all occurrences of `v'.
require
v_not_void: v /= Void
do
values.prune_all (v)
ensure
not_has_new_value: not values.has (v)
end
require
v_not_void: v /= Void
do
items.prune_all (v)
ensure
not_has_new_value: not items.has (v)
end
wipe_out
-- Remove all items.
do
values.wipe_out
end
do
items.wipe_out
end
feature -- Report
hash_code: INTEGER
-- Hash code value
do
from
values.start
Result := values.item.hash_code
until
values.off
loop
Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code
values.forth
end
Result := Result \\ values.count
end
hash_code: INTEGER
-- Hash code value
local
l_started: BOOLEAN
do
across
items as ic
loop
if l_started then
Result := ((Result \\ 8388593) |<< 8) + ic.item.hash_code
else
Result := ic.item.hash_code
l_started := True
end
end
Result := Result \\ items.count
end
feature -- Conversion
array_representation: ARRAYED_LIST [JSON_VALUE]
-- Representation as a sequences of values
-- be careful, modifying the return object may have impact on the original JSON_ARRAY object
do
Result := values
end
array_representation: ARRAYED_LIST [JSON_VALUE]
-- Representation as a sequences of values.
-- be careful, modifying the return object may have impact on the original JSON_ARRAY object.
do
Result := items
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := count.out + " item(s)"
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := count.out + " item(s)"
end
feature {NONE} -- Implementation
values: ARRAYED_LIST [JSON_VALUE]
-- Value container
items: ARRAYED_LIST [JSON_VALUE]
-- Value container
invariant
value_not_void: values /= Void
items_not_void: items /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,61 +1,87 @@
note
description: "JSON Truth values"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
description: "JSON Boolean values"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
class
JSON_BOOLEAN
JSON_BOOLEAN
inherit
JSON_VALUE
JSON_VALUE
create
make_boolean
make,
make_true, make_false,
make_boolean
feature {NONE} -- Initialization
make_boolean (an_item: BOOLEAN)
--Initialize.
do
item := an_item
end
make (a_value: BOOLEAN)
-- Initialize Current JSON boolean with `a_boolean'.
do
item := a_value
end
make_true
-- Initialize Current JSON boolean with True.
do
make (True)
end
make_false
-- Initialize Current JSON boolean with False.
do
make (False)
end
make_boolean (a_item: BOOLEAN)
-- Initialize.
obsolete
"Use `make' Sept/2014"
do
make (a_item)
end
feature -- Access
item: BOOLEAN
-- Content
item: BOOLEAN
-- Content
hash_code: INTEGER
-- Hash code value
do
Result := item.hash_code
end
hash_code: INTEGER
-- Hash code value
do
Result := item.hash_code
end
representation: STRING
do
if item then
Result := "true"
else
Result := "false"
end
end
representation: STRING
do
if item then
Result := "true"
else
Result := "false"
end
end
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_boolean' procedure on `a_visitor'.)
do
a_visitor.visit_json_boolean (Current)
end
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_boolean' procedure on `a_visitor'.)
do
a_visitor.visit_json_boolean (Current)
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item.out
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item.out
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,47 +1,51 @@
note
description: "JSON Null Values"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
description: "JSON Null Values"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
class
JSON_NULL
JSON_NULL
inherit
JSON_VALUE
JSON_VALUE
feature --Access
hash_code: INTEGER
-- Hash code value
do
Result := null_value.hash_code
end
hash_code: INTEGER
-- Hash code value
do
Result := null_value.hash_code
end
representation: STRING
do
Result := "null"
end
representation: STRING
do
Result := "null"
end
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_element_a' procedure on `a_visitor'.)
do
a_visitor.visit_json_null (Current)
end
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_element_a' procedure on `a_visitor'.)
do
a_visitor.visit_json_null (Current)
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := null_value
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := null_value
end
feature {NONE}-- Implementation
feature {NONE} -- Implementation
null_value: STRING = "null"
null_value: STRING = "null"
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,99 +1,149 @@
note
description: "JSON Numbers, octal and hexadecimal formats are not used."
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
description: "JSON Numbers, octal and hexadecimal formats are not used."
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class
JSON_NUMBER
JSON_NUMBER
inherit
JSON_VALUE
redefine
is_equal
end
JSON_VALUE
redefine
is_equal
end
create
make_integer,
make_natural,
make_real
make_integer, make_natural, make_real
feature {NONE} -- initialization
make_integer (an_argument: INTEGER_64)
-- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'.
do
item := an_argument.out
numeric_type := INTEGER_TYPE
end
make_integer (an_argument: INTEGER_64)
-- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'.
do
item := an_argument.out
numeric_type := integer_type
end
make_natural (an_argument: NATURAL_64)
-- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'.
do
item := an_argument.out
numeric_type := NATURAL_TYPE
end
make_natural (an_argument: NATURAL_64)
-- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'.
do
item := an_argument.out
numeric_type := natural_type
end
make_real (an_argument: DOUBLE)
-- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'.
do
item := an_argument.out
numeric_type := DOUBLE_TYPE
end
make_real (an_argument: REAL_64)
-- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'.
do
item := an_argument.out
numeric_type := double_type
end
feature -- Access
item: STRING
-- Content
item: STRING
-- Content
hash_code: INTEGER
--Hash code value
do
Result := item.hash_code
end
numeric_type: INTEGER
-- Type of number (integer, natural or real).
representation: STRING
do
Result := item
end
feature -- Visitor pattern
hash_code: INTEGER
--Hash code value
do
Result := item.hash_code
end
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_number' procedure on `a_visitor'.)
do
a_visitor.visit_json_number (Current)
end
representation: STRING
do
Result := item
end
feature -- Status
feature -- Conversion
is_equal (other: like Current): BOOLEAN
-- Is `other' attached to an object of the same type
-- as current object and identical to it?
do
Result := item.is_equal (other.item)
end
integer_64_item: INTEGER_64
-- Associated integer value.
require
is_integer: is_integer
do
Result := item.to_integer_64
end
natural_64_item: NATURAL_64
-- Associated natural value.
require
is_natural: is_natural
do
Result := item.to_natural_64
end
double_item, real_64_item: REAL_64
-- Associated real value.
require
is_real: is_real
do
Result := item.to_real_64
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item
end
is_integer: BOOLEAN
-- Is Current an integer number?
do
Result := numeric_type = integer_type
end
is_natural: BOOLEAN
-- Is Current a natural number?
do
Result := numeric_type = natural_type
end
is_double, is_real: BOOLEAN
-- Is Current a real number?
do
Result := numeric_type = real_type
end
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_number' procedure on `a_visitor'.)
do
a_visitor.visit_json_number (Current)
end
feature -- Status
is_equal (other: like Current): BOOLEAN
-- Is `other' attached to an object of the same type
-- as current object and identical to it?
do
Result := item.is_equal (other.item)
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item
end
feature -- Implementation
INTEGER_TYPE: INTEGER = 1
DOUBLE_TYPE: INTEGER = 2
NATURAL_TYPE: INTEGER = 3
integer_type: INTEGER = 1
numeric_type: INTEGER
double_type, real_type: INTEGER = 2
natural_type: INTEGER = 3
invariant
item_not_void: item /= Void
item_not_void: item /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,250 +1,261 @@
note
description: "[
An JSON_OBJECT represent an object in JSON.
An object is an unordered set of name/value pairs
Examples:
object
{}
{"key": "value"}
]"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
description: "[
An JSON_OBJECT represent an object in JSON.
An object is an unordered set of name/value pairs
Examples:
object
{}
{"key": value}
{"key": "value"}
]"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class
JSON_OBJECT
JSON_OBJECT
inherit
JSON_VALUE
TABLE_ITERABLE [JSON_VALUE, JSON_STRING]
JSON_VALUE
DEBUG_OUTPUT
TABLE_ITERABLE [JSON_VALUE, JSON_STRING]
DEBUG_OUTPUT
create
make
make_empty, make_with_capacity, make
feature {NONE} -- Initialization
make
-- Initialize
do
create object.make (10)
end
make_with_capacity (nb: INTEGER)
-- Initialize with a capacity of `nb' items.
do
create items.make (nb)
end
make_empty
-- Initialize as empty object.
do
make_with_capacity (0)
end
make
-- Initialize with default capacity.
do
make_with_capacity (3)
end
feature -- Change Element
put (value: detachable JSON_VALUE; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: like value
do
l_value := value
if l_value = Void then
create {JSON_NULL} l_value
end
object.extend (l_value, key)
end
put_string (value: READABLE_STRING_GENERAL; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_STRING
do
create l_value.make_json_from_string_32 (value.as_string_32)
put (l_value, key)
end
put_integer (value: INTEGER_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_NUMBER
do
create l_value.make_integer (value)
put (l_value, key)
end
put_natural (value: NATURAL_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_NUMBER
do
create l_value.make_natural (value)
put (l_value, key)
end
put_real (value: DOUBLE; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_NUMBER
do
create l_value.make_real (value)
put (l_value, key)
end
put_boolean (value: BOOLEAN; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
require
key_not_present: not has_key (key)
local
l_value: JSON_BOOLEAN
do
create l_value.make_boolean (value)
put (l_value, key)
end
replace (value: detachable JSON_VALUE; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: like value
do
l_value := value
if l_value = Void then
create {JSON_NULL} l_value
end
object.force (l_value, key)
end
replace_with_string (value: READABLE_STRING_GENERAL; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_STRING
do
create l_value.make_json_from_string_32 (value.as_string_32)
replace (l_value, key)
end
replace_with_integer (value: INTEGER_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_NUMBER
do
create l_value.make_integer (value)
replace (l_value, key)
end
replace_with_with_natural (value: NATURAL_64; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_NUMBER
do
create l_value.make_natural (value)
replace (l_value, key)
end
replace_with_real (value: DOUBLE; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_NUMBER
do
create l_value.make_real (value)
replace (l_value, key)
end
replace_with_boolean (value: BOOLEAN; key: JSON_STRING)
-- Assuming there is no item of key `key',
-- insert `value' with `key'.
local
l_value: JSON_BOOLEAN
do
create l_value.make_boolean (value)
replace (l_value, key)
end
remove (key: JSON_STRING)
-- Remove item indexed by `key' if any.
put (a_value: detachable JSON_VALUE; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
require
a_key_not_present: not has_key (a_key)
do
object.remove (key)
if a_value = Void then
items.extend (create {JSON_NULL}, a_key)
else
items.extend (a_value, a_key)
end
end
put_string (a_value: READABLE_STRING_GENERAL; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
require
key_not_present: not has_key (a_key)
local
l_value: JSON_STRING
do
if attached {READABLE_STRING_8} a_value as s then
create l_value.make_from_string (s)
else
create l_value.make_from_string_32 (a_value.as_string_32)
end
put (l_value, a_key)
end
put_integer (a_value: INTEGER_64; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
require
key_not_present: not has_key (a_key)
local
l_value: JSON_NUMBER
do
create l_value.make_integer (a_value)
put (l_value, a_key)
end
put_natural (a_value: NATURAL_64; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
require
key_not_present: not has_key (a_key)
local
l_value: JSON_NUMBER
do
create l_value.make_natural (a_value)
put (l_value, a_key)
end
put_real (a_value: DOUBLE; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
require
key_not_present: not has_key (a_key)
local
l_value: JSON_NUMBER
do
create l_value.make_real (a_value)
put (l_value, a_key)
end
put_boolean (a_value: BOOLEAN; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
require
key_not_present: not has_key (a_key)
local
l_value: JSON_BOOLEAN
do
create l_value.make (a_value)
put (l_value, a_key)
end
replace (a_value: detachable JSON_VALUE; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
do
if a_value = Void then
items.force (create {JSON_NULL}, a_key)
else
items.force (a_value, a_key)
end
end
replace_with_string (a_value: READABLE_STRING_GENERAL; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
local
l_value: JSON_STRING
do
if attached {READABLE_STRING_8} a_value as s then
create l_value.make_from_string (s)
else
create l_value.make_from_string_32 (a_value.as_string_32)
end
replace (l_value, a_key)
end
replace_with_integer (a_value: INTEGER_64; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
local
l_value: JSON_NUMBER
do
create l_value.make_integer (a_value)
replace (l_value, a_key)
end
replace_with_with_natural (a_value: NATURAL_64; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
local
l_value: JSON_NUMBER
do
create l_value.make_natural (a_value)
replace (l_value, a_key)
end
replace_with_real (a_value: DOUBLE; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
local
l_value: JSON_NUMBER
do
create l_value.make_real (a_value)
replace (l_value, a_key)
end
replace_with_boolean (a_value: BOOLEAN; a_key: JSON_STRING)
-- Assuming there is no item of key `a_key',
-- insert `a_value' with `a_key'.
local
l_value: JSON_BOOLEAN
do
create l_value.make (a_value)
replace (l_value, a_key)
end
remove (a_key: JSON_STRING)
-- Remove item indexed by `a_key' if any.
do
items.remove (a_key)
end
wipe_out
-- Reset all items to default values; reset status.
-- Reset all items to default values; reset status.
do
object.wipe_out
items.wipe_out
end
feature -- Status report
has_key (a_key: JSON_STRING): BOOLEAN
-- has the JSON_OBJECT contains a specific key `a_key'.
do
Result := items.has (a_key)
end
has_item (a_value: JSON_VALUE): BOOLEAN
-- has the JSON_OBJECT contain a specfic item `a_value'
do
Result := items.has_item (a_value)
end
feature -- Access
has_key (key: JSON_STRING): BOOLEAN
-- has the JSON_OBJECT contains a specific key 'key'.
do
Result := object.has (key)
end
item (a_key: JSON_STRING): detachable JSON_VALUE
-- the json_value associated with a key `a_key'.
do
Result := items.item (a_key)
end
has_item (value: JSON_VALUE): BOOLEAN
-- has the JSON_OBJECT contain a specfic item 'value'
do
Result := object.has_item (value)
end
current_keys: ARRAY [JSON_STRING]
-- Array containing actually used keys.
do
Result := items.current_keys
end
item (key: JSON_STRING): detachable JSON_VALUE
-- the json_value associated with a key.
do
Result := object.item (key)
end
current_keys: ARRAY [JSON_STRING]
-- array containing actually used keys
do
Result := object.current_keys
end
representation: STRING
local
t: HASH_TABLE [JSON_VALUE, JSON_STRING]
do
create Result.make (2)
Result.append_character ('{')
from
t := map_representation
t.start
until
t.after
loop
Result.append (t.key_for_iteration.representation)
Result.append_character (':')
Result.append (t.item_for_iteration.representation)
t.forth
if not t.after then
Result.append_character (',')
end
end
Result.append_character ('}')
end
representation: STRING
-- <Precursor>
do
create Result.make (2)
Result.append_character ('{')
across
items as ic
loop
if Result.count > 1 then
Result.append_character (',')
end
Result.append (ic.key.representation)
Result.append_character (':')
Result.append (ic.item.representation)
end
Result.append_character ('}')
end
feature -- Mesurement
count: INTEGER
-- Number of field
-- Number of field.
do
Result := object.count
Result := items.count
end
feature -- Access
@@ -252,7 +263,7 @@ feature -- Access
new_cursor: TABLE_ITERATION_CURSOR [JSON_VALUE, JSON_STRING]
-- Fresh cursor associated with current structure
do
Result := object.new_cursor
Result := items.new_cursor
end
feature -- Status report
@@ -260,58 +271,61 @@ feature -- Status report
is_empty: BOOLEAN
-- Is empty object?
do
Result := object.is_empty
Result := items.is_empty
end
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_object' procedure on `a_visitor'.)
do
a_visitor.visit_json_object (Current)
end
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_object' procedure on `a_visitor'.)
do
a_visitor.visit_json_object (Current)
end
feature -- Conversion
map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING]
--A representation that maps keys to values
do
Result := object
end
map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING]
-- A representation that maps keys to values
do
Result := items
end
feature -- Report
hash_code: INTEGER
-- Hash code value
do
from
object.start
Result := object.out.hash_code
until
object.off
loop
Result := ((Result \\ 8388593) |<< 8) + object.item_for_iteration.hash_code
object.forth
end
-- Ensure it is a positive value.
Result := Result.hash_code
end
hash_code: INTEGER
-- Hash code value
do
from
items.start
Result := items.out.hash_code
until
items.off
loop
Result := ((Result \\ 8388593) |<< 8) + items.item_for_iteration.hash_code
items.forth
end
-- Ensure it is a positive value.
Result := Result.hash_code
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := count.out + " item(s)"
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := count.out + "item(s)"
end
feature {NONE} -- Implementation
object: HASH_TABLE [JSON_VALUE, JSON_STRING]
-- Value container
items: HASH_TABLE [JSON_VALUE, JSON_STRING]
-- Value container
invariant
object_not_void: object /= Void
items_not_void: items /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,70 +1,117 @@
note
description: "[
A JSON_STRING represent a string in JSON.
A string is a collection of zero or more Unicodes characters, wrapped in double
quotes, using blackslash espaces.
]"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
description: "[
A JSON_STRING represent a string in JSON.
A string is a collection of zero or more Unicodes characters, wrapped in double
quotes, using blackslash espaces.
]"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class
JSON_STRING
JSON_STRING
inherit
JSON_VALUE
redefine
is_equal
end
JSON_VALUE
redefine
is_equal
end
create
make_json,
make_json_from_string_32,
make_with_escaped_json
make_from_string, make_from_string_32, make_from_string_general,
make_from_escaped_json_string,
make_with_escaped_json, make_json, make_json_from_string_32
convert
make_json ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
make_json_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32})
make_from_string ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
make_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32}),
make_from_string_general ({READABLE_STRING_GENERAL, STRING_GENERAL, IMMUTABLE_STRING_GENERAL})
feature {NONE} -- Initialization
make_json (s: READABLE_STRING_8)
-- Initialize.
require
item_not_void: s /= Void
do
make_with_escaped_json (escaped_json_string (s))
end
make_from_string (s: READABLE_STRING_8)
-- Initialize from ascii string `s'.
require
s_not_void: s /= Void
do
make_from_escaped_json_string (escaped_json_string (s))
end
make_json_from_string_32 (s: READABLE_STRING_32)
-- Initialize from STRING_32 `s'.
require
item_not_void: s /= Void
do
make_with_escaped_json (escaped_json_string_32 (s))
end
make_from_string_32 (s: READABLE_STRING_32)
-- Initialize from unicode string `s'.
require
s_not_void: s /= Void
do
make_from_escaped_json_string (escaped_json_string (s))
end
make_with_escaped_json (s: READABLE_STRING_8)
-- Initialize with an_item already escaped
require
item_not_void: s /= Void
do
item := s
end
make_from_string_general (s: READABLE_STRING_GENERAL)
-- Initialize from string `s'.
require
s_not_void: s /= Void
do
if attached {READABLE_STRING_8} s as s8 then
make_from_string (s8)
else
make_from_string_32 (s.as_string_32)
end
end
make_from_escaped_json_string (a_escaped_string: READABLE_STRING_8)
-- Initialize with `a_escaped_string' already JSON escaped.
require
a_escaped_string_not_void: a_escaped_string /= Void
do
item := a_escaped_string
end
make_with_escaped_json (a_escaped_string: READABLE_STRING_8)
-- Initialize with `a_escaped_string' already JSON escaped.
obsolete
"Use `make_from_escaped_json_string' Sept/2014"
require
a_escaped_string_not_void: a_escaped_string /= Void
do
make_from_escaped_json_string (a_escaped_string)
end
make_from_json_string (a_json: JSON_STRING)
-- Initialize with `a_json' string value.
do
make_from_escaped_json_string (a_json.item)
end
make_json (s: READABLE_STRING_8)
-- Initialize.
obsolete
"Use `make_from_string' Sept/2014"
require
item_not_void: s /= Void
do
make_with_escaped_json (escaped_json_string (s))
end
make_json_from_string_32 (s: READABLE_STRING_32)
-- Initialize from STRING_32 `s'.
obsolete
"Use `make_from_string_32' Sept/2014"
require
item_not_void: s /= Void
do
make_with_escaped_json (escaped_json_string (s))
end
feature -- Access
item: STRING
-- Contents with escaped entities if any
item: STRING
-- Contents with escaped entities if any
feature -- Conversion
unescaped_string_8: STRING_8
-- Unescaped string from `item'.
-- Unescaped ascii string from `item'.
--| note: valid only if `item' does not encode any unicode character.
local
s: like item
@@ -75,7 +122,7 @@ feature -- Conversion
end
unescaped_string_32: STRING_32
-- Unescaped string 32 from `item'
-- Unescaped uncode string from `item'
--| some encoders uses UTF-8 , and not the recommended pure json encoding
--| thus, let's support the UTF-8 encoding during decoding.
local
@@ -86,14 +133,14 @@ feature -- Conversion
unescape_to_string_32 (Result)
end
representation: STRING
-- String representation of `item' with escaped entities if any
do
create Result.make (item.count + 2)
Result.append_character ('%"')
Result.append (item)
Result.append_character ('%"')
end
representation: STRING
-- String representation of `item' with escaped entities if any.
do
create Result.make (item.count + 2)
Result.append_character ('%"')
Result.append (item)
Result.append_character ('%"')
end
unescape_to_string_8 (a_output: STRING_8)
-- Unescape string `item' into `a_output'.
@@ -105,16 +152,23 @@ feature -- Conversion
do
s := item
n := s.count
from i := 1 until i > n loop
c := s[i]
from
i := 1
until
i > n
loop
c := s [i]
if c = '\' then
if i < n then
inspect s[i+1]
inspect s [i + 1]
when '%"' then
a_output.append_character ('%"')
i := i + 2
when '\' then
a_output.append_character ('\')
i := i + 2
when '%"' then
a_output.append_character ('%"')
when '/' then
a_output.append_character ('/')
i := i + 2
when 'b' then
a_output.append_character ('%B')
@@ -132,15 +186,15 @@ feature -- Conversion
a_output.append_character ('%T')
i := i + 2
when 'u' then
--| Leave Unicode \uXXXX unescaped
a_output.append_character ('\')
--| Leave unicode \uXXXX unescaped
a_output.append_character (c) -- '\'
i := i + 1
else
a_output.append_character ('\')
a_output.append_character (c) -- '\'
i := i + 1
end
else
a_output.append_character ('\')
a_output.append_character (c) -- '\'
i := i + 1
end
else
@@ -163,16 +217,23 @@ feature -- Conversion
do
s := item
n := s.count
from i := 1 until i > n loop
from
i := 1
until
i > n
loop
ch := s.item (i)
if ch = '\' then
if i < n then
inspect s[i+1]
inspect s [i + 1]
when '%"' then
a_output.append_character ('%"')
i := i + 2
when '\' then
a_output.append_character ('\')
i := i + 2
when '%"' then
a_output.append_character ('%"')
when '/' then
a_output.append_character ('/')
i := i + 2
when 'b' then
a_output.append_character ('%B')
@@ -194,50 +255,40 @@ feature -- Conversion
if hex.count = 4 then
a_output.append_code (hexadecimal_to_natural_32 (hex))
end
i := i + 6 -- i +2 +4
i := i + 6 -- i+2+4
else
a_output.append_character ('\')
a_output.append_character (ch) -- '\'
i := i + 1
end
else
a_output.append_character ('\')
a_output.append_character (ch) -- '\'
i := i + 1
end
else
c := ch.natural_32_code
if c <= 0x7F then
-- 0xxxxxxx
check ch = c.to_character_32 end
check
ch = c.to_character_32
end
a_output.append_character (ch)
elseif c <= 0xDF then
-- 110xxxxx 10xxxxxx
i := i + 1
if i <= n then
a_output.append_code (
((c & 0x1F) |<< 6) |
(s.code (i) & 0x3F)
)
a_output.append_code (((c & 0x1F) |<< 6) | (s.code (i) & 0x3F))
end
elseif c <= 0xEF then
-- 1110xxxx 10xxxxxx 10xxxxxx
i := i + 2
if i <= n then
a_output.append_code (
((c & 0xF) |<< 12) |
((s.code (i - 1) & 0x3F) |<< 6) |
(s.code (i) & 0x3F)
)
a_output.append_code (((c & 0xF) |<< 12) | ((s.code (i - 1) & 0x3F) |<< 6) | (s.code (i) & 0x3F))
end
elseif c <= 0xF7 then
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
i := i + 3
if i <= n then
a_output.append_code (
((c & 0x7) |<< 18) |
((s.code (i - 2) & 0x3F) |<< 12) |
((s.code (i - 1) & 0x3F) |<< 6) |
(s.code (i) & 0x3F)
)
a_output.append_code (((c & 0x7) |<< 18) | ((s.code (i - 2) & 0x3F) |<< 12) | ((s.code (i - 1) & 0x3F) |<< 6) | (s.code (i) & 0x3F))
end
end
i := i + 1
@@ -247,65 +298,101 @@ feature -- Conversion
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_string' procedure on `a_visitor'.)
do
a_visitor.visit_json_string (Current)
end
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_string' procedure on `a_visitor'.)
do
a_visitor.visit_json_string (Current)
end
feature -- Comparison
is_equal (other: like Current): BOOLEAN
-- Is JSON_STRING made of same character sequence as `other'
-- (possibly with a different capacity)?
do
Result := item.same_string (other.item)
end
is_equal (other: like Current): BOOLEAN
-- Is JSON_STRING made of same character sequence as `other'
-- (possibly with a different capacity)?
do
Result := item.same_string (other.item)
end
feature -- Change Element
append (a_string: STRING)
-- Add a_string
require
a_string_not_void: a_string /= Void
do
item.append_string (a_string)
end
append (a_escaped_string: READABLE_STRING_8)
-- Add JSON escaped string `a_escaped_string'
require
a_escaped_string_not_void: a_escaped_string /= Void
do
item.append_string (a_escaped_string)
end
append_json_string (a_json_string: JSON_STRING)
-- Add JSON string `a_json_string'
require
a_json_string_not_void: a_json_string /= Void
do
append (a_json_string.item)
end
append_string (s: READABLE_STRING_8)
-- Add ascii string `s'
require
s_not_void: s /= Void
do
append (escaped_json_string (s))
end
append_string_32 (s: READABLE_STRING_32)
-- Add unicode string `s'
require
s_not_void: s /= Void
do
append (escaped_json_string (s))
end
append_string_general (s: READABLE_STRING_GENERAL)
-- Add unicode string `s'
require
s_not_void: s /= Void
do
if attached {READABLE_STRING_8} s as s8 then
append_string (s.as_string_8)
else
append_string_32 (s.as_string_32)
end
end
feature -- Status report
hash_code: INTEGER
-- Hash code value
do
Result := item.hash_code
end
hash_code: INTEGER
-- Hash code value
do
Result := item.hash_code
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item
end
feature {NONE} -- Implementation
is_hexadecimal (s: READABLE_STRING_8): BOOLEAN
-- Is `s' an hexadecimal value?
is_hexadecimal (s: READABLE_STRING_8): BOOLEAN
-- Is `s' an hexadecimal value?
local
i: INTEGER
do
do
from
Result := True
i := 1
until
i > s.count or not Result
loop
Result := s[i].is_hexa_digit
Result := s [i].is_hexa_digit
i := i + 1
end
end
end
hexadecimal_to_natural_32 (s: READABLE_STRING_8): NATURAL_32
-- Hexadecimal string `s' converted to NATURAL_32 value
@@ -317,13 +404,11 @@ feature {NONE} -- Implementation
char: CHARACTER
do
nb := s.count
if nb >= 2 and then s.item (2) = 'x' then
i := 3
else
i := 1
end
from
until
i > nb
@@ -339,37 +424,10 @@ feature {NONE} -- Implementation
end
end
escaped_json_string (s: READABLE_STRING_8): STRING_8
-- JSON string with '"' and '\' characters escaped
require
s_not_void: s /= Void
local
i, n: INTEGER
c: CHARACTER_8
do
n := s.count
create Result.make (n + n // 10)
from i := 1 until i > n loop
c := s.item (i)
inspect c
when '%"' then Result.append_string ("\%"")
when '\' then Result.append_string ("\\")
when '%B' then Result.append_string ("\b")
when '%F' then Result.append_string ("\f")
when '%N' then Result.append_string ("\n")
when '%R' then Result.append_string ("\r")
when '%T' then Result.append_string ("\t")
else
Result.extend (c)
end
i := i + 1
end
end
escaped_json_string_32 (s: READABLE_STRING_32): STRING_8
-- JSON string with '"' and '\' characters and Unicode escaped
require
s_not_void: s /= Void
escaped_json_string (s: READABLE_STRING_GENERAL): STRING_8
-- JSON string with '"' and '\' characters and unicode escaped
require
s_not_void: s /= Void
local
i, j, n: INTEGER
uc: CHARACTER_32
@@ -378,25 +436,44 @@ feature {NONE} -- Implementation
do
n := s.count
create Result.make (n + n // 10)
from i := 1 until i > n loop
from
i := 1
until
i > n
loop
uc := s.item (i)
if uc.is_character_8 then
c := uc.to_character_8
inspect c
when '%"' then Result.append_string ("\%"")
when '\' then Result.append_string ("\\")
when '%B' then Result.append_string ("\b")
when '%F' then Result.append_string ("\f")
when '%N' then Result.append_string ("\n")
when '%R' then Result.append_string ("\r")
when '%T' then Result.append_string ("\t")
when '%"' then
Result.append_string ("\%"")
when '\' then
Result.append_string ("\\")
when '/' then
-- To avoid issue with Javascript </script> ...
-- escape only </ to <\/
if s.valid_index (i - 1) and then s.item (i - 1) = '<' then
Result.append_string ("\/")
else
Result.append_string ("/")
end
when '%B' then
Result.append_string ("\b")
when '%F' then
Result.append_string ("\f")
when '%N' then
Result.append_string ("\n")
when '%R' then
Result.append_string ("\r")
when '%T' then
Result.append_string ("\t")
else
Result.extend (c)
end
else
Result.append ("\u")
h := uc.code.to_hex_string
-- Remove first 0 and keep 4 hexa digit
-- Remove first 0 and keep 4 hexa digit
from
j := 1
until
@@ -405,14 +482,15 @@ feature {NONE} -- Implementation
j := j + 1
end
h := h.substring (j, h.count)
from
until
h.count >= 4
loop
h.prepend_integer (0)
end
check h.count = 4 end
check
hexastring_has_4_chars: h.count = 4
end
Result.append (h)
end
i := i + 1
@@ -420,6 +498,9 @@ feature {NONE} -- Implementation
end
invariant
item_not_void: item /= Void
item_not_void: item /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,43 +1,46 @@
note
description:"[
JSON_VALUE represent a value in JSON.
A value can be
* a string in double quotes
* a number
* boolean value(true, false )
* null
* an object
* an array
]"
author: "Javier Velilla"
date: "2008/05/19"
revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
description: "[
JSON_VALUE represent a value in JSON.
A value can be
* a string in double quotes
* a number
* boolean value(true, false )
* null
* an object
* an array
]"
author: "Javier Velilla"
date: "2008/05/19"
revision: "Revision 0.1"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
deferred class
JSON_VALUE
JSON_VALUE
inherit
HASHABLE
DEBUG_OUTPUT
HASHABLE
DEBUG_OUTPUT
feature -- Access
representation: STRING
-- UTF-8 encoded Unicode string representation of Current
deferred
end
representation: STRING
-- UTF-8 encoded Unicode string representation of Current
deferred
end
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_*' procedure on `a_visitor'.)
require
a_visitor_not_void: a_visitor /= Void
deferred
end
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_*' procedure on `a_visitor'.)
require
a_visitor_not_void: a_visitor /= Void
deferred
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,513 +0,0 @@
note
description: "Parse serialized JSON data"
author: "jvelilla"
date: "2008/08/24"
revision: "Revision 0.1"
class
JSON_PARSER
inherit
JSON_READER
JSON_TOKENS
create
make_parser
feature {NONE} -- Initialize
make_parser (a_json: STRING)
-- Initialize.
require
json_not_empty: a_json /= Void and then not a_json.is_empty
do
make (a_json)
is_parsed := True
create errors.make
end
feature -- Status report
is_parsed: BOOLEAN
-- Is parsed?
errors: LINKED_LIST [STRING]
-- Current errors
current_errors: STRING
-- Current errors as string
do
create Result.make_empty
from
errors.start
until
errors.after
loop
Result.append_string (errors.item + "%N")
errors.forth
end
end
feature -- Element change
report_error (e: STRING)
-- Report error `e'
require
e_not_void: e /= Void
do
errors.force (e)
end
feature -- Commands
parse_json: detachable JSON_VALUE
-- Parse JSON data `representation'
-- start ::= object | array
do
if is_valid_start_symbol then
Result := parse
if extra_elements then
is_parsed := False
end
else
is_parsed := False
report_error ("Syntax error unexpected token, expecting `{' or `['")
end
end
parse: detachable JSON_VALUE
-- Parse JSON data `representation'
local
c: CHARACTER
do
if is_parsed then
skip_white_spaces
c := actual
inspect c
when j_OBJECT_OPEN then
Result := parse_object
when j_STRING then
Result := parse_string
when j_ARRAY_OPEN then
Result := parse_array
else
if c.is_digit or c = j_MINUS then
Result := parse_number
elseif is_null then
Result := create {JSON_NULL}
next
next
next
elseif is_true then
Result := create {JSON_BOOLEAN}.make_boolean (True)
next
next
next
elseif is_false then
Result := create {JSON_BOOLEAN}.make_boolean (False)
next
next
next
next
else
is_parsed := False
report_error ("JSON is not well formed in parse")
Result := Void
end
end
end
ensure
is_parsed_implies_result_not_void: is_parsed implies Result /= Void
end
parse_object: JSON_OBJECT
-- object
-- {}
-- {"key" : "value" [,]}
local
has_more: BOOLEAN
l_json_string: detachable JSON_STRING
l_value: detachable JSON_VALUE
do
create Result.make
-- check if is an empty object {}
next
skip_white_spaces
if actual = j_OBJECT_CLOSE then
--is an empty object
else
-- a complex object {"key" : "value"}
previous
from has_more := True until not has_more loop
next
skip_white_spaces
l_json_string := parse_string
next
skip_white_spaces
if actual = ':' then
next
skip_white_spaces
else
is_parsed := False
report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
has_more := False
end
l_value := parse
if is_parsed and then (l_value /= Void and l_json_string /= Void) then
Result.put (l_value, l_json_string)
next
skip_white_spaces
if actual = j_OBJECT_CLOSE then
has_more := False
elseif actual /= ',' then
has_more := False
is_parsed := False
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
end
else
has_more := False
-- explain the error
end
end
end
end
parse_string: detachable JSON_STRING
-- Parsed string
local
has_more: BOOLEAN
l_json_string: STRING
l_unicode: STRING
c: like actual
do
create l_json_string.make_empty
if actual = j_STRING then
from
has_more := True
until
not has_more
loop
next
c := actual
if c = j_STRING then
has_more := False
elseif c = '%H' then
next
c := actual
if c = 'u' then
create l_unicode.make_from_string ("\u")
l_unicode.append (read_unicode)
c := actual
if is_valid_unicode (l_unicode) then
l_json_string.append (l_unicode)
else
has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
end
elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else
l_json_string.append_character ('\')
l_json_string.append_character (c)
end
else
if is_special_character (c) and c /= '/' then
has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else
l_json_string.append_character (c)
end
end
end
create Result.make_with_escaped_json (l_json_string)
else
Result := Void
end
end
parse_array: JSON_ARRAY
-- array
-- []
-- [elements [,]]
local
flag: BOOLEAN
l_value: detachable JSON_VALUE
c: like actual
do
create Result.make_array
--check if is an empty array []
next
skip_white_spaces
if actual = j_array_close then
--is an empty array
else
previous
from
flag := True
until
not flag
loop
next
skip_white_spaces
l_value := parse
if is_parsed and then l_value /= Void then
Result.add (l_value)
next
skip_white_spaces
c := actual
if c = j_ARRAY_CLOSE then
flag := False
elseif c /= ',' then
flag := False
is_parsed := False
report_error ("Array is not well formed JSON, found [" + c.out + " ]")
end
else
flag := False
report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
end
end
end
end
parse_number: detachable JSON_NUMBER
-- Parsed number
local
sb: STRING
flag: BOOLEAN
is_integer: BOOLEAN
c: like actual
do
create sb.make_empty
sb.append_character (actual)
from
flag := True
until
not flag
loop
next
c := actual
if not has_next or is_close_token (c)
or c = ',' or c = '%N' or c = '%R'
then
flag := False
previous
else
sb.append_character (c)
end
end
if is_valid_number (sb) then
if sb.is_integer then
create Result.make_integer (sb.to_integer)
is_integer := True
elseif sb.is_double and not is_integer then
create Result.make_real (sb.to_double)
end
else
is_parsed := False
report_error ("Expected a number, found: [ " + sb + " ]")
end
end
is_null: BOOLEAN
-- Word at index represents null?
local
l_null: STRING
l_string: STRING
do
l_null := null_id
l_string := json_substring (index,index + l_null.count - 1)
if l_string.is_equal (l_null) then
Result := True
end
end
is_false: BOOLEAN
-- Word at index represents false?
local
l_false: STRING
l_string: STRING
do
l_false := false_id
l_string := json_substring (index, index + l_false.count - 1)
if l_string.is_equal (l_false) then
Result := True
end
end
is_true: BOOLEAN
-- Word at index represents true?
local
l_true: STRING
l_string: STRING
do
l_true := true_id
l_string := json_substring (index,index + l_true.count - 1)
if l_string.is_equal (l_true) then
Result := True
end
end
read_unicode: STRING
-- Read Unicode and return value
local
i: INTEGER
do
create Result.make_empty
from
i := 1
until
i > 4 or not has_next
loop
next
Result.append_character (actual)
i := i + 1
end
end
feature {NONE} -- Implementation
is_valid_number (a_number: STRING): BOOLEAN
-- is 'a_number' a valid number based on this regular expression
-- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"?
local
s: detachable STRING
c: CHARACTER
i,n: INTEGER
do
create s.make_empty
n := a_number.count
if n = 0 then
Result := False
else
Result := True
i := 1
--| "-?"
c := a_number[i]
if c = '-' then
s.extend (c); i := i + 1; c := a_number[i]
end
--| "0|[1-9]\d*
if c.is_digit then
if c = '0' then
--| "0"
s.extend (c); i := i + 1; c := a_number[i]
else
--| "[1-9]"
s.extend (c); i := i + 1; c := a_number[i]
--| "\d*"
from until i > n or not c.is_digit loop
s.extend (c); i := i + 1; c := a_number[i]
end
end
end
end
if Result then
--| "(\.\d+)?"
if c = '.' then
--| "\.\d+" = "\.\d\d*"
s.extend (c); i := i + 1; c := a_number[i]
if c.is_digit then
from until i > n or not c.is_digit loop
s.extend (c); i := i + 1; c := a_number[i]
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "(?:[eE][+-]?\d+)?\b"
if c = 'e' or c = 'E' then
--| "[eE][+-]?\d+"
s.extend (c); i := i + 1; c := a_number[i]
if c = '+' or c = '-' then
s.extend (c); i := i + 1; c := a_number[i]
end
if c.is_digit then
from until i > n or not c.is_digit loop
s.extend (c); i := i + 1; c := a_number[i]
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "\b"
from until i > n or not c.is_space loop
s.extend (c); i := i + 1; c := a_number[i]
end
Result := i > n and then s.same_string (a_number)
end
end
is_valid_unicode (a_unicode: STRING): BOOLEAN
-- is 'a_unicode' a valid Unicode based on this regular expression
-- "\\u[0-9a-fA-F]{4}"
local
i: INTEGER
do
if
a_unicode.count = 6 and then
a_unicode[1] = '\' and then
a_unicode[2] = 'u'
then
from
Result := True
i := 3
until
i > 6 or Result = False
loop
inspect a_unicode[i]
when '0'..'9', 'a'..'f', 'A'..'F' then
else
Result := False
end
i := i + 1
end
end
end
extra_elements: BOOLEAN
-- has more elements?
local
c: like actual
do
if has_next then
next
end
from
c := actual
until
c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
loop
next
end
Result := has_next
end
is_valid_start_symbol : BOOLEAN
-- expecting `{' or `[' as start symbol
do
if attached representation as s and then s.count > 0 then
Result := s[1] = '{' or s[1] = '['
end
end
feature {NONE} -- Constants
false_id: STRING = "false"
true_id: STRING = "true"
null_id: STRING = "null"
end

View File

@@ -1,77 +0,0 @@
note
description: ""
author: "jvelilla"
date: "2008/08/24"
revision: "0.1"
class
JSON_TOKENS
feature -- Access
j_OBJECT_OPEN: CHARACTER = '{'
j_ARRAY_OPEN: CHARACTER = '['
j_OBJECT_CLOSE: CHARACTER = '}'
j_ARRAY_CLOSE: CHARACTER = ']'
j_STRING: CHARACTER = '"'
j_PLUS: CHARACTER = '+'
j_MINUS: CHARACTER = '-'
j_DOT: CHARACTER = '.'
feature -- Status report
is_open_token (c: CHARACTER): BOOLEAN
-- Characters which open a type
do
inspect c
when j_OBJECT_OPEN, j_ARRAY_OPEN, j_STRING, j_PLUS, j_MINUS, j_DOT then
Result := True
else
end
end
is_close_token (c: CHARACTER): BOOLEAN
-- Characters which close a type
do
inspect c
when j_OBJECT_CLOSE, j_ARRAY_CLOSE, j_STRING then
Result := True
else
end
end
is_special_character (c: CHARACTER): BOOLEAN
-- Control Characters
-- %F Form feed
-- %H backslasH
-- %N Newline
-- %R carriage Return
-- %T horizontal Tab
-- %B Backspace
-- / Solidus
-- " Quotation
do
inspect c
when '%F', '%H', '%N', '%R', '%T', '%B', '/', '"' then
Result := True
else
end
end
is_special_control (c: CHARACTER): BOOLEAN
--Control Characters
-- \b\f\n\r\t
do
inspect c
when 'b', 'f', 'n', 'r', 't' then
Result := True
else
end
end
end

View File

@@ -1,38 +0,0 @@
note
description: "[
Shared factory class for creating JSON objects. Maps JSON
objects to ELKS HASH_TABLEs and JSON arrays to ELKS
LINKED_LISTs. Use non-conforming inheritance from this
class to ensure that your classes share the same
JSON_FACTORY instance.
]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision: 89185 $"
file: "$HeadURL: $"
class SHARED_EJSON
feature
json: EJSON
-- A shared EJSON instance with default converters for
--LINKED_LIST [ANY] and HASH_TABLE [ANY, HASHABLE]
local
jalc: JSON_ARRAYED_LIST_CONVERTER
jllc: JSON_LINKED_LIST_CONVERTER
jhtc: JSON_HASH_TABLE_CONVERTER
once
create Result
create jalc.make
Result.add_converter (jalc)
create jllc.make
Result.add_converter (jllc)
create jhtc.make
Result.add_converter (jhtc)
end
end -- class SHARED_EJSON

View File

@@ -0,0 +1,4 @@
${NOTE_KEYWORD}
copyright: "2010-${YEAR}, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"

View File

@@ -0,0 +1,679 @@
note
description: "Parse serialized JSON data"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
class
JSON_PARSER
inherit
JSON_READER
rename
make as make_reader,
reset as reset_reader
end
JSON_TOKENS
create
make_with_string,
make_parser
feature {NONE} -- Initialize
make_with_string (a_content: STRING)
-- Initialize parser with JSON content `a_content'.
require
a_content_not_empty: a_content /= Void and then not a_content.is_empty
do
create errors.make
make_reader (a_content)
reset
end
make_parser (a_json: STRING)
-- Initialize.
obsolete
"Use `make_with_string' [sept/2014]."
do
make_with_string (a_json)
end
feature -- Status report
is_parsed: BOOLEAN
-- Is parsed ?
is_valid: BOOLEAN
-- Is valid?
do
Result := not has_error
end
has_error: BOOLEAN
-- Has error?
errors: LINKED_LIST [STRING]
-- Current errors
errors_as_string: STRING
-- String representation of `errors'.
do
create Result.make_empty
across
errors as ic
loop
Result.append_string (ic.item)
Result.append_character ('%N')
end
end
current_errors: STRING
-- Current errors as string
obsolete
"USe errors_as_string [sept/2014]"
do
Result := errors_as_string
end
feature -- Access
parsed_json_value: detachable JSON_VALUE
-- Parsed json value if any.
require
is_parsed: is_parsed
attribute
ensure
attached_result_if_valid: is_valid implies Result /= Void
end
parsed_json_object: detachable JSON_OBJECT
-- parsed json value as a JSON_OBJECT if it is an object.
require
is_parsed: is_parsed
do
if attached {JSON_OBJECT} parsed_json_value as j_object then
Result := j_object
end
end
parsed_json_array: detachable JSON_ARRAY
-- parsed json value as a JSON_OBJECT if it is an array.
require
is_parsed: is_parsed
do
if attached {JSON_ARRAY} parsed_json_value as j_array then
Result := j_array
end
end
feature -- Commands
reset
-- Reset parsing values.
do
parsed_json_value := Void
errors.wipe_out
has_error := False
is_parsed := False
end
parse_content
-- Parse JSON content `representation'.
-- start ::= object | array
do
reset
reset_reader
if is_valid_start_symbol then
parsed_json_value := next_json_value
if extra_elements then
report_error ("Remaining element outside the main json value!")
end
else
report_error ("Syntax error unexpected token, expecting `{' or `['")
end
is_parsed := is_valid
end
feature -- Element change
report_error (e: STRING)
-- Report error `e'
require
e_not_void: e /= Void
do
has_error := True
errors.force (e)
ensure
has_error: has_error
is_not_valid: not is_valid
end
feature -- Obsolete commands
parse_json: detachable JSON_VALUE
-- Parse JSON data `representation'
-- start ::= object | array
obsolete
"Use `parse_content' and `parsed_json_value' [sept/2014]."
do
parse_content
if is_parsed then
Result := parsed_json_value
end
end
parse_object: detachable JSON_OBJECT
-- Parse JSON data `representation'
-- start ::= object | array
obsolete
"Use `parse_content' and `parsed_json_value' [nov/2014]."
do
parse_content
if is_parsed and then attached {JSON_OBJECT} parsed_json_value as jo then
Result := jo
end
end
parse: detachable JSON_VALUE
-- Next JSON value from current position on `representation'.
obsolete
"Use restricted `next_parsed_json_value' [sept/2014]."
do
Result := next_parsed_json_value
is_parsed := is_valid
end
feature {JSON_PARSER_ACCESS} -- Obsolete commands: restricted area
next_parsed_json_value: detachable JSON_VALUE
-- Return next json value from current position.
--| this does not call `reset_reader'.
do
reset
Result := next_json_value
end
feature {NONE} -- Implementation: parsing
next_json_value: detachable JSON_VALUE
-- Next JSON value from current position on `representation'.
local
c: CHARACTER
do
if not has_error then
skip_white_spaces
c := actual
inspect c
when token_object_open then
Result := next_json_object
when token_double_quote then
Result := parse_string
when token_array_open then
Result := parse_array
else
if c.is_digit or c = token_minus then
Result := parse_number
elseif is_null then
Result := create {JSON_NULL}
next
next
next
elseif is_true then
Result := create {JSON_BOOLEAN}.make_true
next
next
next
elseif is_false then
Result := create {JSON_BOOLEAN}.make_false
next
next
next
next
else
report_error ("JSON is not well formed in parse")
Result := Void
end
end
end
ensure
is_parsed_implies_result_not_void: not has_error implies Result /= Void
end
next_json_object: JSON_OBJECT
-- object
-- {}
-- {"key" : "value" [,]}
local
has_more: BOOLEAN
l_json_string: detachable JSON_STRING
l_value: detachable JSON_VALUE
do
create Result.make
--| check if is an empty object {}
next
skip_white_spaces
if actual = token_object_close then
--| is an empty object
else
--| a complex object {"key" : "value"}
previous
from
has_more := True
until
not has_more
loop
next
skip_white_spaces
l_json_string := parse_string
next
skip_white_spaces
if actual = token_colon then --| token_colon = ':'
next
skip_white_spaces
else
report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
has_more := False
end
l_value := next_json_value
if not has_error and then (l_value /= Void and l_json_string /= Void) then
Result.put (l_value, l_json_string)
next
skip_white_spaces
if actual = token_object_close then
has_more := False
elseif actual /= token_comma then
has_more := False
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
end
else
has_more := False
-- explain the error
end
end
end
end
parse_string: detachable JSON_STRING
-- Parsed string
local
has_more: BOOLEAN
l_json_string: STRING
l_unicode: STRING
c: like actual
do
create l_json_string.make_empty
if actual = token_double_quote then
from
has_more := True
until
not has_more
loop
next
c := actual
if c = token_double_quote then
has_more := False
elseif c = '%H' then -- '%H' = '\' = reverse solidus
next
c := actual
if c = 'u' then
create l_unicode.make_from_string ("\u")
l_unicode.append (read_unicode)
c := actual
if is_valid_unicode (l_unicode) then
l_json_string.append (l_unicode)
else
has_more := False
report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
end
elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
has_more := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else
l_json_string.append_character ('\')
l_json_string.append_character (c)
end
else
if is_special_character (c) and c /= '/' then
has_more := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else
l_json_string.append_character (c)
end
end
end
create Result.make_from_escaped_json_string (l_json_string)
else
Result := Void
end
end
parse_array: JSON_ARRAY
-- array
-- []
-- [elements [,]]
local
flag: BOOLEAN
l_value: detachable JSON_VALUE
c: like actual
do
create Result.make_empty
-- check if is an empty array []
next
skip_white_spaces
if actual = token_array_close then
-- is an empty array
else
previous
from
flag := True
until
not flag
loop
next
skip_white_spaces
l_value := next_json_value
if not has_error and then l_value /= Void then
Result.add (l_value)
next
skip_white_spaces
c := actual
if c = token_array_close then
flag := False
elseif c /= token_comma then
flag := False
report_error ("Array is not well formed JSON, found [" + c.out + " ]")
end
else
flag := False
report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
end
end
end
end
parse_number: detachable JSON_NUMBER
-- Parsed number
local
sb: STRING
flag: BOOLEAN
is_integer: BOOLEAN
c: like actual
do
create sb.make_empty
sb.append_character (actual)
from
flag := True
until
not flag
loop
next
c := actual
if not has_next or is_close_token (c) or c = token_comma or c = '%N' or c = '%R' then
flag := False
previous
else
sb.append_character (c)
end
end
if is_valid_number (sb) then
if sb.is_integer then
create Result.make_integer (sb.to_integer)
is_integer := True
elseif sb.is_double and not is_integer then
create Result.make_real (sb.to_double)
end
else
report_error ("Expected a number, found: [ " + sb + " ]")
end
end
is_null: BOOLEAN
-- Word at index represents null?
local
l_null: STRING
l_string: STRING
do
l_null := null_id
l_string := json_substring (index, index + l_null.count - 1)
if l_string.is_equal (l_null) then
Result := True
end
end
is_false: BOOLEAN
-- Word at index represents false?
local
l_false: STRING
l_string: STRING
do
l_false := false_id
l_string := json_substring (index, index + l_false.count - 1)
if l_string.is_equal (l_false) then
Result := True
end
end
is_true: BOOLEAN
-- Word at index represents true?
local
l_true: STRING
l_string: STRING
do
l_true := true_id
l_string := json_substring (index, index + l_true.count - 1)
if l_string.is_equal (l_true) then
Result := True
end
end
read_unicode: STRING
-- Read unicode and return value.
local
i: INTEGER
do
create Result.make_empty
from
i := 1
until
i > 4 or not has_next
loop
next
Result.append_character (actual)
i := i + 1
end
end
feature {NONE} -- Implementation
is_valid_number (a_number: STRING): BOOLEAN
-- is 'a_number' a valid number based on this regular expression
-- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"?
local
s: detachable STRING
c: CHARACTER
i, n: INTEGER
do
create s.make_empty
n := a_number.count
if n = 0 then
Result := False
else
Result := True
i := 1
--| "-?"
c := a_number [i]
if c = token_minus then
s.extend (c)
i := i + 1
if i > n then
Result := False
else
c := a_number [i]
end
end
--| "0|[1-9]\d*
if Result and c.is_digit then
if c = '0' then
--| "0"
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
else
--| "[1-9]"
s.extend (c)
--| "\d*"
i := i + 1
if i <= n then
c := a_number [i]
from
until
i > n or not c.is_digit
loop
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
end
end
end
end
if i > n then
-- Exit
else
if Result then
--| "(\.\d+)?"
if c = token_dot then
--| "\.\d+" = "\.\d\d*"
s.extend (c)
i := i + 1
c := a_number [i]
if c.is_digit then
from
until
i > n or not c.is_digit
loop
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "(?:[eE][+-]?\d+)?\b"
if is_exp_token (c) then
--| "[eE][+-]?\d+"
s.extend (c)
i := i + 1
c := a_number [i]
if c = token_plus or c = token_minus then
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
if c.is_digit then
from
until
i > n or not c.is_digit
loop
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "\b"
from
until
i > n or not c.is_space
loop
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
Result := i > n and then s.same_string (a_number)
end
end
end
is_valid_unicode (a_unicode: STRING): BOOLEAN
-- is 'a_unicode' a valid unicode based on the regular expression "\\u[0-9a-fA-F]{4}" .
local
i: INTEGER
do
if a_unicode.count = 6 and then a_unicode [1] = '\' and then a_unicode [2] = 'u' then
from
Result := True
i := 3
until
i > 6 or Result = False
loop
inspect a_unicode [i]
when '0'..'9', 'a'..'f', 'A'..'F' then
else
Result := False
end
i := i + 1
end
end
end
extra_elements: BOOLEAN
-- has more elements?
local
c: like actual
do
if has_next then
next
end
from
c := actual
until
c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
loop
next
end
Result := has_next
end
is_valid_start_symbol: BOOLEAN
-- expecting `{' or `[' as start symbol
do
if attached representation as s and then s.count > 0 then
Result := s [1] = token_object_open or s [1] = token_array_open
end
end
feature {NONE} -- Constants
false_id: STRING = "false"
true_id: STRING = "true"
null_id: STRING = "null"
note
copyright: "2010-2015, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,12 @@
note
description: "Inherit to access restricted feature from {JSON_PARSER}."
date: "$Date$"
revision: "$Revision$"
deferred class
JSON_PARSER_ACCESS
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -12,22 +12,28 @@ create
feature {NONE} -- Initialization
make (a_json: STRING)
-- Initialize Reader
do
set_representation (a_json)
end
make (a_json: STRING)
-- Initialize Reader
do
set_representation (a_json)
end
feature -- Commands
set_representation (a_json: STRING)
-- Set `representation'.
do
a_json.left_adjust
a_json.right_adjust
reset
-- Reset reader
do
index := 1
end
set_representation (a_json: STRING)
-- Set `representation'.
do
a_json.left_adjust
a_json.right_adjust
representation := a_json
index := 1
end
reset
end
read: CHARACTER
-- Read character
@@ -65,7 +71,7 @@ feature -- Commands
from
c := actual
until
(c /= ' ' and c /= '%N' and c /= '%R' and c /= '%U' and c /= '%T' ) or not has_next
(c /= ' ' and c /= '%N' and c /= '%R' and c /= '%U' and c /= '%T') or not has_next
loop
next
c := actual
@@ -115,4 +121,7 @@ feature {NONE} -- Implementation
invariant
representation_not_void: representation /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,90 @@
note
description: "Token used by the JSON_PARSER"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
class
JSON_TOKENS
feature -- Access
token_object_open: CHARACTER = '{'
token_object_close: CHARACTER = '}'
token_array_open: CHARACTER = '['
token_array_close: CHARACTER = ']'
token_double_quote: CHARACTER = '"'
token_plus: CHARACTER = '+'
token_minus: CHARACTER = '-'
token_dot: CHARACTER = '.'
token_exp: CHARACTER = 'e'
token_comma: CHARACTER = ','
token_colon: CHARACTER = ':'
feature -- Status report
is_open_token (c: CHARACTER): BOOLEAN
-- Characters which open a type
do
inspect c
when token_object_open, token_array_open, token_double_quote, token_plus, token_minus, token_dot then
Result := True
else
end
end
is_close_token (c: CHARACTER): BOOLEAN
-- Characters which close a type
do
inspect c
when token_object_close, token_array_close, token_double_quote then
Result := True
else
end
end
is_special_character (c: CHARACTER): BOOLEAN
-- Control Characters
-- %F Form feed
-- %H backslasH
-- %N Newline
-- %R carriage Return
-- %T horizontal Tab
-- %B Backspace
-- / Solidus
-- " Quotation
do
inspect c
when '"', '%H' , '/', '%B', '%F', '%N', '%R', '%T' then -- '%H' = '\' = reverse solidus
Result := True
else
end
end
is_special_control (c: CHARACTER): BOOLEAN
-- Control Characters
-- \b\f\n\r\t
do
inspect c
when 'b', 'f', 'n', 'r', 't' then
Result := True
else
end
end
is_exp_token (c: CHARACTER): BOOLEAN
-- Is number exposant token?
do
Result := c = token_exp or else c.as_lower = token_exp
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,49 @@
note
description: "Objects that ..."
author: ""
date: "$Date$"
revision: "$Revision$"
class
JSON_FILE_READER
feature -- Access
read_json_from (a_path: READABLE_STRING_GENERAL): detachable STRING
local
l_file: PLAIN_TEXT_FILE
l_last_string: detachable STRING
l_file_count: INTEGER
l_fetch_done: BOOLEAN
do
create l_file.make_with_name (a_path)
-- We perform several checks until we make a real attempt to open the file.
if not l_file.exists then
print ("error: '" + a_path.out + "' does not exist%N") -- FIXME: unicode may be truncated
else
if not l_file.is_readable then
print ("error: '" + a_path.out + "' is not readable.%N") -- FIXME: unicode may be truncated
else
l_file_count := l_file.count
l_file.open_read
from
create Result.make (l_file_count)
until
l_fetch_done
loop
l_file.read_stream (1_024)
l_last_string := l_file.last_string
l_fetch_done := l_file.exhausted or l_file.end_of_file or l_last_string.count < 1_024
if not l_last_string.is_empty then
Result.append (l_last_string)
end
end
l_file.close
end
end
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,11 +1,8 @@
note
description:
"JSON Iterator"
description: "JSON Iterator"
pattern: "Iterator visitor"
author: "Jocelyn Fiat"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
date: "2013/08/01"
revision: "Revision 0.1"
@@ -13,6 +10,7 @@ deferred class
JSON_ITERATOR
inherit
JSON_VISITOR
feature -- Visitor Pattern
@@ -52,9 +50,12 @@ feature -- Visitor Pattern
end
end
visit_json_string (a_json_string: JSON_STRING)
visit_json_string (a_json_string: JSON_STRING)
-- Visit `a_json_string'.
do
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -6,6 +6,7 @@ class
JSON_PRETTY_STRING_VISITOR
inherit
JSON_VISITOR
create
@@ -26,21 +27,58 @@ feature -- Initialization
output := a_output
create indentation.make_empty
indentation_step := "%T"
object_count_inlining := a_object_count_inlining
array_count_inlining := a_array_count_inlining
end
feature -- Access
output: STRING_32
-- JSON representation
output: STRING_GENERAL
-- JSON representation
indentation: like output
feature -- Settings
indentation_step: like indentation
indentation_step: STRING
-- Text used for indentation.
--| by default a tabulation "%T"
line_number: INTEGER
object_count_inlining: INTEGER
-- Inline where object item count is under `object_count_inlining'.
--| ex 3:
--| { "a", "b", "c" }
--| ex 2:
--| {
--| "a",
--| "b",
--| "c"
--| }
array_count_inlining: INTEGER
-- Inline where array item count is under `object_count_inlining'.
feature -- Element change
set_indentation_step (a_step: STRING)
-- Set `indentation_step' to `a_step'.
do
indentation_step := a_step
end
set_object_count_inlining (a_nb: INTEGER)
-- Set `object_count_inlining' to `a_nb'.
do
object_count_inlining := a_nb
end
set_array_count_inlining (a_nb: INTEGER)
-- Set `array_count_inlining' to `a_nb'.
do
array_count_inlining := a_nb
end
feature {NONE} -- Implementation
indentation: STRING
indent
do
@@ -59,8 +97,7 @@ feature -- Access
line_number := line_number + 1
end
object_count_inlining: INTEGER
array_count_inlining: INTEGER
line_number: INTEGER
feature -- Visitor Pattern
@@ -71,10 +108,14 @@ feature -- Visitor Pattern
l_json_array: ARRAYED_LIST [JSON_VALUE]
l_line: like line_number
l_multiple_lines: BOOLEAN
l_output: like output
do
l_output := output
l_json_array := a_json_array.array_representation
l_multiple_lines := l_json_array.count >= array_count_inlining or across l_json_array as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
output.append ("[")
l_multiple_lines := l_json_array.count >= array_count_inlining
or across l_json_array as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
l_output.append_code (91) -- '[' : 91
l_line := line_number
indent
from
@@ -82,27 +123,21 @@ feature -- Visitor Pattern
until
l_json_array.off
loop
if
line_number > l_line or
l_multiple_lines
then
if line_number > l_line or l_multiple_lines then
new_line
end
value := l_json_array.item
value.accept (Current)
l_json_array.forth
if not l_json_array.after then
output.append (", ")
l_output.append (", ")
end
end
exdent
if
line_number > l_line or
l_json_array.count >= array_count_inlining
then
if line_number > l_line or l_json_array.count >= array_count_inlining then
new_line
end
output.append ("]")
l_output.append_code (93) -- ']' : 93
end
visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
@@ -129,10 +164,12 @@ feature -- Visitor Pattern
l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING]
l_line: like line_number
l_multiple_lines: BOOLEAN
l_output: like output
do
l_output := output
l_pairs := a_json_object.map_representation
l_multiple_lines := l_pairs.count >= object_count_inlining or across l_pairs as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
output.append ("{")
l_output.append_code (123) -- '{' : 123
l_line := line_number
indent
from
@@ -140,36 +177,36 @@ feature -- Visitor Pattern
until
l_pairs.off
loop
if
line_number > l_line or
l_multiple_lines
then
if line_number > l_line or l_multiple_lines then
new_line
end
l_pairs.key_for_iteration.accept (Current)
output.append (": ")
l_output.append (": ")
l_pairs.item_for_iteration.accept (Current)
l_pairs.forth
if not l_pairs.after then
output.append (", ")
l_output.append (", ")
end
end
exdent
if
line_number > l_line or
l_pairs.count >= object_count_inlining
then
if line_number > l_line or l_pairs.count >= object_count_inlining then
new_line
end
output.append ("}")
l_output.append_code (125) -- '}' : 125
end
visit_json_string (a_json_string: JSON_STRING)
visit_json_string (a_json_string: JSON_STRING)
-- Visit `a_json_string'.
local
l_output: like output
do
output.append ("%"")
output.append (a_json_string.item)
output.append ("%"")
l_output := output
l_output.append_code (34) -- '%"' : 34
l_output.append (a_json_string.item)
l_output.append_code (34) -- '%"' : 34
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,11 +1,8 @@
note
description:
"JSON Visitor"
description: "JSON Visitor"
pattern: "Visitor"
author: "Javier Velilla"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
date: "2008/08/24"
revision: "Revision 0.1"
@@ -49,11 +46,14 @@ feature -- Visitor Pattern
deferred
end
visit_json_string (a_json_string: JSON_STRING)
visit_json_string (a_json_string: JSON_STRING)
-- Visit `a_json_string'.
require
a_json_string_not_void: a_json_string /= Void
deferred
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -8,9 +8,11 @@ class
PRINT_JSON_VISITOR
inherit
JSON_VISITOR
create make
create
make
feature -- Initialization
@@ -23,7 +25,7 @@ feature -- Initialization
feature -- Access
to_json: STRING
-- JSON representation
-- JSON representation
feature -- Visitor Pattern
@@ -33,7 +35,7 @@ feature -- Visitor Pattern
value: JSON_VALUE
l_json_array: ARRAYED_LIST [JSON_VALUE]
do
l_json_array:=a_json_array.array_representation
l_json_array := a_json_array.array_representation
to_json.append ("[")
from
l_json_array.start
@@ -44,7 +46,7 @@ feature -- Visitor Pattern
value.accept (Current)
l_json_array.forth
if not l_json_array.after then
to_json.append(",")
to_json.append (",")
end
end
to_json.append ("]")
@@ -71,7 +73,7 @@ feature -- Visitor Pattern
visit_json_object (a_json_object: JSON_OBJECT)
-- Visit `a_json_object'.
local
l_pairs: HASH_TABLE[JSON_VALUE,JSON_STRING]
l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING]
do
l_pairs := a_json_object.map_representation
to_json.append ("{")
@@ -91,7 +93,7 @@ feature -- Visitor Pattern
to_json.append ("}")
end
visit_json_string (a_json_string: JSON_STRING)
visit_json_string (a_json_string: JSON_STRING)
-- Visit `a_json_string'.
do
to_json.append ("%"")
@@ -99,4 +101,7 @@ feature -- Visitor Pattern
to_json.append ("%"")
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,16 @@
package json
project
json_safe = "library/json-safe.ecf"
json = "library/json.ecf"
json_gobo_extension = "library/json_gobo_extension.ecf"
note
title: Eiffel JSON
description: Eiffel JSON parser and visitors
tags: json,parser,text
license: MIT
copyright: Copyright (c) 2010-2014 Javier Velilla, Jocelyn Fiat and others,
link[github]: "project" https://github.com/eiffelhub/json
end

View File

@@ -1,12 +1,13 @@
note
description : "test_suite application root class"
date : "$Date$"
revision : "$Revision$"
description: "test_suite application root class"
date: "$Date$"
revision: "$Revision$"
class
APPLICATION
inherit
ARGUMENTS
create
@@ -17,7 +18,7 @@ feature {NONE} -- Initialization
make
-- Run application.
do
--| Add your code here
--| Add your code here
print ("Hello Eiffel World!%N")
end

View File

@@ -1,24 +1,32 @@
class AUTHOR
class
AUTHOR
create
make
make
feature {NONE} -- Initialization
make (a_name: STRING_32)
do
set_name (a_name)
end
make (a_name: STRING_32)
-- Create an author with `a_name' as `name'.
do
set_name (a_name)
ensure
name_set: name = a_name
end
feature -- Access
name: STRING_32
name: STRING_32
-- Author name
feature -- Status setting
feature -- Change
set_name (a_name: STRING_32)
do
name := a_name
end
set_name (a_name: STRING_32)
-- Set `name' with `a_name'.
do
name := a_name
ensure
name_set: name = a_name
end
end -- class AUTHOR

View File

@@ -1,40 +1,59 @@
class BOOK
class
BOOK
create
make
make
feature {NONE} -- Initialization
make (a_title: STRING_32; an_author: AUTHOR; an_isbn: STRING_32)
do
set_title (a_title)
set_author (an_author)
set_isbn (an_isbn)
end
make (a_title: STRING_32; a_author: AUTHOR; a_isbn: STRING_32)
-- Create a book with `a_title' as `title',
-- `a_author' as `author', and `a_isbn' as `isbn'.
do
set_title (a_title)
set_author (a_author)
set_isbn (a_isbn)
ensure
title_set: title = a_title
author_set: author = a_author
isbn_set: isbn = a_isbn
end
feature -- Access
title: STRING_32
title: STRING_32
-- Main title.
isbn: STRING_32
isbn: STRING_32
-- ISBN.
author: AUTHOR
author: AUTHOR
-- Author.
feature -- Status setting
feature -- Change
set_title (a_title: STRING_32)
do
title := a_title
end
set_title (a_title: STRING_32)
-- Set `title' with `a_title'.
do
title := a_title
ensure
title_set: title = a_title
end
set_author (an_author: AUTHOR)
do
author := an_author
end
set_author (a_author: AUTHOR)
-- Set `author' with `a_author'.
do
author := a_author
ensure
author_set: author = a_author
end
set_isbn (an_isbn: STRING_32)
do
isbn := an_isbn
end
set_isbn (a_isbn: STRING_32)
-- Set `isbn' with `a_isbn'.
do
isbn := a_isbn
ensure
isbn_set: isbn = a_isbn
end
end -- class BOOK

View File

@@ -1,80 +1,82 @@
class BOOK_COLLECTION
class
BOOK_COLLECTION
create
make
make
feature {NONE} -- Initialization
make (a_name: STRING_32)
do
set_name (a_name)
create book_index.make (10)
end
make (a_name: STRING_32)
-- Create a book collection with `a_name' as `name'.
do
set_name (a_name)
create book_index.make (10)
ensure
name_set: name = a_name
end
feature -- Access
name: STRING_32
name: STRING_32
-- Name.
books: LIST [BOOK]
do
from
create {LINKED_LIST [BOOK]} Result.make
book_index.start
until
book_index.after
loop
Result.append (book_index.item_for_iteration)
book_index.forth
end
end
books: LIST [BOOK]
-- collection of book.
do
create {LINKED_LIST [BOOK]} Result.make
across
book_index as it
loop
Result.append (it.item)
end
end
books_by_author (an_author: STRING_32): detachable LIST [BOOK]
do
if book_index.has (an_author) then
Result := book_index @ an_author
else
create {LINKED_LIST [BOOK]} Result.make
end
end
books_by_author (a_author: STRING_32): LIST [BOOK]
-- Books wrote by `a_author' in this collection.
do
if attached book_index [a_author] as l_result then
Result := l_result
else
create {LINKED_LIST [BOOK]} Result.make
end
end
feature -- Status setting
feature -- Change
set_name (a_name: STRING_32)
do
name := a_name
end
set_name (a_name: STRING_32)
-- Set `name' with `a_name'.
do
name := a_name
ensure
name_set: name = a_name
end
add_book (a_book: BOOK)
local
l: detachable LIST [BOOK]
do
if book_index.has (a_book.author.name) then
l := book_index.at ( a_book.author.name )
else
create {LINKED_LIST [BOOK]} l.make
book_index.put (l, a_book.author.name)
end
if attached l as la then
la.force (a_book)
end
add_book (a_book: BOOK)
-- Extend collection with `a_book'.
local
l: detachable LIST [BOOK]
do
l := book_index.at (a_book.author.name)
if l = Void then
create {LINKED_LIST [BOOK]} l.make
book_index.put (l, a_book.author.name)
end
l.force (a_book)
end
end
add_books (book_list: like books)
do
from
book_list.start
until
book_list.after
loop
add_book (book_list.item)
book_list.forth
end
end
add_books (book_list: like books)
-- Append collection with `book_list'.
do
across
book_list as it
loop
add_book (it.item)
end
end
feature {NONE} -- Implementation
book_index: HASH_TABLE [LIST [BOOK], STRING_32]
book_index: HASH_TABLE [LIST [BOOK], STRING_32]
-- Association of author name and its books.
end -- class BOOK_COLLECTION

View File

@@ -1,53 +1,54 @@
note
description: "A JSON converter for AUTHOR"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
description: "A JSON converter for AUTHOR"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
class JSON_AUTHOR_CONVERTER
class
JSON_AUTHOR_CONVERTER
inherit
JSON_CONVERTER
JSON_CONVERTER
create
make
make
feature {NONE} -- Initialization
make
local
ucs: STRING_32
do
create ucs.make_from_string ("")
create object.make (ucs)
end
make
local
ucs: STRING_32
do
create ucs.make_from_string ("")
create object.make (ucs)
end
feature -- Access
object: AUTHOR
object: AUTHOR
feature -- Conversion
from_json (j: like to_json): detachable like object
local
ucs: detachable STRING_32
do
ucs ?= json.object (j.item (name_key), Void)
check ucs /= Void end
create Result.make (ucs)
end
from_json (j: like to_json): detachable like object
do
if attached {STRING_32} json.object (j.item (name_key), Void) as l_name then
create Result.make (l_name)
end
end
to_json (o: like object): JSON_OBJECT
do
create Result.make
Result.put (json.value (o.name), name_key)
end
to_json (o: like object): JSON_OBJECT
do
create Result.make
Result.put (json.value (o.name), name_key)
end
feature {NONE} -- Implementation
feature {NONE} -- Implementation
name_key: JSON_STRING
once
create Result.make_json ("name")
end
name_key: JSON_STRING
-- Author's name label.
once
create Result.make_from_string ("name")
end
end -- class JSON_AUTHOR_CONVERTER

View File

@@ -1,78 +1,82 @@
note
description: "A JSON converter for BOOK_COLLECTION"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
description: "A JSON converter for BOOK_COLLECTION"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
class JSON_BOOK_COLLECTION_CONVERTER
class
JSON_BOOK_COLLECTION_CONVERTER
inherit
JSON_CONVERTER
JSON_CONVERTER
create
make
make
feature {NONE} -- Initialization
make
local
ucs: STRING_32
do
create ucs.make_from_string ("")
create object.make (ucs)
end
make
local
ucs: STRING_32
do
create ucs.make_from_string ("")
create object.make (ucs)
end
feature -- Access
object: BOOK_COLLECTION
object: BOOK_COLLECTION
feature -- Conversion
from_json (j: like to_json): detachable like object
local
ucs: detachable STRING_32
ll: LINKED_LIST [BOOK]
b: detachable BOOK
ja: detachable JSON_ARRAY
i: INTEGER
do
ucs ?= json.object (j.item (name_key), Void)
check ucs /= Void end
create Result.make (ucs)
ja ?= j.item (books_key)
check ja /= Void end
from
i := 1
create ll.make
until
i > ja.count
loop
b ?= json.object (ja [i], "BOOK")
check b /= Void end
ll.force (b)
i := i + 1
end
check ll /= Void end
Result.add_books (ll)
end
from_json (j: like to_json): detachable like object
local
l_books: LINKED_LIST [BOOK]
do
if
attached {STRING_32} json.object (j.item (name_key), Void) as l_name and
attached {JSON_ARRAY} j.item (books_key) as l_json_array
then
create Result.make (l_name)
create l_books.make
across
l_json_array as it
until
Result = Void
loop
if attached {BOOK} json.object (it.item, "BOOK") as l_book then
l_books.extend (l_book)
else
Result := Void
-- Failed
end
end
if Result /= Void then
Result.add_books (l_books)
end
end
end
to_json (o: like object): JSON_OBJECT
do
create Result.make
Result.put (json.value (o.name), name_key)
Result.put (json.value (o.books), books_key)
end
to_json (o: like object): JSON_OBJECT
do
create Result.make_with_capacity (2)
Result.put (json.value (o.name), name_key)
Result.put (json.value (o.books), books_key)
end
feature {NONE} -- Implementation
feature {NONE} -- Implementation
name_key: JSON_STRING
once
create Result.make_json ("name")
end
name_key: JSON_STRING
-- Collection's name label.
once
create Result.make_from_string ("name")
end
books_key: JSON_STRING
once
create Result.make_json ("books")
end
books_key: JSON_STRING
-- Book list label.
once
create Result.make_from_string ("books")
end
end -- class JSON_BOOK_COLLECTION_CONVERTER

View File

@@ -1,72 +1,74 @@
note
description: "A JSON converter for BOOK"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
description: "A JSON converter for BOOK"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
class JSON_BOOK_CONVERTER
class
JSON_BOOK_CONVERTER
inherit
JSON_CONVERTER
JSON_CONVERTER
create
make
make
feature {NONE} -- Initialization
make
local
ucs: STRING_32
a: AUTHOR
do
create ucs.make_from_string ("")
create a.make (ucs)
create object.make (ucs, a, ucs)
end
make
local
ucs: STRING_32
a: AUTHOR
do
create ucs.make_from_string ("")
create a.make (ucs)
create object.make (ucs, a, ucs)
end
feature -- Access
object: BOOK
object: BOOK
feature -- Conversion
from_json (j: like to_json): detachable like object
local
ucs1, ucs2: detachable STRING_32
a: detachable AUTHOR
do
ucs1 ?= json.object (j.item (title_key), Void)
check ucs1 /= Void end
ucs2 ?= json.object (j.item (isbn_key), Void)
check ucs2 /= Void end
a ?= json.object (j.item (author_key), "AUTHOR")
check a /= Void end
create Result.make (ucs1, a, ucs2)
end
from_json (j: like to_json): detachable like object
do
if
attached {STRING_32} json.object (j.item (title_key), Void) as l_title and
attached {STRING_32} json.object (j.item (isbn_key), Void) as l_isbn and
attached {AUTHOR} json.object (j.item (author_key), "AUTHOR") as l_author
then
create Result.make (l_title, l_author, l_isbn)
end
end
to_json (o: like object): JSON_OBJECT
do
create Result.make
Result.put (json.value (o.title), title_key)
Result.put (json.value (o.isbn), isbn_key)
Result.put (json.value (o.author), author_key)
end
to_json (o: like object): JSON_OBJECT
do
create Result.make_with_capacity (3)
Result.put (json.value (o.title), title_key)
Result.put (json.value (o.isbn), isbn_key)
Result.put (json.value (o.author), author_key)
end
feature {NONE} -- Implementation
feature {NONE} -- Implementation
title_key: JSON_STRING
once
create Result.make_json ("title")
end
title_key: JSON_STRING
-- Book's title label.
once
create Result.make_from_string ("title")
end
isbn_key: JSON_STRING
once
create Result.make_json ("isbn")
end
isbn_key: JSON_STRING
-- Book ISBN label.
once
create Result.make_from_string ("isbn")
end
author_key: JSON_STRING
once
create Result.make_json ("author")
end
author_key: JSON_STRING
-- Author label.
once
create Result.make_from_string ("author")
end
end -- class JSON_BOOK_CONVERTER

View File

@@ -1,74 +1,72 @@
class TEST_DS
note
description: "Linked list and hash table converters test."
date: "$Date$"
revision: "$Revision$"
class
TEST_DS
inherit
SHARED_EJSON
rename default_create as shared_default_create end
EQA_TEST_SET
select default_create end
SHARED_EJSON
undefine
default_create
end
EQA_TEST_SET
feature -- Test
test_linked_list_converter
local
jc: JSON_LINKED_LIST_CONVERTER
l: LINKED_LIST [STRING]
l2: detachable LINKED_LIST [detachable ANY]
s: STRING
jv: detachable JSON_VALUE
do
create jc.make
json.add_converter (jc)
create l.make
s := "foo"
l.force (s)
s := "bar"
l.force (s)
jv := json.value (l)
assert ("jv /= Void", jv /= Void)
if attached jv as l_jv then
s := jv.representation
l2 ?= json.object (jv, "LINKED_LIST")
assert ("l2 /= Void", l2 /= Void)
end
end
test_linked_list_converter
-- Convert a linked list to a json value and
-- convert this one to a linked list.
local
l: LINKED_LIST [STRING]
s: STRING
do
create l.make
l.force ("foo")
l.force ("bar")
if attached json.value (l) as l_value then
s := l_value.representation
assert ("JSON array converted to LINKED_LIST", attached {LINKED_LIST [detachable ANY]} json.object (l_value, "LINKED_LIST"))
else
assert ("LINKED_LIST converted to a JSON value", False)
end
end
test_hash_table_converter
local
tc: JSON_HASH_TABLE_CONVERTER
t: HASH_TABLE [STRING, STRING]
t2: detachable HASH_TABLE [ANY, HASHABLE]
s: STRING
ucs_key, ucs_value: detachable STRING_32
jv: detachable JSON_VALUE
do
create tc.make
json.add_converter (tc)
create t.make (2)
t.put ("foo", "1")
t.put ("bar", "2")
jv := json.value (t)
assert ("jv /= Void", jv /= Void)
if attached jv as l_jv then
s := l_jv.representation
t2 ?= json.object (l_jv, "HASH_TABLE")
assert ("t2 /= Void", t2 /= Void)
end
create ucs_key.make_from_string ("1")
if attached t2 as l_t2 then
ucs_value ?= t2 @ ucs_key
assert ("ucs_value /= Void", ucs_value /= Void)
if attached ucs_value as l_ucs_value then
assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.string.is_equal ("foo"))
end
create ucs_key.make_from_string ("2")
ucs_value ?= t2 @ ucs_key
assert ("ucs_value /= Void", ucs_value /= Void)
if attached ucs_value as l_ucs_value then
assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.string.is_equal ("bar"))
end
end
end
test_hash_table_converter
-- Convert a hash table to a json value and
-- convert this one to a hash table.
local
t: HASH_TABLE [STRING, STRING]
s: STRING
l_ucs_key: detachable STRING_32
do
create t.make (2)
t.put ("foo", "1")
t.put ("bar", "2")
if attached json.value (t) as l_value then
s := l_value.representation
if attached {HASH_TABLE [ANY, HASHABLE]} json.object (l_value, "HASH_TABLE") as t2 then
create l_ucs_key.make_from_string ("1")
if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then
assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.same_string_general ("foo"))
else
assert ("ucs_value /= Void", False)
end
create l_ucs_key.make_from_string ("2")
if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then
assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.same_string_general ("bar"))
else
assert ("ucs_value /= Void", False)
end
else
assert ("JSON object converted to HASH_TABLE", False);
end
else
assert ("HASH_TABLE converted to a JSON value", False)
end
end
end -- class TEST_DS

View File

@@ -1,42 +1,52 @@
class TEST_JSON_CUSTOM_CLASSES
note
description: "Parsing and converter of book collection test."
date: "$Date$"
revision: "$Revision$"
class
TEST_JSON_CUSTOM_CLASSES
inherit
SHARED_EJSON
rename default_create as shared_default_create end
SHARED_EJSON
undefine
default_create
end
EQA_TEST_SET
select default_create end
feature -- Test
test_custom_classes
local
bc: detachable BOOK_COLLECTION
jbc: JSON_BOOK_CONVERTER
jbcc: JSON_BOOK_COLLECTION_CONVERTER
jac: JSON_AUTHOR_CONVERTER
jo: detachable JSON_OBJECT
parser: JSON_PARSER
jrep: STRING
do
create jbc.make
json.add_converter (jbc)
create jbcc.make
json.add_converter (jbcc)
create jac.make
json.add_converter (jac)
jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"
create parser.make_parser (jrep)
jo := Void
jo ?= parser.parse
assert ("jo /= Void", jo /= Void)
bc := Void
bc ?= json.object (jo, "BOOK_COLLECTION")
assert ("bc /= Void", bc /= Void)
jo ?= json.value (bc)
assert ("jo /= Void", jo /= Void)
if attached jo as l_jo then
assert ("JSON representation is correct", l_jo.representation.same_string ("{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"))
end
end
test_custom_classes
-- Parse JSON representation to JSON_OBJECT and test book collection converter.
local
jbc: JSON_BOOK_CONVERTER
jbcc: JSON_BOOK_COLLECTION_CONVERTER
jac: JSON_AUTHOR_CONVERTER
parser: JSON_PARSER
jrep: STRING
do
create jbc.make
json.add_converter (jbc)
create jbcc.make
json.add_converter (jbcc)
create jac.make
json.add_converter (jac)
jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"
create parser.make_parser (jrep)
if attached {JSON_OBJECT} parser.parse as l_json_object then
if attached {BOOK_COLLECTION} json.object (l_json_object, "BOOK_COLLECTION") as l_collection then
if attached {JSON_OBJECT} json.value (l_collection) as l_json_object_2 then
assert ("JSON representation is correct", l_json_object_2.representation.same_string (jrep))
else
assert ("BOOK_COLLECTION converted to JSON_OBJECT", False)
end
else
assert ("JSON_OBJECT converted to BOOK_COLLECTION", False)
end
else
assert ("JSON object representation to JSON_OBJECT", False)
end
end
end -- class TEST_JSON_CUSTOM_CLASS

View File

@@ -1,4 +1,4 @@
note
note
description: "[
Eiffel tests that can be executed by testing tool.
]"
@@ -33,8 +33,8 @@ feature -- Tests Pass
do
if attached json_file_from ("pass1.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("pass1.json",parse_json.is_parsed = True)
parse_json.parse_content
assert ("pass1.json", parse_json.is_valid)
end
end
@@ -45,8 +45,8 @@ feature -- Tests Pass
do
if attached json_file_from ("pass2.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("pass2.json",parse_json.is_parsed = True)
parse_json.parse_content
assert ("pass2.json",parse_json.is_valid)
end
end
@@ -57,8 +57,8 @@ feature -- Tests Pass
do
if attached json_file_from ("pass3.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("pass3.json",parse_json.is_parsed = True)
parse_json.parse_content
assert ("pass3.json",parse_json.is_valid)
end
end
@@ -68,20 +68,16 @@ feature -- Tests Pass
utf: UTF_CONVERTER
s: READABLE_STRING_32
do
s := {STRING_32} "{ %"nihaoma%": %"你好吗\t?%" }"
s := {STRING_32} "{ %"nihaoma%": %"你好吗\t?%" }"
parse_json := new_json_parser (utf.string_32_to_utf_8_string_8 (s))
json_value := parse_json.parse_json
assert ("utf8.pass1.json", parse_json.is_parsed = True)
if
attached {JSON_OBJECT} json_value as jo and then
attached {JSON_STRING} jo.item ("nihaoma") as js
then
assert ("utf8.nihaoma", js.unescaped_string_32.same_string ({STRING_32} "你好吗%T?"))
parse_json.parse_content
assert ("utf8.pass1.json", parse_json.is_valid)
if attached {JSON_OBJECT} parse_json.parsed_json_value as jo and then attached {JSON_STRING} jo.item ("nihaoma") as js then
assert ("utf8.nihaoma", js.unescaped_string_32.same_string ({STRING_32} "你好吗%T?"))
else
assert ("utf8.nihaoma", False)
end
end
end
end
feature -- Tests Failures
test_json_fail1
@@ -91,8 +87,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail1.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail1.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail1.json", parse_json.is_valid = False)
end
end
@@ -103,8 +99,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail2.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail2.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail2.json",parse_json.is_valid = False)
end
end
@@ -115,8 +111,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail3.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail3.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail3.json",parse_json.is_valid = False)
end
end
@@ -127,8 +123,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail4.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail4.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail4.json",parse_json.is_valid = False)
end
end
@@ -139,8 +135,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail5.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail5.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail5.json",parse_json.is_valid = False)
end
end
@@ -152,8 +148,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail6.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail6.json",parse_json.is_parsed = False )
parse_json.parse_content
assert ("fail6.json",parse_json.is_valid = False )
end
end
@@ -164,8 +160,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail7.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail7.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail7.json",parse_json.is_valid = False)
end
end
@@ -176,8 +172,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail8.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail8.json",parse_json.is_parsed = False )
parse_json.parse_content
assert ("fail8.json",parse_json.is_valid = False )
end
end
@@ -189,8 +185,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail9.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail9.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail9.json",parse_json.is_valid = False)
end
end
@@ -202,8 +198,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail10.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail10.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail10.json",parse_json.is_valid = False)
end
end
@@ -214,8 +210,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail11.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail11.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail11.json",parse_json.is_valid = False)
end
end
@@ -226,8 +222,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail12.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail12.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail12.json",parse_json.is_valid = False)
end
end
@@ -238,8 +234,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail13.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail13.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail13.json",parse_json.is_valid = False)
end
end
@@ -250,8 +246,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail14.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail14.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail14.json",parse_json.is_valid = False)
end
end
@@ -262,8 +258,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail15.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail15.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail15.json",parse_json.is_valid = False)
end
end
@@ -274,8 +270,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail16.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail16.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail16.json",parse_json.is_valid = False)
end
end
@@ -286,8 +282,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail17.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail17.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail17.json",parse_json.is_valid = False)
end
end
@@ -298,8 +294,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail18.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail18.json",parse_json.is_parsed = True)
parse_json.parse_content
assert ("fail18.json",parse_json.is_valid = True)
end
end
@@ -310,8 +306,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail19.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail19.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail19.json",parse_json.is_valid = False)
end
end
@@ -322,8 +318,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail20.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail20.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail20.json",parse_json.is_valid = False)
end
end
@@ -334,8 +330,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail21.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail21.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail21.json",parse_json.is_valid = False)
end
end
@@ -347,8 +343,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail22.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail22.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail22.json",parse_json.is_valid = False)
end
end
@@ -359,8 +355,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail23.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail23.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail23.json",parse_json.is_valid = False)
end
end
@@ -371,8 +367,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail24.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail24.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail24.json",parse_json.is_valid = False)
end
end
@@ -383,8 +379,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail25.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail25.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail25.json",parse_json.is_valid = False)
end
end
@@ -396,8 +392,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail26.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail26.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail26.json",parse_json.is_valid = False)
end
end
@@ -409,8 +405,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail27.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail27.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail27.json",parse_json.is_valid = False)
end
end
@@ -422,8 +418,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail28.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail28.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail28.json",parse_json.is_valid = False)
end
end
@@ -435,8 +431,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail29.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail29.json",parse_json.is_parsed = False )
parse_json.parse_content
assert ("fail29.json",parse_json.is_valid = False )
end
end
@@ -448,8 +444,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail30.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail30.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail30.json",parse_json.is_valid = False)
end
end
@@ -460,8 +456,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail31.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail31.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail31.json",parse_json.is_valid = False)
end
end
@@ -472,8 +468,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail32.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail32.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail32.json",parse_json.is_valid = False)
end
end
@@ -484,8 +480,8 @@ feature -- Tests Failures
do
if attached json_file_from ("fail33.json") as json_file then
parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json
assert ("fail33.json",parse_json.is_parsed = False)
parse_json.parse_content
assert ("fail33.json",parse_json.is_valid = False)
end
end
@@ -493,52 +489,47 @@ feature -- JSON_FROM_FILE
file_reader: JSON_FILE_READER
json_value: detachable JSON_VALUE
json_file_from (fn: STRING): detachable STRING
local
f: RAW_FILE
l_path: STRING
test_dir: STRING
json_file_from (fn: READABLE_STRING_GENERAL): detachable STRING
local
f: RAW_FILE
l_path: PATH
test_dir: PATH
i: INTEGER
do
test_dir := (create {EXECUTION_ENVIRONMENT}).current_working_directory
test_dir.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
l_path := test_dir + fn
create f.make_with_name (l_path)
test_dir := (create {EXECUTION_ENVIRONMENT}).current_working_path
l_path := test_dir.extended (fn)
create f.make_with_path (l_path)
if f.exists then
-- Found json file
else
-- before EiffelStudio 7.3 , the current dir of autotest execution was not the parent dir of ecf but something like
-- ..json\test\autotest\test_suite\EIFGENs\test_suite\Testing\execution\TEST_JSON_SUITE.test_json_fail1\..\..\..\..\..\fail1.json
-- before EiffelStudio 7.3 , the current dir of autotest execution was not the parent dir of ecf but something like
-- ..json\test\autotest\test_suite\EIFGENs\test_suite\Testing\execution\TEST_JSON_SUITE.test_json_fail1\..\..\..\..\..\fail1.json
from
i := 5
until
i = 0
loop
test_dir.append_character ('.')
test_dir.append_character ('.')
test_dir.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
test_dir := test_dir.extended ("..")
i := i - 1
end
l_path := test_dir + fn
l_path := test_dir.extended (fn)
end
create f.make_with_name (l_path)
create f.make_with_path (l_path)
if f.exists then
Result := file_reader.read_json_from (l_path)
Result := file_reader.read_json_from (l_path.name)
end
assert ("File contains json data", Result /= Void)
end
assert ("File contains json data", Result /= Void)
end
new_json_parser (a_string: STRING): JSON_PARSER
do
create Result.make_parser (a_string)
create Result.make_with_string (a_string)
end
invariant
file_reader /= Void
end

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="test_suite" uuid="EA141B17-6A21-4781-8B5F-E9939BAE968A">
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="test_suite" uuid="EA141B17-6A21-4781-8B5F-E9939BAE968A">
<target name="test_suite">
<root cluster="test_suite" class="APPLICATION" feature="make"/>
<file_rule>
@@ -7,11 +7,11 @@
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="standard">
<option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="standard">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="json" location="..\..\..\library\json-safe.ecf"/>
<library name="json" location="..\..\..\library\json-safe.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<cluster name="test_suite" location=".\" recursive="true"/>
</target>