Compare commits
183 Commits
v0
...
es_rev9927
| Author | SHA1 | Date | |
|---|---|---|---|
| f12158e535 | |||
| 080881368a | |||
|
|
3e935c7e33 | ||
|
|
ad2bb0d1a7 | ||
| 7a546622bc | |||
| aed7461faf | |||
| 56819d6793 | |||
| b4fd04ad9f | |||
| 71a98f3c28 | |||
| ed22be2551 | |||
| 77085364ee | |||
| 0217c6d3f4 | |||
| 55fec2423c | |||
| 1f7a81a2d6 | |||
| 612ff243c1 | |||
| 40fb3893af | |||
| 21407f8dcf | |||
| 356eb143ea | |||
| df551d4a4f | |||
| f010da04e9 | |||
| 5029049ef0 | |||
| 80254b2278 | |||
| 210fae5000 | |||
| 9cc9b95190 | |||
| 8b172b5d33 | |||
| cc2d7dbb1c | |||
| c88394b9fd | |||
| 4283662f43 | |||
| 1b951376f9 | |||
| 193cc3cbde | |||
| b49e841ac7 | |||
| 8ba74e1c90 | |||
| 0cecb9594c | |||
| e384a6d6ed | |||
| 71a5c086a5 | |||
| dfa60bf8f5 | |||
| 113aa69efc | |||
| af5fc75743 | |||
|
|
e53c960a89 | ||
|
|
63be2c278c | ||
|
|
f8ba741aa2 | ||
|
|
fe07af587d | ||
|
|
a3a9dd1393 | ||
|
|
fbb860024d | ||
|
|
a14488346f | ||
|
|
f74d1b3069 | ||
|
|
1ba3528974 | ||
| 5890ca6f73 | |||
| 7f4bf09d84 | |||
|
|
ad90e7c135 | ||
| cc3c8af6b4 | |||
| b35ec65577 | |||
| 4482520a86 | |||
| e9afc9ad17 | |||
| 55ab6969ee | |||
| d982bc06ad | |||
| 2ca87d53b8 | |||
| 1a4db1d7c6 | |||
| 3bb9101b07 | |||
| 1b2496b7f0 | |||
| d20c377580 | |||
| 166d0839b7 | |||
| fbe0732210 | |||
| b5d6a75155 | |||
| 4fc4b02449 | |||
| 5276bd1479 | |||
|
|
81ab31b19a | ||
|
|
e21e30ff74 | ||
|
|
3a9ba75717 | ||
| 7d94413297 | |||
| 35855941e6 | |||
| 50ba8ca703 | |||
| dde6a0b7de | |||
| b64a281d75 | |||
| b69b8aaaf9 | |||
| 65b28ed877 | |||
| 6c7637716b | |||
| ff9a238f5c | |||
| eec3cbdba1 | |||
| 29c4931dc0 | |||
|
|
9cd0f0b117 | ||
|
|
aa0eb4fc43 | ||
|
|
dbdc594b59 | ||
|
|
4176a8c68b | ||
|
|
0557d1ee2d | ||
|
|
eed8af9a0a | ||
|
|
1b881c4f60 | ||
|
|
770488dbd3 | ||
| 3f69081d32 | |||
| 7033db7dc4 | |||
| a1a16b4a22 | |||
| 98e92ee0fe | |||
| 29b55f36cf | |||
| 061e88c9fe | |||
| 66f204b1f2 | |||
| c92b1b8c3b | |||
| 98c12b8fb9 | |||
| 5fee483fd9 | |||
| f7a7afccd6 | |||
| e2c70e6d70 | |||
| a5e150d1c0 | |||
| 39887c8bdb | |||
|
|
1f1e2abbda | ||
| 1796d9631f | |||
| 389975e409 | |||
| 6c51590369 | |||
|
|
cc65bae644 | ||
|
|
c824f707cf | ||
| 47c5b798b3 | |||
| f0cba1d536 | |||
| ed891546bc | |||
| 8651ff6e1e | |||
| 629edea991 | |||
|
|
1e10ce8518 | ||
| 4f8f17ad48 | |||
| 148518984e | |||
| 33150e34d6 | |||
| af60a5719e | |||
| 31557cfc33 | |||
| 78c0cd5b0d | |||
| 412534d0be | |||
|
|
0f6aa8d7ae | ||
|
|
2c745c63d3 | ||
|
|
efd80c1287 | ||
|
|
01f649fd88 | ||
|
|
f23aeb6412 | ||
|
|
1a4596c79b | ||
|
|
b16e4aa570 | ||
|
|
5255b15fa9 | ||
|
|
57048373f4 | ||
|
|
9e06fb2ab8 | ||
|
|
f2405e0ccd | ||
|
|
6e3a7deb6e | ||
|
|
f254b599c0 | ||
| 99a05b95ba | |||
| 54dd43c38a | |||
| 903f925a79 | |||
| 80709578d6 | |||
| c0d5b7c968 | |||
| 7bea163f46 | |||
| 8992dbc515 | |||
| c2d3ea6138 | |||
| 9e336deb49 | |||
| 0160ce05dd | |||
| 7d089a88c2 | |||
| ab0bc7b314 | |||
| 0e3e97a7fd | |||
| b790c7fd21 | |||
| d0836d49a4 | |||
| 9424b1e369 | |||
| 64463df552 | |||
| dd5c89e31c | |||
| fffa763d05 | |||
| d015c065f6 | |||
| 8ea443c115 | |||
| 019393fdb1 | |||
| da8028f8b3 | |||
| 20ed000879 | |||
|
|
24620b228c | ||
|
|
9c7e29b836 | ||
|
|
a0e9a41e21 | ||
|
|
dd9aff03d3 | ||
|
|
dc35925eb0 | ||
| a1a620a9c3 | |||
| d8ea9ba63c | |||
| c42af5b2de | |||
| d9cbc72058 | |||
| 7e057b20b1 | |||
| 3165c1e5c6 | |||
| 89e26519e4 | |||
| 9d20e85c03 | |||
| 48cb99498c | |||
| 8246bc1444 | |||
| 9e1083eba8 | |||
| 4907bc3085 | |||
| 7d2ce8a77f | |||
| b4a9c92ffc | |||
| bf0eb9a02d | |||
| ddf73077b3 | |||
| 3da80fce0d | |||
| 0970de5dc6 | |||
| 557b11f4e6 | |||
| 7f27a6c797 |
@@ -1,38 +1,7 @@
|
|||||||
History for Eiffel-Web-Framework
|
History for Eiffel-Web-Framework
|
||||||
|
[2015-06-10]
|
||||||
|
* Updated EWF design to better support concurrency, including SCOOP via
|
||||||
|
the new standalone connector.
|
||||||
|
|
||||||
[2011-09-23] Jocelyn
|
|
||||||
* library "ewsgi":
|
|
||||||
- NEW simple autotest cases using Nino web server
|
|
||||||
-fixed issue with RAW_POST_DATA being added in form_data_parameters
|
|
||||||
instead of meta_variables ...
|
|
||||||
- Implemented WGI_VALUE for parameter's type (query_parameter,
|
|
||||||
form_data_parameter, item ...)
|
|
||||||
* Nino connector: added feature to shutdown the server from the WGI application
|
|
||||||
* NEW library "http_client": a new library to perform simple http requests
|
|
||||||
such as get, head, post, put, ... (currently implemented with Eiffel cURL)
|
|
||||||
* NEW library "http_authorization": added simple library to support
|
|
||||||
HTTP_AUTHORIZATION. For now only "Basic" auth type is supported ..
|
|
||||||
|
|
||||||
[2011-09-22] Javier
|
|
||||||
* NEW Example: added partial Restbuck example
|
|
||||||
|
|
||||||
[2011-09-21] Jocelyn
|
|
||||||
* Nino connector: fixed an issue with missing value for Content-Type and Content-Length
|
|
||||||
|
|
||||||
[2011-09-13] Jocelyn
|
|
||||||
* library "router": now using a generic design to allow customization of
|
|
||||||
request handler context class.
|
|
||||||
* NEW library "server/request/rest": first attempt to provide a library to
|
|
||||||
help building RESTful application (the interfaces are likely to change
|
|
||||||
soon) EXPERIMENTAL
|
|
||||||
|
|
||||||
[2011-09-09] Jocelyn
|
|
||||||
* library "uri-template": better support for {/vars} and {?vars}
|
|
||||||
|
|
||||||
[2011-09-07] Jocelyn
|
|
||||||
* library "router": now routing depends on uri (or uri template) and request methods
|
|
||||||
* Nino connector: Fixed issue where HTTP_ prefix were missing for header meta variable.
|
|
||||||
|
|
||||||
[2011-09-07] Jocelyn
|
|
||||||
* changelog: starting to write down changelogs file
|
|
||||||
|
|
||||||
|
[Previous ] Many significant changes in v0
|
||||||
|
|||||||
121
MIGRATION.md
Normal file
121
MIGRATION.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
Date: 2015-june
|
||||||
|
|
||||||
|
# Goal:
|
||||||
|
=======
|
||||||
|
- support safe concurrency with EWF
|
||||||
|
- provide a concurrent standalone connector
|
||||||
|
|
||||||
|
# Status:
|
||||||
|
=========
|
||||||
|
- The version v0 of EWF has mainly 3 connectors: CGI, libFCGI, and nino.
|
||||||
|
- CGI and libFCGI connectors does not need any concurrency support.
|
||||||
|
- But the nino connector had a pseudo concurrency support with Thread, however one could do write code that result in hasardeous concurrency execution.
|
||||||
|
|
||||||
|
So, it was decided to provide an improved Eiffel web nino connector, and update EWF design to make it concurrency compliant.
|
||||||
|
|
||||||
|
# Decisions:
|
||||||
|
============
|
||||||
|
- instead of updating current nino library, we now have a new "standalone" connector which is inspired by nino, but have support for the 3 concurrency modes: none, thread and SCOOP.
|
||||||
|
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
==========
|
||||||
|
Adding support for SCOOP concurrency mode add constraints to the design, but also helps ensuring the concurrency design of EWF is correct.
|
||||||
|
|
||||||
|
As a consequence, we had to introduce a new interface WSF_EXECUTION which is instantiated for each incoming request. See its simplified interface :
|
||||||
|
<code lang="eiffel">
|
||||||
|
deferred class WSF_EXECUTION
|
||||||
|
|
||||||
|
feature -- Initialization
|
||||||
|
|
||||||
|
make (req: WGI_REQUEST; res: WGI_RESPONSE)
|
||||||
|
do
|
||||||
|
...
|
||||||
|
īnitialize
|
||||||
|
end
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize Current object.
|
||||||
|
--| To be redefined if needed.
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
request: WSF_REQUEST
|
||||||
|
-- Access to request data.
|
||||||
|
-- Header, Query, Post, Input data..
|
||||||
|
|
||||||
|
response: WSF_RESPONSE
|
||||||
|
-- Access to output stream, back to the client.
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
execute
|
||||||
|
-- Execute Current `request',
|
||||||
|
-- getting data from `request'
|
||||||
|
-- and response to client via `response'.
|
||||||
|
deferred
|
||||||
|
ensure
|
||||||
|
is_valid_end_of_execution: is_valid_end_of_execution
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
</code>
|
||||||
|
|
||||||
|
And the related request execution routines are extracted from WSF_SERVICE which becomes almost useless. The "service" part is not mostly responsible of launching the expected connector and set optional options, and declare the type of "execution" interface.
|
||||||
|
|
||||||
|
As a result, the well known WSF_DEFAULT_SERVICE has now a formal generic that should conform to WSF_EXECUTION with a `make' creation procedure. See update code:
|
||||||
|
|
||||||
|
<code lang="eiffel">
|
||||||
|
class
|
||||||
|
APPLICATION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION]
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make_and_launch
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize current service.
|
||||||
|
do
|
||||||
|
set_service_option ("port", 9090)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
</code>
|
||||||
|
|
||||||
|
Where APPLICATION_EXECUTION is an implementation of the WSF_EXECUTION interface (with the `make' creation procedure).
|
||||||
|
|
||||||
|
In addition to add better and safer concurrency support, there are other advantages:
|
||||||
|
- we now have a clear separation between the service launcher, and the request execution itself.
|
||||||
|
- the WSF_EXECUTION is created per request, with two main attributes <code>request: WSF_REQUEST</code> and <code>response: WSF_RESPONSE</code>.
|
||||||
|
|
||||||
|
# How to migrate to new design
|
||||||
|
- you can check the various example from the EWF repository, there should all be migrated to new design and comparing previous and new code, this will show you how the migration was done.
|
||||||
|
- a frequent process:
|
||||||
|
- identify the root class of your service, (the class implementing the WSF_SERVICE), let us name it APPLICATION_SERVICE
|
||||||
|
- copy the APPLICATION_SERVICE file to APPLICATION_EXECUTION file.
|
||||||
|
- change the class name to be APPLICATION_EXECUTION, and replace _SERVICE occurences by _EXECUTION (note the new WSF_ROUTED_EXECUTION and so on, which are mainly migration from previous WSF_ROUTED_SERVICE .., and also WSF_FILTERED_ROUTED_EXECUTION which is new.
|
||||||
|
- replace "make_and_launch" by "make", remove the initialize redefinition if any.
|
||||||
|
- in the APPLICATION_SERVICE class, remove most of the ROUTED, FILTERED ... inheritance, and keep WSF_DEFAULT_SERVICE, with a new formal generic i.e WSF_DEFAULT_SERVICE [APPLICATION_EXECUTION].
|
||||||
|
- in the eventual redefined initialize, remove code related to routers, filters, ...
|
||||||
|
- remove all the execution related code.
|
||||||
|
- And you should be done.
|
||||||
|
- To be short, this is mostly creating a new _EXECUTION class, and move the execution related code into this class from the _SERVICE class.
|
||||||
|
- Then, you can replace the usage of nino connector by using the new "Standalone" connector, and switch to SCOOP concurrency mode, to ensure you are not messing up with concurrency. Your own code/libraris may not be SCOOP compliant, we recommend to migrate to SCOOP, but as an intermediate solutioņ, you can use the other concurrency mode (none or thread).
|
||||||
|
|
||||||
|
Note: the new design impacts the _SERVICE classes, connectors, but WSF_REQUEST, WSF_RESPONSE , WSF_ROUTER are compatible, so the migration is really easy.
|
||||||
|
|
||||||
|
We may take the opportunity to update the design deeper according to user feedback, and eventually "wsf" library will be renamed "wsf2".
|
||||||
|
This is work in progress, all comments , feedback, suggestions, bug report are welcome.
|
||||||
|
Hopefully before the final version of the new design is out.
|
||||||
|
|
||||||
|
|
||||||
@@ -29,7 +29,9 @@
|
|||||||
|
|
||||||
<target name="_build_tpl_" >
|
<target name="_build_tpl_" >
|
||||||
<argument name="_target_name" />
|
<argument name="_target_name" />
|
||||||
<geant target="${_target_name}" dir="ise_library" file="build.eant" reuse_variables="true" />
|
<!--
|
||||||
|
<geant target="${_target_name}" dir="library" file="build.eant" reuse_variables="true" />
|
||||||
|
-->
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
|
|
||||||
<project name="build_library" default="help">
|
|
||||||
<description>
|
|
||||||
description: "Compile Eiffel Web Framework / Contrib / ISE library"
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<target name="help">
|
|
||||||
<echo message="usage:"/>
|
|
||||||
<echo message=" geant compile"/>
|
|
||||||
<echo message=" geant clean"/>
|
|
||||||
<echo message=" geant clobber"/>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="compile" >
|
|
||||||
<echo message="- Compile ise_library" />
|
|
||||||
<geant target="_build_tpl_" arguments="compile" />
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="clean" >
|
|
||||||
<echo message="- Clean ise_library" />
|
|
||||||
<geant target="_build_tpl_" arguments="clean" />
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="clobber" >
|
|
||||||
<echo message="- Clobber ise_library" />
|
|
||||||
<geant target="_build_tpl_" arguments="clobber" />
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="_build_tpl_" >
|
|
||||||
<argument name="_target_name" />
|
|
||||||
</target>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -17,10 +17,21 @@ create
|
|||||||
make_server_by_port
|
make_server_by_port
|
||||||
|
|
||||||
create {NETWORK_STREAM_SOCKET}
|
create {NETWORK_STREAM_SOCKET}
|
||||||
make_from_descriptor_and_address
|
make_from_descriptor_and_address,
|
||||||
|
make_empty
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_server_by_address_and_port (a_address: INET_ADDRESS; a_port: INTEGER)
|
||||||
|
-- Create server socket on `a_address' and `a_port'.
|
||||||
|
require
|
||||||
|
valid_port: a_port >= 0
|
||||||
|
do
|
||||||
|
make
|
||||||
|
create address.make_from_address_and_port (a_address, a_port)
|
||||||
|
bind
|
||||||
|
end
|
||||||
|
|
||||||
make
|
make
|
||||||
-- Create a network stream socket.
|
-- Create a network stream socket.
|
||||||
do
|
do
|
||||||
@@ -28,16 +39,6 @@ feature {NONE} -- Initialization
|
|||||||
set_reuse_address
|
set_reuse_address
|
||||||
end
|
end
|
||||||
|
|
||||||
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
|
|
||||||
-- Create server socket on `an_address' and `a_port'.
|
|
||||||
require
|
|
||||||
valid_port: a_port >= 0
|
|
||||||
do
|
|
||||||
make
|
|
||||||
create address.make_from_address_and_port (an_address, a_port)
|
|
||||||
bind
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Basic operation
|
feature -- Basic operation
|
||||||
|
|
||||||
send_message (a_msg: STRING)
|
send_message (a_msg: STRING)
|
||||||
@@ -29,16 +29,6 @@ feature {NONE} -- Initialization
|
|||||||
set_reuse_address
|
set_reuse_address
|
||||||
end
|
end
|
||||||
|
|
||||||
make_server_by_address_and_port (an_address: INET_ADDRESS; a_port: INTEGER)
|
|
||||||
-- Create server socket on `an_address' and `a_port'.
|
|
||||||
require
|
|
||||||
valid_port: a_port >= 0
|
|
||||||
do
|
|
||||||
make
|
|
||||||
create address.make_from_address_and_port (an_address, a_port)
|
|
||||||
bind
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Basic operation
|
feature -- Basic operation
|
||||||
|
|
||||||
send_message (a_msg: STRING)
|
send_message (a_msg: STRING)
|
||||||
|
|||||||
@@ -22,13 +22,13 @@
|
|||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>tcp_stream_socket.e</exclude>
|
<exclude>tcp_stream_socket.e</exclude>
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="15.01.9.6506"/>
|
<version type="compiler" max="16.11"/>
|
||||||
</condition>
|
</condition>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
</cluster>
|
</cluster>
|
||||||
<cluster name="spec_before_15_01" location=".\library\spec\before_15_01\" recursive="true">
|
<cluster name="spec_until_16_05" location=".\library\spec\until_16_05\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="15.01.9.6506"/>
|
<version type="compiler" max="16.11"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</target>
|
</target>
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?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="nino" uuid="32C1D67D-33DE-4F1E-864B-D45388F2E3E6" library_target="nino">
|
<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="nino" uuid="32C1D67D-33DE-4F1E-864B-D45388F2E3E6" library_target="nino">
|
||||||
<target name="nino">
|
<target name="nino">
|
||||||
<root all_classes="true"/>
|
<root all_classes="true"/>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>/.git$</exclude>
|
<exclude>/.git$</exclude>
|
||||||
<exclude>/EIFGENs$</exclude>
|
<exclude>/EIFGENs$</exclude>
|
||||||
<exclude>/CVS$</exclude>
|
<exclude>/CVS$</exclude>
|
||||||
<exclude>/.svn$</exclude>
|
<exclude>/.svn$</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<option warning="true" void_safety="none">
|
<option warning="true" void_safety="none">
|
||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||||
</option>
|
</option>
|
||||||
<setting name="concurrency" value="thread"/>
|
<setting name="concurrency" value="thread"/>
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
<library name="net" location="$ISE_LIBRARY\library\net\net.ecf"/>
|
||||||
<library name="thread" location="$ISE_LIBRARY\library\thread\thread.ecf"/>
|
<library name="thread" location="$ISE_LIBRARY\library\thread\thread.ecf"/>
|
||||||
<cluster name="nino" location=".\library\" recursive="true">
|
<cluster name="nino" location=".\library\" recursive="true">
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>spec</exclude>
|
<exclude>spec</exclude>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
<file_rule>
|
<file_rule>
|
||||||
<exclude>tcp_stream_socket.e</exclude>
|
<exclude>tcp_stream_socket.e</exclude>
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="15.01.9.6506"/>
|
<version type="compiler" max="16.11"/>
|
||||||
</condition>
|
</condition>
|
||||||
</file_rule>
|
</file_rule>
|
||||||
</cluster>
|
</cluster>
|
||||||
<cluster name="spec_before_15_01" location=".\library\spec\before_15_01\" recursive="true">
|
<cluster name="spec_until_16_05" location=".\library\spec\until_16_05\" recursive="true">
|
||||||
<condition>
|
<condition>
|
||||||
<version type="compiler" max="15.01.9.6506"/>
|
<version type="compiler" max="16.11"/>
|
||||||
</condition>
|
</condition>
|
||||||
</cluster>
|
</cluster>
|
||||||
</target>
|
</target>
|
||||||
</system>
|
</system>
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ note
|
|||||||
title: Eiffel Nino Web Server
|
title: Eiffel Nino Web Server
|
||||||
description: Simple HTTPd server written in Eiffel
|
description: Simple HTTPd server written in Eiffel
|
||||||
tags: web, httpd, server
|
tags: web, httpd, server
|
||||||
|
copyright: Javier Velilla, Jocelyn Fiat and Eiffel Software.
|
||||||
license: Eiffel Forum v2
|
license: Eiffel Forum v2
|
||||||
copyright: Javier Velilla, Jocelyn Fiat.
|
link[license]: http://www.eiffel.com/licensing/forum.txt
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
10
contrib/library/text/parser/json/.gitattributes
vendored
10
contrib/library/text/parser/json/.gitattributes
vendored
@@ -1,10 +0,0 @@
|
|||||||
# Set default behaviour, in case users don't have core.autocrlf set.
|
|
||||||
# * text=auto
|
|
||||||
|
|
||||||
# Explicitly declare text files we want to always be normalized and converted
|
|
||||||
# to native line endings on checkout.
|
|
||||||
*.e text
|
|
||||||
*.ecf text
|
|
||||||
*.bat text
|
|
||||||
*.json text
|
|
||||||
*.txt text
|
|
||||||
2
contrib/library/text/parser/json/.gitignore
vendored
2
contrib/library/text/parser/json/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
*.swp
|
|
||||||
EIFGENs/
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
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++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
|
|
||||||
*Updated skip_white_spaces, now check %U and %T codes
|
|
||||||
|
|
||||||
*Undo changes to is_a_valid_number, because it's doesn't follow the
|
|
||||||
JSON spec. Tests : fail13.json, fail29.json and fail30.json are valid
|
|
||||||
with this implementation, so we go back to the previous
|
|
||||||
implementation.
|
|
||||||
|
|
||||||
*Added autotest test suite
|
|
||||||
|
|
||||||
*Added getest based test program
|
|
||||||
|
|
||||||
*Updated Eiffel configuration file, updated to the new clusters
|
|
||||||
|
|
||||||
*Added converters and factory classes
|
|
||||||
|
|
||||||
*Added new top level directories; library, test, build and example
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
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
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
Readme file for eJSON
|
|
||||||
=====================
|
|
||||||
|
|
||||||
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. 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, Jocelyn Fiat and others. It is licensed
|
|
||||||
under the MIT License. See the file license.txt in the same directory as this
|
|
||||||
readme file.
|
|
||||||
|
|
||||||
3. Versioning scheme
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
eJSON version numbers has the form:
|
|
||||||
|
|
||||||
«major number».«minor number».«patch level»
|
|
||||||
|
|
||||||
eJSON will retain the major number 0 as long as it has beta status. A change in
|
|
||||||
major number indicates that a release is not backward compatible. A change in
|
|
||||||
minor number indicates that a release is backward compatible (within that major
|
|
||||||
number) but that new useful features may have been added. A change in patch
|
|
||||||
level simply indicates that the release contains bug fixes for the previous
|
|
||||||
release. Note that as long as eJSON is in beta status (0.Y.Z) backward
|
|
||||||
compatibility is not guranteed for changes in minor numbers!
|
|
||||||
|
|
||||||
4. Documentation
|
|
||||||
---------------
|
|
||||||
|
|
||||||
Currently the only documentation on eJSON is available at:
|
|
||||||
|
|
||||||
https://github.com/eiffelhub/json/wiki/User-guide
|
|
||||||
|
|
||||||
5. Requirements and installation
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
EJSON requires that you have:
|
|
||||||
|
|
||||||
1. One of the following compiler combinations installed:
|
|
||||||
* ISE Eiffel 13.11 or later.
|
|
||||||
* gec [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.
|
|
||||||
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.
|
|
||||||
|
|
||||||
6. Contents of eJSON
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
All directory names below are relative to the root directory of your ejson
|
|
||||||
installation.
|
|
||||||
|
|
||||||
Directory Description
|
|
||||||
--------- -----------
|
|
||||||
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»
|
|
||||||
Jocelyn Fiat «jfiat@eiffel.com»
|
|
||||||
|
|
||||||
8. Releases
|
|
||||||
-----------
|
|
||||||
|
|
||||||
For more information on what was changed in each release look in the file
|
|
||||||
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
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
== 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.
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for ARRAYED_LIST [ANY]"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_ARRAYED_LIST_CONVERTER
|
|
||||||
|
|
||||||
obsolete
|
|
||||||
"This JSON converter design has issues [Sept/2014]."
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_LIST_CONVERTER
|
|
||||||
redefine
|
|
||||||
object
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: ARRAYED_LIST [detachable ANY]
|
|
||||||
|
|
||||||
feature {NONE} -- Factory
|
|
||||||
|
|
||||||
new_object (nb: INTEGER): like object
|
|
||||||
do
|
|
||||||
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
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,88 +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
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for LINKED_LIST [ANY]"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_LINKED_LIST_CONVERTER
|
|
||||||
|
|
||||||
obsolete
|
|
||||||
"This JSON converter design has issues [Sept/2014]."
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_LIST_CONVERTER
|
|
||||||
redefine
|
|
||||||
object
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: LINKED_LIST [detachable ANY]
|
|
||||||
|
|
||||||
feature {NONE} -- Factory
|
|
||||||
|
|
||||||
new_object (nb: INTEGER): like object
|
|
||||||
do
|
|
||||||
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
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
note
|
|
||||||
description: "Core factory class for creating JSON objects and corresponding Eiffel objects."
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class
|
|
||||||
EJSON
|
|
||||||
|
|
||||||
obsolete
|
|
||||||
"This JSON converter design has issues [Sept/2014]."
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
EXCEPTIONS
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
value (an_object: detachable ANY): detachable JSON_VALUE
|
|
||||||
-- JSON value from Eiffel object. Raises an "eJSON exception" if
|
|
||||||
-- unable to convert value.
|
|
||||||
local
|
|
||||||
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.
|
|
||||||
if an_object = Void then
|
|
||||||
create {JSON_NULL} Result
|
|
||||||
elseif attached {BOOLEAN} an_object as b then
|
|
||||||
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
|
|
||||||
create {JSON_NUMBER} Result.make_integer (i16)
|
|
||||||
elseif attached {INTEGER_32} an_object as i32 then
|
|
||||||
create {JSON_NUMBER} Result.make_integer (i32)
|
|
||||||
elseif attached {INTEGER_64} an_object as i64 then
|
|
||||||
create {JSON_NUMBER} Result.make_integer (i64)
|
|
||||||
elseif attached {NATURAL_8} an_object as n8 then
|
|
||||||
create {JSON_NUMBER} Result.make_natural (n8)
|
|
||||||
elseif attached {NATURAL_16} an_object as n16 then
|
|
||||||
create {JSON_NUMBER} Result.make_natural (n16)
|
|
||||||
elseif attached {NATURAL_32} an_object as n32 then
|
|
||||||
create {JSON_NUMBER} Result.make_natural (n32)
|
|
||||||
elseif attached {NATURAL_64} an_object as n64 then
|
|
||||||
create {JSON_NUMBER} Result.make_natural (n64)
|
|
||||||
elseif attached {REAL_32} an_object as r32 then
|
|
||||||
create {JSON_NUMBER} Result.make_real (r32)
|
|
||||||
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 (a.count)
|
|
||||||
from
|
|
||||||
i := a.lower
|
|
||||||
until
|
|
||||||
i > a.upper
|
|
||||||
loop
|
|
||||||
if attached value (a @ i) as v then
|
|
||||||
ja.add (v)
|
|
||||||
else
|
|
||||||
check
|
|
||||||
value_attached: False
|
|
||||||
end
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
Result := ja
|
|
||||||
elseif attached {CHARACTER_8} an_object as c8 then
|
|
||||||
create {JSON_STRING} Result.make_from_string (c8.out)
|
|
||||||
elseif attached {CHARACTER_32} an_object as c32 then
|
|
||||||
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_from_string (s8)
|
|
||||||
elseif attached {STRING_32} an_object as s32 then
|
|
||||||
create {JSON_STRING} Result.make_from_string_32 (s32)
|
|
||||||
end
|
|
||||||
if Result = Void then
|
|
||||||
-- 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
|
|
||||||
raise (exception_failed_to_convert_to_json (an_object))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
object (a_value: detachable JSON_VALUE; base_class: detachable STRING): detachable ANY
|
|
||||||
-- Eiffel object from JSON value. If `base_class' /= Void an eiffel
|
|
||||||
-- object based on `base_class' will be returned. Raises an "eJSON
|
|
||||||
-- exception" if unable to convert value.
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
ll: LINKED_LIST [detachable ANY]
|
|
||||||
t: HASH_TABLE [detachable ANY, STRING_GENERAL]
|
|
||||||
keys: ARRAY [JSON_STRING]
|
|
||||||
do
|
|
||||||
if a_value = Void then
|
|
||||||
Result := Void
|
|
||||||
else
|
|
||||||
if base_class = Void then
|
|
||||||
if a_value = Void then
|
|
||||||
Result := Void
|
|
||||||
elseif attached {JSON_NULL} a_value then
|
|
||||||
Result := Void
|
|
||||||
elseif attached {JSON_BOOLEAN} a_value as jb then
|
|
||||||
Result := jb.item
|
|
||||||
elseif attached {JSON_NUMBER} a_value as jn then
|
|
||||||
if jn.item.is_integer_8 then
|
|
||||||
Result := jn.item.to_integer_8
|
|
||||||
elseif jn.item.is_integer_16 then
|
|
||||||
Result := jn.item.to_integer_16
|
|
||||||
elseif jn.item.is_integer_32 then
|
|
||||||
Result := jn.item.to_integer_32
|
|
||||||
elseif jn.item.is_integer_64 then
|
|
||||||
Result := jn.item.to_integer_64
|
|
||||||
elseif jn.item.is_natural_64 then
|
|
||||||
Result := jn.item.to_natural_64
|
|
||||||
elseif jn.item.is_double then
|
|
||||||
Result := jn.item.to_double
|
|
||||||
end
|
|
||||||
elseif attached {JSON_STRING} a_value as js then
|
|
||||||
create {STRING_32} Result.make_from_string (js.unescaped_string_32)
|
|
||||||
elseif attached {JSON_ARRAY} a_value as ja then
|
|
||||||
from
|
|
||||||
create ll.make
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > ja.count
|
|
||||||
loop
|
|
||||||
ll.extend (object (ja [i], Void))
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
Result := ll
|
|
||||||
elseif attached {JSON_OBJECT} a_value as jo then
|
|
||||||
keys := jo.current_keys
|
|
||||||
create t.make (keys.count)
|
|
||||||
from
|
|
||||||
i := keys.lower
|
|
||||||
until
|
|
||||||
i > keys.upper
|
|
||||||
loop
|
|
||||||
if attached {STRING_GENERAL} object (keys [i], Void) as s then
|
|
||||||
t.put (object (jo.item (keys [i]), Void), s)
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
Result := t
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if converters.has_key (base_class) and then attached converters.found_item as jc then
|
|
||||||
Result := jc.from_json (a_value)
|
|
||||||
else
|
|
||||||
raise (exception_failed_to_convert_to_eiffel (a_value, base_class))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
object_from_json (json: STRING; base_class: detachable STRING): detachable ANY
|
|
||||||
-- Eiffel object from JSON representation. If `base_class' /= Void an
|
|
||||||
-- Eiffel object based on `base_class' will be returned. Raises an
|
|
||||||
-- "eJSON exception" if unable to convert value.
|
|
||||||
require
|
|
||||||
json_not_void: json /= Void
|
|
||||||
do
|
|
||||||
json_parser.set_representation (json)
|
|
||||||
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
|
|
||||||
|
|
||||||
converter_for (an_object: ANY): detachable JSON_CONVERTER
|
|
||||||
-- Converter for objects. Returns Void if none found.
|
|
||||||
require
|
|
||||||
an_object_not_void: an_object /= Void
|
|
||||||
do
|
|
||||||
if converters.has_key (an_object.generator) then
|
|
||||||
Result := converters.found_item
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
json_reference (s: STRING): JSON_OBJECT
|
|
||||||
-- A JSON (Dojo style) reference object using `s' as the
|
|
||||||
-- reference value. The caller is responsable for ensuring
|
|
||||||
-- the validity of `s' as a json reference.
|
|
||||||
require
|
|
||||||
s_not_void: s /= Void
|
|
||||||
local
|
|
||||||
js_key, js_value: JSON_STRING
|
|
||||||
do
|
|
||||||
create Result.make
|
|
||||||
create js_key.make_from_string ("$ref")
|
|
||||||
create js_value.make_from_string (s)
|
|
||||||
Result.put (js_value, js_key)
|
|
||||||
end
|
|
||||||
|
|
||||||
json_references (l: LIST [STRING]): JSON_ARRAY
|
|
||||||
-- A JSON array of JSON (Dojo style) reference objects using the
|
|
||||||
-- strings in `l' as reference values. The caller is responsable
|
|
||||||
-- for ensuring the validity of all strings in `l' as json
|
|
||||||
-- references.
|
|
||||||
require
|
|
||||||
l_not_void: l /= Void
|
|
||||||
local
|
|
||||||
c: ITERATION_CURSOR [STRING]
|
|
||||||
do
|
|
||||||
create Result.make (l.count)
|
|
||||||
from
|
|
||||||
c := l.new_cursor
|
|
||||||
until
|
|
||||||
c.after
|
|
||||||
loop
|
|
||||||
Result.add (json_reference (c.item))
|
|
||||||
c.forth
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Change
|
|
||||||
|
|
||||||
add_converter (jc: JSON_CONVERTER)
|
|
||||||
-- Add the converter `jc'.
|
|
||||||
require
|
|
||||||
jc_not_void: jc /= Void
|
|
||||||
do
|
|
||||||
converters.force (jc, jc.object.generator)
|
|
||||||
ensure
|
|
||||||
has_converter: converter_for (jc.object) /= Void
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
converters: HASH_TABLE [JSON_CONVERTER, STRING]
|
|
||||||
-- Converters hashed by generator (base class)
|
|
||||||
once
|
|
||||||
create Result.make (10)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation (Exceptions)
|
|
||||||
|
|
||||||
exception_prefix: STRING = "eJSON exception: "
|
|
||||||
|
|
||||||
exception_failed_to_convert_to_eiffel (a_value: JSON_VALUE; base_class: detachable STRING): STRING
|
|
||||||
-- Exception message for failing to convert a JSON_VALUE to an instance of `a'.
|
|
||||||
do
|
|
||||||
Result := exception_prefix + "Failed to convert JSON_VALUE to an Eiffel object: " + a_value.generator
|
|
||||||
if base_class /= Void then
|
|
||||||
Result.append (" -> {" + base_class + "}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
exception_failed_to_convert_to_json (an_object: detachable ANY): STRING
|
|
||||||
-- Exception message for failing to convert `a' to a JSON_VALUE.
|
|
||||||
do
|
|
||||||
Result := exception_prefix + "Failed to convert Eiffel object to a JSON_VALUE"
|
|
||||||
if an_object /= Void then
|
|
||||||
Result.append (" : {" + an_object.generator + "}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation (JSON parser)
|
|
||||||
|
|
||||||
json_parser: JSON_PARSER
|
|
||||||
once
|
|
||||||
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
|
|
||||||
@@ -1,43 +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
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for DS_HASH_TABLE [ANY, HASHABLE]"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date: $"
|
|
||||||
revision: "$Revision: $"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class JSON_DS_HASH_TABLE_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_CONVERTER
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
do
|
|
||||||
create object.make (0)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
value: JSON_OBJECT
|
|
||||||
|
|
||||||
object: DS_HASH_TABLE [ANY, HASHABLE]
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
from_json (j: like value): detachable like object
|
|
||||||
local
|
|
||||||
keys: ARRAY [JSON_STRING]
|
|
||||||
i: INTEGER
|
|
||||||
h: HASHABLE
|
|
||||||
a: ANY
|
|
||||||
do
|
|
||||||
keys := j.current_keys
|
|
||||||
create Result.make (keys.count)
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > keys.count
|
|
||||||
loop
|
|
||||||
h ?= json.object (keys [i], void)
|
|
||||||
check h /= Void end
|
|
||||||
a := json.object (j.item (keys [i]), Void)
|
|
||||||
Result.put (a, h)
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
to_json (o: like object): like value
|
|
||||||
local
|
|
||||||
c: DS_HASH_TABLE_CURSOR [ANY, HASHABLE]
|
|
||||||
js: JSON_STRING
|
|
||||||
jv: JSON_VALUE
|
|
||||||
failed: BOOLEAN
|
|
||||||
do
|
|
||||||
create Result.make
|
|
||||||
from
|
|
||||||
c := o.new_cursor
|
|
||||||
c.start
|
|
||||||
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
|
|
||||||
jv := json.value (c.item)
|
|
||||||
if jv /= Void then
|
|
||||||
Result.put (jv, js)
|
|
||||||
else
|
|
||||||
failed := True
|
|
||||||
end
|
|
||||||
c.forth
|
|
||||||
end
|
|
||||||
if failed then
|
|
||||||
Result := Void
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class JSON_DS_HASH_TABLE_CONVERTER
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for DS_LINKED_LIST [ANY]"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date: $"
|
|
||||||
revision: "$Revision: $"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class JSON_DS_LINKED_LIST_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_CONVERTER
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
do
|
|
||||||
create object.make
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
value: JSON_ARRAY
|
|
||||||
|
|
||||||
object: DS_LINKED_LIST [ANY]
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
from_json (j: like value): detachable like object
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
do
|
|
||||||
create Result.make
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > j.count
|
|
||||||
loop
|
|
||||||
Result.put_last (json.object (j [i], Void))
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
to_json (o: like object): like value
|
|
||||||
local
|
|
||||||
c: DS_LIST_CURSOR [ANY]
|
|
||||||
do
|
|
||||||
create Result.make_array
|
|
||||||
from
|
|
||||||
c := o.new_cursor
|
|
||||||
c.start
|
|
||||||
until
|
|
||||||
c.after
|
|
||||||
loop
|
|
||||||
Result.add (json.value (c.item))
|
|
||||||
c.forth
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class JSON_DS_LINKED_LIST_CONVERTER
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
note
|
|
||||||
description: "[
|
|
||||||
Shared factory class for creating JSON objects. Maps JSON
|
|
||||||
objects to Gobo DS_HASH_TABLEs and JSON arrays to Gobo
|
|
||||||
DS_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$"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class SHARED_GOBO_EJSON
|
|
||||||
|
|
||||||
feature
|
|
||||||
|
|
||||||
json: EJSON
|
|
||||||
-- A shared EJSON instance with default converters for
|
|
||||||
-- DS_LINKED_LIST [ANY] and DS_HASH_TABLE [ANY, HASHABLE]
|
|
||||||
local
|
|
||||||
jllc: JSON_DS_LINKED_LIST_CONVERTER
|
|
||||||
jhtc: JSON_DS_HASH_TABLE_CONVERTER
|
|
||||||
once
|
|
||||||
create Result
|
|
||||||
create jllc.make
|
|
||||||
Result.add_converter (jllc)
|
|
||||||
create jhtc.make
|
|
||||||
Result.add_converter (jhtc)
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class SHARED_GOBO_EJSON
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
||||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-12-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-12-0 http://www.eiffel.com/developers/xml/configuration-1-12-0.xsd" name="json" uuid="4E21C3BD-7951-4C6E-A673-431E762D7414" library_target="json">
|
|
||||||
<target name="json">
|
|
||||||
<root all_classes="true"/>
|
|
||||||
<file_rule>
|
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/CVS$</exclude>
|
|
||||||
<exclude>/.svn$</exclude>
|
|
||||||
</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/>
|
|
||||||
</option>
|
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="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>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?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="json" uuid="4E21C3BD-7951-4C6E-A673-431E762D7414" library_target="json">
|
|
||||||
<target name="json">
|
|
||||||
<root all_classes="true"/>
|
|
||||||
<file_rule>
|
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/CVS$</exclude>
|
|
||||||
<exclude>/.svn$</exclude>
|
|
||||||
</file_rule>
|
|
||||||
<option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" void_safety="none" syntax="standard" namespace="EJSON.Library">
|
|
||||||
<assertions/>
|
|
||||||
</option>
|
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="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>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<?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="json_gobo" uuid="437195AB-8B3C-4238-8998-A932A1423449" library_target="json_gobo">
|
|
||||||
<target name="json_gobo">
|
|
||||||
<root all_classes="true"/>
|
|
||||||
<file_rule>
|
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/CVS$</exclude>
|
|
||||||
<exclude>/.svn$</exclude>
|
|
||||||
</file_rule>
|
|
||||||
<option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" void_safety="none" syntax="standard" namespace="EJSON.Library">
|
|
||||||
</option>
|
|
||||||
<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_converter" location=".\gobo_converter" recursive="true" />
|
|
||||||
</target>
|
|
||||||
</system>
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
note
|
|
||||||
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
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
ITERABLE [JSON_VALUE]
|
|
||||||
|
|
||||||
DEBUG_OUTPUT
|
|
||||||
|
|
||||||
create
|
|
||||||
make, make_empty,
|
|
||||||
make_array
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
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 := items.i_th (i)
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
new_cursor: ITERATION_CURSOR [JSON_VALUE]
|
|
||||||
-- Fresh cursor associated with current structure
|
|
||||||
do
|
|
||||||
Result := items.new_cursor
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Mesurement
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Change Element
|
|
||||||
|
|
||||||
put_front (v: JSON_VALUE)
|
|
||||||
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
|
|
||||||
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
|
|
||||||
items.prune_all (v)
|
|
||||||
ensure
|
|
||||||
not_has_new_value: not items.has (v)
|
|
||||||
end
|
|
||||||
|
|
||||||
wipe_out
|
|
||||||
-- Remove all items.
|
|
||||||
do
|
|
||||||
items.wipe_out
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Report
|
|
||||||
|
|
||||||
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 := 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
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
items: ARRAYED_LIST [JSON_VALUE]
|
|
||||||
-- Value container
|
|
||||||
|
|
||||||
invariant
|
|
||||||
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
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
note
|
|
||||||
description: "JSON Boolean values"
|
|
||||||
author: "$Author$"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_BOOLEAN
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
create
|
|
||||||
make,
|
|
||||||
make_true, make_false,
|
|
||||||
make_boolean
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
note
|
|
||||||
description: "JSON Null Values"
|
|
||||||
author: "Javier Velilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_NULL
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
feature --Access
|
|
||||||
|
|
||||||
hash_code: INTEGER
|
|
||||||
-- Hash code value
|
|
||||||
do
|
|
||||||
Result := null_value.hash_code
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
debug_output: STRING
|
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
|
||||||
do
|
|
||||||
Result := null_value
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
note
|
|
||||||
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
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VALUE
|
|
||||||
redefine
|
|
||||||
is_equal
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
|
||||||
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_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: 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
|
|
||||||
|
|
||||||
numeric_type: INTEGER
|
|
||||||
-- Type of number (integer, natural or real).
|
|
||||||
|
|
||||||
hash_code: INTEGER
|
|
||||||
--Hash code value
|
|
||||||
do
|
|
||||||
Result := item.hash_code
|
|
||||||
end
|
|
||||||
|
|
||||||
representation: STRING
|
|
||||||
do
|
|
||||||
Result := item
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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, real_type: INTEGER = 2
|
|
||||||
|
|
||||||
natural_type: INTEGER = 3
|
|
||||||
|
|
||||||
invariant
|
|
||||||
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
|
|
||||||
@@ -1,331 +0,0 @@
|
|||||||
note
|
|
||||||
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
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
TABLE_ITERABLE [JSON_VALUE, JSON_STRING]
|
|
||||||
|
|
||||||
DEBUG_OUTPUT
|
|
||||||
|
|
||||||
create
|
|
||||||
make_empty, make_with_capacity, make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
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 (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
|
|
||||||
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.
|
|
||||||
do
|
|
||||||
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
|
|
||||||
|
|
||||||
item (a_key: JSON_STRING): detachable JSON_VALUE
|
|
||||||
-- the json_value associated with a key `a_key'.
|
|
||||||
do
|
|
||||||
Result := items.item (a_key)
|
|
||||||
end
|
|
||||||
|
|
||||||
current_keys: ARRAY [JSON_STRING]
|
|
||||||
-- Array containing actually used keys.
|
|
||||||
do
|
|
||||||
Result := items.current_keys
|
|
||||||
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.
|
|
||||||
do
|
|
||||||
Result := items.count
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
new_cursor: TABLE_ITERATION_CURSOR [JSON_VALUE, JSON_STRING]
|
|
||||||
-- Fresh cursor associated with current structure
|
|
||||||
do
|
|
||||||
Result := items.new_cursor
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
is_empty: BOOLEAN
|
|
||||||
-- Is empty object?
|
|
||||||
do
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
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
|
|
||||||
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
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
items: HASH_TABLE [JSON_VALUE, JSON_STRING]
|
|
||||||
-- Value container
|
|
||||||
|
|
||||||
invariant
|
|
||||||
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
|
|
||||||
@@ -1,506 +0,0 @@
|
|||||||
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: "$Author$"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_STRING
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VALUE
|
|
||||||
redefine
|
|
||||||
is_equal
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
|
||||||
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_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_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_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_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
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
unescaped_string_8: STRING_8
|
|
||||||
-- Unescaped ascii string from `item'.
|
|
||||||
--| note: valid only if `item' does not encode any unicode character.
|
|
||||||
local
|
|
||||||
s: like item
|
|
||||||
do
|
|
||||||
s := item
|
|
||||||
create Result.make (s.count)
|
|
||||||
unescape_to_string_8 (Result)
|
|
||||||
end
|
|
||||||
|
|
||||||
unescaped_string_32: STRING_32
|
|
||||||
-- 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
|
|
||||||
s: READABLE_STRING_8
|
|
||||||
do
|
|
||||||
s := item
|
|
||||||
create Result.make (s.count)
|
|
||||||
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
|
|
||||||
|
|
||||||
unescape_to_string_8 (a_output: STRING_8)
|
|
||||||
-- Unescape string `item' into `a_output'.
|
|
||||||
--| note: valid only if `item' does not encode any unicode character.
|
|
||||||
local
|
|
||||||
s: like item
|
|
||||||
i, n: INTEGER
|
|
||||||
c: CHARACTER
|
|
||||||
do
|
|
||||||
s := item
|
|
||||||
n := s.count
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > n
|
|
||||||
loop
|
|
||||||
c := s [i]
|
|
||||||
if c = '\' then
|
|
||||||
if i < n then
|
|
||||||
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 ('/')
|
|
||||||
i := i + 2
|
|
||||||
when 'b' then
|
|
||||||
a_output.append_character ('%B')
|
|
||||||
i := i + 2
|
|
||||||
when 'f' then
|
|
||||||
a_output.append_character ('%F')
|
|
||||||
i := i + 2
|
|
||||||
when 'n' then
|
|
||||||
a_output.append_character ('%N')
|
|
||||||
i := i + 2
|
|
||||||
when 'r' then
|
|
||||||
a_output.append_character ('%R')
|
|
||||||
i := i + 2
|
|
||||||
when 't' then
|
|
||||||
a_output.append_character ('%T')
|
|
||||||
i := i + 2
|
|
||||||
when 'u' then
|
|
||||||
--| Leave unicode \uXXXX unescaped
|
|
||||||
a_output.append_character (c) -- '\'
|
|
||||||
i := i + 1
|
|
||||||
else
|
|
||||||
a_output.append_character (c) -- '\'
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
a_output.append_character (c) -- '\'
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
a_output.append_character (c)
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
unescape_to_string_32 (a_output: STRING_32)
|
|
||||||
-- Unescape string `item' into `a_output' string 32.
|
|
||||||
--| some encoders uses UTF-8 , and not the recommended pure json encoding
|
|
||||||
--| thus, let's support the UTF-8 encoding during decoding.
|
|
||||||
local
|
|
||||||
s: READABLE_STRING_8
|
|
||||||
i, n: INTEGER
|
|
||||||
c: NATURAL_32
|
|
||||||
ch: CHARACTER_8
|
|
||||||
hex: READABLE_STRING_8
|
|
||||||
do
|
|
||||||
s := item
|
|
||||||
n := s.count
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > n
|
|
||||||
loop
|
|
||||||
ch := s.item (i)
|
|
||||||
if ch = '\' then
|
|
||||||
if i < n then
|
|
||||||
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 ('/')
|
|
||||||
i := i + 2
|
|
||||||
when 'b' then
|
|
||||||
a_output.append_character ('%B')
|
|
||||||
i := i + 2
|
|
||||||
when 'f' then
|
|
||||||
a_output.append_character ('%F')
|
|
||||||
i := i + 2
|
|
||||||
when 'n' then
|
|
||||||
a_output.append_character ('%N')
|
|
||||||
i := i + 2
|
|
||||||
when 'r' then
|
|
||||||
a_output.append_character ('%R')
|
|
||||||
i := i + 2
|
|
||||||
when 't' then
|
|
||||||
a_output.append_character ('%T')
|
|
||||||
i := i + 2
|
|
||||||
when 'u' then
|
|
||||||
hex := s.substring (i + 2, i + 5) -- i+2 , i+2+4-1
|
|
||||||
if hex.count = 4 then
|
|
||||||
a_output.append_code (hexadecimal_to_natural_32 (hex))
|
|
||||||
end
|
|
||||||
i := i + 6 -- i+2+4
|
|
||||||
else
|
|
||||||
a_output.append_character (ch) -- '\'
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
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
|
|
||||||
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))
|
|
||||||
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))
|
|
||||||
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))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Change Element
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
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?
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
do
|
|
||||||
from
|
|
||||||
Result := True
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > s.count or not Result
|
|
||||||
loop
|
|
||||||
Result := s [i].is_hexa_digit
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
hexadecimal_to_natural_32 (s: READABLE_STRING_8): NATURAL_32
|
|
||||||
-- Hexadecimal string `s' converted to NATURAL_32 value
|
|
||||||
require
|
|
||||||
s_not_void: s /= Void
|
|
||||||
is_hexadecimal: is_hexadecimal (s)
|
|
||||||
local
|
|
||||||
i, nb: INTEGER
|
|
||||||
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
|
|
||||||
loop
|
|
||||||
Result := Result * 16
|
|
||||||
char := s.item (i)
|
|
||||||
if char >= '0' and then char <= '9' then
|
|
||||||
Result := Result + (char |-| '0').to_natural_32
|
|
||||||
else
|
|
||||||
Result := Result + (char.lower |-| 'a' + 10).to_natural_32
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
c: CHARACTER_8
|
|
||||||
h: STRING_8
|
|
||||||
do
|
|
||||||
n := s.count
|
|
||||||
create Result.make (n + n // 10)
|
|
||||||
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 '/' 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
|
|
||||||
from
|
|
||||||
j := 1
|
|
||||||
until
|
|
||||||
h.count = 4 or (j <= h.count and then h.item (j) /= '0')
|
|
||||||
loop
|
|
||||||
j := j + 1
|
|
||||||
end
|
|
||||||
h := h.substring (j, h.count)
|
|
||||||
from
|
|
||||||
until
|
|
||||||
h.count >= 4
|
|
||||||
loop
|
|
||||||
h.prepend_integer (0)
|
|
||||||
end
|
|
||||||
check
|
|
||||||
hexastring_has_4_chars: h.count = 4
|
|
||||||
end
|
|
||||||
Result.append (h)
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
invariant
|
|
||||||
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
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
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)"
|
|
||||||
|
|
||||||
deferred class
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
HASHABLE
|
|
||||||
|
|
||||||
DEBUG_OUTPUT
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
note
|
|
||||||
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
|
|
||||||
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
|
|
||||||
end
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
${NOTE_KEYWORD}
|
|
||||||
copyright: "2010-${YEAR}, Javier Velilla and others https://github.com/eiffelhub/json."
|
|
||||||
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
|
|
||||||
|
|
||||||
@@ -1,679 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
note
|
|
||||||
description: "Objects that ..."
|
|
||||||
author: "jvelilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_READER
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make (a_json: STRING)
|
|
||||||
-- Initialize Reader
|
|
||||||
do
|
|
||||||
set_representation (a_json)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Commands
|
|
||||||
|
|
||||||
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
|
|
||||||
reset
|
|
||||||
end
|
|
||||||
|
|
||||||
read: CHARACTER
|
|
||||||
-- Read character
|
|
||||||
do
|
|
||||||
if not representation.is_empty then
|
|
||||||
Result := representation.item (index)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
next
|
|
||||||
-- Move to next index
|
|
||||||
require
|
|
||||||
has_more_elements: has_next
|
|
||||||
do
|
|
||||||
index := index + 1
|
|
||||||
ensure
|
|
||||||
incremented: old index + 1 = index
|
|
||||||
end
|
|
||||||
|
|
||||||
previous
|
|
||||||
-- Move to previous index
|
|
||||||
require
|
|
||||||
not_is_first: has_previous
|
|
||||||
do
|
|
||||||
index := index - 1
|
|
||||||
ensure
|
|
||||||
incremented: old index - 1 = index
|
|
||||||
end
|
|
||||||
|
|
||||||
skip_white_spaces
|
|
||||||
-- Remove white spaces
|
|
||||||
local
|
|
||||||
c: like actual
|
|
||||||
do
|
|
||||||
from
|
|
||||||
c := actual
|
|
||||||
until
|
|
||||||
(c /= ' ' and c /= '%N' and c /= '%R' and c /= '%U' and c /= '%T') or not has_next
|
|
||||||
loop
|
|
||||||
next
|
|
||||||
c := actual
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
json_substring (start_index, end_index: INTEGER_32): STRING
|
|
||||||
-- JSON representation between `start_index' and `end_index'
|
|
||||||
do
|
|
||||||
Result := representation.substring (start_index, end_index)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
has_next: BOOLEAN
|
|
||||||
-- Has a next character?
|
|
||||||
do
|
|
||||||
Result := index <= representation.count
|
|
||||||
end
|
|
||||||
|
|
||||||
has_previous: BOOLEAN
|
|
||||||
-- Has a previous character?
|
|
||||||
do
|
|
||||||
Result := index >= 1
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
representation: STRING
|
|
||||||
-- Serialized representation of the original JSON string
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
actual: CHARACTER
|
|
||||||
-- Current character or '%U' if none
|
|
||||||
do
|
|
||||||
if index > representation.count then
|
|
||||||
Result := '%U'
|
|
||||||
else
|
|
||||||
Result := representation.item (index)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
index: INTEGER
|
|
||||||
-- Actual index
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
note
|
|
||||||
description: "JSON Iterator"
|
|
||||||
pattern: "Iterator visitor"
|
|
||||||
author: "Jocelyn Fiat"
|
|
||||||
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
|
||||||
date: "2013/08/01"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
|
|
||||||
deferred class
|
|
||||||
JSON_ITERATOR
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VISITOR
|
|
||||||
|
|
||||||
feature -- Visitor Pattern
|
|
||||||
|
|
||||||
visit_json_array (a_json_array: JSON_ARRAY)
|
|
||||||
-- Visit `a_json_array'.
|
|
||||||
do
|
|
||||||
across
|
|
||||||
a_json_array as c
|
|
||||||
loop
|
|
||||||
c.item.accept (Current)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
|
|
||||||
-- Visit `a_json_boolean'.
|
|
||||||
do
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_null (a_json_null: JSON_NULL)
|
|
||||||
-- Visit `a_json_null'.
|
|
||||||
do
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_number (a_json_number: JSON_NUMBER)
|
|
||||||
-- Visit `a_json_number'.
|
|
||||||
do
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_object (a_json_object: JSON_OBJECT)
|
|
||||||
-- Visit `a_json_object'.
|
|
||||||
do
|
|
||||||
across
|
|
||||||
a_json_object as c
|
|
||||||
loop
|
|
||||||
c.item.accept (Current)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
note
|
|
||||||
description: "JSON_PRETTY_STRING_VISITOR Generates the JSON-String for a JSON_VALUE"
|
|
||||||
revision: "0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_PRETTY_STRING_VISITOR
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VISITOR
|
|
||||||
|
|
||||||
create
|
|
||||||
make,
|
|
||||||
make_custom
|
|
||||||
|
|
||||||
feature -- Initialization
|
|
||||||
|
|
||||||
make (a_output: like output)
|
|
||||||
-- Create a new instance
|
|
||||||
do
|
|
||||||
make_custom (a_output, 1, 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
make_custom (a_output: like output; a_object_count_inlining, a_array_count_inlining: INTEGER)
|
|
||||||
-- Create a new instance
|
|
||||||
do
|
|
||||||
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_GENERAL
|
|
||||||
-- JSON representation
|
|
||||||
|
|
||||||
feature -- Settings
|
|
||||||
|
|
||||||
indentation_step: STRING
|
|
||||||
-- Text used for indentation.
|
|
||||||
--| by default a tabulation "%T"
|
|
||||||
|
|
||||||
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
|
|
||||||
indentation.append (indentation_step)
|
|
||||||
end
|
|
||||||
|
|
||||||
exdent
|
|
||||||
do
|
|
||||||
indentation.remove_tail (indentation_step.count)
|
|
||||||
end
|
|
||||||
|
|
||||||
new_line
|
|
||||||
do
|
|
||||||
output.append ("%N")
|
|
||||||
output.append (indentation)
|
|
||||||
line_number := line_number + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
line_number: INTEGER
|
|
||||||
|
|
||||||
feature -- Visitor Pattern
|
|
||||||
|
|
||||||
visit_json_array (a_json_array: JSON_ARRAY)
|
|
||||||
-- Visit `a_json_array'.
|
|
||||||
local
|
|
||||||
value: JSON_VALUE
|
|
||||||
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
|
|
||||||
l_output.append_code (91) -- '[' : 91
|
|
||||||
|
|
||||||
l_line := line_number
|
|
||||||
indent
|
|
||||||
from
|
|
||||||
l_json_array.start
|
|
||||||
until
|
|
||||||
l_json_array.off
|
|
||||||
loop
|
|
||||||
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
|
|
||||||
l_output.append (", ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
exdent
|
|
||||||
if line_number > l_line or l_json_array.count >= array_count_inlining then
|
|
||||||
new_line
|
|
||||||
end
|
|
||||||
l_output.append_code (93) -- ']' : 93
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
|
|
||||||
-- Visit `a_json_boolean'.
|
|
||||||
do
|
|
||||||
output.append (a_json_boolean.item.out)
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_null (a_json_null: JSON_NULL)
|
|
||||||
-- Visit `a_json_null'.
|
|
||||||
do
|
|
||||||
output.append ("null")
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_number (a_json_number: JSON_NUMBER)
|
|
||||||
-- Visit `a_json_number'.
|
|
||||||
do
|
|
||||||
output.append (a_json_number.item)
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_object (a_json_object: JSON_OBJECT)
|
|
||||||
-- Visit `a_json_object'.
|
|
||||||
local
|
|
||||||
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
|
|
||||||
l_output.append_code (123) -- '{' : 123
|
|
||||||
l_line := line_number
|
|
||||||
indent
|
|
||||||
from
|
|
||||||
l_pairs.start
|
|
||||||
until
|
|
||||||
l_pairs.off
|
|
||||||
loop
|
|
||||||
if line_number > l_line or l_multiple_lines then
|
|
||||||
new_line
|
|
||||||
end
|
|
||||||
l_pairs.key_for_iteration.accept (Current)
|
|
||||||
l_output.append (": ")
|
|
||||||
l_pairs.item_for_iteration.accept (Current)
|
|
||||||
l_pairs.forth
|
|
||||||
if not l_pairs.after then
|
|
||||||
l_output.append (", ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
exdent
|
|
||||||
if line_number > l_line or l_pairs.count >= object_count_inlining then
|
|
||||||
new_line
|
|
||||||
end
|
|
||||||
l_output.append_code (125) -- '}' : 125
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_string (a_json_string: JSON_STRING)
|
|
||||||
-- Visit `a_json_string'.
|
|
||||||
local
|
|
||||||
l_output: like output
|
|
||||||
do
|
|
||||||
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
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
note
|
|
||||||
description: "JSON Visitor"
|
|
||||||
pattern: "Visitor"
|
|
||||||
author: "Javier Velilla"
|
|
||||||
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
|
|
||||||
deferred class
|
|
||||||
JSON_VISITOR
|
|
||||||
|
|
||||||
feature -- Visitor Pattern
|
|
||||||
|
|
||||||
visit_json_array (a_json_array: JSON_ARRAY)
|
|
||||||
-- Visit `a_json_array'.
|
|
||||||
require
|
|
||||||
a_json_array_not_void: a_json_array /= Void
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
|
|
||||||
-- Visit `a_json_boolean'.
|
|
||||||
require
|
|
||||||
a_json_boolean_not_void: a_json_boolean /= Void
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_null (a_json_null: JSON_NULL)
|
|
||||||
-- Visit `a_json_null'.
|
|
||||||
require
|
|
||||||
a_json_null_not_void: a_json_null /= Void
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_number (a_json_number: JSON_NUMBER)
|
|
||||||
-- Visit `a_json_number'.
|
|
||||||
require
|
|
||||||
a_json_number_not_void: a_json_number /= Void
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_object (a_json_object: JSON_OBJECT)
|
|
||||||
-- Visit `a_json_object'.
|
|
||||||
require
|
|
||||||
a_json_object_not_void: a_json_object /= Void
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
note
|
|
||||||
description: "PRINT_JSON_VISITOR Generates the JSON-String for a JSON_VALUE"
|
|
||||||
author: "jvelilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
PRINT_JSON_VISITOR
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_VISITOR
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
-- Create a new instance
|
|
||||||
do
|
|
||||||
create to_json.make_empty
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
to_json: STRING
|
|
||||||
-- JSON representation
|
|
||||||
|
|
||||||
feature -- Visitor Pattern
|
|
||||||
|
|
||||||
visit_json_array (a_json_array: JSON_ARRAY)
|
|
||||||
-- Visit `a_json_array'.
|
|
||||||
local
|
|
||||||
value: JSON_VALUE
|
|
||||||
l_json_array: ARRAYED_LIST [JSON_VALUE]
|
|
||||||
do
|
|
||||||
l_json_array := a_json_array.array_representation
|
|
||||||
to_json.append ("[")
|
|
||||||
from
|
|
||||||
l_json_array.start
|
|
||||||
until
|
|
||||||
l_json_array.off
|
|
||||||
loop
|
|
||||||
value := l_json_array.item
|
|
||||||
value.accept (Current)
|
|
||||||
l_json_array.forth
|
|
||||||
if not l_json_array.after then
|
|
||||||
to_json.append (",")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
to_json.append ("]")
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
|
|
||||||
-- Visit `a_json_boolean'.
|
|
||||||
do
|
|
||||||
to_json.append (a_json_boolean.item.out)
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_null (a_json_null: JSON_NULL)
|
|
||||||
-- Visit `a_json_null'.
|
|
||||||
do
|
|
||||||
to_json.append ("null")
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_number (a_json_number: JSON_NUMBER)
|
|
||||||
-- Visit `a_json_number'.
|
|
||||||
do
|
|
||||||
to_json.append (a_json_number.item)
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_object (a_json_object: JSON_OBJECT)
|
|
||||||
-- Visit `a_json_object'.
|
|
||||||
local
|
|
||||||
l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING]
|
|
||||||
do
|
|
||||||
l_pairs := a_json_object.map_representation
|
|
||||||
to_json.append ("{")
|
|
||||||
from
|
|
||||||
l_pairs.start
|
|
||||||
until
|
|
||||||
l_pairs.off
|
|
||||||
loop
|
|
||||||
l_pairs.key_for_iteration.accept (Current)
|
|
||||||
to_json.append (":")
|
|
||||||
l_pairs.item_for_iteration.accept (Current)
|
|
||||||
l_pairs.forth
|
|
||||||
if not l_pairs.after then
|
|
||||||
to_json.append (",")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
to_json.append ("}")
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_string (a_json_string: JSON_STRING)
|
|
||||||
-- Visit `a_json_string'.
|
|
||||||
do
|
|
||||||
to_json.append ("%"")
|
|
||||||
to_json.append (a_json_string.item)
|
|
||||||
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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
note
|
|
||||||
description: "test_suite application root class"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
APPLICATION
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
ARGUMENTS
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
-- Run application.
|
|
||||||
do
|
|
||||||
--| Add your code here
|
|
||||||
print ("Hello Eiffel World!%N")
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
class
|
|
||||||
AUTHOR
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
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
|
|
||||||
-- Author name
|
|
||||||
|
|
||||||
feature -- Change
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
class
|
|
||||||
BOOK
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
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
|
|
||||||
-- Main title.
|
|
||||||
|
|
||||||
isbn: STRING_32
|
|
||||||
-- ISBN.
|
|
||||||
|
|
||||||
author: AUTHOR
|
|
||||||
-- Author.
|
|
||||||
|
|
||||||
feature -- Change
|
|
||||||
|
|
||||||
set_title (a_title: STRING_32)
|
|
||||||
-- Set `title' with `a_title'.
|
|
||||||
do
|
|
||||||
title := a_title
|
|
||||||
ensure
|
|
||||||
title_set: title = a_title
|
|
||||||
end
|
|
||||||
|
|
||||||
set_author (a_author: AUTHOR)
|
|
||||||
-- Set `author' with `a_author'.
|
|
||||||
do
|
|
||||||
author := a_author
|
|
||||||
ensure
|
|
||||||
author_set: author = a_author
|
|
||||||
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
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
class
|
|
||||||
BOOK_COLLECTION
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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 (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 -- Change
|
|
||||||
|
|
||||||
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)
|
|
||||||
-- 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
|
|
||||||
|
|
||||||
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]
|
|
||||||
-- Association of author name and its books.
|
|
||||||
|
|
||||||
end -- class BOOK_COLLECTION
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
"A JSON payload should be an object or array, not a string."
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Extra value after close": true} "misplaced quoted value"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Illegal expression": 1 + 2}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Illegal invocation": alert()}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Numbers cannot have leading zeroes": 013}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Numbers cannot be hex": 0x14}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["Illegal backslash escape: \x15"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[\naked]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["Illegal backslash escape: \017"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Missing colon" null}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["Unclosed array"
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Double colon":: null}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Comma instead of colon", null}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["Colon instead of comma": false]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["Bad value", truth]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
['single quote']
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[" tab character in string "]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["tab\ character\ in\ string\ "]
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
["line
|
|
||||||
break"]
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
["line\
|
|
||||||
break"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[0e]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{unquoted_key: "keys must be quoted"}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[0e+]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[0e+-1]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Comma instead if closing brace": true,
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["mismatch"}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["extra comma",]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["double extra comma",,]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[ , "<-- missing value"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["Comma after the close"],
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
["Extra close"]]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"Extra comma": true,}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for AUTHOR"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_AUTHOR_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_CONVERTER
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
local
|
|
||||||
ucs: STRING_32
|
|
||||||
do
|
|
||||||
create ucs.make_from_string ("")
|
|
||||||
create object.make (ucs)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: AUTHOR
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
name_key: JSON_STRING
|
|
||||||
-- Author's name label.
|
|
||||||
once
|
|
||||||
create Result.make_from_string ("name")
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class JSON_AUTHOR_CONVERTER
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for BOOK_COLLECTION"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_BOOK_COLLECTION_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_CONVERTER
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
local
|
|
||||||
ucs: STRING_32
|
|
||||||
do
|
|
||||||
create ucs.make_from_string ("")
|
|
||||||
create object.make (ucs)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: BOOK_COLLECTION
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
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_with_capacity (2)
|
|
||||||
Result.put (json.value (o.name), name_key)
|
|
||||||
Result.put (json.value (o.books), books_key)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
name_key: JSON_STRING
|
|
||||||
-- Collection's name label.
|
|
||||||
once
|
|
||||||
create Result.make_from_string ("name")
|
|
||||||
end
|
|
||||||
|
|
||||||
books_key: JSON_STRING
|
|
||||||
-- Book list label.
|
|
||||||
once
|
|
||||||
create Result.make_from_string ("books")
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class JSON_BOOK_COLLECTION_CONVERTER
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for BOOK"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_BOOK_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
JSON_CONVERTER
|
|
||||||
|
|
||||||
create
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: BOOK
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
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_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
|
|
||||||
|
|
||||||
title_key: JSON_STRING
|
|
||||||
-- Book's title label.
|
|
||||||
once
|
|
||||||
create Result.make_from_string ("title")
|
|
||||||
end
|
|
||||||
|
|
||||||
isbn_key: JSON_STRING
|
|
||||||
-- Book ISBN label.
|
|
||||||
once
|
|
||||||
create Result.make_from_string ("isbn")
|
|
||||||
end
|
|
||||||
|
|
||||||
author_key: JSON_STRING
|
|
||||||
-- Author label.
|
|
||||||
once
|
|
||||||
create Result.make_from_string ("author")
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class JSON_BOOK_CONVERTER
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{ "menu": {
|
|
||||||
"id": "file",
|
|
||||||
"value": "File",
|
|
||||||
"popup": {
|
|
||||||
"menuitem": [
|
|
||||||
{"value": "New", "onclick": "CreateNewDoc()"},
|
|
||||||
{"value": "Open", "onclick": "OpenDoc()"},
|
|
||||||
{"value": "Close", "onclick": "CloseDoc()"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
[
|
|
||||||
"JSON Test Pattern pass1",
|
|
||||||
{"object with 1 member":["array with 1 element"]},
|
|
||||||
{},
|
|
||||||
[],
|
|
||||||
-42,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
{
|
|
||||||
"integer": 1234567890,
|
|
||||||
"real": -9876.543210,
|
|
||||||
"e": 0.123456789e-12,
|
|
||||||
"E": 1.234567890E+34,
|
|
||||||
"": 23456789012E66,
|
|
||||||
"zero": 0,
|
|
||||||
"one": 1,
|
|
||||||
"space": " ",
|
|
||||||
"quote": "\"",
|
|
||||||
"backslash": "\\",
|
|
||||||
"controls": "\b\f\n\r\t",
|
|
||||||
"slash": "/ & \/",
|
|
||||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
|
||||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
|
||||||
"digit": "0123456789",
|
|
||||||
"0123456789": "digit",
|
|
||||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
|
||||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
|
||||||
"true": true,
|
|
||||||
"false": false,
|
|
||||||
"null": null,
|
|
||||||
"array":[ ],
|
|
||||||
"object":{ },
|
|
||||||
"address": "50 St. James Street",
|
|
||||||
"url": "http://www.JSON.org/",
|
|
||||||
"comment": "// /* <!-- --",
|
|
||||||
"# -- --> */": " ",
|
|
||||||
" s p a c e d " :[1,2 , 3
|
|
||||||
|
|
||||||
,
|
|
||||||
|
|
||||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
|
||||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
|
||||||
"quotes": "" \u0022 %22 0x22 034 "",
|
|
||||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
|
||||||
: "A key can be any string"
|
|
||||||
},
|
|
||||||
0.5 ,98.6
|
|
||||||
,
|
|
||||||
99.44
|
|
||||||
,
|
|
||||||
|
|
||||||
1066,
|
|
||||||
1e1,
|
|
||||||
0.1e1,
|
|
||||||
1e-1,
|
|
||||||
1e00,2e+00,2e-00
|
|
||||||
,"rosebud"]
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"JSON Test Pattern pass3": {
|
|
||||||
"The outermost value": "must be an object or array.",
|
|
||||||
"In this test": "It is an object."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
note
|
|
||||||
description: "Linked list and hash table converters test."
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
TEST_DS
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
SHARED_EJSON
|
|
||||||
undefine
|
|
||||||
default_create
|
|
||||||
end
|
|
||||||
|
|
||||||
EQA_TEST_SET
|
|
||||||
|
|
||||||
feature -- Test
|
|
||||||
|
|
||||||
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
|
|
||||||
-- 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
|
|
||||||
@@ -1,888 +0,0 @@
|
|||||||
class
|
|
||||||
TEST_JSON_CORE
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
SHARED_EJSON
|
|
||||||
undefine
|
|
||||||
default_create
|
|
||||||
end
|
|
||||||
|
|
||||||
EQA_TEST_SET
|
|
||||||
|
|
||||||
JSON_PARSER_ACCESS
|
|
||||||
undefine
|
|
||||||
default_create
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Test
|
|
||||||
|
|
||||||
test_json_number_and_integer
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
i := 42
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_integer (i)
|
|
||||||
assert ("jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (i) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
|
|
||||||
else
|
|
||||||
assert ("json.value (i) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation-> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_8 since the value is 42
|
|
||||||
jrep := "42"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
|
|
||||||
assert ("l_i8 = 42", l_i8 = 42)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a INTEGER_8", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_integer_8
|
|
||||||
local
|
|
||||||
i8: INTEGER_8
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
i8 := 42
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_integer (i8)
|
|
||||||
assert ("jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (i8) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
|
|
||||||
else
|
|
||||||
assert ("json.value (i8) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_8 since the value is 42
|
|
||||||
jrep := "42"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
|
|
||||||
assert ("l_i8 = 42", l_i8 = 42)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a INTEGER_8", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_integer_16
|
|
||||||
local
|
|
||||||
i16: INTEGER_16
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
i16 := 300
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_integer (i16)
|
|
||||||
assert ("jn.representation.same_string (%"300%")", jn.representation.same_string ("300"))
|
|
||||||
-- Eiffel value -> JSON with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (i16) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"300%")", l_jn.representation.same_string ("300"))
|
|
||||||
else
|
|
||||||
assert ("json.value (i16) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_16 since the value is 300
|
|
||||||
jrep := "300"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_16} json.object (jn, Void) as l_i16 then
|
|
||||||
assert ("l_i16 = 300", l_i16 = 300)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a INTEGER_16", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_integer_32
|
|
||||||
local
|
|
||||||
i32: INTEGER_32
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
i32 := 100000
|
|
||||||
-- Eiffel value -> JSON representation -> JSON value
|
|
||||||
create jn.make_integer (i32)
|
|
||||||
assert ("jn.representation.same_string (%"100000%")", jn.representation.same_string ("100000"))
|
|
||||||
-- Eiffel value -> JSON representation -> JSON value with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (i32) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"100000%")", l_jn.representation.same_string ("100000"))
|
|
||||||
else
|
|
||||||
assert ("json.value (i32) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_32 since the value is 100000
|
|
||||||
jrep := "100000"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_32} json.object (jn, Void) as l_i32 then
|
|
||||||
assert ("l_i32 = 100000", l_i32 = 100000)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a INTEGER_32", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_integer_64
|
|
||||||
local
|
|
||||||
i64: INTEGER_64
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
i64 := 42949672960
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_integer (i64)
|
|
||||||
assert ("jn.representation.same_string (%"42949672960%")", jn.representation.same_string ("42949672960"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (i64) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"42949672960%")", l_jn.representation.same_string ("42949672960"))
|
|
||||||
else
|
|
||||||
assert ("json.value (i64) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_32 since the value is 42949672960
|
|
||||||
jrep := "42949672960"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_64} json.object (jn, Void) as l_i64 then
|
|
||||||
assert ("l_i64 = 42949672960", l_i64 = 42949672960)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a INTEGER_64", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_natural_8
|
|
||||||
local
|
|
||||||
n8: NATURAL_8
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
n8 := 200
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_natural (n8)
|
|
||||||
assert ("jn.representation.same_string (%"200%")", jn.representation.same_string ("200"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (n8) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"200%")", l_jn.representation.same_string ("200"))
|
|
||||||
else
|
|
||||||
assert ("json.value (n8) is a JSON_NUMBER}", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_16 since the value is 200
|
|
||||||
jrep := "200"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_16} json.object (jn, Void) as i16 then
|
|
||||||
assert ("i16 = 200", i16 = 200)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is an INTEGER_16", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_natural_16
|
|
||||||
local
|
|
||||||
n16: NATURAL_16
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
n16 := 32768
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_natural (n16)
|
|
||||||
assert ("jn.representation.same_string (%"32768%")", jn.representation.same_string ("32768"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (n16) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"32768%")", l_jn.representation.same_string ("32768"))
|
|
||||||
else
|
|
||||||
assert ("json.value (n16) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_32 since the value is 32768
|
|
||||||
jrep := "32768"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_32} json.object (jn, Void) as i32 then
|
|
||||||
assert ("i32 = 32768", i32 = 32768)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a INTEGER_32", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_natural_32
|
|
||||||
local
|
|
||||||
n32: NATURAL_32
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
n32 := 2147483648
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_natural (n32)
|
|
||||||
assert ("jn.representation.same_string (%"2147483648%")", jn.representation.same_string ("2147483648"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached json.value (n32) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"2147483648%")", l_jn.representation.same_string ("2147483648"))
|
|
||||||
else
|
|
||||||
assert ("json.value (n32) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_64 since the value is 2147483648
|
|
||||||
jrep := "2147483648"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {INTEGER_64} json.object (jn, Void) as i64 then
|
|
||||||
assert ("i64 = 2147483648", i64 = 2147483648)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a INTEGER_64", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_large_integers
|
|
||||||
local
|
|
||||||
jrep: STRING
|
|
||||||
n64: NATURAL_64
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
n64 := 9223372036854775808
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_natural (n64)
|
|
||||||
assert ("jn.representation.same_string (%"9223372036854775808%")", jn.representation.same_string ("9223372036854775808"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (n64) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"9223372036854775808%")", l_jn.representation.same_string ("9223372036854775808"))
|
|
||||||
else
|
|
||||||
assert ("json.value (n64) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- we know it is INTEGER_32 since the value is 42949672960
|
|
||||||
jrep := "9223372036854775808" -- 1 higher than largest positive number that can be represented by INTEGER 64
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {NATURAL_64} json.object (jn, Void) as l_n64 then
|
|
||||||
assert ("l_n64 = 9223372036854775808", l_n64 = 9223372036854775808)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a NATURAL_64", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_eiffel_real
|
|
||||||
local
|
|
||||||
r: REAL
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
r := 3.14
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_real (r)
|
|
||||||
assert ("jn.representation.same_string (%"3.1400001049041748%")", jn.representation.same_string ("3.1400001049041748"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (r) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"3.1400001049041748%")", l_jn.representation.same_string ("3.1400001049041748"))
|
|
||||||
else
|
|
||||||
assert ("json.value (r) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will always return a REAL_64 if the value
|
|
||||||
-- of the JSON number is a floating point number
|
|
||||||
jrep := "3.14"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {REAL_64} json.object (jn, Void) as r64 then
|
|
||||||
assert ("3.14 <= r64 and r64 <= 3.141", 3.14 <= r64 and r64 <= 3.141)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a REAL_64", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_eiffel_real_32
|
|
||||||
local
|
|
||||||
r32: REAL_32
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
r32 := 3.14
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_real (r32)
|
|
||||||
assert ("jn.representation.same_string (%"3.1400001049041748%")", jn.representation.same_string ("3.1400001049041748"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (r32) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"3.1400001049041748%")", l_jn.representation.same_string ("3.1400001049041748"))
|
|
||||||
else
|
|
||||||
assert ("json.value (r32) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
jrep := "3.1400001049041748"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {REAL_64} json.object (l_jn, Void) as r64 then
|
|
||||||
assert ("r64 = 3.1400001049041748", r64 = 3.1400001049041748)
|
|
||||||
else
|
|
||||||
assert ("json.object (l_jn, Void) is a REAL_64", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_number_and_eiffel_real_64
|
|
||||||
local
|
|
||||||
r64: REAL_64
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
r64 := 3.1415926535897931
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn.make_real (r64)
|
|
||||||
assert ("jn.representation.same_string (%"3.1415926535897931%")", jn.representation.same_string ("3.1415926535897931"))
|
|
||||||
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NUMBER} json.value (r64) as l_jn then
|
|
||||||
assert ("l_jn.representation.same_string (%"3.1415926535897931%")", l_jn.representation.same_string ("3.1415926535897931"))
|
|
||||||
else
|
|
||||||
assert ("json.value (r64) is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
jrep := "3.1415926535897931"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
|
|
||||||
if attached {REAL_64} json.object (jn, Void) as l_r64 then
|
|
||||||
assert ("l_r64 = 3.1415926535897931", l_r64 = 3.1415926535897931)
|
|
||||||
else
|
|
||||||
assert ("json.object (jn, Void) is a REAL_64", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_boolean
|
|
||||||
local
|
|
||||||
parser: JSON_PARSER
|
|
||||||
jb: JSON_BOOLEAN
|
|
||||||
b: BOOLEAN
|
|
||||||
do
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
b := True
|
|
||||||
create jb.make (b)
|
|
||||||
assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_BOOLEAN} json.value (b) as l_jb then
|
|
||||||
assert ("l_jb.representation.same_string (%"true%")", l_jb.representation.same_string ("true"))
|
|
||||||
else
|
|
||||||
assert ("l_jb /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
create parser.make_with_string ("true")
|
|
||||||
if attached {JSON_BOOLEAN} parser.next_parsed_json_value as l_jb then
|
|
||||||
if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
|
|
||||||
assert ("l_b = True", l_b = True)
|
|
||||||
else
|
|
||||||
assert ("json.object (l_jb, Void) is BOOLEAN", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_BOOLEAN", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
b := False
|
|
||||||
create jb.make (b)
|
|
||||||
assert ("jb.representation.same_string (%"false%")", jb.representation.same_string ("false"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_BOOLEAN} json.value (b) as l_jb then
|
|
||||||
assert ("l_jb.representation.same_string (%"false%")", l_jb.representation.same_string ("false"))
|
|
||||||
else
|
|
||||||
assert ("json.value (b) is a JSON_BOOLEAN", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
create parser.make_with_string ("false")
|
|
||||||
if attached {JSON_BOOLEAN} parser.next_parsed_json_value as l_jb then
|
|
||||||
if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
|
|
||||||
assert ("l_b = False", l_b = False)
|
|
||||||
else
|
|
||||||
assert ("json.object (l_jb, Void) is a BOOLEAN", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value is a JSON_BOOLEAN", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_null
|
|
||||||
local
|
|
||||||
jrep: STRING
|
|
||||||
jn: JSON_NULL
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create jn
|
|
||||||
jrep := "null"
|
|
||||||
assert ("jn.representation.is_equal (%"%"null%"%")", jn.representation.is_equal (jrep))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_NULL} json.value (Void) as l_json_null then
|
|
||||||
assert ("jn.representation.is_equal (%"null%")", l_json_null.representation.is_equal ("null"))
|
|
||||||
else
|
|
||||||
assert ("json.value (Void) /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached parser.next_parsed_json_value as l_json_null then
|
|
||||||
assert ("a = Void", json.object (l_json_null, Void) = Void)
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_string_and_character
|
|
||||||
local
|
|
||||||
c: CHARACTER
|
|
||||||
jrep: STRING
|
|
||||||
js: JSON_STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
c := 'a'
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create js.make_from_string (c.out)
|
|
||||||
assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%""))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_STRING} json.value (c) as l_json_str then
|
|
||||||
assert ("js.representation.is_equal (%"%"a%"%")", l_json_str.representation.is_equal ("%"a%""))
|
|
||||||
else
|
|
||||||
assert ("json.value (c) /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
jrep := "%"a%""
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_STRING} parser.next_parsed_json_value as l_json_str then
|
|
||||||
if attached {STRING_32} json.object (l_json_str, Void) as ucs then
|
|
||||||
assert ("ucs.string.is_equal (%"a%")", ucs.string.is_equal ("a"))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_string_and_string
|
|
||||||
local
|
|
||||||
s: STRING
|
|
||||||
js: detachable JSON_STRING
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
s := "foobar"
|
|
||||||
jrep := "%"foobar%""
|
|
||||||
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create js.make_from_string (s)
|
|
||||||
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_STRING} json.value (s) as l_js then
|
|
||||||
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
|
|
||||||
else
|
|
||||||
assert ("json.value (s) /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
|
|
||||||
if attached {STRING_32} json.object (l_js, Void) as l_ucs then
|
|
||||||
assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_string_and_uc_string
|
|
||||||
local
|
|
||||||
js: detachable JSON_STRING
|
|
||||||
ucs: detachable STRING_32
|
|
||||||
jrep, s: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
s := "foobar"
|
|
||||||
jrep := "%"foobar%""
|
|
||||||
create ucs.make_from_string (s)
|
|
||||||
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create js.make_from_string (ucs)
|
|
||||||
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
|
|
||||||
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_STRING} json.value (ucs) as l_js then
|
|
||||||
assert ("js.representation.is_equal (%"%"foobar%"%")", l_js.representation.is_equal (jrep))
|
|
||||||
else
|
|
||||||
assert ("json.value (ucs) /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
|
|
||||||
if attached {STRING_32} json.object (l_js, Void) as l_ucs then
|
|
||||||
assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s))
|
|
||||||
else
|
|
||||||
assert ("json.object (js, Void) /= Void", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_string_and_special_characters
|
|
||||||
local
|
|
||||||
js: detachable JSON_STRING
|
|
||||||
s: detachable STRING_8
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
jrep := "%"foo\\bar%""
|
|
||||||
create s.make_from_string ("foo\bar")
|
|
||||||
create js.make_from_string (s)
|
|
||||||
assert ("js.representation.same_string (%"%"foo\\bar%"%")", js.representation.same_string (jrep))
|
|
||||||
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_STRING} json.value (s) as l_js then
|
|
||||||
assert ("js.representation.is_equal (%"%"foobar%"%")", l_js.representation.same_string (jrep))
|
|
||||||
else
|
|
||||||
assert ("json.value (s) /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
|
|
||||||
if attached {STRING_32} json.object (l_js, Void) as l_ucs then
|
|
||||||
assert ("ucs.same_string (%"foo\bar%")", l_ucs.same_string ("foo\bar"))
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
jrep := "%"foo\\bar%""
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_STRING} parser.next_parsed_json_value as jstring then
|
|
||||||
assert ("unescaped string %"foo\\bar%" to %"foo\bar%"", jstring.unescaped_string_8.same_string ("foo\bar"))
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
create js.make_from_string_32 ({STRING_32} "你好")
|
|
||||||
assert ("escaping unicode string32 %"%%/20320/%%/22909/%" %"\u4F60\u597D%"", js.item.same_string ("\u4F60\u597D"))
|
|
||||||
jrep := "%"\u4F60\u597D%"" --| Ni hao
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_STRING} parser.next_parsed_json_value as jstring then
|
|
||||||
assert ("same unicode string32 %"%%/20320/%%/22909/%"", jstring.unescaped_string_32.same_string ({STRING_32} "你好"))
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_string_and_special_characters_2
|
|
||||||
local
|
|
||||||
js: detachable JSON_STRING
|
|
||||||
s,j: STRING
|
|
||||||
do
|
|
||||||
s := "foo%Tbar"
|
|
||||||
j := "foo\tbar"
|
|
||||||
create js.make_from_string (s)
|
|
||||||
assert ("string %"" + s + "%" to json %"" + j + "%"", js.item.same_string (j))
|
|
||||||
create js.make_from_escaped_json_string (js.item)
|
|
||||||
assert ("json %"" + j + "%" to string %"" + s + "%"", js.unescaped_string_8.same_string (s))
|
|
||||||
|
|
||||||
s := "tab=%T cr=%R newline=%N backslash=%H slash=/ end"
|
|
||||||
j := "tab=\t cr=\r newline=\n backslash=\\ slash=/ end"
|
|
||||||
create js.make_from_string (s)
|
|
||||||
assert ("string %"" + s + "%" to json %"" + j + "%"", js.item.same_string (j))
|
|
||||||
create js.make_from_escaped_json_string (js.item)
|
|
||||||
assert ("json %"" + j + "%" to string %"" + s + "%"", js.unescaped_string_8.same_string (s))
|
|
||||||
|
|
||||||
s := "<script>tab=%T cr=%R newline=%N backslash=%H slash=/ end</script>"
|
|
||||||
j := "<script>tab=\t cr=\r newline=\n backslash=\\ slash=/ end<\/script>"
|
|
||||||
create js.make_from_string (s)
|
|
||||||
assert ("string %"" + s + "%" to json %"" + j + "%"", js.item.same_string (j))
|
|
||||||
create js.make_from_escaped_json_string (js.item)
|
|
||||||
assert ("json %"" + j + "%" to string %"" + s + "%"", js.unescaped_string_8.same_string (s))
|
|
||||||
|
|
||||||
create js.make_from_escaped_json_string ("tab=\t")
|
|
||||||
assert ("js.item.same_string (%"tab=\t%")", js.item.same_string ("tab=\t"))
|
|
||||||
create js.make_from_escaped_json_string (js.item)
|
|
||||||
assert ("js.item.same_string (%"tab=\t%")", js.item.same_string ("tab=\t"))
|
|
||||||
|
|
||||||
|
|
||||||
-- <\/script>
|
|
||||||
create js.make_from_escaped_json_string ("<script>tab=\t<\/script>")
|
|
||||||
assert ("js.item.same_string (%"<script>tab=\t<\/script>%")", js.item.same_string ("<script>tab=\t<\/script>"))
|
|
||||||
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
|
|
||||||
|
|
||||||
create js.make_from_escaped_json_string (js.item)
|
|
||||||
assert ("js.item.same_string (%"<script>tab=\t<\/script>%")", js.item.same_string ("<script>tab=\t<\/script>"))
|
|
||||||
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
|
|
||||||
|
|
||||||
-- </script>
|
|
||||||
create js.make_from_escaped_json_string ("<script>tab=\t</script>")
|
|
||||||
assert ("js.item.same_string (%"<script>tab=\t</script>%")", js.item.same_string ("<script>tab=\t</script>"))
|
|
||||||
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
|
|
||||||
|
|
||||||
create js.make_from_escaped_json_string (js.item)
|
|
||||||
assert ("js.item.same_string (%"<script>tab=\t<\/script>%")", js.item.same_string ("<script>tab=\t</script>"))
|
|
||||||
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_array
|
|
||||||
local
|
|
||||||
ll: LINKED_LIST [INTEGER_8]
|
|
||||||
ja: detachable JSON_ARRAY
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
create ll.make
|
|
||||||
ll.extend (0)
|
|
||||||
ll.extend (1)
|
|
||||||
ll.extend (1)
|
|
||||||
ll.extend (2)
|
|
||||||
ll.extend (3)
|
|
||||||
ll.extend (5)
|
|
||||||
-- Note: Currently there is no simple way of creating a JSON_ARRAY
|
|
||||||
-- from an LINKED_LIST.
|
|
||||||
create ja.make (ll.count)
|
|
||||||
from
|
|
||||||
ll.start
|
|
||||||
until
|
|
||||||
ll.after
|
|
||||||
loop
|
|
||||||
create jn.make_integer (ll.item)
|
|
||||||
ja.add (jn)
|
|
||||||
ll.forth
|
|
||||||
end
|
|
||||||
assert ("ja /= Void", ja /= Void)
|
|
||||||
assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]"))
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
if attached {JSON_ARRAY} json.value (ll) as l_ja then
|
|
||||||
assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", l_ja.representation.is_equal ("[0,1,1,2,3,5]"))
|
|
||||||
else
|
|
||||||
assert ("json.value (ll) /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value
|
|
||||||
-- Note: The JSON_FACTORY will return the smallest INTEGER_* object
|
|
||||||
-- that can represent the value of the JSON number, in this case
|
|
||||||
-- it means we will get an LINKED_LIST [ANY] containing the INTEGER_8
|
|
||||||
-- values 0, 1, 1, 2, 3, 5
|
|
||||||
jrep := "[0,1,1,2,3,5]"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_ARRAY} parser.next_parsed_json_value as l_ja then
|
|
||||||
if attached {LINKED_LIST [detachable ANY]} json.object (ja, Void) as l_ll2 then
|
|
||||||
assert ("ll2.is_equal (ll)", l_ll2.is_equal (ll))
|
|
||||||
else
|
|
||||||
assert ("json.object (ja, Void) /= Void", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_object
|
|
||||||
local
|
|
||||||
t: detachable HASH_TABLE [detachable ANY, STRING_GENERAL]
|
|
||||||
i: INTEGER
|
|
||||||
ucs_key, ucs: STRING_32
|
|
||||||
a: ARRAY [INTEGER]
|
|
||||||
jo: detachable JSON_OBJECT
|
|
||||||
jn: JSON_NUMBER
|
|
||||||
js_key, js: JSON_STRING
|
|
||||||
ja: JSON_ARRAY
|
|
||||||
jrep: STRING
|
|
||||||
parser: JSON_PARSER
|
|
||||||
do
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation
|
|
||||||
-- Note: Currently there is now way of creating a JSON_OBJECT from
|
|
||||||
-- a HASH_TABLE, so we do it manually.
|
|
||||||
-- t = {"name": "foobar", "size": 42, "contents", [0, 1, 1, 2, 3, 5]}
|
|
||||||
create jo.make
|
|
||||||
create js_key.make_from_string ("name")
|
|
||||||
create js.make_from_string ("foobar")
|
|
||||||
jo.put (js, js_key)
|
|
||||||
create js_key.make_from_string ("size")
|
|
||||||
create jn.make_integer (42)
|
|
||||||
jo.put (jn, js_key)
|
|
||||||
create js_key.make_from_string ("contents")
|
|
||||||
create ja.make (6)
|
|
||||||
create jn.make_integer (0)
|
|
||||||
ja.add (jn)
|
|
||||||
create jn.make_integer (1)
|
|
||||||
ja.add (jn)
|
|
||||||
create jn.make_integer (1)
|
|
||||||
ja.add (jn)
|
|
||||||
create jn.make_integer (2)
|
|
||||||
ja.add (jn)
|
|
||||||
create jn.make_integer (3)
|
|
||||||
ja.add (jn)
|
|
||||||
create jn.make_integer (5)
|
|
||||||
ja.add (jn)
|
|
||||||
jo.put (ja, js_key)
|
|
||||||
assert ("jo /= Void", jo /= Void)
|
|
||||||
assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
|
|
||||||
|
|
||||||
-- Eiffel value -> JSON value -> JSON representation with factory
|
|
||||||
create t.make (3)
|
|
||||||
create ucs_key.make_from_string ("name")
|
|
||||||
create ucs.make_from_string ("foobar")
|
|
||||||
t.put (ucs, ucs_key)
|
|
||||||
create ucs_key.make_from_string ("size")
|
|
||||||
i := 42
|
|
||||||
t.put (i, ucs_key)
|
|
||||||
create ucs_key.make_from_string ("contents")
|
|
||||||
a := <<0, 1, 1, 2, 3, 5>>
|
|
||||||
t.put (a, ucs_key)
|
|
||||||
if attached {JSON_OBJECT} json.value (t) as l_jo then
|
|
||||||
assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", l_jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
|
|
||||||
else
|
|
||||||
assert ("json.value (t) /= Void", False)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation
|
|
||||||
jrep := "{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"
|
|
||||||
create parser.make_with_string (jrep)
|
|
||||||
if attached {JSON_OBJECT} parser.next_parsed_json_value as l_jo then
|
|
||||||
if attached {HASH_TABLE [detachable ANY, STRING_GENERAL]} json.object (l_jo, Void) as l_t2 then
|
|
||||||
if attached json.value (l_t2) as l_jo_2 then
|
|
||||||
assert ("jrep.is_equal (jo.representation)", jrep.is_equal (l_jo_2.representation))
|
|
||||||
else
|
|
||||||
assert ("json.value (t2) /= Void", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("json.object (jo, Void) /= Void", False)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
assert ("parser.next_parsed_json_value /= Void", jo /= Void)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_object_hash_code
|
|
||||||
local
|
|
||||||
ht: HASH_TABLE [ANY, JSON_VALUE]
|
|
||||||
jo: JSON_OBJECT
|
|
||||||
do
|
|
||||||
create ht.make (1)
|
|
||||||
create jo.make
|
|
||||||
ht.force ("", jo)
|
|
||||||
assert ("ht.has_key (jo)", ht.has_key (jo))
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_failed_json_conversion
|
|
||||||
-- Test converting an Eiffel object to JSON that is based on a class
|
|
||||||
-- for which no JSON converter has been registered.
|
|
||||||
local
|
|
||||||
gv: OPERATING_ENVIRONMENT
|
|
||||||
jv: detachable JSON_VALUE
|
|
||||||
exception: BOOLEAN
|
|
||||||
do
|
|
||||||
if not exception then
|
|
||||||
create gv
|
|
||||||
jv := json.value (gv)
|
|
||||||
else
|
|
||||||
assert ("exceptions.is_developer_exception", json.is_developer_exception)
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
exception := True
|
|
||||||
retry
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_failed_eiffel_conversion
|
|
||||||
-- Test converting from a JSON value to an Eiffel object based on a
|
|
||||||
-- class for which no JSON converter has been registered.
|
|
||||||
local
|
|
||||||
gv: detachable ANY
|
|
||||||
jo: JSON_OBJECT
|
|
||||||
exception: BOOLEAN
|
|
||||||
do
|
|
||||||
if not exception then
|
|
||||||
create jo.make
|
|
||||||
gv := json.object (jo, "OPERATING_ENVIRONMENT")
|
|
||||||
else
|
|
||||||
assert ("exceptions.is_developer_exception", json.is_developer_exception)
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
exception := True
|
|
||||||
retry
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class TEST_JSON_CORE
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
note
|
|
||||||
description: "Parsing and converter of book collection test."
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
TEST_JSON_CUSTOM_CLASSES
|
|
||||||
|
|
||||||
inherit
|
|
||||||
|
|
||||||
SHARED_EJSON
|
|
||||||
undefine
|
|
||||||
default_create
|
|
||||||
end
|
|
||||||
|
|
||||||
EQA_TEST_SET
|
|
||||||
|
|
||||||
feature -- Test
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,535 +0,0 @@
|
|||||||
note
|
|
||||||
description: "[
|
|
||||||
Eiffel tests that can be executed by testing tool.
|
|
||||||
]"
|
|
||||||
author: "EiffelStudio test wizard"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
testing: "type/manual"
|
|
||||||
|
|
||||||
class
|
|
||||||
TEST_JSON_SUITE
|
|
||||||
|
|
||||||
inherit
|
|
||||||
EQA_TEST_SET
|
|
||||||
redefine
|
|
||||||
on_prepare
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Events
|
|
||||||
|
|
||||||
on_prepare
|
|
||||||
-- <Precursor>
|
|
||||||
do
|
|
||||||
create file_reader
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Tests Pass
|
|
||||||
|
|
||||||
test_json_pass1
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("pass1.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("pass1.json", parse_json.is_valid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_pass2
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("pass2.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("pass2.json",parse_json.is_valid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_pass3
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("pass3.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("pass3.json",parse_json.is_valid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_utf_8_pass1
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
utf: UTF_CONVERTER
|
|
||||||
s: READABLE_STRING_32
|
|
||||||
do
|
|
||||||
s := {STRING_32} "{ %"nihaoma%": %"ä½ å¥½å—\t?%" }"
|
|
||||||
parse_json := new_json_parser (utf.string_32_to_utf_8_string_8 (s))
|
|
||||||
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
|
|
||||||
|
|
||||||
feature -- Tests Failures
|
|
||||||
test_json_fail1
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail1.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail1.json", parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail2
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail2.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail2.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail3
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail3.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail3.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail4
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail4.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail4.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail5
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail5.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail5.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail6
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail6.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail6.json",parse_json.is_valid = False )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail7
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail7.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail7.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail8
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail8.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail8.json",parse_json.is_valid = False )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail9
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail9.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail9.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail10
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail10.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail10.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail11
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail11.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail11.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail12
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail12.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail12.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail13
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail13.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail13.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail14
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail14.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail14.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail15
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail15.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail15.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail16
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail16.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail16.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail17
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail17.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail17.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail18
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail18.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail18.json",parse_json.is_valid = True)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail19
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail19.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail19.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail20
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail20.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail20.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail21
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail21.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail21.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail22
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail22.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail22.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail23
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail23.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail23.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail24
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail24.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail24.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail25
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail25.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail25.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail26
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail26.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail26.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail27
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail27.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail27.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail28
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail28.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail28.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail29
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail29.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail29.json",parse_json.is_valid = False )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
test_json_fail30
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail30.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail30.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail31
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail31.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail31.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail32
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail32.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail32.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test_json_fail33
|
|
||||||
--
|
|
||||||
local
|
|
||||||
parse_json: like new_json_parser
|
|
||||||
do
|
|
||||||
if attached json_file_from ("fail33.json") as json_file then
|
|
||||||
parse_json := new_json_parser (json_file)
|
|
||||||
parse_json.parse_content
|
|
||||||
assert ("fail33.json",parse_json.is_valid = False)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- JSON_FROM_FILE
|
|
||||||
|
|
||||||
file_reader: JSON_FILE_READER
|
|
||||||
|
|
||||||
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_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
|
|
||||||
from
|
|
||||||
i := 5
|
|
||||||
until
|
|
||||||
i = 0
|
|
||||||
loop
|
|
||||||
test_dir := test_dir.extended ("..")
|
|
||||||
i := i - 1
|
|
||||||
end
|
|
||||||
l_path := test_dir.extended (fn)
|
|
||||||
end
|
|
||||||
create f.make_with_path (l_path)
|
|
||||||
if f.exists then
|
|
||||||
Result := file_reader.read_json_from (l_path.name)
|
|
||||||
end
|
|
||||||
assert ("File contains json data", Result /= Void)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
new_json_parser (a_string: STRING): JSON_PARSER
|
|
||||||
do
|
|
||||||
create Result.make_with_string (a_string)
|
|
||||||
end
|
|
||||||
|
|
||||||
invariant
|
|
||||||
file_reader /= Void
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?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="test_suite" uuid="EA141B17-6A21-4781-8B5F-E9939BAE968A">
|
|
||||||
<target name="test_suite">
|
|
||||||
<root cluster="test_suite" class="APPLICATION" feature="make"/>
|
|
||||||
<file_rule>
|
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/CVS$</exclude>
|
|
||||||
<exclude>/.svn$</exclude>
|
|
||||||
</file_rule>
|
|
||||||
<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" readonly="false"/>
|
|
||||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
|
||||||
<cluster name="test_suite" location=".\" recursive="true"/>
|
|
||||||
</target>
|
|
||||||
</system>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
||||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-5-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-5-0 http://www.eiffel.com/developers/xml/configuration-1-5-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>
|
|
||||||
<exclude>/EIFGENs$</exclude>
|
|
||||||
<exclude>/CVS$</exclude>
|
|
||||||
<exclude>/.svn$</exclude>
|
|
||||||
</file_rule>
|
|
||||||
<option warning="true">
|
|
||||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
|
||||||
</option>
|
|
||||||
<precompile name="base_pre" location="$ISE_PRECOMP\base.ecf"/>
|
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
|
||||||
<library name="json" location="..\..\..\library\json.ecf"/>
|
|
||||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing.ecf"/>
|
|
||||||
<cluster name="test_suite" location=".\" recursive="true"/>
|
|
||||||
</target>
|
|
||||||
</system>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
class AUTHOR
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make (a_name: UC_STRING) is
|
|
||||||
do
|
|
||||||
set_name (a_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
name: UC_STRING
|
|
||||||
|
|
||||||
feature -- Status setting
|
|
||||||
|
|
||||||
set_name (a_name: UC_STRING) is
|
|
||||||
do
|
|
||||||
name := a_name
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class AUTHOR
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user