Compare commits
52
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0da4b7d61b | ||
|
|
5c5ba9f038 | ||
|
|
d65c8de1d2 | ||
|
|
3d93dbc66d | ||
|
|
436f2afd00 | ||
|
|
73284575d4 | ||
|
|
e9b05ffc0b | ||
|
|
012bb2f6c9 | ||
|
|
e883163fe9 | ||
|
|
e5fb3f8328 | ||
|
|
302ae8d030 | ||
|
|
694c0a193c | ||
|
|
4075b08b7e | ||
|
|
65800371cd | ||
|
|
2c6196017e | ||
|
|
5a155e0cee | ||
|
|
08bec49da4 | ||
|
|
4940ddb8f5 | ||
|
|
6599bf1a07 | ||
|
|
0ef88eadf5 | ||
|
|
e1ef4c390e | ||
|
|
11baeefe1c | ||
|
|
ac7f58722d | ||
|
|
acd395376a | ||
|
|
a7a27bee0a | ||
|
|
fc0a25acc9 | ||
|
|
0d363f065b | ||
|
|
51b70a2490 | ||
|
|
917f80c0c8 | ||
|
|
73e5fd6cd6 | ||
|
|
0abab83566 | ||
|
|
f764e63b45 | ||
|
|
0a1c4676a4 | ||
|
|
8a38519fb0 | ||
|
|
54c9addb30 | ||
|
|
30d4843a5b | ||
|
|
3e73298806 | ||
|
|
01b16d0a82 | ||
|
|
ac97d6019b | ||
|
|
4e2f0dbc72 | ||
|
|
9d1fb56cc1 | ||
|
|
bc98c5a317 | ||
|
|
681bb19ab7 | ||
|
|
026b4f8682 | ||
|
|
f74ac66569 | ||
|
|
4fb42df5fb | ||
|
|
f1d8d18811 | ||
|
|
545db51fc9 | ||
|
|
20bf9efaa0 | ||
|
|
a168cc62e7 | ||
|
|
b9e89758ce | ||
|
|
19da9436ff |
@@ -0,0 +1,2 @@
|
|||||||
|
EIFGENs
|
||||||
|
tests/temp/
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[submodule "doc/wiki"]
|
||||||
|
path = doc/wiki
|
||||||
|
url = https://github.com/Eiffel-World/Eiffel-Web-Framework.wiki.git
|
||||||
|
[submodule "ext/server/nino"]
|
||||||
|
path = ext/server/nino
|
||||||
|
url = http://github.com/Eiffel-World/EiffelWebNino.git
|
||||||
|
[submodule "ext/text/json"]
|
||||||
|
path = ext/text/json
|
||||||
|
url = http://github.com/Eiffel-World/ejson-svn.git
|
||||||
-26
@@ -1,26 +0,0 @@
|
|||||||
History file for EJSON
|
|
||||||
======================
|
|
||||||
|
|
||||||
team: ""
|
|
||||||
date: "2011-07-06"
|
|
||||||
revision: "0.3.0"
|
|
||||||
|
|
||||||
|
|
||||||
+++++++++++++++++++++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
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Eiffel Forum License, version 2
|
||||||
|
|
||||||
|
1. Permission is hereby granted to use, copy, modify and/or distribute
|
||||||
|
this package, provided that:
|
||||||
|
* copyright notices are retained unchanged,
|
||||||
|
* any distribution of this package, whether modified or not,
|
||||||
|
includes this license text.
|
||||||
|
|
||||||
|
2. Permission is hereby also granted to distribute binary programs which
|
||||||
|
depend on this package. If the binary program depends on a modified
|
||||||
|
version of this package, you are encouraged to publicly release the
|
||||||
|
modified version of this package.
|
||||||
|
|
||||||
|
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.
|
||||||
|
|
||||||
-20
@@ -1,20 +0,0 @@
|
|||||||
Copyright (c) 2010 Javier Velilla and others, http://ejson.origo.ethz.ch
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
Official project site for Eiffel Web Framework:
|
||||||
|
* https://github.com/Eiffel-World/Eiffel-Web-Framework
|
||||||
|
|
||||||
|
For more information please have a look at the related wiki:
|
||||||
|
* https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki
|
||||||
|
|
||||||
|
How to get the source code?
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
git clone https://github.com/Eiffel-World/Eiffel-Web-Framework.git
|
||||||
|
cd Eiffel-Web-Framework
|
||||||
|
git submodule update --init
|
||||||
|
git submodule foreach git pull origin master
|
||||||
|
git submodule foreach git checkout master
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
* library/server/ewsgi: Eiffel Web Server Gateway Interface
|
||||||
|
* library/server/ewsgi/connectors: various web server connectors for EWSGI
|
||||||
|
* library/server/libfcgi: Wrapper for libfcgi SDK
|
||||||
|
|
||||||
|
* library/protocol/http: HTTP related classes, constants for status code, content types, ...
|
||||||
|
* library/protocol/uri_template: URI Template library (parsing and expander)
|
||||||
|
|
||||||
|
* library/error: very simple/basic library to handle error
|
||||||
|
* library/text/encoder: Various simpler encoder: base64, url-encoder, xml entities, html entities
|
||||||
|
|
||||||
|
For more information please have a look at the related wiki:
|
||||||
|
* https://github.com/Eiffel-World/Eiffel-Web-Framework/wiki
|
||||||
-97
@@ -1,97 +0,0 @@
|
|||||||
Readme file for eJSON
|
|
||||||
=====================
|
|
||||||
|
|
||||||
team: "Javier Velilla,Jocelyn Fiat, Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
1. Introduction
|
|
||||||
---------------
|
|
||||||
|
|
||||||
eJSON stands for Eiffel JSON library and is a small Eiffel library for dealing
|
|
||||||
with the JSON format. The objective of the library is to provide two basic
|
|
||||||
features Eiffel2JSON and JSON2Eiffel.
|
|
||||||
|
|
||||||
2. Legal stuff
|
|
||||||
--------------
|
|
||||||
|
|
||||||
eJSON is copyrighted by the author Javier Velilla 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:
|
|
||||||
|
|
||||||
http://ejson.origo.ethz.ch/wiki/user_guide
|
|
||||||
|
|
||||||
5. Requirements and installation
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
EJSON requires that you have:
|
|
||||||
|
|
||||||
1. Gobo 3.9 installed or later
|
|
||||||
2. One of the following compiler combinations installed:
|
|
||||||
* ISE Eiffel 6.5 or later.
|
|
||||||
* gec [try to test]
|
|
||||||
* tecomp [try to test]
|
|
||||||
|
|
||||||
eJSON probably works fine with other versions of the above compilers.
|
|
||||||
There are no known platform dependencies (Windows, Linux).
|
|
||||||
|
|
||||||
To install eJSON simply extract the ejson-X.Y.Z.zip file to some appropriate
|
|
||||||
place on your hard disk. There are no requirements on environment variables or
|
|
||||||
registry variables.
|
|
||||||
|
|
||||||
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 the eJSON.pdf documentation file.
|
|
||||||
examples Contains the two example programs.
|
|
||||||
ejson Contains the actual eJSON library classes.
|
|
||||||
test Contains a test program for eJSON.
|
|
||||||
|
|
||||||
7. Contacting the Team
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Contact the team:
|
|
||||||
|
|
||||||
Javier Velilla «javier.hector@gmail.com»
|
|
||||||
Paul Cohen «paco@seibostudios.se»
|
|
||||||
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.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
|
|
||||||
Submodule
+1
Submodule doc/wiki added at c7f4f45f5e
@@ -0,0 +1 @@
|
|||||||
|
Examples ...
|
||||||
Submodule
+1
Submodule ext/server/nino added at 9dd1439a2f
Submodule
+1
Submodule ext/text/json added at e1c66b50ca
@@ -0,0 +1,16 @@
|
|||||||
|
<?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="error" uuid="C2DFF741-7091-43C7-B8B1-B075E7FF914F" library_target="error">
|
||||||
|
<target name="error">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?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="error" uuid="C2DFF741-7091-43C7-B8B1-B075E7FF914F" library_target="error">
|
||||||
|
<target name="error">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<cluster name="src" location="src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
${NOTE_KEYWORD}
|
||||||
|
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
note
|
||||||
|
description : "Objects that represent an error"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
ERROR
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
code: INTEGER
|
||||||
|
deferred
|
||||||
|
ensure
|
||||||
|
result_not_zero: Result /= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
name: STRING
|
||||||
|
deferred
|
||||||
|
ensure
|
||||||
|
result_attached: Result /= Void
|
||||||
|
end
|
||||||
|
|
||||||
|
message: detachable STRING_32
|
||||||
|
-- Potential error message
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
parent: detachable ERROR
|
||||||
|
-- Eventual error prior to Current
|
||||||
|
|
||||||
|
feature -- String representation
|
||||||
|
|
||||||
|
string_representation: STRING_32
|
||||||
|
-- String representation for Current
|
||||||
|
do
|
||||||
|
create Result.make_from_string (name.as_string_32)
|
||||||
|
Result.append_character (' ')
|
||||||
|
Result.append_character ('(')
|
||||||
|
Result.append_integer (code)
|
||||||
|
Result.append_character (')')
|
||||||
|
if attached message as m then
|
||||||
|
Result.append_character (':')
|
||||||
|
Result.append_character (' ')
|
||||||
|
Result.append_string (m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Change
|
||||||
|
|
||||||
|
set_parent (a_parent: like parent)
|
||||||
|
-- Set `parent' to `a_parent'
|
||||||
|
do
|
||||||
|
parent := a_parent
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Visitor
|
||||||
|
|
||||||
|
process (a_visitor: ERROR_VISITOR)
|
||||||
|
-- Process Current using `a_visitor'.
|
||||||
|
require
|
||||||
|
a_visitor_not_void: a_visitor /= Void
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
invariant
|
||||||
|
name_attached: name /= Void
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
note
|
||||||
|
description : "Objects that represent a custom error"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
ERROR_CUSTOM
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ERROR
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_code: INTEGER; a_name: STRING; a_message: detachable like message)
|
||||||
|
-- Initialize `Current'.
|
||||||
|
do
|
||||||
|
code := a_code
|
||||||
|
name := a_name
|
||||||
|
if attached a_message then
|
||||||
|
message := a_message
|
||||||
|
else
|
||||||
|
message := "Error: " + a_name + " (code=" + a_code.out + ")"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
code: INTEGER
|
||||||
|
|
||||||
|
name: STRING
|
||||||
|
|
||||||
|
message: STRING_32
|
||||||
|
|
||||||
|
feature -- Visitor
|
||||||
|
|
||||||
|
process (a_visitor: ERROR_VISITOR)
|
||||||
|
-- Process Current using `a_visitor'.
|
||||||
|
do
|
||||||
|
a_visitor.process_custom (Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
note
|
||||||
|
description : "Objects that represent a group of errors"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
ERROR_GROUP
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ERROR
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_errors: LIST [ERROR])
|
||||||
|
-- Initialize `Current'.
|
||||||
|
do
|
||||||
|
name := a_errors.count.out + " errors"
|
||||||
|
create {ARRAYED_LIST [ERROR]} sub_errors.make (a_errors.count)
|
||||||
|
sub_errors.fill (a_errors)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
code: INTEGER = -1
|
||||||
|
|
||||||
|
name: STRING
|
||||||
|
|
||||||
|
message: detachable STRING_32
|
||||||
|
do
|
||||||
|
create Result.make_from_string (name)
|
||||||
|
from
|
||||||
|
sub_errors.start
|
||||||
|
until
|
||||||
|
sub_errors.after
|
||||||
|
loop
|
||||||
|
if
|
||||||
|
attached sub_errors.item as e and then
|
||||||
|
attached e.message as m
|
||||||
|
then
|
||||||
|
|
||||||
|
Result.append_character ('%N')
|
||||||
|
Result.append_string (m)
|
||||||
|
end
|
||||||
|
sub_errors.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sub_errors: LIST [ERROR]
|
||||||
|
-- Error contained by Current
|
||||||
|
|
||||||
|
feature -- Visitor
|
||||||
|
|
||||||
|
process (a_visitor: ERROR_VISITOR)
|
||||||
|
-- Process Current using `a_visitor'.
|
||||||
|
do
|
||||||
|
a_visitor.process_group (Current)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
note
|
||||||
|
description : "Objects that handle error..."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
ERROR_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make
|
||||||
|
-- Initialize `Current'.
|
||||||
|
do
|
||||||
|
create {ARRAYED_LIST [ERROR]} errors.make (3)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status
|
||||||
|
|
||||||
|
has_error: BOOLEAN
|
||||||
|
-- Has error?
|
||||||
|
do
|
||||||
|
Result := count > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
count: INTEGER
|
||||||
|
do
|
||||||
|
Result := errors.count
|
||||||
|
end
|
||||||
|
|
||||||
|
errors: LIST [ERROR]
|
||||||
|
-- Errors container
|
||||||
|
|
||||||
|
feature -- Basic operation
|
||||||
|
|
||||||
|
add_error (a_error: ERROR)
|
||||||
|
-- Add `a_error' to the stack of error
|
||||||
|
do
|
||||||
|
errors.force (a_error)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_error_details, add_custom_error (a_code: INTEGER; a_name: STRING; a_message: detachable STRING_32)
|
||||||
|
-- Add custom error to the stack of error
|
||||||
|
local
|
||||||
|
e: ERROR_CUSTOM
|
||||||
|
do
|
||||||
|
create e.make (a_code, a_name, a_message)
|
||||||
|
add_error (e)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
as_single_error: detachable ERROR
|
||||||
|
do
|
||||||
|
if count > 1 then
|
||||||
|
create {ERROR_GROUP} Result.make (errors)
|
||||||
|
elseif count > 0 then
|
||||||
|
Result := errors.first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Element changes
|
||||||
|
|
||||||
|
concatenate
|
||||||
|
-- Concatenate into a single error if any
|
||||||
|
do
|
||||||
|
if count > 1 and then attached as_single_error as e then
|
||||||
|
wipe_out
|
||||||
|
add_error (e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
reset, wipe_out
|
||||||
|
do
|
||||||
|
errors.wipe_out
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
note
|
||||||
|
description : "Error list iterator"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
ERROR_ITERATOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ERROR_VISITOR
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
process_error (e: ERROR)
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
|
process_custom (e: ERROR_CUSTOM)
|
||||||
|
do
|
||||||
|
process_error (e)
|
||||||
|
end
|
||||||
|
|
||||||
|
process_group (g: ERROR_GROUP)
|
||||||
|
do
|
||||||
|
if attached g.sub_errors as err then
|
||||||
|
from
|
||||||
|
err.start
|
||||||
|
until
|
||||||
|
err.after
|
||||||
|
loop
|
||||||
|
process_error (err.item)
|
||||||
|
err.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
note
|
||||||
|
description : "Null error visitor"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
ERROR_NULL_VISITOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ERROR_VISITOR
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
process_error (e: ERROR)
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
|
process_custom (e: ERROR_CUSTOM)
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
|
process_group (g: ERROR_GROUP)
|
||||||
|
do
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
note
|
||||||
|
description : "Objects to visit an ERROR"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
ERROR_VISITOR
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
process_error (e: ERROR)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
process_custom (e: ERROR_CUSTOM)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
process_group (g: ERROR_GROUP)
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
note
|
||||||
|
description: "File error output visitor"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
FILE_OUTPUT_ERROR_VISITOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
OUTPUT_ERROR_VISITOR
|
||||||
|
redefine
|
||||||
|
output_integer,
|
||||||
|
output_new_line
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Initialization
|
||||||
|
|
||||||
|
make (f: like file)
|
||||||
|
require
|
||||||
|
f_open_write: f /= Void and then f.is_open_write
|
||||||
|
do
|
||||||
|
file := f
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
file: FILE
|
||||||
|
|
||||||
|
feature -- Output
|
||||||
|
|
||||||
|
output_string (a_str: detachable STRING_GENERAL)
|
||||||
|
-- Output Unicode string
|
||||||
|
do
|
||||||
|
if a_str /= Void then
|
||||||
|
to_implement ("Convert into UTF-8 or console encoding before output")
|
||||||
|
file.put_string (a_str.as_string_8)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
output_integer (i: INTEGER)
|
||||||
|
do
|
||||||
|
file.put_integer (i)
|
||||||
|
end
|
||||||
|
|
||||||
|
output_new_line
|
||||||
|
do
|
||||||
|
file.put_new_line
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
note
|
||||||
|
description: "General error output visitor"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
OUTPUT_ERROR_VISITOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ERROR_VISITOR
|
||||||
|
|
||||||
|
REFACTORING_HELPER
|
||||||
|
|
||||||
|
feature -- Output
|
||||||
|
|
||||||
|
output_string (a_str: detachable STRING_GENERAL)
|
||||||
|
-- Output Unicode string
|
||||||
|
deferred
|
||||||
|
end
|
||||||
|
|
||||||
|
output_any (obj: detachable ANY)
|
||||||
|
-- Output Unicode string
|
||||||
|
do
|
||||||
|
if attached {STRING_GENERAL} obj as l_str then
|
||||||
|
to_implement ("Convert into UTF-8 or console encoding before output")
|
||||||
|
output_string (l_str)
|
||||||
|
elseif obj /= Void then
|
||||||
|
output_string (obj.out)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
output_integer (i: INTEGER)
|
||||||
|
do
|
||||||
|
output_string (i.out)
|
||||||
|
end
|
||||||
|
|
||||||
|
output_new_line
|
||||||
|
do
|
||||||
|
output_string ("%N")
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Process
|
||||||
|
|
||||||
|
process_error (e: ERROR)
|
||||||
|
do
|
||||||
|
output_string ({STRING_32}"Error Name: ")
|
||||||
|
output_string (e.name)
|
||||||
|
output_string ({STRING_32}"Code: ")
|
||||||
|
output_integer (e.code)
|
||||||
|
output_new_line
|
||||||
|
output_string ({STRING_32}"%TMessage: ")
|
||||||
|
output_string (e.message)
|
||||||
|
output_new_line
|
||||||
|
end
|
||||||
|
|
||||||
|
process_custom (e: ERROR_CUSTOM)
|
||||||
|
do
|
||||||
|
output_string ({STRING_32}"Error Name: ")
|
||||||
|
output_string (e.name)
|
||||||
|
output_string ({STRING_32}"Code: ")
|
||||||
|
output_integer (e.code)
|
||||||
|
output_new_line
|
||||||
|
output_string ({STRING_32}"%TMessage: ")
|
||||||
|
output_string (e.message)
|
||||||
|
output_new_line
|
||||||
|
end
|
||||||
|
|
||||||
|
process_group (g: ERROR_GROUP)
|
||||||
|
local
|
||||||
|
l_errors: LIST [ERROR]
|
||||||
|
do
|
||||||
|
from
|
||||||
|
l_errors := g.sub_errors
|
||||||
|
l_errors.start
|
||||||
|
until
|
||||||
|
l_errors.after
|
||||||
|
loop
|
||||||
|
l_errors.item.process (Current)
|
||||||
|
l_errors.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
note
|
||||||
|
description: "Text error output visitor"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEXT_OUTPUT_ERROR_VISITOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
OUTPUT_ERROR_VISITOR
|
||||||
|
redefine
|
||||||
|
output_integer,
|
||||||
|
output_new_line
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Initialization
|
||||||
|
|
||||||
|
make (buf: like buffer)
|
||||||
|
require
|
||||||
|
buf_attached: buf /= Void
|
||||||
|
do
|
||||||
|
buffer := buf
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
buffer: STRING
|
||||||
|
|
||||||
|
feature -- Output
|
||||||
|
|
||||||
|
output_string (a_str: detachable STRING_GENERAL)
|
||||||
|
-- Output Unicode string
|
||||||
|
do
|
||||||
|
if a_str /= Void then
|
||||||
|
to_implement ("Convert into UTF-8 or console encoding before output")
|
||||||
|
buffer.append_string_general (a_str)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
output_integer (i: INTEGER)
|
||||||
|
do
|
||||||
|
buffer.append_integer (i)
|
||||||
|
end
|
||||||
|
|
||||||
|
output_new_line
|
||||||
|
do
|
||||||
|
buffer.append_character ('%N')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
note
|
|
||||||
description: "Objects that ..."
|
|
||||||
author: ""
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_FILE_READER
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
read_json_from (a_path: STRING): detachable STRING
|
|
||||||
local
|
|
||||||
l_file: PLAIN_TEXT_FILE
|
|
||||||
template_content: STRING
|
|
||||||
l_last_string: detachable STRING
|
|
||||||
do
|
|
||||||
create l_file.make (a_path)
|
|
||||||
-- We perform several checks until we make a real attempt to open the file.
|
|
||||||
if not l_file.exists then
|
|
||||||
print ("error: '" + a_path + "' does not exist%N")
|
|
||||||
else
|
|
||||||
if not l_file.is_readable then
|
|
||||||
print ("error: '" + a_path + "' is not readable.%N")
|
|
||||||
else
|
|
||||||
l_file.open_read
|
|
||||||
create template_content.make_empty
|
|
||||||
l_file.read_stream (l_file.count)
|
|
||||||
l_last_string := l_file.last_string
|
|
||||||
check l_last_string /= Void end -- implied by postcondition of `l_file.read_stream'
|
|
||||||
template_content.append (l_last_string.string)
|
|
||||||
Result := template_content
|
|
||||||
l_file.close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,175 +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_32
|
|
||||||
-- JSON representation
|
|
||||||
|
|
||||||
indentation: like output
|
|
||||||
|
|
||||||
indentation_step: like indentation
|
|
||||||
|
|
||||||
line_number: INTEGER
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
object_count_inlining: INTEGER
|
|
||||||
array_count_inlining: 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
|
|
||||||
do
|
|
||||||
l_json_array := a_json_array.array_representation
|
|
||||||
l_multiple_lines := l_json_array.count >= array_count_inlining or across l_json_array as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
|
|
||||||
output.append ("[")
|
|
||||||
l_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
|
|
||||||
output.append (", ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
exdent
|
|
||||||
if
|
|
||||||
line_number > l_line or
|
|
||||||
l_json_array.count >= array_count_inlining
|
|
||||||
then
|
|
||||||
new_line
|
|
||||||
end
|
|
||||||
output.append ("]")
|
|
||||||
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
|
|
||||||
do
|
|
||||||
l_pairs := a_json_object.map_representation
|
|
||||||
l_multiple_lines := l_pairs.count >= object_count_inlining or across l_pairs as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
|
|
||||||
output.append ("{")
|
|
||||||
l_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)
|
|
||||||
output.append (": ")
|
|
||||||
l_pairs.item_for_iteration.accept (Current)
|
|
||||||
l_pairs.forth
|
|
||||||
if not l_pairs.after then
|
|
||||||
output.append (", ")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
exdent
|
|
||||||
if
|
|
||||||
line_number > l_line or
|
|
||||||
l_pairs.count >= object_count_inlining
|
|
||||||
then
|
|
||||||
new_line
|
|
||||||
end
|
|
||||||
output.append ("}")
|
|
||||||
end
|
|
||||||
|
|
||||||
visit_json_string (a_json_string: JSON_STRING)
|
|
||||||
-- Visit `a_json_string'.
|
|
||||||
do
|
|
||||||
output.append ("%"")
|
|
||||||
output.append (a_json_string.item)
|
|
||||||
output.append ("%"")
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,102 +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
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,81 +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
|
|
||||||
create js.make_json (c.key.out)
|
|
||||||
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,28 +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" is_attached_by_default="true" void_safety="all" syntax="standard" namespace="EJSON.Library">
|
|
||||||
<assertions/>
|
|
||||||
<warning name="export_class_missing" enabled="false"/>
|
|
||||||
<warning name="old_verbatim_strings" enabled="false"/>
|
|
||||||
<warning name="syntax" enabled="false"/>
|
|
||||||
<warning name="vjrv" enabled="false"/>
|
|
||||||
</option>
|
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/>
|
|
||||||
<cluster name="json" location=".\" recursive="true">
|
|
||||||
<file_rule>
|
|
||||||
<exclude>^/gobo$</exclude>
|
|
||||||
<exclude>^/kernel$</exclude>
|
|
||||||
<exclude>^/extras$</exclude>
|
|
||||||
</file_rule>
|
|
||||||
<cluster name="kernel" location=".\kernel\" recursive="true"/>
|
|
||||||
<cluster name="extras" location=".\extras\" recursive="true"/>
|
|
||||||
</cluster>
|
|
||||||
</target>
|
|
||||||
</system>
|
|
||||||
@@ -1,28 +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/>
|
|
||||||
<warning name="export_class_missing" enabled="false"/>
|
|
||||||
<warning name="old_verbatim_strings" enabled="false"/>
|
|
||||||
<warning name="syntax" enabled="false"/>
|
|
||||||
<warning name="vjrv" enabled="false"/>
|
|
||||||
</option>
|
|
||||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/>
|
|
||||||
<cluster name="json" location=".\" recursive="true">
|
|
||||||
<file_rule>
|
|
||||||
<exclude>^/gobo$</exclude>
|
|
||||||
<exclude>^/kernel$</exclude>
|
|
||||||
<exclude>^/extras$</exclude>
|
|
||||||
</file_rule>
|
|
||||||
<cluster name="kernel" location=".\kernel\" recursive="true"/>
|
|
||||||
<cluster name="extras" location=".\extras\" recursive="true"/>
|
|
||||||
</cluster>
|
|
||||||
</target>
|
|
||||||
</system>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -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" location=".\gobo" recursive="true" />
|
|
||||||
</target>
|
|
||||||
</system>
|
|
||||||
@@ -1,30 +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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
end -- class JSON_ARRAYED_LIST_CONVERTER
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
deferred class JSON_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
SHARED_EJSON
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: ANY
|
|
||||||
-- Eiffel object
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
from_json (j: attached like to_json): detachable like object
|
|
||||||
-- Convert from JSON value.
|
|
||||||
-- Returns Void if unable to convert
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
to_json (o: like object): detachable JSON_VALUE
|
|
||||||
-- Convert to JSON value
|
|
||||||
deferred
|
|
||||||
end
|
|
||||||
|
|
||||||
invariant
|
|
||||||
has_eiffel_object: object /= Void -- An empty object must be created at creation time!
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class JSON_HASH_TABLE_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_CONVERTER
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
do
|
|
||||||
create object.make (0)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: HASH_TABLE [ANY, HASHABLE]
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
from_json (j: attached like to_json): like object
|
|
||||||
local
|
|
||||||
keys: ARRAY [JSON_STRING]
|
|
||||||
i: INTEGER
|
|
||||||
h: detachable HASHABLE
|
|
||||||
jv: detachable JSON_VALUE
|
|
||||||
a: detachable 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
|
|
||||||
jv := j.item (keys [i])
|
|
||||||
if jv /= Void then
|
|
||||||
a := json.object (jv, Void)
|
|
||||||
if a /= Void then
|
|
||||||
Result.put (a, h)
|
|
||||||
else
|
|
||||||
check a_attached: a /= Void end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
check j_has_item: False end
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
to_json (o: like object): detachable JSON_OBJECT
|
|
||||||
local
|
|
||||||
c: HASH_TABLE_ITERATION_CURSOR [ANY, HASHABLE]
|
|
||||||
js: JSON_STRING
|
|
||||||
jv: detachable JSON_VALUE
|
|
||||||
failed: BOOLEAN
|
|
||||||
do
|
|
||||||
create Result.make
|
|
||||||
from
|
|
||||||
c := o.new_cursor
|
|
||||||
until
|
|
||||||
c.after
|
|
||||||
loop
|
|
||||||
create js.make_json (c.key.out)
|
|
||||||
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_HASH_TABLE_CONVERTER
|
|
||||||
@@ -1,30 +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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
end -- class JSON_LINKED_LIST_CONVERTER
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
note
|
|
||||||
description: "A JSON converter for LIST [ANY]"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision$"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
deferred class JSON_LIST_CONVERTER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_CONVERTER
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
do
|
|
||||||
object := new_object (0)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
object: LIST [detachable ANY]
|
|
||||||
|
|
||||||
feature {NONE} -- Factory
|
|
||||||
|
|
||||||
new_object (nb: INTEGER): like object
|
|
||||||
deferred
|
|
||||||
ensure
|
|
||||||
Result /= Void
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
from_json (j: attached like to_json): detachable like object
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
do
|
|
||||||
Result := new_object (j.count)
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > j.count
|
|
||||||
loop
|
|
||||||
Result.extend (json.object (j [i], Void))
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
to_json (o: like object): detachable JSON_ARRAY
|
|
||||||
local
|
|
||||||
c: ITERATION_CURSOR [detachable ANY]
|
|
||||||
jv: detachable JSON_VALUE
|
|
||||||
failed: BOOLEAN
|
|
||||||
do
|
|
||||||
create Result.make_array
|
|
||||||
from
|
|
||||||
c := o.new_cursor
|
|
||||||
until
|
|
||||||
c.after
|
|
||||||
loop
|
|
||||||
jv := json.value (c.item)
|
|
||||||
if jv /= Void then
|
|
||||||
Result.add (jv)
|
|
||||||
else
|
|
||||||
failed := True
|
|
||||||
end
|
|
||||||
c.forth
|
|
||||||
end
|
|
||||||
if failed then
|
|
||||||
Result := Void
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class JSON_ARRAYED_LIST_CONVERTER
|
|
||||||
@@ -1,268 +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
|
|
||||||
|
|
||||||
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_boolean (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_array
|
|
||||||
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_json (c8.out)
|
|
||||||
elseif attached {CHARACTER_32} an_object as c32 then
|
|
||||||
create {JSON_STRING} Result.make_json (c32.out)
|
|
||||||
|
|
||||||
elseif attached {STRING_8} an_object as s8 then
|
|
||||||
create {JSON_STRING} Result.make_json (s8)
|
|
||||||
elseif attached {STRING_32} an_object as s32 then
|
|
||||||
create {JSON_STRING} Result.make_json_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
|
|
||||||
local
|
|
||||||
jv: detachable JSON_VALUE
|
|
||||||
do
|
|
||||||
json_parser.set_representation (json)
|
|
||||||
jv := json_parser.parse
|
|
||||||
if jv /= Void 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_json ("$ref")
|
|
||||||
create js_value.make_json (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_array
|
|
||||||
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 := ": " + an_object.generator
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation (JSON parser)
|
|
||||||
|
|
||||||
json_parser: JSON_PARSER
|
|
||||||
once
|
|
||||||
create Result.make_parser ("")
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class EJSON
|
|
||||||
@@ -1,141 +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: "Javier Velilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_ARRAY
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
DEBUG_OUTPUT
|
|
||||||
|
|
||||||
create
|
|
||||||
make_array
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make_array
|
|
||||||
-- Initialize JSON Array
|
|
||||||
do
|
|
||||||
create values.make (10)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
i_th alias "[]" (i: INTEGER): JSON_VALUE
|
|
||||||
-- Item at `i'-th position
|
|
||||||
require
|
|
||||||
is_valid_index: valid_index (i)
|
|
||||||
do
|
|
||||||
Result := values.i_th (i)
|
|
||||||
end
|
|
||||||
|
|
||||||
representation: STRING
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
do
|
|
||||||
Result := "["
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > count
|
|
||||||
loop
|
|
||||||
Result.append (i_th (i).representation)
|
|
||||||
i := i + 1
|
|
||||||
if i <= count then
|
|
||||||
Result.append_character (',')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Result.append_character (']')
|
|
||||||
end
|
|
||||||
|
|
||||||
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 -- Mesurement
|
|
||||||
|
|
||||||
count: INTEGER
|
|
||||||
-- Number of items.
|
|
||||||
do
|
|
||||||
Result := values.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
|
|
||||||
|
|
||||||
add (value: JSON_VALUE)
|
|
||||||
require
|
|
||||||
value_not_null: value /= void
|
|
||||||
do
|
|
||||||
values.extend (value)
|
|
||||||
ensure
|
|
||||||
has_new_value: old values.count + 1 = values.count and
|
|
||||||
values.has (value)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Report
|
|
||||||
|
|
||||||
hash_code: INTEGER
|
|
||||||
-- Hash code value
|
|
||||||
do
|
|
||||||
from
|
|
||||||
values.start
|
|
||||||
Result := values.item.hash_code
|
|
||||||
until
|
|
||||||
values.off
|
|
||||||
loop
|
|
||||||
Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code
|
|
||||||
values.forth
|
|
||||||
end
|
|
||||||
Result := Result \\ values.count
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Conversion
|
|
||||||
|
|
||||||
array_representation: ARRAYED_LIST [JSON_VALUE]
|
|
||||||
-- Representation as a sequences of values
|
|
||||||
do
|
|
||||||
Result := values
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
debug_output: STRING
|
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
|
||||||
do
|
|
||||||
Result := count.out
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
values: ARRAYED_LIST [JSON_VALUE]
|
|
||||||
-- Value container
|
|
||||||
|
|
||||||
invariant
|
|
||||||
value_not_void: values /= Void
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
note
|
|
||||||
description: "JSON Truth values"
|
|
||||||
author: "Javier Velilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_BOOLEAN
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
create
|
|
||||||
make_boolean
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make_boolean (an_item: BOOLEAN)
|
|
||||||
--Initialize.
|
|
||||||
do
|
|
||||||
item := an_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
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,47 +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"
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
note
|
|
||||||
|
|
||||||
description: "JSON Numbers, octal and hexadecimal formats are not used."
|
|
||||||
author: "Javier Velilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
|
||||||
|
|
||||||
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: DOUBLE)
|
|
||||||
-- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'.
|
|
||||||
do
|
|
||||||
item := an_argument.out
|
|
||||||
numeric_type := DOUBLE_TYPE
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
item: STRING
|
|
||||||
-- Content
|
|
||||||
|
|
||||||
hash_code: INTEGER
|
|
||||||
--Hash code value
|
|
||||||
do
|
|
||||||
Result := item.hash_code
|
|
||||||
end
|
|
||||||
|
|
||||||
representation: STRING
|
|
||||||
do
|
|
||||||
Result := item
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Visitor pattern
|
|
||||||
|
|
||||||
accept (a_visitor: JSON_VISITOR)
|
|
||||||
-- Accept `a_visitor'.
|
|
||||||
-- (Call `visit_json_number' procedure on `a_visitor'.)
|
|
||||||
do
|
|
||||||
a_visitor.visit_json_number (Current)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status
|
|
||||||
|
|
||||||
is_equal (other: like Current): BOOLEAN
|
|
||||||
-- Is `other' attached to an object of the same type
|
|
||||||
-- as current object and identical to it?
|
|
||||||
do
|
|
||||||
Result := item.is_equal (other.item)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
debug_output: STRING
|
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
|
||||||
do
|
|
||||||
Result := item
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Implementation
|
|
||||||
|
|
||||||
INTEGER_TYPE: INTEGER = 1
|
|
||||||
DOUBLE_TYPE: INTEGER = 2
|
|
||||||
NATURAL_TYPE: INTEGER = 3
|
|
||||||
|
|
||||||
numeric_type: INTEGER
|
|
||||||
|
|
||||||
invariant
|
|
||||||
item_not_void: item /= Void
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,191 +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"}
|
|
||||||
|
|
||||||
]"
|
|
||||||
author: "Javier Velilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_OBJECT
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_VALUE
|
|
||||||
|
|
||||||
TABLE_ITERABLE [JSON_VALUE, JSON_STRING]
|
|
||||||
|
|
||||||
create
|
|
||||||
make
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make
|
|
||||||
-- Initialize
|
|
||||||
do
|
|
||||||
create object.make (10)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Change Element
|
|
||||||
|
|
||||||
put (value: detachable JSON_VALUE; key: JSON_STRING)
|
|
||||||
-- Assuming there is no item of key `key',
|
|
||||||
-- insert `value' with `key'.
|
|
||||||
require
|
|
||||||
key_not_present: not has_key (key)
|
|
||||||
local
|
|
||||||
l_value: like value
|
|
||||||
do
|
|
||||||
l_value := value
|
|
||||||
if l_value = Void then
|
|
||||||
create {JSON_NULL} l_value
|
|
||||||
end
|
|
||||||
object.extend (l_value, key)
|
|
||||||
end
|
|
||||||
|
|
||||||
replace (value: detachable JSON_VALUE; key: JSON_STRING)
|
|
||||||
-- Assuming there is no item of key `key',
|
|
||||||
-- insert `value' with `key'.
|
|
||||||
local
|
|
||||||
l_value: like value
|
|
||||||
do
|
|
||||||
l_value := value
|
|
||||||
if l_value = Void then
|
|
||||||
create {JSON_NULL} l_value
|
|
||||||
end
|
|
||||||
object.force (l_value, key)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
has_key (key: JSON_STRING): BOOLEAN
|
|
||||||
-- has the JSON_OBJECT contains a specific key 'key'.
|
|
||||||
do
|
|
||||||
Result := object.has (key)
|
|
||||||
end
|
|
||||||
|
|
||||||
has_item (value: JSON_VALUE): BOOLEAN
|
|
||||||
-- has the JSON_OBJECT contain a specfic item 'value'
|
|
||||||
do
|
|
||||||
Result := object.has_item (value)
|
|
||||||
end
|
|
||||||
|
|
||||||
item (key: JSON_STRING): detachable JSON_VALUE
|
|
||||||
-- the json_value associated with a key.
|
|
||||||
do
|
|
||||||
Result := object.item (key)
|
|
||||||
end
|
|
||||||
|
|
||||||
current_keys: ARRAY [JSON_STRING]
|
|
||||||
-- array containing actually used keys
|
|
||||||
do
|
|
||||||
Result := object.current_keys
|
|
||||||
end
|
|
||||||
|
|
||||||
representation: STRING
|
|
||||||
local
|
|
||||||
t: HASH_TABLE [JSON_VALUE, JSON_STRING]
|
|
||||||
do
|
|
||||||
Result := "{"
|
|
||||||
from
|
|
||||||
t := map_representation
|
|
||||||
t.start
|
|
||||||
until
|
|
||||||
t.after
|
|
||||||
loop
|
|
||||||
Result.append (t.key_for_iteration.representation)
|
|
||||||
Result.append (":")
|
|
||||||
Result.append (t.item_for_iteration.representation)
|
|
||||||
t.forth
|
|
||||||
if not t.after then
|
|
||||||
Result.append_character (',')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Result.append_character ('}')
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Mesurement
|
|
||||||
|
|
||||||
count: INTEGER
|
|
||||||
-- Number of field
|
|
||||||
do
|
|
||||||
Result := object.count
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
new_cursor: TABLE_ITERATION_CURSOR [JSON_VALUE, JSON_STRING]
|
|
||||||
-- Fresh cursor associated with current structure
|
|
||||||
do
|
|
||||||
Result := object.new_cursor
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
is_empty: BOOLEAN
|
|
||||||
-- Is empty object?
|
|
||||||
do
|
|
||||||
Result := object.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 := object
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Report
|
|
||||||
|
|
||||||
hash_code: INTEGER
|
|
||||||
-- Hash code value
|
|
||||||
do
|
|
||||||
from
|
|
||||||
object.start
|
|
||||||
Result := object.item_for_iteration.hash_code
|
|
||||||
until
|
|
||||||
object.off
|
|
||||||
loop
|
|
||||||
Result := ((Result \\ 8388593) |<< 8) + object.item_for_iteration.hash_code
|
|
||||||
object.forth
|
|
||||||
end
|
|
||||||
-- Ensure it is a positive value.
|
|
||||||
Result := Result.hash_code
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
debug_output: STRING
|
|
||||||
-- String that should be displayed in debugger to represent `Current'.
|
|
||||||
do
|
|
||||||
Result := object.count.out
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
object: HASH_TABLE [JSON_VALUE, JSON_STRING]
|
|
||||||
-- Value container
|
|
||||||
|
|
||||||
invariant
|
|
||||||
object_not_null: object /= Void
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,329 +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: "Javier Velilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
|
||||||
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_STRING
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_VALUE
|
|
||||||
redefine
|
|
||||||
is_equal
|
|
||||||
end
|
|
||||||
|
|
||||||
create
|
|
||||||
make_json,
|
|
||||||
make_json_from_string_32,
|
|
||||||
make_with_escaped_json
|
|
||||||
|
|
||||||
convert
|
|
||||||
make_json ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
|
|
||||||
make_json_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32})
|
|
||||||
|
|
||||||
feature {NONE} -- Initialization
|
|
||||||
|
|
||||||
make_json (s: READABLE_STRING_8)
|
|
||||||
-- Initialize.
|
|
||||||
require
|
|
||||||
item_not_void: s /= Void
|
|
||||||
do
|
|
||||||
make_with_escaped_json (escaped_json_string (s))
|
|
||||||
end
|
|
||||||
|
|
||||||
make_json_from_string_32 (s: READABLE_STRING_32)
|
|
||||||
-- Initialize from STRING_32 `s'.
|
|
||||||
require
|
|
||||||
item_not_void: s /= Void
|
|
||||||
do
|
|
||||||
make_with_escaped_json (escaped_json_string_32 (s))
|
|
||||||
end
|
|
||||||
|
|
||||||
make_with_escaped_json (s: READABLE_STRING_8)
|
|
||||||
-- Initialize with an_item already escaped
|
|
||||||
require
|
|
||||||
item_not_void: s /= Void
|
|
||||||
do
|
|
||||||
item := s
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
item: STRING
|
|
||||||
-- Contents with escaped entities if any
|
|
||||||
|
|
||||||
unescaped_string_8: STRING_8
|
|
||||||
-- Unescaped string from `item'
|
|
||||||
local
|
|
||||||
s: like item
|
|
||||||
i, n: INTEGER
|
|
||||||
c: CHARACTER
|
|
||||||
do
|
|
||||||
s := item
|
|
||||||
n := s.count
|
|
||||||
create Result.make (n)
|
|
||||||
from i := 1 until i > n loop
|
|
||||||
c := s[i]
|
|
||||||
if c = '\' then
|
|
||||||
if i < n then
|
|
||||||
inspect s[i+1]
|
|
||||||
when '\' then
|
|
||||||
Result.append_character ('\')
|
|
||||||
i := i + 2
|
|
||||||
when '%"' then
|
|
||||||
Result.append_character ('%"')
|
|
||||||
i := i + 2
|
|
||||||
when 'n' then
|
|
||||||
Result.append_character ('%N')
|
|
||||||
i := i + 2
|
|
||||||
when 'r' then
|
|
||||||
Result.append_character ('%R')
|
|
||||||
i := i + 2
|
|
||||||
when 'u' then
|
|
||||||
--| Leave unicode \uXXXX unescaped
|
|
||||||
Result.append_character ('\')
|
|
||||||
i := i + 1
|
|
||||||
else
|
|
||||||
Result.append_character ('\')
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result.append_character ('\')
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result.append_character (c)
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
unescaped_string_32: STRING_32
|
|
||||||
-- Unescaped string 32 from `item'
|
|
||||||
local
|
|
||||||
s: like item
|
|
||||||
i, n: INTEGER
|
|
||||||
c: CHARACTER
|
|
||||||
hex: STRING
|
|
||||||
do
|
|
||||||
s := item
|
|
||||||
n := s.count
|
|
||||||
create Result.make (n)
|
|
||||||
from i := 1 until i > n loop
|
|
||||||
c := s[i]
|
|
||||||
if c = '\' then
|
|
||||||
if i < n then
|
|
||||||
inspect s[i+1]
|
|
||||||
when '\' then
|
|
||||||
Result.append_character ('\')
|
|
||||||
i := i + 2
|
|
||||||
when '%"' then
|
|
||||||
Result.append_character ('%"')
|
|
||||||
i := i + 2
|
|
||||||
when 'n' then
|
|
||||||
Result.append_character ('%N')
|
|
||||||
i := i + 2
|
|
||||||
when 'r' then
|
|
||||||
Result.append_character ('%R')
|
|
||||||
i := i + 2
|
|
||||||
when 'u' then
|
|
||||||
hex := s.substring (i+2, i+2+4 - 1)
|
|
||||||
if hex.count = 4 then
|
|
||||||
Result.append_code (hexadecimal_to_natural_32 (hex))
|
|
||||||
end
|
|
||||||
i := i + 2 + 4
|
|
||||||
else
|
|
||||||
Result.append_character ('\')
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result.append_character ('\')
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result.append_character (c.to_character_32)
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
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
|
|
||||||
|
|
||||||
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_string: STRING)
|
|
||||||
-- Add a_string
|
|
||||||
require
|
|
||||||
a_string_not_void: a_string /= Void
|
|
||||||
do
|
|
||||||
item.append_string (a_string)
|
|
||||||
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?
|
|
||||||
do
|
|
||||||
Result := across s as scur all scur.item.is_hexa_digit 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_8): STRING_8
|
|
||||||
-- JSON string with '"' and '\' characters escaped
|
|
||||||
require
|
|
||||||
s_not_void: s /= Void
|
|
||||||
local
|
|
||||||
i, n: INTEGER
|
|
||||||
c: CHARACTER_8
|
|
||||||
do
|
|
||||||
n := s.count
|
|
||||||
create Result.make (n + n // 10)
|
|
||||||
from i := 1 until i > n loop
|
|
||||||
c := s.item (i)
|
|
||||||
inspect c
|
|
||||||
when '%"' then Result.append_string ("\%"")
|
|
||||||
when '\' then Result.append_string ("\\")
|
|
||||||
when '%R' then Result.append_string ("\r")
|
|
||||||
when '%N' then Result.append_string ("\n")
|
|
||||||
else
|
|
||||||
Result.extend (c)
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
escaped_json_string_32 (s: READABLE_STRING_32): STRING_8
|
|
||||||
-- JSON string with '"' and '\' characters and unicode escaped
|
|
||||||
require
|
|
||||||
s_not_void: s /= Void
|
|
||||||
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 '%R' then Result.append_string ("\r")
|
|
||||||
when '%N' then Result.append_string ("\n")
|
|
||||||
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 h.count = 4 end
|
|
||||||
Result.append (h)
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
invariant
|
|
||||||
item_not_void: item /= Void
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,43 +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
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,513 +0,0 @@
|
|||||||
note
|
|
||||||
|
|
||||||
description: "Parse serialized JSON data"
|
|
||||||
author: "jvelilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "Revision 0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_PARSER
|
|
||||||
|
|
||||||
inherit
|
|
||||||
JSON_READER
|
|
||||||
JSON_TOKENS
|
|
||||||
|
|
||||||
create
|
|
||||||
make_parser
|
|
||||||
|
|
||||||
feature {NONE} -- Initialize
|
|
||||||
|
|
||||||
make_parser (a_json: STRING)
|
|
||||||
-- Initialize.
|
|
||||||
require
|
|
||||||
json_not_empty: a_json /= Void and then not a_json.is_empty
|
|
||||||
do
|
|
||||||
make (a_json)
|
|
||||||
is_parsed := True
|
|
||||||
create errors.make
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
is_parsed: BOOLEAN
|
|
||||||
-- Is parsed?
|
|
||||||
|
|
||||||
errors: LINKED_LIST [STRING]
|
|
||||||
-- Current errors
|
|
||||||
|
|
||||||
current_errors: STRING
|
|
||||||
-- Current errors as string
|
|
||||||
do
|
|
||||||
create Result.make_empty
|
|
||||||
from
|
|
||||||
errors.start
|
|
||||||
until
|
|
||||||
errors.after
|
|
||||||
loop
|
|
||||||
Result.append_string (errors.item + "%N")
|
|
||||||
errors.forth
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Element change
|
|
||||||
|
|
||||||
report_error (e: STRING)
|
|
||||||
-- Report error `e'
|
|
||||||
require
|
|
||||||
e_not_void: e /= Void
|
|
||||||
do
|
|
||||||
errors.force (e)
|
|
||||||
end
|
|
||||||
|
|
||||||
feature -- Commands
|
|
||||||
|
|
||||||
parse_json: detachable JSON_VALUE
|
|
||||||
-- Parse JSON data `representation'
|
|
||||||
-- start ::= object | array
|
|
||||||
do
|
|
||||||
if is_valid_start_symbol then
|
|
||||||
Result := parse
|
|
||||||
if extra_elements then
|
|
||||||
is_parsed := False
|
|
||||||
end
|
|
||||||
else
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("Syntax error unexpected token, expecting `{' or `['")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parse: detachable JSON_VALUE
|
|
||||||
-- Parse JSON data `representation'
|
|
||||||
local
|
|
||||||
c: CHARACTER
|
|
||||||
do
|
|
||||||
if is_parsed then
|
|
||||||
skip_white_spaces
|
|
||||||
c := actual
|
|
||||||
inspect c
|
|
||||||
when j_OBJECT_OPEN then
|
|
||||||
Result := parse_object
|
|
||||||
when j_STRING then
|
|
||||||
Result := parse_string
|
|
||||||
when j_ARRAY_OPEN then
|
|
||||||
Result := parse_array
|
|
||||||
else
|
|
||||||
if c.is_digit or c = j_MINUS then
|
|
||||||
Result := parse_number
|
|
||||||
elseif is_null then
|
|
||||||
Result := create {JSON_NULL}
|
|
||||||
next
|
|
||||||
next
|
|
||||||
next
|
|
||||||
elseif is_true then
|
|
||||||
Result := create {JSON_BOOLEAN}.make_boolean (True)
|
|
||||||
next
|
|
||||||
next
|
|
||||||
next
|
|
||||||
elseif is_false then
|
|
||||||
Result := create {JSON_BOOLEAN}.make_boolean (False)
|
|
||||||
next
|
|
||||||
next
|
|
||||||
next
|
|
||||||
next
|
|
||||||
else
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("JSON is not well formed in parse")
|
|
||||||
Result := Void
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
is_parsed_implies_result_not_void: is_parsed implies Result /= Void
|
|
||||||
end
|
|
||||||
|
|
||||||
parse_object: JSON_OBJECT
|
|
||||||
-- object
|
|
||||||
-- {}
|
|
||||||
-- {"key" : "value" [,]}
|
|
||||||
local
|
|
||||||
has_more: BOOLEAN
|
|
||||||
l_json_string: detachable JSON_STRING
|
|
||||||
l_value: detachable JSON_VALUE
|
|
||||||
do
|
|
||||||
create Result.make
|
|
||||||
-- check if is an empty object {}
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
if actual = j_OBJECT_CLOSE then
|
|
||||||
--is an empty object
|
|
||||||
else
|
|
||||||
-- a complex object {"key" : "value"}
|
|
||||||
previous
|
|
||||||
from has_more := True until not has_more loop
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
l_json_string := parse_string
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
if actual = ':' then
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
else
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
|
|
||||||
has_more := False
|
|
||||||
end
|
|
||||||
|
|
||||||
l_value := parse
|
|
||||||
if is_parsed and then (l_value /= Void and l_json_string /= Void) then
|
|
||||||
Result.put (l_value, l_json_string)
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
if actual = j_OBJECT_CLOSE then
|
|
||||||
has_more := False
|
|
||||||
elseif actual /= ',' then
|
|
||||||
has_more := False
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
has_more := False
|
|
||||||
-- explain the error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parse_string: detachable JSON_STRING
|
|
||||||
-- Parsed string
|
|
||||||
local
|
|
||||||
has_more: BOOLEAN
|
|
||||||
l_json_string: STRING
|
|
||||||
l_unicode: STRING
|
|
||||||
c: like actual
|
|
||||||
do
|
|
||||||
create l_json_string.make_empty
|
|
||||||
if actual = j_STRING then
|
|
||||||
from
|
|
||||||
has_more := True
|
|
||||||
until
|
|
||||||
not has_more
|
|
||||||
loop
|
|
||||||
next
|
|
||||||
c := actual
|
|
||||||
if c = j_STRING then
|
|
||||||
has_more := False
|
|
||||||
elseif c = '%H' then
|
|
||||||
next
|
|
||||||
c := actual
|
|
||||||
if c = 'u' then
|
|
||||||
create l_unicode.make_from_string ("\u")
|
|
||||||
l_unicode.append (read_unicode)
|
|
||||||
c := actual
|
|
||||||
if is_valid_unicode (l_unicode) then
|
|
||||||
l_json_string.append (l_unicode)
|
|
||||||
else
|
|
||||||
has_more := False
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
|
|
||||||
end
|
|
||||||
elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
|
|
||||||
has_more := False
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
|
|
||||||
else
|
|
||||||
l_json_string.append_character ('\')
|
|
||||||
l_json_string.append_character (c)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if is_special_character (c) and c /= '/' then
|
|
||||||
has_more := False
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
|
|
||||||
else
|
|
||||||
l_json_string.append_character (c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
create Result.make_with_escaped_json (l_json_string)
|
|
||||||
else
|
|
||||||
Result := Void
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parse_array: JSON_ARRAY
|
|
||||||
-- array
|
|
||||||
-- []
|
|
||||||
-- [elements [,]]
|
|
||||||
local
|
|
||||||
flag: BOOLEAN
|
|
||||||
l_value: detachable JSON_VALUE
|
|
||||||
c: like actual
|
|
||||||
do
|
|
||||||
create Result.make_array
|
|
||||||
--check if is an empty array []
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
if actual = j_array_close then
|
|
||||||
--is an empty array
|
|
||||||
else
|
|
||||||
previous
|
|
||||||
from
|
|
||||||
flag := True
|
|
||||||
until
|
|
||||||
not flag
|
|
||||||
loop
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
l_value := parse
|
|
||||||
if is_parsed and then l_value /= Void then
|
|
||||||
Result.add (l_value)
|
|
||||||
next
|
|
||||||
skip_white_spaces
|
|
||||||
c := actual
|
|
||||||
if c = j_ARRAY_CLOSE then
|
|
||||||
flag := False
|
|
||||||
elseif c /= ',' then
|
|
||||||
flag := False
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("Array is not well formed JSON, found [" + c.out + " ]")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
flag := False
|
|
||||||
report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parse_number: detachable JSON_NUMBER
|
|
||||||
-- Parsed number
|
|
||||||
local
|
|
||||||
sb: STRING
|
|
||||||
flag: BOOLEAN
|
|
||||||
is_integer: BOOLEAN
|
|
||||||
c: like actual
|
|
||||||
do
|
|
||||||
create sb.make_empty
|
|
||||||
sb.append_character (actual)
|
|
||||||
|
|
||||||
from
|
|
||||||
flag := True
|
|
||||||
until
|
|
||||||
not flag
|
|
||||||
loop
|
|
||||||
next
|
|
||||||
c := actual
|
|
||||||
if not has_next or is_close_token (c)
|
|
||||||
or c = ',' or c = '%N' or c = '%R'
|
|
||||||
then
|
|
||||||
flag := False
|
|
||||||
previous
|
|
||||||
else
|
|
||||||
sb.append_character (c)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if is_valid_number (sb) then
|
|
||||||
if sb.is_integer then
|
|
||||||
create Result.make_integer (sb.to_integer)
|
|
||||||
is_integer := True
|
|
||||||
elseif sb.is_double and not is_integer then
|
|
||||||
create Result.make_real (sb.to_double)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
is_parsed := False
|
|
||||||
report_error ("Expected a number, found: [ " + sb + " ]")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_null: BOOLEAN
|
|
||||||
-- Word at index represents null?
|
|
||||||
local
|
|
||||||
l_null: STRING
|
|
||||||
l_string: STRING
|
|
||||||
do
|
|
||||||
l_null := null_id
|
|
||||||
l_string := json_substring (index,index + l_null.count - 1)
|
|
||||||
if l_string.is_equal (l_null) then
|
|
||||||
Result := True
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_false: BOOLEAN
|
|
||||||
-- Word at index represents false?
|
|
||||||
local
|
|
||||||
l_false: STRING
|
|
||||||
l_string: STRING
|
|
||||||
do
|
|
||||||
l_false := false_id
|
|
||||||
l_string := json_substring (index, index + l_false.count - 1)
|
|
||||||
if l_string.is_equal (l_false) then
|
|
||||||
Result := True
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_true: BOOLEAN
|
|
||||||
-- Word at index represents true?
|
|
||||||
local
|
|
||||||
l_true: STRING
|
|
||||||
l_string: STRING
|
|
||||||
do
|
|
||||||
l_true := true_id
|
|
||||||
l_string := json_substring (index,index + l_true.count - 1)
|
|
||||||
if l_string.is_equal (l_true) then
|
|
||||||
Result := True
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
read_unicode: STRING
|
|
||||||
-- Read unicode and return value
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
do
|
|
||||||
create Result.make_empty
|
|
||||||
from
|
|
||||||
i := 1
|
|
||||||
until
|
|
||||||
i > 4 or not has_next
|
|
||||||
loop
|
|
||||||
next
|
|
||||||
Result.append_character (actual)
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Implementation
|
|
||||||
|
|
||||||
is_valid_number (a_number: STRING): BOOLEAN
|
|
||||||
-- is 'a_number' a valid number based on this regular expression
|
|
||||||
-- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"?
|
|
||||||
local
|
|
||||||
s: detachable STRING
|
|
||||||
c: CHARACTER
|
|
||||||
i,n: INTEGER
|
|
||||||
do
|
|
||||||
create s.make_empty
|
|
||||||
n := a_number.count
|
|
||||||
if n = 0 then
|
|
||||||
Result := False
|
|
||||||
else
|
|
||||||
Result := True
|
|
||||||
i := 1
|
|
||||||
--| "-?"
|
|
||||||
c := a_number[i]
|
|
||||||
if c = '-' then
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
end
|
|
||||||
--| "0|[1-9]\d*
|
|
||||||
if c.is_digit then
|
|
||||||
if c = '0' then
|
|
||||||
--| "0"
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
else
|
|
||||||
--| "[1-9]"
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
--| "\d*"
|
|
||||||
from until i > n or not c.is_digit loop
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if Result then
|
|
||||||
--| "(\.\d+)?"
|
|
||||||
if c = '.' then
|
|
||||||
--| "\.\d+" = "\.\d\d*"
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
if c.is_digit then
|
|
||||||
from until i > n or not c.is_digit loop
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result := False --| expecting digit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if Result then --| "(?:[eE][+-]?\d+)?\b"
|
|
||||||
if c = 'e' or c = 'E' then
|
|
||||||
--| "[eE][+-]?\d+"
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
if c = '+' or c = '-' then
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
end
|
|
||||||
if c.is_digit then
|
|
||||||
from until i > n or not c.is_digit loop
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result := False --| expecting digit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if Result then --| "\b"
|
|
||||||
from until i > n or not c.is_space loop
|
|
||||||
s.extend (c); i := i + 1; c := a_number[i]
|
|
||||||
end
|
|
||||||
Result := i > n and then s.same_string (a_number)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_valid_unicode (a_unicode: STRING): BOOLEAN
|
|
||||||
-- is 'a_unicode' a valid unicode based on this regular expression
|
|
||||||
-- "\\u[0-9a-fA-F]{4}"
|
|
||||||
local
|
|
||||||
i: INTEGER
|
|
||||||
do
|
|
||||||
if
|
|
||||||
a_unicode.count = 6 and then
|
|
||||||
a_unicode[1] = '\' and then
|
|
||||||
a_unicode[2] = 'u'
|
|
||||||
then
|
|
||||||
from
|
|
||||||
Result := True
|
|
||||||
i := 3
|
|
||||||
until
|
|
||||||
i > 6 or Result = False
|
|
||||||
loop
|
|
||||||
inspect a_unicode[i]
|
|
||||||
when '0'..'9', 'a'..'f', 'A'..'F' then
|
|
||||||
else
|
|
||||||
Result := False
|
|
||||||
end
|
|
||||||
i := i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
extra_elements: BOOLEAN
|
|
||||||
-- has more elements?
|
|
||||||
local
|
|
||||||
c: like actual
|
|
||||||
do
|
|
||||||
if has_next then
|
|
||||||
next
|
|
||||||
end
|
|
||||||
from
|
|
||||||
c := actual
|
|
||||||
until
|
|
||||||
c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
|
|
||||||
loop
|
|
||||||
next
|
|
||||||
end
|
|
||||||
Result := has_next
|
|
||||||
end
|
|
||||||
|
|
||||||
is_valid_start_symbol : BOOLEAN
|
|
||||||
-- expecting `{' or `[' as start symbol
|
|
||||||
do
|
|
||||||
if attached representation as s and then s.count > 0 then
|
|
||||||
Result := s[1] = '{' or s[1] = '['
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
feature {NONE} -- Constants
|
|
||||||
|
|
||||||
false_id: STRING = "false"
|
|
||||||
|
|
||||||
true_id: STRING = "true"
|
|
||||||
|
|
||||||
null_id: STRING = "null"
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,118 +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
|
|
||||||
|
|
||||||
set_representation (a_json: STRING)
|
|
||||||
-- Set `representation'.
|
|
||||||
do
|
|
||||||
a_json.left_adjust
|
|
||||||
a_json.right_adjust
|
|
||||||
representation := a_json
|
|
||||||
index := 1
|
|
||||||
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
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
note
|
|
||||||
description: ""
|
|
||||||
author: "jvelilla"
|
|
||||||
date: "2008/08/24"
|
|
||||||
revision: "0.1"
|
|
||||||
|
|
||||||
class
|
|
||||||
JSON_TOKENS
|
|
||||||
|
|
||||||
feature -- Access
|
|
||||||
|
|
||||||
j_OBJECT_OPEN: CHARACTER = '{'
|
|
||||||
j_ARRAY_OPEN: CHARACTER = '['
|
|
||||||
j_OBJECT_CLOSE: CHARACTER = '}'
|
|
||||||
j_ARRAY_CLOSE: CHARACTER = ']'
|
|
||||||
|
|
||||||
j_STRING: CHARACTER = '"'
|
|
||||||
j_PLUS: CHARACTER = '+'
|
|
||||||
j_MINUS: CHARACTER = '-'
|
|
||||||
j_DOT: CHARACTER = '.'
|
|
||||||
|
|
||||||
feature -- Status report
|
|
||||||
|
|
||||||
is_open_token (c: CHARACTER): BOOLEAN
|
|
||||||
-- Characters which open a type
|
|
||||||
do
|
|
||||||
inspect c
|
|
||||||
when j_OBJECT_OPEN, j_ARRAY_OPEN, j_STRING, j_PLUS, j_MINUS, j_DOT then
|
|
||||||
Result := True
|
|
||||||
else
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_close_token (c: CHARACTER): BOOLEAN
|
|
||||||
-- Characters which close a type
|
|
||||||
do
|
|
||||||
inspect c
|
|
||||||
when j_OBJECT_CLOSE, j_ARRAY_CLOSE, j_STRING then
|
|
||||||
Result := True
|
|
||||||
else
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_special_character (c: CHARACTER): BOOLEAN
|
|
||||||
-- Control Characters
|
|
||||||
-- %F Form feed
|
|
||||||
-- %H backslasH
|
|
||||||
-- %N Newline
|
|
||||||
-- %R carriage Return
|
|
||||||
-- %T horizontal Tab
|
|
||||||
-- %B Backspace
|
|
||||||
-- / Solidus
|
|
||||||
-- " Quotation
|
|
||||||
do
|
|
||||||
inspect c
|
|
||||||
when '%F', '%H', '%N', '%R', '%T', '%B', '/', '"' then
|
|
||||||
Result := True
|
|
||||||
else
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
is_special_control (c: CHARACTER): BOOLEAN
|
|
||||||
--Control Characters
|
|
||||||
-- \b\f\n\r\t
|
|
||||||
do
|
|
||||||
inspect c
|
|
||||||
when 'b', 'f', 'n', 'r', 't' then
|
|
||||||
Result := True
|
|
||||||
else
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
note
|
|
||||||
description: "[
|
|
||||||
Shared factory class for creating JSON objects. Maps JSON
|
|
||||||
objects to ELKS HASH_TABLEs and JSON arrays to ELKS
|
|
||||||
LINKED_LISTs. Use non-conforming inheritance from this
|
|
||||||
class to ensure that your classes share the same
|
|
||||||
JSON_FACTORY instance.
|
|
||||||
]"
|
|
||||||
author: "Paul Cohen"
|
|
||||||
date: "$Date$"
|
|
||||||
revision: "$Revision: 89185 $"
|
|
||||||
file: "$HeadURL: $"
|
|
||||||
|
|
||||||
class SHARED_EJSON
|
|
||||||
|
|
||||||
feature
|
|
||||||
|
|
||||||
json: EJSON
|
|
||||||
-- A shared EJSON instance with default converters for
|
|
||||||
--LINKED_LIST [ANY] and HASH_TABLE [ANY, HASHABLE]
|
|
||||||
local
|
|
||||||
jalc: JSON_ARRAYED_LIST_CONVERTER
|
|
||||||
jllc: JSON_LINKED_LIST_CONVERTER
|
|
||||||
jhtc: JSON_HASH_TABLE_CONVERTER
|
|
||||||
once
|
|
||||||
create Result
|
|
||||||
|
|
||||||
create jalc.make
|
|
||||||
Result.add_converter (jalc)
|
|
||||||
|
|
||||||
create jllc.make
|
|
||||||
Result.add_converter (jllc)
|
|
||||||
|
|
||||||
create jhtc.make
|
|
||||||
Result.add_converter (jhtc)
|
|
||||||
end
|
|
||||||
|
|
||||||
end -- class SHARED_EJSON
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?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="http" uuid="F8BE3C55-88E8-4103-A936-B1E5CB1D330E" library_target="http">
|
||||||
|
<target name="http">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?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="http" uuid="F8BE3C55-88E8-4103-A936-B1E5CB1D330E" library_target="http">
|
||||||
|
<target name="http">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
${NOTE_KEYWORD}
|
||||||
|
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_CONSTANTS}."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Ports
|
||||||
|
|
||||||
|
default_http_port: INTEGER = 80
|
||||||
|
default_https_port: INTEGER = 443
|
||||||
|
|
||||||
|
feature -- Method
|
||||||
|
|
||||||
|
method_get: STRING = "GET"
|
||||||
|
method_post: STRING = "POST"
|
||||||
|
method_put: STRING = "PUT"
|
||||||
|
method_delete: STRING = "DELETE"
|
||||||
|
method_head: STRING = "HEAD"
|
||||||
|
method_download: STRING = "DOWNLOAD"
|
||||||
|
|
||||||
|
feature -- Content type
|
||||||
|
|
||||||
|
octet_stream: STRING = "application/octet-stream"
|
||||||
|
-- Octet stream content-type header
|
||||||
|
multipart_form: STRING = "multipart/form-data"
|
||||||
|
-- Starting chars of multipart form data content-type header
|
||||||
|
form_encoded: STRING = "application/x-www-form-urlencoded"
|
||||||
|
-- Starting chars of form url-encoded data content-type header
|
||||||
|
xml_text: STRING = "text/xml"
|
||||||
|
-- XML text content-type header
|
||||||
|
html_text: STRING = "text/html"
|
||||||
|
-- HTML text content-type header
|
||||||
|
json_text: STRING = "text/json"
|
||||||
|
-- JSON text content-type header
|
||||||
|
json_app: STRING = "application/json"
|
||||||
|
-- JSON application content-type header
|
||||||
|
js_text: STRING = "text/javascript"
|
||||||
|
-- Javascript text content-type header
|
||||||
|
js_app: STRING = "application/javascript"
|
||||||
|
-- JavaScript application content-type header
|
||||||
|
plain_text: STRING = "text/plain"
|
||||||
|
-- Plain text content-type header
|
||||||
|
|
||||||
|
feature -- Server
|
||||||
|
|
||||||
|
http_version_1_0: STRING = "HTTP/1.0"
|
||||||
|
http_version_1_1: STRING = "HTTP/1.1"
|
||||||
|
http_host_header: STRING = "Host"
|
||||||
|
http_authorization_header: STRING = "Authorization: "
|
||||||
|
http_end_of_header_line: STRING = "%R%N"
|
||||||
|
http_end_of_command: STRING = "%R%N%R%N"
|
||||||
|
http_content_length: STRING = "Content-Length: "
|
||||||
|
http_content_type: STRING = "Content-Type: "
|
||||||
|
http_content_location: STRING = "Content-Location: "
|
||||||
|
http_content_disposition: STRING = "Content-Disposition: "
|
||||||
|
http_path_translated: STRING = "Path-Translated: "
|
||||||
|
http_agent: STRING = "User-agent: "
|
||||||
|
http_from: STRING = "From: "
|
||||||
|
|
||||||
|
feature -- Server: header
|
||||||
|
|
||||||
|
header_host: STRING = "Host"
|
||||||
|
header_authorization: STRING = "Authorization"
|
||||||
|
header_content_length: STRING = "Content-Length"
|
||||||
|
header_content_type: STRING = "Content-Type"
|
||||||
|
header_content_location: STRING = "Content-Location"
|
||||||
|
header_content_disposition: STRING = "Content-Disposition"
|
||||||
|
header_cache_control: STRING = "Cache-Control"
|
||||||
|
header_path_translated: STRING = "Path-Translated"
|
||||||
|
header_agent: STRING = "User-Agent"
|
||||||
|
header_referer: STRING = "Referer" -- Officially mispelled in std
|
||||||
|
header_location: STRING = "Location"
|
||||||
|
header_from: STRING = "From"
|
||||||
|
header_status: STRING = "Status"
|
||||||
|
header_multipart_tag_value_separator: CHARACTER = ';'
|
||||||
|
|
||||||
|
feature -- Misc
|
||||||
|
|
||||||
|
http_status_ok: STRING = "200 OK"
|
||||||
|
|
||||||
|
default_bufsize: INTEGER = 16384 --| 16K
|
||||||
|
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_DATE_TIME_UTILITIES}."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_DATE_TIME_UTILITIES
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
now_utc: DATE_TIME
|
||||||
|
do
|
||||||
|
create Result.make_now_utc
|
||||||
|
end
|
||||||
|
|
||||||
|
epoch: DATE_TIME
|
||||||
|
once ("THREAD")
|
||||||
|
create Result.make_from_epoch (0)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Unix time stamp
|
||||||
|
|
||||||
|
unix_time_stamp (dt: detachable DATE_TIME): INTEGER_64
|
||||||
|
-- Unix time stamp from `dt' if attached or from epoch is detached
|
||||||
|
local
|
||||||
|
l_date_time: DATE_TIME
|
||||||
|
do
|
||||||
|
if dt /= Void then
|
||||||
|
l_date_time := dt
|
||||||
|
else
|
||||||
|
l_date_time := now_utc
|
||||||
|
end
|
||||||
|
Result := l_date_time.definite_duration (epoch).seconds_count
|
||||||
|
end
|
||||||
|
|
||||||
|
fine_unix_time_stamp (dt: detachable DATE_TIME): DOUBLE
|
||||||
|
-- Fine unix time stamp from `dt' if attached or from epoch is detached
|
||||||
|
local
|
||||||
|
l_date_time: DATE_TIME
|
||||||
|
do
|
||||||
|
if dt /= Void then
|
||||||
|
l_date_time := dt
|
||||||
|
else
|
||||||
|
l_date_time := now_utc
|
||||||
|
end
|
||||||
|
Result := l_date_time.definite_duration (epoch).fine_seconds_count
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Unix time stamp conversion
|
||||||
|
|
||||||
|
unix_time_stamp_to_date_time (i64: INTEGER_64): DATE_TIME
|
||||||
|
-- Date time related to `i64'
|
||||||
|
do
|
||||||
|
create Result.make_from_epoch (i64.as_integer_32)
|
||||||
|
ensure
|
||||||
|
same_unix_time_stamp: unix_time_stamp (Result) = i64
|
||||||
|
end
|
||||||
|
|
||||||
|
;note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_FORMAT_CONSTANTS}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_FORMAT_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Id
|
||||||
|
|
||||||
|
json: INTEGER = 0x1
|
||||||
|
|
||||||
|
xml: INTEGER = 0x2
|
||||||
|
|
||||||
|
text: INTEGER = 0x4
|
||||||
|
|
||||||
|
html: INTEGER = 0x8
|
||||||
|
|
||||||
|
rss: INTEGER = 0x10
|
||||||
|
|
||||||
|
atom: INTEGER = 0x20
|
||||||
|
|
||||||
|
feature -- Name
|
||||||
|
|
||||||
|
json_name: STRING = "json"
|
||||||
|
|
||||||
|
xml_name: STRING = "xml"
|
||||||
|
|
||||||
|
text_name: STRING = "text"
|
||||||
|
|
||||||
|
html_name: STRING = "html"
|
||||||
|
|
||||||
|
rss_name: STRING = "rss"
|
||||||
|
|
||||||
|
atom_name: STRING = "atom"
|
||||||
|
|
||||||
|
empty_name: STRING = ""
|
||||||
|
|
||||||
|
feature -- Query
|
||||||
|
|
||||||
|
format_id (a_id: STRING): INTEGER
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s := a_id.as_lower
|
||||||
|
if s.same_string (json_name) then
|
||||||
|
Result := json
|
||||||
|
elseif s.same_string (xml_name) then
|
||||||
|
Result := xml
|
||||||
|
elseif s.same_string (text_name) then
|
||||||
|
Result := text
|
||||||
|
elseif s.same_string (html_name) then
|
||||||
|
Result := html
|
||||||
|
elseif s.same_string (rss_name) then
|
||||||
|
Result := rss
|
||||||
|
elseif s.same_string (atom_name) then
|
||||||
|
Result := atom
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
format_name (a_id: INTEGER): STRING
|
||||||
|
do
|
||||||
|
inspect a_id
|
||||||
|
when json then Result := json_name
|
||||||
|
when xml then Result := xml_name
|
||||||
|
when text then Result := text_name
|
||||||
|
when html then Result := html_name
|
||||||
|
when rss then Result := rss_name
|
||||||
|
when atom then Result := atom_name
|
||||||
|
else Result := empty_name
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
result_is_lower_case: Result /= Void and then Result.as_lower ~ Result
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {HTTP_REQUEST_METHOD_CONSTANTS}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_REQUEST_METHOD_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Id
|
||||||
|
|
||||||
|
method_get: INTEGER = 0x1
|
||||||
|
|
||||||
|
method_post: INTEGER = 0x2
|
||||||
|
|
||||||
|
method_put: INTEGER = 0x4
|
||||||
|
|
||||||
|
method_delete: INTEGER = 0x8
|
||||||
|
|
||||||
|
method_head: INTEGER = 0x10
|
||||||
|
|
||||||
|
feature -- Name
|
||||||
|
|
||||||
|
method_get_name: STRING = "GET"
|
||||||
|
|
||||||
|
method_post_name: STRING = "POST"
|
||||||
|
|
||||||
|
method_put_name: STRING = "PUT"
|
||||||
|
|
||||||
|
method_delete_name: STRING = "DELETE"
|
||||||
|
|
||||||
|
method_head_name: STRING = "HEAD"
|
||||||
|
|
||||||
|
method_empty_name: STRING = ""
|
||||||
|
|
||||||
|
feature -- Query
|
||||||
|
|
||||||
|
method_id (a_id: STRING): INTEGER
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
s := a_id.as_lower
|
||||||
|
if s.same_string (method_get_name) then
|
||||||
|
Result := method_get
|
||||||
|
elseif s.same_string (method_post_name) then
|
||||||
|
Result := method_post
|
||||||
|
elseif s.same_string (method_put_name) then
|
||||||
|
Result := method_put
|
||||||
|
elseif s.same_string (method_delete_name) then
|
||||||
|
Result := method_delete
|
||||||
|
elseif s.same_string (method_head_name) then
|
||||||
|
Result := method_head
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
method_name (a_id: INTEGER): STRING
|
||||||
|
do
|
||||||
|
inspect a_id
|
||||||
|
when method_get then Result := method_get_name
|
||||||
|
when method_post then Result := method_post_name
|
||||||
|
when method_put then Result := method_put_name
|
||||||
|
when method_delete then Result := method_delete_name
|
||||||
|
when method_head then Result := method_head_name
|
||||||
|
else Result := method_empty_name
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
result_is_upper_case: Result /= Void and then Result.as_upper ~ Result
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Status code constants pertaining to the HTTP protocol
|
||||||
|
See http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
|
||||||
|
]"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_STATUS_CODE
|
||||||
|
|
||||||
|
feature -- 1xx : Informational
|
||||||
|
|
||||||
|
continue: INTEGER = 100
|
||||||
|
switching_protocols: INTEGER = 101
|
||||||
|
processing: INTEGER = 102 -- WebDAV RFC 2518
|
||||||
|
ie7_request_uri_too_long: INTEGER = 122 -- non standard, IE7 only
|
||||||
|
|
||||||
|
feature -- 2xx : Success
|
||||||
|
|
||||||
|
ok: INTEGER = 200
|
||||||
|
created: INTEGER = 201
|
||||||
|
accepted: INTEGER = 202
|
||||||
|
nonauthoritative_info: INTEGER = 203
|
||||||
|
no_content: INTEGER = 204
|
||||||
|
reset_content: INTEGER = 205
|
||||||
|
partial_content: INTEGER = 206
|
||||||
|
multistatus: INTEGER = 207 -- WebDAV RFC 4918
|
||||||
|
im_used: INTEGER = 226 -- RFC 4918
|
||||||
|
|
||||||
|
feature -- 3xx : Redirection
|
||||||
|
|
||||||
|
multiple_choices: INTEGER = 300
|
||||||
|
moved_permanently: INTEGER = 301
|
||||||
|
found: INTEGER = 302
|
||||||
|
see_other: INTEGER = 303
|
||||||
|
not_modified: INTEGER = 304
|
||||||
|
use_proxy: INTEGER = 305
|
||||||
|
switch_proxy: INTEGER = 306
|
||||||
|
temp_redirect: INTEGER = 307
|
||||||
|
|
||||||
|
feature -- 4xx : Client Error
|
||||||
|
|
||||||
|
bad_request: INTEGER = 400
|
||||||
|
unauthorized: INTEGER = 401
|
||||||
|
payment_required: INTEGER = 402
|
||||||
|
forbidden: INTEGER = 403
|
||||||
|
not_found: INTEGER = 404
|
||||||
|
method_not_allowed: INTEGER = 405
|
||||||
|
not_acceptable: INTEGER = 406
|
||||||
|
proxy_auth_required: INTEGER = 407
|
||||||
|
request_timeout: INTEGER = 408
|
||||||
|
conflict: INTEGER = 409
|
||||||
|
gone: INTEGER = 410
|
||||||
|
length_required: INTEGER = 411
|
||||||
|
precondition_failed: INTEGER = 412
|
||||||
|
request_entity_too_large: INTEGER = 413
|
||||||
|
request_uri_too_long: INTEGER = 414
|
||||||
|
unsupported_media_type: INTEGER = 415
|
||||||
|
request_range_not_satisfiable: INTEGER = 416
|
||||||
|
expectation_failed: INTEGER = 417
|
||||||
|
teapot: INTEGER = 418
|
||||||
|
|
||||||
|
feature -- 4xx : Client Error : WebDAV errors
|
||||||
|
|
||||||
|
too_many_connections: INTEGER = 421
|
||||||
|
unprocessable_entity: INTEGER = 422
|
||||||
|
locked: INTEGER = 423
|
||||||
|
failed_dependency: INTEGER = 424
|
||||||
|
unordered_collection: INTEGER = 425
|
||||||
|
|
||||||
|
upgrade_required: INTEGER = 426
|
||||||
|
no_response: INTEGER = 444
|
||||||
|
retry_with: INTEGER = 449
|
||||||
|
blocked_parental: INTEGER = 450
|
||||||
|
client_closed_request: INTEGER = 499
|
||||||
|
|
||||||
|
feature -- 5xx : Server Error
|
||||||
|
|
||||||
|
internal_server_error: INTEGER = 500
|
||||||
|
not_implemented: INTEGER = 501
|
||||||
|
bad_gateway: INTEGER = 502
|
||||||
|
service_unavailable: INTEGER = 503
|
||||||
|
gateway_timeout: INTEGER = 504
|
||||||
|
http_version_not_supported: INTEGER = 505
|
||||||
|
variant_also_negotiates: INTEGER = 506
|
||||||
|
insufficient_storage: INTEGER = 507 -- WebDAV RFC 4918
|
||||||
|
|
||||||
|
bandwidth_limit_exceeded: INTEGER = 509
|
||||||
|
not_extended: INTEGER = 510
|
||||||
|
|
||||||
|
user_access_denied: INTEGER = 530
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Status code constants pertaining to the HTTP protocol
|
||||||
|
See http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
|
||||||
|
]"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
HTTP_STATUS_CODE_MESSAGES
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTP_STATUS_CODE
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
is_valid_http_status_code (v: INTEGER): BOOLEAN
|
||||||
|
-- Is the given value a valid http status code?
|
||||||
|
do
|
||||||
|
Result := v >= continue and v <= user_access_denied
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status messages
|
||||||
|
|
||||||
|
http_status_code_message (a_code: INTEGER): detachable STRING
|
||||||
|
-- Header message related to HTTP status code `a_code'
|
||||||
|
do
|
||||||
|
inspect a_code
|
||||||
|
when continue then
|
||||||
|
Result := "Continue"
|
||||||
|
when switching_protocols then
|
||||||
|
Result := "Switching Protocols"
|
||||||
|
when processing then
|
||||||
|
Result := "Processing"
|
||||||
|
when ok then
|
||||||
|
Result := "OK"
|
||||||
|
when created then
|
||||||
|
Result := "Created"
|
||||||
|
when accepted then
|
||||||
|
Result := "Accepted"
|
||||||
|
when nonauthoritative_info then
|
||||||
|
Result := "Non-Authoritative Information"
|
||||||
|
when no_content then
|
||||||
|
Result := "No Content"
|
||||||
|
when reset_content then
|
||||||
|
Result := "Reset Content"
|
||||||
|
when partial_content then
|
||||||
|
Result := "Partial Content"
|
||||||
|
when multistatus then
|
||||||
|
Result := "Multi-Status"
|
||||||
|
when multiple_choices then
|
||||||
|
Result := "Multiple Choices"
|
||||||
|
when moved_permanently then
|
||||||
|
Result := "Moved Permanently"
|
||||||
|
when found then
|
||||||
|
Result := "Found"
|
||||||
|
when see_other then
|
||||||
|
Result := "See Other"
|
||||||
|
when not_modified then
|
||||||
|
Result := "Not Modified"
|
||||||
|
when use_proxy then
|
||||||
|
Result := "Use Proxy"
|
||||||
|
when switch_proxy then
|
||||||
|
Result := "Switch Proxy"
|
||||||
|
when temp_redirect then
|
||||||
|
Result := "Temporary Redirect"
|
||||||
|
when bad_request then
|
||||||
|
Result := "Bad Request"
|
||||||
|
when unauthorized then
|
||||||
|
Result := "Unauthorized"
|
||||||
|
when payment_required then
|
||||||
|
Result := "Payment Required"
|
||||||
|
when forbidden then
|
||||||
|
Result := "Forbidden"
|
||||||
|
when not_found then
|
||||||
|
Result := "Not Found"
|
||||||
|
when method_not_allowed then
|
||||||
|
Result := "Method Not Allowed"
|
||||||
|
when not_acceptable then
|
||||||
|
Result := "Not Acceptable"
|
||||||
|
when proxy_auth_required then
|
||||||
|
Result := "Proxy Authentication Required"
|
||||||
|
when request_timeout then
|
||||||
|
Result := "Request Timeout"
|
||||||
|
when conflict then
|
||||||
|
Result := "Conflict"
|
||||||
|
when gone then
|
||||||
|
Result := "Gone"
|
||||||
|
when length_required then
|
||||||
|
Result := "Length Required"
|
||||||
|
when precondition_failed then
|
||||||
|
Result := "Precondition Failed"
|
||||||
|
when request_entity_too_large then
|
||||||
|
Result := "Request Entity Too Large"
|
||||||
|
when request_uri_too_long then
|
||||||
|
Result := "Request-URI Too Long"
|
||||||
|
when unsupported_media_type then
|
||||||
|
Result := "Unsupported Media Type"
|
||||||
|
when request_range_not_satisfiable then
|
||||||
|
Result := "Requested Range Not Satisfiable"
|
||||||
|
when expectation_failed then
|
||||||
|
Result := "Expectation Failed"
|
||||||
|
when teapot then
|
||||||
|
Result := "I'm a teapot"
|
||||||
|
when too_many_connections then
|
||||||
|
Result := "There are too many connections from your internet address"
|
||||||
|
when unprocessable_entity then
|
||||||
|
Result := "Unprocessable Entity"
|
||||||
|
when locked then
|
||||||
|
Result := "Locked"
|
||||||
|
when failed_dependency then
|
||||||
|
Result := "Failed Dependency"
|
||||||
|
when unordered_collection then
|
||||||
|
Result := "Unordered Collection"
|
||||||
|
when upgrade_required then
|
||||||
|
Result := "Upgrade Required"
|
||||||
|
when retry_with then
|
||||||
|
Result := "Retry With"
|
||||||
|
when blocked_parental then
|
||||||
|
Result := "Blocked by Windows Parental Controls"
|
||||||
|
when internal_server_error then
|
||||||
|
Result := "Internal Server Error"
|
||||||
|
when not_implemented then
|
||||||
|
Result := "Not Implemented"
|
||||||
|
when bad_gateway then
|
||||||
|
Result := "Bad Gateway"
|
||||||
|
when service_unavailable then
|
||||||
|
Result := "Service Unavailable"
|
||||||
|
when gateway_timeout then
|
||||||
|
Result := "Gateway Timeout"
|
||||||
|
when http_version_not_supported then
|
||||||
|
Result := "HTTP Version Not Supported"
|
||||||
|
when variant_also_negotiates then
|
||||||
|
Result := "Variant Also Negotiates"
|
||||||
|
when insufficient_storage then
|
||||||
|
Result := "Insufficient Storage"
|
||||||
|
when bandwidth_limit_exceeded then
|
||||||
|
Result := "Bandwidth Limit Exceeded"
|
||||||
|
when not_extended then
|
||||||
|
Result := "Not Extended"
|
||||||
|
when user_access_denied then
|
||||||
|
Result := "User access denied"
|
||||||
|
else
|
||||||
|
Result := Void
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
Most recent spec/draft/in-progress http://code.google.com/p/uri-templates/source/browse/trunk/spec/draft-gregorio-uritemplate.xml
|
||||||
|
|
||||||
|
svn cat http://uri-templates.googlecode.com/svn/trunk/spec/draft-gregorio-uritemplate.xml > uritemplate-draft-gregorio-trunk.xml
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
|||||||
|
${NOTE_KEYWORD}
|
||||||
|
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Summary description for {URI_TEMPLATE_CONSTANTS}.
|
||||||
|
|
||||||
|
see http://tools.ietf.org/html/draft-gregorio-uritemplate-05
|
||||||
|
]"
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Operator
|
||||||
|
|
||||||
|
Reserved_operator: CHARACTER = '+'
|
||||||
|
|
||||||
|
Form_style_query_operator: CHARACTER = '?'
|
||||||
|
|
||||||
|
Path_style_parameters_operator: CHARACTER = ';'
|
||||||
|
|
||||||
|
Path_segment_operator: CHARACTER = '/'
|
||||||
|
|
||||||
|
Label_operator: CHARACTER = '.'
|
||||||
|
|
||||||
|
feature -- Separator
|
||||||
|
|
||||||
|
Default_delimiter: CHARACTER = '|' --| Draft 05
|
||||||
|
|
||||||
|
feature -- Explode
|
||||||
|
|
||||||
|
Explode_plus: CHARACTER = '+'
|
||||||
|
|
||||||
|
Explode_star: CHARACTER = '*'
|
||||||
|
|
||||||
|
feature -- Modified
|
||||||
|
|
||||||
|
Modifier_substring: CHARACTER = ':'
|
||||||
|
|
||||||
|
Modifier_remainder: CHARACTER = '^'
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,381 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Summary description for {URI_TEMPLATE}.
|
||||||
|
|
||||||
|
See http://tools.ietf.org/html/draft-gregorio-uritemplate-04
|
||||||
|
|
||||||
|
note for draft 05, check {URI_TEMPLATE_CONSTANTS}.Default_delimiter
|
||||||
|
|
||||||
|
]"
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HASHABLE
|
||||||
|
|
||||||
|
DEBUG_OUTPUT
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (s: STRING)
|
||||||
|
do
|
||||||
|
template := s
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
template: STRING
|
||||||
|
-- URI string representation
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
debug_output: STRING
|
||||||
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
|
do
|
||||||
|
create Result.make_from_string (template)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
hash_code: INTEGER
|
||||||
|
-- Hash code value
|
||||||
|
do
|
||||||
|
Result := template.hash_code
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Structures
|
||||||
|
|
||||||
|
variable_names: LIST [STRING]
|
||||||
|
-- All variable names
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
if attached expressions as l_expressions then
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (l_expressions.count)
|
||||||
|
from
|
||||||
|
l_expressions.start
|
||||||
|
until
|
||||||
|
l_expressions.after
|
||||||
|
loop
|
||||||
|
Result.append (l_expressions.item.variable_names)
|
||||||
|
l_expressions.forth
|
||||||
|
end
|
||||||
|
else
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
path_variable_names: LIST [STRING]
|
||||||
|
-- All variable names part of the path
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
if attached expressions as l_expressions then
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (l_expressions.count)
|
||||||
|
from
|
||||||
|
l_expressions.start
|
||||||
|
until
|
||||||
|
l_expressions.after
|
||||||
|
loop
|
||||||
|
if not l_expressions.item.is_query then
|
||||||
|
Result.append (l_expressions.item.variable_names)
|
||||||
|
end
|
||||||
|
l_expressions.forth
|
||||||
|
end
|
||||||
|
else
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
query_variable_names: LIST [STRING]
|
||||||
|
-- All variable names part of the query (i.e after '?')
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
if attached expressions as l_expressions then
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (l_expressions.count)
|
||||||
|
from
|
||||||
|
l_expressions.start
|
||||||
|
until
|
||||||
|
l_expressions.after
|
||||||
|
loop
|
||||||
|
if l_expressions.item.is_query then
|
||||||
|
Result.append (l_expressions.item.variable_names)
|
||||||
|
end
|
||||||
|
l_expressions.forth
|
||||||
|
end
|
||||||
|
else
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Builder
|
||||||
|
|
||||||
|
expanded_string (a_ht: HASH_TABLE [detachable ANY, STRING]): STRING
|
||||||
|
-- Expanded template using variable from `a_ht'
|
||||||
|
local
|
||||||
|
tpl: like template
|
||||||
|
exp: URI_TEMPLATE_EXPRESSION
|
||||||
|
p,q: INTEGER
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
tpl := template
|
||||||
|
if attached expressions as l_expressions then
|
||||||
|
create Result.make (tpl.count)
|
||||||
|
from
|
||||||
|
l_expressions.start
|
||||||
|
p := 1
|
||||||
|
until
|
||||||
|
l_expressions.after
|
||||||
|
loop
|
||||||
|
q := l_expressions.item.position
|
||||||
|
--| Added inter variable text
|
||||||
|
Result.append (tpl.substring (p, q - 1))
|
||||||
|
--| Expand variables ...
|
||||||
|
exp := l_expressions.item
|
||||||
|
exp.append_expanded_to_string (a_ht, Result)
|
||||||
|
|
||||||
|
p := q + l_expressions.item.expression.count + 2
|
||||||
|
|
||||||
|
l_expressions.forth
|
||||||
|
end
|
||||||
|
Result.append (tpl.substring (p, tpl.count))
|
||||||
|
else
|
||||||
|
create Result.make_from_string (tpl)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Match
|
||||||
|
|
||||||
|
match (a_uri: STRING): detachable URI_TEMPLATE_MATCH_RESULT
|
||||||
|
local
|
||||||
|
b: BOOLEAN
|
||||||
|
tpl: like template
|
||||||
|
l_offset: INTEGER
|
||||||
|
p,q: INTEGER
|
||||||
|
exp: URI_TEMPLATE_EXPRESSION
|
||||||
|
vn, s,t: STRING
|
||||||
|
vv: STRING
|
||||||
|
l_vars, l_path_vars, l_query_vars: HASH_TABLE [STRING, STRING]
|
||||||
|
l_uri_count: INTEGER
|
||||||
|
do
|
||||||
|
--| Extract expansion parts "\\{([^\\}]*)\\}"
|
||||||
|
analyze
|
||||||
|
if attached expressions as l_expressions then
|
||||||
|
create l_path_vars.make (l_expressions.count)
|
||||||
|
create l_query_vars.make (l_expressions.count)
|
||||||
|
l_vars := l_path_vars
|
||||||
|
b := True
|
||||||
|
l_uri_count := a_uri.count
|
||||||
|
tpl := template
|
||||||
|
if l_expressions.is_empty then
|
||||||
|
b := a_uri.substring (1, tpl.count).same_string (tpl)
|
||||||
|
else
|
||||||
|
from
|
||||||
|
l_expressions.start
|
||||||
|
p := 0
|
||||||
|
l_offset := 0
|
||||||
|
until
|
||||||
|
l_expressions.after or not b
|
||||||
|
loop
|
||||||
|
exp := l_expressions.item
|
||||||
|
vn := exp.expression
|
||||||
|
q := exp.position
|
||||||
|
--| Check text between vars
|
||||||
|
if p = q then
|
||||||
|
--| There should be at least one literal between two expression
|
||||||
|
--| {var}{foobar} is ambigous for matching ...
|
||||||
|
b := False
|
||||||
|
elseif q > p then
|
||||||
|
if p = 0 then
|
||||||
|
p := 1
|
||||||
|
end
|
||||||
|
t := tpl.substring (p, q - 1)
|
||||||
|
s := a_uri.substring (p + l_offset, q + l_offset - 1)
|
||||||
|
b := s.same_string (t)
|
||||||
|
p := exp.end_position
|
||||||
|
end
|
||||||
|
--| Check related variable
|
||||||
|
if b and then not vn.is_empty then
|
||||||
|
if exp.is_query then
|
||||||
|
l_vars := l_query_vars
|
||||||
|
else
|
||||||
|
l_vars := l_path_vars
|
||||||
|
end
|
||||||
|
if q + l_offset <= l_uri_count then
|
||||||
|
inspect vn[1]
|
||||||
|
when '?' then
|
||||||
|
import_form_style_parameters_into (a_uri.substring (q + l_offset + 1, l_uri_count), l_vars)
|
||||||
|
when ';' then
|
||||||
|
import_path_style_parameters_into (a_uri.substring (q + l_offset, l_uri_count), l_vars)
|
||||||
|
else
|
||||||
|
vv := next_path_variable_value (a_uri, q + l_offset)
|
||||||
|
l_vars.force (vv, vn)
|
||||||
|
l_offset := l_offset + vv.count - (vn.count + 2)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
b := exp.is_query --| query are optional
|
||||||
|
end
|
||||||
|
end
|
||||||
|
l_expressions.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if b then
|
||||||
|
create Result.make (l_path_vars, l_query_vars)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Internal Access
|
||||||
|
|
||||||
|
expressions: detachable LIST [URI_TEMPLATE_EXPRESSION]
|
||||||
|
-- Expansion parts
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
analyze
|
||||||
|
local
|
||||||
|
l_expressions: like expressions
|
||||||
|
c: CHARACTER
|
||||||
|
i,p,n: INTEGER
|
||||||
|
tpl: like template
|
||||||
|
in_x: BOOLEAN
|
||||||
|
in_query: BOOLEAN
|
||||||
|
x: STRING
|
||||||
|
exp: URI_TEMPLATE_EXPRESSION
|
||||||
|
do
|
||||||
|
l_expressions := expressions
|
||||||
|
if l_expressions = Void then
|
||||||
|
tpl := template
|
||||||
|
|
||||||
|
--| Extract expansion parts "\\{([^\\}]*)\\}"
|
||||||
|
create {ARRAYED_LIST [like expressions.item]} l_expressions.make (tpl.occurrences ('{'))
|
||||||
|
from
|
||||||
|
i := 1
|
||||||
|
n := tpl.count
|
||||||
|
create x.make_empty
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
c := tpl[i]
|
||||||
|
if in_x then
|
||||||
|
if c = '}' then
|
||||||
|
create exp.make (p, x.twin, in_query)
|
||||||
|
l_expressions.force (exp)
|
||||||
|
x.wipe_out
|
||||||
|
in_x := False
|
||||||
|
else
|
||||||
|
x.extend (c)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
inspect c
|
||||||
|
when '{' then
|
||||||
|
check x_is_empty: x.is_empty end
|
||||||
|
p := i
|
||||||
|
in_x := True
|
||||||
|
if not in_query then
|
||||||
|
in_query := tpl.valid_index (i+1) and then tpl[i+1] = '?'
|
||||||
|
end
|
||||||
|
when '?' then
|
||||||
|
in_query := True
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
expressions := l_expressions
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
import_path_style_parameters_into (a_content: STRING; res: HASH_TABLE [STRING, STRING])
|
||||||
|
require
|
||||||
|
a_content_attached: a_content /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
do
|
||||||
|
import_custom_style_parameters_into (a_content, ';', res)
|
||||||
|
end
|
||||||
|
|
||||||
|
import_form_style_parameters_into (a_content: STRING; res: HASH_TABLE [STRING, STRING])
|
||||||
|
require
|
||||||
|
a_content_attached: a_content /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
do
|
||||||
|
import_custom_style_parameters_into (a_content, '&', res)
|
||||||
|
end
|
||||||
|
|
||||||
|
import_custom_style_parameters_into (a_content: STRING; a_separator: CHARACTER; res: HASH_TABLE [STRING, STRING])
|
||||||
|
require
|
||||||
|
a_content_attached: a_content /= Void
|
||||||
|
res_attached: res /= Void
|
||||||
|
local
|
||||||
|
n, p, i, j: INTEGER
|
||||||
|
s: STRING
|
||||||
|
l_name,l_value: STRING
|
||||||
|
do
|
||||||
|
n := a_content.count
|
||||||
|
if n > 0 then
|
||||||
|
from
|
||||||
|
p := 1
|
||||||
|
until
|
||||||
|
p = 0
|
||||||
|
loop
|
||||||
|
i := a_content.index_of (a_separator, p)
|
||||||
|
if i = 0 then
|
||||||
|
s := a_content.substring (p, n)
|
||||||
|
p := 0
|
||||||
|
else
|
||||||
|
s := a_content.substring (p, i - 1)
|
||||||
|
p := i + 1
|
||||||
|
end
|
||||||
|
if not s.is_empty then
|
||||||
|
j := s.index_of ('=', 1)
|
||||||
|
if j > 0 then
|
||||||
|
l_name := s.substring (1, j - 1)
|
||||||
|
l_value := s.substring (j + 1, s.count)
|
||||||
|
res.force (l_value, l_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
next_path_variable_value (a_uri: STRING; a_index: INTEGER): STRING
|
||||||
|
require
|
||||||
|
valid_index: a_index <= a_uri.count
|
||||||
|
local
|
||||||
|
i,n,p: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
i := a_index
|
||||||
|
n := a_uri.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
inspect a_uri[i]
|
||||||
|
when '/', '?' then
|
||||||
|
i := n
|
||||||
|
else
|
||||||
|
p := i
|
||||||
|
end
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
Result := a_uri.substring (a_index, p)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Summary description for {URI_TEMPLATE_CONSTANTS}.
|
||||||
|
|
||||||
|
see http://tools.ietf.org/html/draft-gregorio-uritemplate-04
|
||||||
|
]"
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE_CONSTANTS
|
||||||
|
|
||||||
|
feature -- Operator
|
||||||
|
|
||||||
|
Reserved_operator: CHARACTER = '+'
|
||||||
|
|
||||||
|
Form_style_query_operator: CHARACTER = '?'
|
||||||
|
|
||||||
|
Path_style_parameters_operator: CHARACTER = ';'
|
||||||
|
|
||||||
|
Path_segment_operator: CHARACTER = '/'
|
||||||
|
|
||||||
|
Label_operator: CHARACTER = '.'
|
||||||
|
|
||||||
|
feature -- Separator
|
||||||
|
|
||||||
|
Default_delimiter: CHARACTER = '=' --| Draft 0.4 , change to '|' for Draft 0.5
|
||||||
|
|
||||||
|
feature -- Explode
|
||||||
|
|
||||||
|
Explode_plus: CHARACTER = '+'
|
||||||
|
|
||||||
|
Explode_star: CHARACTER = '*'
|
||||||
|
|
||||||
|
feature -- Modified
|
||||||
|
|
||||||
|
Modifier_substring: CHARACTER = ':'
|
||||||
|
|
||||||
|
Modifier_remainder: CHARACTER = '^'
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {URI_TEMPLATE_EXPRESSION}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE_EXPRESSION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ANY
|
||||||
|
|
||||||
|
DEBUG_OUTPUT
|
||||||
|
|
||||||
|
URI_TEMPLATE_CONSTANTS
|
||||||
|
export {NONE} all end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_position: INTEGER; a_expression: STRING; a_is_query: BOOLEAN)
|
||||||
|
do
|
||||||
|
position := a_position
|
||||||
|
expression := a_expression
|
||||||
|
is_query := a_is_query
|
||||||
|
operator := '%U'
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Processing
|
||||||
|
|
||||||
|
analyze
|
||||||
|
local
|
||||||
|
exp: like expression
|
||||||
|
s: detachable STRING
|
||||||
|
lst: LIST [STRING]
|
||||||
|
p: INTEGER
|
||||||
|
vars: like variables
|
||||||
|
vn: STRING
|
||||||
|
vmodifier: detachable STRING
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
if not is_analyzed then
|
||||||
|
exp := expression
|
||||||
|
if not exp.is_empty then
|
||||||
|
op_prefix := '%U'
|
||||||
|
op_delimiter := ','
|
||||||
|
inspect exp[1]
|
||||||
|
when Reserved_operator then
|
||||||
|
--| '+'
|
||||||
|
reserved := True
|
||||||
|
operator := '+'
|
||||||
|
when Label_operator then
|
||||||
|
--| '.'
|
||||||
|
operator := '.'
|
||||||
|
op_prefix := '.'
|
||||||
|
op_delimiter := '.'
|
||||||
|
when Path_segment_operator then
|
||||||
|
--| '/'
|
||||||
|
operator := '/'
|
||||||
|
op_prefix := '/'
|
||||||
|
op_delimiter := '/'
|
||||||
|
when Path_style_parameters_operator then
|
||||||
|
--| ';'
|
||||||
|
operator := ';'
|
||||||
|
op_prefix := ';'
|
||||||
|
op_delimiter := ';'
|
||||||
|
when Form_style_query_operator then
|
||||||
|
--| '?'
|
||||||
|
operator := '?'
|
||||||
|
op_prefix := '?'
|
||||||
|
op_delimiter := '&'
|
||||||
|
when '|', '!', '@' then
|
||||||
|
operator := exp[1]
|
||||||
|
else
|
||||||
|
operator := '%U'
|
||||||
|
end
|
||||||
|
if operator /= '%U' then
|
||||||
|
s := exp.substring (2, exp.count)
|
||||||
|
else
|
||||||
|
s := exp
|
||||||
|
end
|
||||||
|
|
||||||
|
lst := s.split (',')
|
||||||
|
from
|
||||||
|
create {ARRAYED_LIST [like variables.item]} vars.make (lst.count)
|
||||||
|
lst.start
|
||||||
|
until
|
||||||
|
lst.after
|
||||||
|
loop
|
||||||
|
s := lst.item
|
||||||
|
vmodifier := Void
|
||||||
|
p := s.index_of (Default_delimiter, 1)
|
||||||
|
if p > 0 then
|
||||||
|
vn := s.substring (1, p - 1)
|
||||||
|
s := s.substring (p + 1, s.count)
|
||||||
|
else
|
||||||
|
vn := s
|
||||||
|
s := Void
|
||||||
|
end
|
||||||
|
from
|
||||||
|
vmodifier := Void
|
||||||
|
i := 1
|
||||||
|
n := vn.count
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
inspect vn[i]
|
||||||
|
when Explode_plus, Explode_star, Modifier_substring, Modifier_remainder then
|
||||||
|
vmodifier := vn.substring (i, n)
|
||||||
|
vn := vn.substring (1, i - 1)
|
||||||
|
i := n + 1 --| exit
|
||||||
|
else
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vars.force (create {URI_TEMPLATE_EXPRESSION_VARIABLE}.make (Current, vn, s, vmodifier))
|
||||||
|
lst.forth
|
||||||
|
end
|
||||||
|
variables := vars
|
||||||
|
end
|
||||||
|
is_analyzed := True
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
position: INTEGER
|
||||||
|
-- Character position on Current in the template
|
||||||
|
|
||||||
|
end_position: INTEGER
|
||||||
|
do
|
||||||
|
Result := position + expression.count + 2 --| '{' + `expression' + '}'
|
||||||
|
end
|
||||||
|
|
||||||
|
expression: STRING
|
||||||
|
-- Operator? + VariableName + modifier
|
||||||
|
|
||||||
|
is_query: BOOLEAN
|
||||||
|
-- Is in the query part (i.e: after '?' ?)
|
||||||
|
|
||||||
|
feature -- Status
|
||||||
|
|
||||||
|
operator: CHARACTER
|
||||||
|
-- First character of `expression' if among
|
||||||
|
|
||||||
|
reserved: BOOLEAN
|
||||||
|
-- Is reserved
|
||||||
|
-- i.e: do not url-encode the reserved character
|
||||||
|
|
||||||
|
op_prefix: CHARACTER
|
||||||
|
-- When expanding list of table, first character to use
|
||||||
|
--| ex: '?' for {?var}
|
||||||
|
|
||||||
|
op_delimiter: CHARACTER
|
||||||
|
-- When expanding list of table, delimiter character to use
|
||||||
|
--| ex: ',' for {?var}
|
||||||
|
|
||||||
|
variables: detachable LIST [URI_TEMPLATE_EXPRESSION_VARIABLE]
|
||||||
|
-- List of variables declared in `expression'
|
||||||
|
--| ex: "foo", "bar" for {?foo,bar}
|
||||||
|
|
||||||
|
variable_names: LIST [STRING]
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
if attached variables as vars then
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (vars.count)
|
||||||
|
from
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
vars.after
|
||||||
|
loop
|
||||||
|
Result.force (vars.item.name)
|
||||||
|
vars.forth
|
||||||
|
end
|
||||||
|
else
|
||||||
|
create {ARRAYED_LIST [STRING]} Result.make (0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
is_analyzed: BOOLEAN
|
||||||
|
|
||||||
|
feature -- Report
|
||||||
|
|
||||||
|
append_expanded_to_string (a_ht: HASH_TABLE [detachable ANY, STRING]; a_buffer: STRING)
|
||||||
|
do
|
||||||
|
analyze
|
||||||
|
if attached variables as vars then
|
||||||
|
append_custom_variables_to_string (a_ht, vars, op_prefix, op_delimiter, True, a_buffer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
append_custom_variables_to_string (a_ht: HASH_TABLE [detachable ANY, STRING]; vars: like variables; prefix_char, delimiter_char: CHARACTER; a_include_name: BOOLEAN; a_buffer: STRING)
|
||||||
|
-- If `first_char' is '%U' do not print any first character
|
||||||
|
local
|
||||||
|
vi: like variables.item
|
||||||
|
l_is_first: BOOLEAN
|
||||||
|
vdata: detachable ANY
|
||||||
|
vstr: detachable STRING
|
||||||
|
l_use_default: BOOLEAN
|
||||||
|
do
|
||||||
|
if vars /= Void then
|
||||||
|
from
|
||||||
|
vars.start
|
||||||
|
l_is_first := True
|
||||||
|
until
|
||||||
|
vars.after
|
||||||
|
loop
|
||||||
|
vi := vars.item
|
||||||
|
vdata := a_ht.item (vi.name)
|
||||||
|
vstr := Void
|
||||||
|
if vdata /= Void then
|
||||||
|
vstr := vi.expanded_string (vdata)
|
||||||
|
if vstr = Void and vi.has_explode then
|
||||||
|
--| Missing or list empty
|
||||||
|
vstr := vi.default_value
|
||||||
|
l_use_default := True
|
||||||
|
else
|
||||||
|
l_use_default := False
|
||||||
|
end
|
||||||
|
else
|
||||||
|
--| Missing
|
||||||
|
vstr := vi.default_value
|
||||||
|
l_use_default := True
|
||||||
|
end
|
||||||
|
if vstr /= Void then
|
||||||
|
if l_is_first then
|
||||||
|
if prefix_char /= '%U' then
|
||||||
|
a_buffer.append_character (prefix_char)
|
||||||
|
end
|
||||||
|
l_is_first := False
|
||||||
|
else
|
||||||
|
a_buffer.append_character (delimiter_char)
|
||||||
|
end
|
||||||
|
if l_use_default and (operator = Form_style_query_operator) and not vi.has_explode_star then
|
||||||
|
a_buffer.append (vi.name)
|
||||||
|
if vi.has_explode_plus then
|
||||||
|
a_buffer.append_character ('.')
|
||||||
|
else
|
||||||
|
a_buffer.append_character ('=')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
a_buffer.append (vstr)
|
||||||
|
end
|
||||||
|
vars.forth
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status report
|
||||||
|
|
||||||
|
debug_output: STRING
|
||||||
|
-- String that should be displayed in debugger to represent `Current'.
|
||||||
|
do
|
||||||
|
Result := expression
|
||||||
|
end
|
||||||
|
|
||||||
|
;note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,412 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {URI_TEMPLATE_EXPRESSION_VARIABLE}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE_EXPRESSION_VARIABLE
|
||||||
|
|
||||||
|
inherit
|
||||||
|
ANY
|
||||||
|
|
||||||
|
URI_TEMPLATE_CONSTANTS
|
||||||
|
export {NONE} all end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (exp: like expression; n: like name; d: like default_value; em: detachable STRING)
|
||||||
|
-- Create based on expression `exp', variable name `n', default value `d' if any
|
||||||
|
-- and explode or modifier string `em'
|
||||||
|
do
|
||||||
|
expression := exp
|
||||||
|
operator := exp.operator
|
||||||
|
name := n
|
||||||
|
default_value := d
|
||||||
|
if em /= Void and then em.count > 0 then
|
||||||
|
inspect em[1]
|
||||||
|
when Explode_star, Explode_plus then
|
||||||
|
explode := em[1]
|
||||||
|
when Modifier_substring, Modifier_remainder then
|
||||||
|
modifier := em
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
op_prefix := '%U'
|
||||||
|
op_separator := ','
|
||||||
|
|
||||||
|
inspect operator
|
||||||
|
when Reserved_operator then --| '+'
|
||||||
|
reserved := True
|
||||||
|
when Form_style_query_operator then --| '?'
|
||||||
|
op_prefix := '?'
|
||||||
|
op_separator := '&'
|
||||||
|
when Path_style_parameters_operator then --| ';'
|
||||||
|
op_prefix := ';'
|
||||||
|
op_separator := ';'
|
||||||
|
when Path_segment_operator then --| '/'
|
||||||
|
op_prefix := '/'
|
||||||
|
op_separator := '/'
|
||||||
|
when Label_operator then --| '.'
|
||||||
|
op_prefix := '.'
|
||||||
|
op_separator := '.'
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
expression: URI_TEMPLATE_EXPRESSION
|
||||||
|
-- Parent expression
|
||||||
|
|
||||||
|
operator: CHARACTER
|
||||||
|
-- First character of related `expression'
|
||||||
|
|
||||||
|
name: STRING
|
||||||
|
-- variable name
|
||||||
|
|
||||||
|
default_value: detachable STRING
|
||||||
|
-- default value if any
|
||||||
|
|
||||||
|
reserved: BOOLEAN
|
||||||
|
-- Is reserved?
|
||||||
|
-- i.e: do not url-encode the reserved character
|
||||||
|
|
||||||
|
op_prefix: CHARACTER
|
||||||
|
-- When expanding list of table, first character to use
|
||||||
|
--| ex: '?' for {?var}
|
||||||
|
|
||||||
|
op_separator: CHARACTER
|
||||||
|
-- When expanding list of table, delimiter character to use
|
||||||
|
--| ex: ',' for {?var}
|
||||||
|
|
||||||
|
explode: CHARACTER
|
||||||
|
-- Explode character , '*' or '+'
|
||||||
|
|
||||||
|
modifier: detachable STRING
|
||||||
|
-- Modifier expression, starting by ':' or '^'
|
||||||
|
--| ":3" , "-3", "^4", ...
|
||||||
|
|
||||||
|
modified_string (s: READABLE_STRING_GENERAL): READABLE_STRING_GENERAL
|
||||||
|
local
|
||||||
|
t: STRING
|
||||||
|
i,n: INTEGER
|
||||||
|
do
|
||||||
|
Result := s
|
||||||
|
if attached modifier as m and then m.count > 1 then
|
||||||
|
n := s.count
|
||||||
|
t := m.substring (2, m.count)
|
||||||
|
if t.is_integer then
|
||||||
|
i := t.to_integer
|
||||||
|
inspect m[1]
|
||||||
|
when Modifier_substring then
|
||||||
|
if i > 0 then
|
||||||
|
if i < n then
|
||||||
|
Result := s.substring (1, i)
|
||||||
|
end
|
||||||
|
elseif i < 0 then
|
||||||
|
Result := s.substring (n - i, n)
|
||||||
|
end
|
||||||
|
when Modifier_remainder then
|
||||||
|
if i > 0 then
|
||||||
|
if i < n then
|
||||||
|
Result := s.substring (i + 1, n)
|
||||||
|
end
|
||||||
|
elseif i < 0 then
|
||||||
|
Result := s.substring (1, n + i) --| n + i = n - (-i)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
check Known_modified: False end
|
||||||
|
-- Unchanged
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
has_explode: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := explode = Explode_plus or explode = Explode_star
|
||||||
|
end
|
||||||
|
|
||||||
|
has_explode_plus: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := explode = Explode_plus
|
||||||
|
end
|
||||||
|
|
||||||
|
has_explode_star: BOOLEAN
|
||||||
|
do
|
||||||
|
Result := explode = Explode_star
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Report
|
||||||
|
|
||||||
|
expanded_string (d: detachable ANY): detachable STRING
|
||||||
|
local
|
||||||
|
l_delimiter: CHARACTER
|
||||||
|
v_enc: detachable STRING
|
||||||
|
k_enc: STRING
|
||||||
|
l_obj: detachable ANY
|
||||||
|
i,n: INTEGER
|
||||||
|
explode_is_plus: BOOLEAN
|
||||||
|
explode_is_star: BOOLEAN
|
||||||
|
l_has_explode: BOOLEAN
|
||||||
|
dft: detachable ANY
|
||||||
|
has_list_op: BOOLEAN
|
||||||
|
op: like operator
|
||||||
|
do
|
||||||
|
l_has_explode := has_explode
|
||||||
|
if l_has_explode then
|
||||||
|
explode_is_plus := has_explode_plus
|
||||||
|
explode_is_star := has_explode_star
|
||||||
|
end
|
||||||
|
op := operator
|
||||||
|
has_list_op := op /= '%U' and op /= Reserved_operator
|
||||||
|
dft := default_value
|
||||||
|
create Result.make (20)
|
||||||
|
if attached {READABLE_STRING_GENERAL} d as l_string then
|
||||||
|
v_enc := url_encoded_string (modified_string (l_string), not reserved)
|
||||||
|
if op = Form_style_query_operator then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
elseif op = Path_style_parameters_operator then
|
||||||
|
Result.append (name)
|
||||||
|
if not v_enc.is_empty then
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Result.append (v_enc)
|
||||||
|
elseif attached {ARRAY [detachable ANY]} d as l_array then
|
||||||
|
if l_array.is_empty then
|
||||||
|
if dft /= Void then
|
||||||
|
inspect op
|
||||||
|
when Form_style_query_operator, Path_style_parameters_operator then
|
||||||
|
if not l_has_explode then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
Result.append (dft.out)
|
||||||
|
else
|
||||||
|
if explode_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
when Path_segment_operator then
|
||||||
|
if explode_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
when Label_operator then
|
||||||
|
else
|
||||||
|
if l_has_explode then
|
||||||
|
if explode_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- nothing ...
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if l_has_explode then
|
||||||
|
l_delimiter := op_separator
|
||||||
|
else
|
||||||
|
l_delimiter := ','
|
||||||
|
inspect op
|
||||||
|
when Form_style_query_operator then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
from
|
||||||
|
i := l_array.lower
|
||||||
|
n := l_array.upper
|
||||||
|
until
|
||||||
|
i > n
|
||||||
|
loop
|
||||||
|
l_obj := l_array[i]
|
||||||
|
if l_obj /= Void then
|
||||||
|
v_enc := url_encoded_string (l_obj.out, not reserved)
|
||||||
|
else
|
||||||
|
v_enc := ""
|
||||||
|
end
|
||||||
|
if explode_is_plus then
|
||||||
|
if
|
||||||
|
(op = Form_style_query_operator and explode_is_plus) or
|
||||||
|
(op = Path_style_parameters_operator and l_has_explode)
|
||||||
|
then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
else
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
elseif explode_is_star and op = Form_style_query_operator then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
Result.append (v_enc)
|
||||||
|
if i < n then
|
||||||
|
Result.append_character (l_delimiter)
|
||||||
|
end
|
||||||
|
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Result.is_empty then
|
||||||
|
Result := Void
|
||||||
|
end
|
||||||
|
elseif attached {HASH_TABLE [detachable ANY, STRING]} d as l_table then
|
||||||
|
if l_table.is_empty then
|
||||||
|
if dft /= Void then
|
||||||
|
inspect op
|
||||||
|
when Form_style_query_operator, Path_style_parameters_operator then
|
||||||
|
if not l_has_explode then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
Result.append (dft.out)
|
||||||
|
else
|
||||||
|
if explode_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
when Path_segment_operator then
|
||||||
|
if explode_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
when Label_operator then
|
||||||
|
else
|
||||||
|
if l_has_explode then
|
||||||
|
if explode_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
Result.append (dft.out)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- nothing ...
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if l_has_explode then
|
||||||
|
l_delimiter := op_separator
|
||||||
|
else
|
||||||
|
l_delimiter := ','
|
||||||
|
inspect op
|
||||||
|
when Form_style_query_operator then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('=')
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
from
|
||||||
|
l_table.start
|
||||||
|
until
|
||||||
|
l_table.after
|
||||||
|
loop
|
||||||
|
k_enc := url_encoded_string (l_table.key_for_iteration, not reserved)
|
||||||
|
l_obj := l_table.item_for_iteration
|
||||||
|
if l_obj /= Void then
|
||||||
|
v_enc := url_encoded_string (l_obj.out, not reserved)
|
||||||
|
else
|
||||||
|
v_enc := ""
|
||||||
|
end
|
||||||
|
|
||||||
|
if explode_is_plus then
|
||||||
|
Result.append (name)
|
||||||
|
Result.append_character ('.')
|
||||||
|
end
|
||||||
|
if
|
||||||
|
l_has_explode
|
||||||
|
then
|
||||||
|
Result.append (k_enc)
|
||||||
|
Result.append_character ('=')
|
||||||
|
else
|
||||||
|
Result.append (k_enc)
|
||||||
|
Result.append_character (l_delimiter)
|
||||||
|
end
|
||||||
|
Result.append (v_enc)
|
||||||
|
|
||||||
|
l_table.forth
|
||||||
|
if not l_table.after then
|
||||||
|
Result.append_character (l_delimiter)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if Result.is_empty then
|
||||||
|
Result := Void
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if d /= Void then
|
||||||
|
v_enc := url_encoded_string (d.out, not reserved)
|
||||||
|
elseif dft /= Void then
|
||||||
|
v_enc := url_encoded_string (dft.out, not reserved)
|
||||||
|
else
|
||||||
|
v_enc := default_value
|
||||||
|
end
|
||||||
|
if op = Form_style_query_operator then
|
||||||
|
Result.append (name)
|
||||||
|
if v_enc /= Void then
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
elseif op = Path_style_parameters_operator then
|
||||||
|
Result.append (name)
|
||||||
|
if v_enc /= Void and then not v_enc.is_empty then
|
||||||
|
Result.append_character ('=')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if v_enc /= Void then
|
||||||
|
Result.append (v_enc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
url_encoded_string (s: READABLE_STRING_GENERAL; a_encoded: BOOLEAN): STRING
|
||||||
|
do
|
||||||
|
if a_encoded then
|
||||||
|
Result := url_encoder.encoded_string (s.as_string_32)
|
||||||
|
else
|
||||||
|
Result := url_encoder.partial_encoded_string (s.as_string_32, <<
|
||||||
|
':', ',',
|
||||||
|
Reserved_operator,
|
||||||
|
Label_operator,
|
||||||
|
Path_segment_operator,
|
||||||
|
Path_style_parameters_operator,
|
||||||
|
Form_style_query_operator,
|
||||||
|
'|', '!', '@'
|
||||||
|
>>)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
url_encoder: URL_ENCODER
|
||||||
|
once
|
||||||
|
create Result
|
||||||
|
end
|
||||||
|
|
||||||
|
;note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {URI_TEMPLATE_HANDLER}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
URI_TEMPLATE_HANDLER
|
||||||
|
|
||||||
|
feature -- Events
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {URI_TEMPLATE_MATCH_RESULT}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
URI_TEMPLATE_MATCH_RESULT
|
||||||
|
|
||||||
|
create
|
||||||
|
make,
|
||||||
|
make_empty
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (p: like path_variables; q: like query_variables)
|
||||||
|
do
|
||||||
|
path_variables := p
|
||||||
|
query_variables := q
|
||||||
|
end
|
||||||
|
|
||||||
|
make_empty
|
||||||
|
do
|
||||||
|
make (create {like path_variables}.make (0), create {like query_variables}.make (0))
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
variable (n: STRING): detachable STRING
|
||||||
|
-- Value related to variable name `n'
|
||||||
|
do
|
||||||
|
Result := query_variables.item (n)
|
||||||
|
if Result = Void then
|
||||||
|
Result := path_variables.item (n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
path_variables: HASH_TABLE [STRING, STRING]
|
||||||
|
-- Variables being part of the path segments
|
||||||
|
|
||||||
|
query_variables: HASH_TABLE [STRING, STRING]
|
||||||
|
-- Variables being part of the query segments (i.e: after the ? )
|
||||||
|
|
||||||
|
;note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="test_uri_template_draft_05" uuid="1B44EA8C-7D88-4823-B16A-C9FA8DA3ACFF" library_target="test_uri_template_draft_05">
|
||||||
|
<target name="test_uri_template_draft_05">
|
||||||
|
<root class="ANY" feature="default_create"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<variable name="uri_template" value="draft_05"/>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||||
|
<library name="uri_template" location="uri_template-safe.ecf"/>
|
||||||
|
<tests name="tests" location=".\tests\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/test_uri_template.e$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
</tests>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,638 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Eiffel tests that can be executed by testing tool.
|
||||||
|
]"
|
||||||
|
author: "EiffelStudio test wizard"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
testing: "type/manual"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEST_URI_TEMPLATE_DRAFT_05
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EQA_TEST_SET
|
||||||
|
|
||||||
|
feature -- Test routines
|
||||||
|
|
||||||
|
test_uri_template_parser
|
||||||
|
note
|
||||||
|
testing: "uri-template-05"
|
||||||
|
do
|
||||||
|
uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>)
|
||||||
|
uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_uri_template_matcher
|
||||||
|
note
|
||||||
|
testing: "uri-template-05"
|
||||||
|
local
|
||||||
|
tpl: URI_TEMPLATE
|
||||||
|
do
|
||||||
|
create tpl.make ("{version}/{id}")
|
||||||
|
uri_template_match (tpl, "v2/123", <<["version", "v2"], ["id" , "123"]>>, <<>>)
|
||||||
|
|
||||||
|
create tpl.make ("api/{foo}{bar}/id/{id}")
|
||||||
|
uri_template_mismatch (tpl, "api/foobar/id/123")
|
||||||
|
|
||||||
|
create tpl.make ("api/foo/{foo_id}/{?id,extra}")
|
||||||
|
uri_template_match (tpl, "api/foo/bar/", <<["foo_id", "bar"]>>, <<>>)
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123", <<["foo_id", "bar"]>>, <<["id", "123"]>>)
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123&extra=test", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>)
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123&extra=test&one=more", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>)
|
||||||
|
uri_template_mismatch (tpl, "")
|
||||||
|
uri_template_mismatch (tpl, "/")
|
||||||
|
uri_template_mismatch (tpl, "foo/bar/?id=123")
|
||||||
|
uri_template_mismatch (tpl, "/api/foo/bar/")
|
||||||
|
uri_template_mismatch (tpl, "api/foo/bar")
|
||||||
|
|
||||||
|
create tpl.make ("weather/{state}/{city}?forecast={day}")
|
||||||
|
uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_string_errors: detachable LIST [STRING]
|
||||||
|
|
||||||
|
test_uri_template_string_builder
|
||||||
|
note
|
||||||
|
testing: "uri-template-05"
|
||||||
|
local
|
||||||
|
ht: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
empty_keys: HASH_TABLE [STRING, STRING]
|
||||||
|
empty_list: ARRAY [STRING]
|
||||||
|
favs: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
keys: HASH_TABLE [STRING, STRING]
|
||||||
|
colors: ARRAY [STRING]
|
||||||
|
names: ARRAY [STRING]
|
||||||
|
semi_dot: HASH_TABLE [STRING, STRING]
|
||||||
|
vals: ARRAY [STRING]
|
||||||
|
do
|
||||||
|
create ht.make (3)
|
||||||
|
ht.force ("FooBar", "foo_id")
|
||||||
|
ht.force ("That's right!", "extra")
|
||||||
|
ht.force ("123", "id")
|
||||||
|
ht.force ("California", "state")
|
||||||
|
ht.force ("Goleta", "city")
|
||||||
|
ht.force ("today", "day")
|
||||||
|
|
||||||
|
ht.force ("value", "var")
|
||||||
|
ht.force ("Hello World!", "hello")
|
||||||
|
ht.force ("", "empty")
|
||||||
|
ht.force ("/foo/bar", "path")
|
||||||
|
ht.force ("1024", "x")
|
||||||
|
ht.force ("768", "y")
|
||||||
|
ht.force ("fred", "foo")
|
||||||
|
ht.force ("That's right!", "foo2")
|
||||||
|
ht.force ("http://example.com/home/", "base")
|
||||||
|
|
||||||
|
names := <<"Fred", "Wilma", "Pebbles">>
|
||||||
|
ht.force (names, "name")
|
||||||
|
create favs.make (2)
|
||||||
|
favs.force ("red", "color")
|
||||||
|
favs.force ("high", "volume")
|
||||||
|
ht.force (favs, "favs")
|
||||||
|
|
||||||
|
create empty_list.make_empty
|
||||||
|
ht.force (empty_list,"empty_list")
|
||||||
|
|
||||||
|
create empty_keys.make (0)
|
||||||
|
ht.force (empty_keys,"empty_keys")
|
||||||
|
|
||||||
|
vals := <<"val1", "val2", "val3">>
|
||||||
|
ht.force (vals, "list")
|
||||||
|
create keys.make (2)
|
||||||
|
keys.force ("val1", "key1")
|
||||||
|
keys.force ("val2", "key2")
|
||||||
|
ht.force (keys, "keys")
|
||||||
|
|
||||||
|
colors := <<"red", "green", "blue">>
|
||||||
|
create semi_dot.make (3)
|
||||||
|
semi_dot.force (";", "semi")
|
||||||
|
semi_dot.force (".", "dot")
|
||||||
|
semi_dot.force (",", "comma")
|
||||||
|
|
||||||
|
create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10)
|
||||||
|
|
||||||
|
|
||||||
|
--| Simple string expansion
|
||||||
|
uri_template_string (ht, "{var}", "value")
|
||||||
|
uri_template_string (ht, "{hello}", "Hello+World%%21")
|
||||||
|
uri_template_string (ht, "O{empty}X", "OX")
|
||||||
|
uri_template_string (ht, "O{undef}X", "OX")
|
||||||
|
|
||||||
|
--| String expansion with defaults
|
||||||
|
uri_template_string (ht, "{var|default}", "value")
|
||||||
|
uri_template_string (ht, "O{empty|default}X", "OX")
|
||||||
|
uri_template_string (ht, "O{undef|default}X", "OdefaultX")
|
||||||
|
|
||||||
|
--| Reserved expansion with defaults
|
||||||
|
uri_template_string (ht, "{+var}", "value")
|
||||||
|
uri_template_string (ht, "{+hello}", "Hello+World!")
|
||||||
|
uri_template_string (ht, "{+path}/here", "/foo/bar/here")
|
||||||
|
uri_template_string (ht, "here?ref={+path}", "here?ref=/foo/bar")
|
||||||
|
uri_template_string (ht, "up{+path}{x}/here", "up/foo/bar1024/here")
|
||||||
|
uri_template_string (ht, "up{+empty|/1}/here", "up/here")
|
||||||
|
uri_template_string (ht, "up{+undef|/1}/here", "up/1/here")
|
||||||
|
|
||||||
|
--| String expansion with multiple variables
|
||||||
|
uri_template_string (ht, "{x,y}", "1024,768")
|
||||||
|
uri_template_string (ht, "{x,hello,y}", "1024,Hello+World%%21,768")
|
||||||
|
uri_template_string (ht, "?{x,empty}", "?1024,")
|
||||||
|
uri_template_string (ht, "?{x,undef}", "?1024")
|
||||||
|
uri_template_string (ht, "?{undef,y}", "?768")
|
||||||
|
uri_template_string (ht, "?{x,undef|0}", "?1024,0")
|
||||||
|
|
||||||
|
--| Reserved expansion with multiple variables
|
||||||
|
uri_template_string (ht, "{+x,hello,y}", "1024,Hello+World!,768")
|
||||||
|
uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here")
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var}", "X.value")
|
||||||
|
uri_template_string (ht, "X{.empty}", "X.")
|
||||||
|
uri_template_string (ht, "X{.undef}", "X")
|
||||||
|
|
||||||
|
--| Path segments, slash-prefixed
|
||||||
|
uri_template_string (ht, "{/var}", "/value")
|
||||||
|
uri_template_string (ht, "{/var,empty}", "/value/")
|
||||||
|
uri_template_string (ht, "{/var,undef}", "/value")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;x,y}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty")
|
||||||
|
uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768")
|
||||||
|
|
||||||
|
--| Form-style query, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?x,y}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=")
|
||||||
|
uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768")
|
||||||
|
|
||||||
|
|
||||||
|
ht.force (colors, "list")
|
||||||
|
ht.force (semi_dot, "keys")
|
||||||
|
--| String expansion with value modifiers
|
||||||
|
uri_template_string (ht, "{var:3}", "val")
|
||||||
|
uri_template_string (ht, "{var:30}", "value")
|
||||||
|
uri_template_string (ht, "{var^3}", "ue")
|
||||||
|
uri_template_string (ht, "{var^-3}", "va")
|
||||||
|
|
||||||
|
uri_template_string (ht, "{list}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{list*}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{keys}", "semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{keys*}", "semi=%%3B,dot=.,comma=%%2C")
|
||||||
|
--| Reserved expansion with value modifiers
|
||||||
|
uri_template_string (ht, "{+path:6}/here", "/foo/b/here")
|
||||||
|
uri_template_string (ht, "{+list}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{+list*}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{+keys}", "semi,;,dot,.,comma,,")
|
||||||
|
uri_template_string (ht, "{+keys*}", "semi=;,dot=.,comma=,")
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var:3}", "X.val")
|
||||||
|
uri_template_string (ht, "X{.list}", "X.red,green,blue")
|
||||||
|
uri_template_string (ht, "X{.list*}", "X.red.green.blue")
|
||||||
|
uri_template_string (ht, "X{.keys}", "X.semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "X{.keys*}", "X.semi=%%3B.dot=..comma=%%2C")
|
||||||
|
|
||||||
|
--| Path segments, slash-prefixed
|
||||||
|
uri_template_string (ht, "{/var:1,var}", "/v/value")
|
||||||
|
uri_template_string (ht, "{/list}", "/red,green,blue")
|
||||||
|
uri_template_string (ht, "{/list*}", "/red/green/blue")
|
||||||
|
uri_template_string (ht, "{/list*,path:4}", "/red/green/blue/%%2Ffoo")
|
||||||
|
uri_template_string (ht, "{/keys}", "/semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{/keys*}", "/semi=%%3B/dot=./comma=%%2C")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;hello:5}", ";hello=Hello")
|
||||||
|
uri_template_string (ht, "{;list}", ";red,green,blue")
|
||||||
|
uri_template_string (ht, "{;list*}", ";red;green;blue")
|
||||||
|
uri_template_string (ht, "{;keys}", ";semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{;keys*}", ";semi=%%3B;dot=.;comma=%%2C")
|
||||||
|
|
||||||
|
--| Form-style query, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?var:3}", "?var=val")
|
||||||
|
uri_template_string (ht, "{?list}", "?list=red,green,blue")
|
||||||
|
uri_template_string (ht, "{?list*}", "?list=red&list=green&list=blue")
|
||||||
|
uri_template_string (ht, "{?keys}", "?keys=semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{?keys*}", "?semi=%%3B&dot=.&comma=%%2C")
|
||||||
|
|
||||||
|
assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_uri_template_string_builder_extra
|
||||||
|
note
|
||||||
|
testing: "uri-template-05"
|
||||||
|
local
|
||||||
|
ht: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
empty_keys: HASH_TABLE [STRING, STRING]
|
||||||
|
empty_list: ARRAY [STRING]
|
||||||
|
favs: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
keys: HASH_TABLE [STRING, STRING]
|
||||||
|
colors: ARRAY [STRING]
|
||||||
|
names: ARRAY [STRING]
|
||||||
|
semi_dot: HASH_TABLE [STRING, STRING]
|
||||||
|
vals: ARRAY [STRING]
|
||||||
|
do
|
||||||
|
create ht.make (3)
|
||||||
|
ht.force ("FooBar", "foo_id")
|
||||||
|
ht.force ("That's right!", "extra")
|
||||||
|
ht.force ("123", "id")
|
||||||
|
ht.force ("California", "state")
|
||||||
|
ht.force ("Goleta", "city")
|
||||||
|
ht.force ("today", "day")
|
||||||
|
|
||||||
|
ht.force ("value", "var")
|
||||||
|
ht.force ("Hello World!", "hello")
|
||||||
|
ht.force ("", "empty")
|
||||||
|
ht.force ("/foo/bar", "path")
|
||||||
|
ht.force ("1024", "x")
|
||||||
|
ht.force ("768", "y")
|
||||||
|
ht.force ("fred", "foo")
|
||||||
|
ht.force ("That's right!", "foo2")
|
||||||
|
ht.force ("http://example.com/home/", "base")
|
||||||
|
|
||||||
|
names := <<"Fred", "Wilma", "Pebbles">>
|
||||||
|
ht.force (names, "name")
|
||||||
|
create favs.make (2)
|
||||||
|
favs.force ("red", "color")
|
||||||
|
favs.force ("high", "volume")
|
||||||
|
ht.force (favs, "favs")
|
||||||
|
|
||||||
|
create empty_list.make_empty
|
||||||
|
ht.force (empty_list,"empty_list")
|
||||||
|
|
||||||
|
create empty_keys.make (0)
|
||||||
|
ht.force (empty_keys,"empty_keys")
|
||||||
|
|
||||||
|
vals := <<"val1", "val2", "val3">>
|
||||||
|
ht.force (vals, "list")
|
||||||
|
create keys.make (2)
|
||||||
|
keys.force ("val1", "key1")
|
||||||
|
keys.force ("val2", "key2")
|
||||||
|
ht.force (keys, "keys")
|
||||||
|
|
||||||
|
colors := <<"red", "green", "blue">>
|
||||||
|
create semi_dot.make (3)
|
||||||
|
semi_dot.force (";", "semi")
|
||||||
|
semi_dot.force (".", "dot")
|
||||||
|
semi_dot.force (",", "comma")
|
||||||
|
|
||||||
|
create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10)
|
||||||
|
|
||||||
|
--| Addition to the spec
|
||||||
|
uri_template_string (ht, "api/foo/{foo_id}/{?id,extra}",
|
||||||
|
"api/foo/FooBar/?id=123&extra=That%%27s+right%%21")
|
||||||
|
|
||||||
|
uri_template_string (ht, "api/foo/{foo_id}/{?id,empty,undef,extra}",
|
||||||
|
"api/foo/FooBar/?id=123&empty=&extra=That%%27s+right%%21")
|
||||||
|
|
||||||
|
uri_template_string (ht, "weather/{state}/{city}?forecast={day}",
|
||||||
|
"weather/California/Goleta?forecast=today")
|
||||||
|
|
||||||
|
|
||||||
|
uri_template_string (ht, "{var|default}", "value")
|
||||||
|
uri_template_string (ht, "{undef|default}", "default")
|
||||||
|
uri_template_string (ht, "{undef:3|default}", "default")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty|_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{undef}y", "xy")
|
||||||
|
uri_template_string (ht, "x{undef|_}y", "x_y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{.name|none}", "x.Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{.name*|none}", "x.Fred.Wilma.Pebbles")
|
||||||
|
uri_template_string (ht, "x{.empty}", "x.")
|
||||||
|
uri_template_string (ht, "x{.empty|none}", "x.")
|
||||||
|
uri_template_string (ht, "x{.undef}", "x")
|
||||||
|
uri_template_string (ht, "x{.undef|none}", "x.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/name|none}", "x/Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name*|none}", "x/Fred/Wilma/Pebbles")
|
||||||
|
uri_template_string (ht, "x{/undef}", "x")
|
||||||
|
uri_template_string (ht, "x{/undef|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty|none}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*|none}", "x/none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;name|none}", "x;name=Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{;favs|none}", "x;favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{;favs*|none}", "x;color=red;volume=high")
|
||||||
|
uri_template_string (ht, "x{;empty}", "x;empty")
|
||||||
|
uri_template_string (ht, "x{;empty|none}", "x;empty")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;undef}", "x")
|
||||||
|
uri_template_string (ht, "x{;undef|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;undef|foo=y}", "x;foo=y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?var|none}", "x?var=value")
|
||||||
|
uri_template_string (ht, "x{?favs|none}", "x?favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{?favs*|none}", "x?color=red&volume=high")
|
||||||
|
uri_template_string (ht, "x{?empty}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?empty|foo=none}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?undef}", "x")
|
||||||
|
uri_template_string (ht, "x{?undef|foo=none}", "x?foo=none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys|none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys|y=z}", "x?y=z")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*|y=z}", "x?y=z")
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty_list}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list|_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list*}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list*|_}y", "x_y")
|
||||||
|
uri_template_string (ht, "x{empty_list+}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list+|_}y", "xempty_list._y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty_keys}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys|_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys*}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys*|_}y", "x_y")
|
||||||
|
uri_template_string (ht, "x{empty_keys+}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys+|_}y", "xempty_keys._y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?name|none}", "x?name=Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{?favs|none}", "x?favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{?favs*|none}", "x?color=red&volume=high")
|
||||||
|
uri_template_string (ht, "x{?favs+|none}", "x?favs.color=red&favs.volume=high")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?undef}", "x")
|
||||||
|
uri_template_string (ht, "x{?undef|none}", "x?undef=none")
|
||||||
|
uri_template_string (ht, "x{?empty}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?empty|none}", "x?empty=")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list|none}", "x?empty_list=none")
|
||||||
|
uri_template_string (ht, "x{?empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list*|none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list+|none}", "x?empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys|none}", "x?empty_keys=none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*|none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys+|none}", "x?empty_keys.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;name|none}", "x;name=Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{;favs|none}", "x;favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{;favs*|none}", "x;color=red;volume=high")
|
||||||
|
uri_template_string (ht, "x{;favs+|none}", "x;favs.color=red;favs.volume=high")
|
||||||
|
uri_template_string (ht, "x{;undef}", "x")
|
||||||
|
uri_template_string (ht, "x{;undef|none}", "x;undef=none")
|
||||||
|
uri_template_string (ht, "x{;undef|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty}", "x;empty")
|
||||||
|
uri_template_string (ht, "x{;empty|none}", "x;empty")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list|none}", "x;empty_list=none")
|
||||||
|
uri_template_string (ht, "x{;empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list*|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list+|none}", "x;empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys|none}", "x;empty_keys=none")
|
||||||
|
uri_template_string (ht, "x{;empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys*|none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys+|none}", "x;empty_keys.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/name|none}", "x/Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name*|none}", "x/Fred/Wilma/Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name+|none}", "x/name.Fred/name.Wilma/name.Pebbles")
|
||||||
|
uri_template_string (ht, "x{/favs|none}", "x/color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{/favs*|none}", "x/color/red/volume/high")
|
||||||
|
uri_template_string (ht, "x{/favs+|none}", "x/favs.color/red/favs.volume/high")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/undef}", "x")
|
||||||
|
uri_template_string (ht, "x{/undef|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty|none}", "x/")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list*|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list+|none}", "x/empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*|none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys+|none}", "x/empty_keys.none")
|
||||||
|
|
||||||
|
--| Simple expansion with comma-separated values
|
||||||
|
uri_template_string (ht, "{var}", "value")
|
||||||
|
uri_template_string (ht, "{hello}", "Hello+World%%21")
|
||||||
|
uri_template_string (ht, "{path}/here", "%%2Ffoo%%2Fbar/here")
|
||||||
|
uri_template_string (ht, "{x,y}", "1024,768")
|
||||||
|
uri_template_string (ht, "{var|default}", "value")
|
||||||
|
uri_template_string (ht, "{undef|default}", "default")
|
||||||
|
uri_template_string (ht, "{list}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{list*}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{list+}", "list.val1,list.val2,list.val3")
|
||||||
|
uri_template_string (ht, "{keys}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{keys*}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{keys+}", "keys.key1,val1,keys.key2,val2")
|
||||||
|
|
||||||
|
--| Reserved expansion with comma-separated values
|
||||||
|
uri_template_string (ht, "{+var}", "value")
|
||||||
|
uri_template_string (ht, "{+hello}", "Hello+World!")
|
||||||
|
uri_template_string (ht, "{+path}/here", "/foo/bar/here")
|
||||||
|
uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here")
|
||||||
|
uri_template_string (ht, "{+path}{x}/here", "/foo/bar1024/here")
|
||||||
|
uri_template_string (ht, "{+empty}/here", "/here")
|
||||||
|
uri_template_string (ht, "{+undef}/here", "/here")
|
||||||
|
uri_template_string (ht, "{+list}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{+list*}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{+list+}", "list.val1,list.val2,list.val3")
|
||||||
|
uri_template_string (ht, "{+keys}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{+keys*}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{+keys+}", "keys.key1,val1,keys.key2,val2")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;x,y}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty")
|
||||||
|
uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;list}", ";list=val1,val2,val3") -- DIFF
|
||||||
|
uri_template_string (ht, "{;list*}", ";val1;val2;val3")
|
||||||
|
uri_template_string (ht, "{;list+}", ";list=val1;list=val2;list=val3")
|
||||||
|
uri_template_string (ht, "{;keys}", ";key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{;keys*}", ";key1=val1;key2=val2")
|
||||||
|
uri_template_string (ht, "{;keys+}", ";keys.key1=val1;keys.key2=val2")
|
||||||
|
|
||||||
|
--| Form-style parameters, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?x,y}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=")
|
||||||
|
uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?list}", "?list=val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{?list*}", "?val1&val2&val3")
|
||||||
|
uri_template_string (ht, "{?list+}", "?list=val1&list=val2&list=val3")
|
||||||
|
uri_template_string (ht, "{?keys}", "?keys=key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{?keys*}", "?key1=val1&key2=val2")
|
||||||
|
uri_template_string (ht, "{?keys+}", "?keys.key1=val1&keys.key2=val2")
|
||||||
|
|
||||||
|
--| Hierarchical path segments, slash-separated
|
||||||
|
uri_template_string (ht, "{/var}", "/value")
|
||||||
|
uri_template_string (ht, "{/var,empty}", "/value/")
|
||||||
|
uri_template_string (ht, "{/var,undef}", "/value")
|
||||||
|
uri_template_string (ht, "{/list}", "/val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{/list*}", "/val1/val2/val3")
|
||||||
|
uri_template_string (ht, "{/list*,x}", "/val1/val2/val3/1024")
|
||||||
|
uri_template_string (ht, "{/list+}", "/list.val1/list.val2/list.val3")
|
||||||
|
uri_template_string (ht, "{/keys}", "/key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{/keys*}", "/key1/val1/key2/val2")
|
||||||
|
uri_template_string (ht, "{/keys+}", "/keys.key1/val1/keys.key2/val2")
|
||||||
|
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var}", "X.value")
|
||||||
|
uri_template_string (ht, "X{.empty}", "X.")
|
||||||
|
uri_template_string (ht, "X{.undef}", "X")
|
||||||
|
uri_template_string (ht, "X{.list}", "X.val1,val2,val3")
|
||||||
|
uri_template_string (ht, "X{.list*}", "X.val1.val2.val3")
|
||||||
|
uri_template_string (ht, "X{.list*,x}", "X.val1.val2.val3.1024")
|
||||||
|
uri_template_string (ht, "X{.list+}", "X.list.val1.list.val2.list.val3")
|
||||||
|
uri_template_string (ht, "X{.keys}", "X.key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "X{.keys*}", "X.key1.val1.key2.val2")
|
||||||
|
uri_template_string (ht, "X{.keys+}", "X.keys.key1.val1.keys.key2.val2")
|
||||||
|
|
||||||
|
--| Simple Expansion
|
||||||
|
uri_template_string (ht, "{foo}", "fred")
|
||||||
|
uri_template_string (ht, "{foo,foo}", "fred,fred")
|
||||||
|
uri_template_string (ht, "{bar,foo}", "fred")
|
||||||
|
uri_template_string (ht, "{bar|wilma}", "wilma")
|
||||||
|
|
||||||
|
--| Reserved Expansion
|
||||||
|
uri_template_string (ht, "{foo2}", "That%%27s+right%%21")
|
||||||
|
uri_template_string (ht, "{+foo2}", "That%%27s+right!")
|
||||||
|
uri_template_string (ht, "{base}index", "http%%3A%%2F%%2Fexample.com%%2Fhome%%2Findex")
|
||||||
|
uri_template_string (ht, "{+base}index", "http://example.com/home/index")
|
||||||
|
|
||||||
|
assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty))
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_string (a_ht: HASH_TABLE [detachable ANY, STRING]; a_expression: STRING; a_expected: STRING)
|
||||||
|
local
|
||||||
|
tpl: URI_TEMPLATE
|
||||||
|
s: STRING
|
||||||
|
m: STRING
|
||||||
|
do
|
||||||
|
create tpl.make (a_expression)
|
||||||
|
s := tpl.expanded_string (a_ht)
|
||||||
|
if not s.same_string (a_expected) then
|
||||||
|
m := "Expected string for %"" + a_expression + "%" expected=%""+ a_expected +"%" but got %"" + s + "%"%N"
|
||||||
|
if attached uri_template_string_errors as err then
|
||||||
|
print (m)
|
||||||
|
err.force (m)
|
||||||
|
else
|
||||||
|
assert (m, False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_parse (s: STRING_8; path_vars: ARRAY [STRING]; query_vars: ARRAY [STRING])
|
||||||
|
local
|
||||||
|
u: URI_TEMPLATE
|
||||||
|
matched: BOOLEAN
|
||||||
|
i: INTEGER
|
||||||
|
do
|
||||||
|
create u.make (s)
|
||||||
|
if attached u.path_variable_names as vars then
|
||||||
|
matched := vars.count = path_vars.count
|
||||||
|
from
|
||||||
|
i := path_vars.lower
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
not matched or i > path_vars.upper
|
||||||
|
loop
|
||||||
|
matched := vars.item.same_string (path_vars[i])
|
||||||
|
vars.forth
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
matched := path_vars.is_empty
|
||||||
|
end
|
||||||
|
assert ("path variables matched", matched)
|
||||||
|
|
||||||
|
if attached u.query_variable_names as vars then
|
||||||
|
matched := vars.count = query_vars.count
|
||||||
|
from
|
||||||
|
i := query_vars.lower
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
not matched or i > query_vars.upper
|
||||||
|
loop
|
||||||
|
matched := vars.item.same_string (query_vars[i])
|
||||||
|
vars.forth
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
matched := query_vars.is_empty
|
||||||
|
end
|
||||||
|
assert ("query variables matched", matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING)
|
||||||
|
local
|
||||||
|
l_match: detachable URI_TEMPLATE_MATCH_RESULT
|
||||||
|
do
|
||||||
|
l_match := a_uri_template.match (a_uri)
|
||||||
|
assert ("uri %"" + a_uri + "%" does not match template %"" + a_uri_template.template + "%"", l_match = Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_match (a_uri_template: URI_TEMPLATE; a_uri: STRING; path_res: ARRAY [TUPLE [name: STRING; value: STRING]]; query_res: ARRAY [TUPLE [name: STRING; value: STRING]])
|
||||||
|
local
|
||||||
|
b: BOOLEAN
|
||||||
|
i: INTEGER
|
||||||
|
l_match: detachable URI_TEMPLATE_MATCH_RESULT
|
||||||
|
do
|
||||||
|
l_match := a_uri_template.match (a_uri)
|
||||||
|
if l_match /= Void then
|
||||||
|
if attached l_match.path_variables as path_ht then
|
||||||
|
b := path_ht.count = path_res.count
|
||||||
|
from
|
||||||
|
i := path_res.lower
|
||||||
|
until
|
||||||
|
not b or i > path_res.upper
|
||||||
|
loop
|
||||||
|
b := attached path_ht.item (path_res[i].name) as s and then s.same_string (path_res[i].value)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
assert ("uri matched path variables", b)
|
||||||
|
end
|
||||||
|
if attached l_match.query_variables as query_ht then
|
||||||
|
b := query_ht.count >= query_res.count
|
||||||
|
from
|
||||||
|
i := query_res.lower
|
||||||
|
until
|
||||||
|
not b or i > query_res.upper
|
||||||
|
loop
|
||||||
|
b := attached query_ht.item (query_res[i].name) as s and then s.same_string (query_res[i].value)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
assert ("uri matched query variables", b)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
assert ("uri matched", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,639 @@
|
|||||||
|
note
|
||||||
|
description: "[
|
||||||
|
Eiffel tests that can be executed by testing tool.
|
||||||
|
]"
|
||||||
|
author: "EiffelStudio test wizard"
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
testing: "type/manual"
|
||||||
|
|
||||||
|
class
|
||||||
|
TEST_URI_TEMPLATE
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EQA_TEST_SET
|
||||||
|
|
||||||
|
feature -- Test routines
|
||||||
|
|
||||||
|
test_uri_template_parser
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
do
|
||||||
|
uri_template_parse ("api/foo/{foo_id}/{?id,extra}", <<"foo_id">>, <<"id", "extra">>)
|
||||||
|
uri_template_parse ("weather/{state}/{city}?forecast={day}", <<"state", "city">>, <<"day">>)
|
||||||
|
end
|
||||||
|
|
||||||
|
test_uri_template_matcher
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
local
|
||||||
|
tpl: URI_TEMPLATE
|
||||||
|
do
|
||||||
|
create tpl.make ("{version}/{id}")
|
||||||
|
uri_template_match (tpl, "v2/123", <<["version", "v2"], ["id" , "123"]>>, <<>>)
|
||||||
|
|
||||||
|
create tpl.make ("api/{foo}{bar}/id/{id}")
|
||||||
|
uri_template_mismatch (tpl, "api/foobar/id/123")
|
||||||
|
|
||||||
|
|
||||||
|
create tpl.make ("api/foo/{foo_id}/{?id,extra}")
|
||||||
|
uri_template_match (tpl, "api/foo/bar/", <<["foo_id", "bar"]>>, <<>>)
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123", <<["foo_id", "bar"]>>, <<["id", "123"]>>)
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123&extra=test", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>)
|
||||||
|
uri_template_match (tpl, "api/foo/bar/?id=123&extra=test&one=more", <<["foo_id", "bar"]>>, <<["id", "123"], ["extra", "test"]>>)
|
||||||
|
uri_template_mismatch (tpl, "")
|
||||||
|
uri_template_mismatch (tpl, "/")
|
||||||
|
uri_template_mismatch (tpl, "foo/bar/?id=123")
|
||||||
|
uri_template_mismatch (tpl, "/api/foo/bar/")
|
||||||
|
uri_template_mismatch (tpl, "api/foo/bar")
|
||||||
|
|
||||||
|
create tpl.make ("weather/{state}/{city}?forecast={day}")
|
||||||
|
uri_template_match (tpl, "weather/California/Goleta?forecast=today", <<["state", "California"], ["city", "Goleta"]>>, <<["day", "today"]>>)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_string_errors: detachable LIST [STRING]
|
||||||
|
|
||||||
|
test_uri_template_string_builder
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
local
|
||||||
|
ht: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
empty_keys: HASH_TABLE [STRING, STRING]
|
||||||
|
empty_list: ARRAY [STRING]
|
||||||
|
favs: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
keys: HASH_TABLE [STRING, STRING]
|
||||||
|
colors: ARRAY [STRING]
|
||||||
|
names: ARRAY [STRING]
|
||||||
|
semi_dot: HASH_TABLE [STRING, STRING]
|
||||||
|
vals: ARRAY [STRING]
|
||||||
|
do
|
||||||
|
create ht.make (3)
|
||||||
|
ht.force ("FooBar", "foo_id")
|
||||||
|
ht.force ("That's right!", "extra")
|
||||||
|
ht.force ("123", "id")
|
||||||
|
ht.force ("California", "state")
|
||||||
|
ht.force ("Goleta", "city")
|
||||||
|
ht.force ("today", "day")
|
||||||
|
|
||||||
|
ht.force ("value", "var")
|
||||||
|
ht.force ("Hello World!", "hello")
|
||||||
|
ht.force ("", "empty")
|
||||||
|
ht.force ("/foo/bar", "path")
|
||||||
|
ht.force ("1024", "x")
|
||||||
|
ht.force ("768", "y")
|
||||||
|
ht.force ("fred", "foo")
|
||||||
|
ht.force ("That's right!", "foo2")
|
||||||
|
ht.force ("http://example.com/home/", "base")
|
||||||
|
|
||||||
|
names := <<"Fred", "Wilma", "Pebbles">>
|
||||||
|
ht.force (names, "name")
|
||||||
|
create favs.make (2)
|
||||||
|
favs.force ("red", "color")
|
||||||
|
favs.force ("high", "volume")
|
||||||
|
ht.force (favs, "favs")
|
||||||
|
|
||||||
|
create empty_list.make_empty
|
||||||
|
ht.force (empty_list,"empty_list")
|
||||||
|
|
||||||
|
create empty_keys.make (0)
|
||||||
|
ht.force (empty_keys,"empty_keys")
|
||||||
|
|
||||||
|
vals := <<"val1", "val2", "val3">>
|
||||||
|
ht.force (vals, "list")
|
||||||
|
create keys.make (2)
|
||||||
|
keys.force ("val1", "key1")
|
||||||
|
keys.force ("val2", "key2")
|
||||||
|
ht.force (keys, "keys")
|
||||||
|
|
||||||
|
colors := <<"red", "green", "blue">>
|
||||||
|
create semi_dot.make (3)
|
||||||
|
semi_dot.force (";", "semi")
|
||||||
|
semi_dot.force (".", "dot")
|
||||||
|
semi_dot.force (",", "comma")
|
||||||
|
|
||||||
|
create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10)
|
||||||
|
|
||||||
|
|
||||||
|
--| Simple string expansion
|
||||||
|
uri_template_string (ht, "{var}", "value")
|
||||||
|
uri_template_string (ht, "{hello}", "Hello+World%%21")
|
||||||
|
uri_template_string (ht, "O{empty}X", "OX")
|
||||||
|
uri_template_string (ht, "O{undef}X", "OX")
|
||||||
|
|
||||||
|
--| String expansion with defaults
|
||||||
|
uri_template_string (ht, "{var=default}", "value")
|
||||||
|
uri_template_string (ht, "O{empty=default}X", "OX")
|
||||||
|
uri_template_string (ht, "O{undef=default}X", "OdefaultX")
|
||||||
|
|
||||||
|
--| Reserved expansion with defaults
|
||||||
|
uri_template_string (ht, "{+var}", "value")
|
||||||
|
uri_template_string (ht, "{+hello}", "Hello+World!")
|
||||||
|
uri_template_string (ht, "{+path}/here", "/foo/bar/here")
|
||||||
|
uri_template_string (ht, "here?ref={+path}", "here?ref=/foo/bar")
|
||||||
|
uri_template_string (ht, "up{+path}{x}/here", "up/foo/bar1024/here")
|
||||||
|
uri_template_string (ht, "up{+empty=/1}/here", "up/here")
|
||||||
|
uri_template_string (ht, "up{+undef=/1}/here", "up/1/here")
|
||||||
|
|
||||||
|
--| String expansion with multiple variables
|
||||||
|
uri_template_string (ht, "{x,y}", "1024,768")
|
||||||
|
uri_template_string (ht, "{x,hello,y}", "1024,Hello+World%%21,768")
|
||||||
|
uri_template_string (ht, "?{x,empty}", "?1024,")
|
||||||
|
uri_template_string (ht, "?{x,undef}", "?1024")
|
||||||
|
uri_template_string (ht, "?{undef,y}", "?768")
|
||||||
|
uri_template_string (ht, "?{x,undef=0}", "?1024,0")
|
||||||
|
|
||||||
|
--| Reserved expansion with multiple variables
|
||||||
|
uri_template_string (ht, "{+x,hello,y}", "1024,Hello+World!,768")
|
||||||
|
uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here")
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var}", "X.value")
|
||||||
|
uri_template_string (ht, "X{.empty}", "X.")
|
||||||
|
uri_template_string (ht, "X{.undef}", "X")
|
||||||
|
|
||||||
|
--| Path segments, slash-prefixed
|
||||||
|
uri_template_string (ht, "{/var}", "/value")
|
||||||
|
uri_template_string (ht, "{/var,empty}", "/value/")
|
||||||
|
uri_template_string (ht, "{/var,undef}", "/value")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;x,y}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty")
|
||||||
|
uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768")
|
||||||
|
|
||||||
|
--| Form-style query, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?x,y}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=")
|
||||||
|
uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768")
|
||||||
|
|
||||||
|
|
||||||
|
ht.force (colors, "list")
|
||||||
|
ht.force (semi_dot, "keys")
|
||||||
|
--| String expansion with value modifiers
|
||||||
|
uri_template_string (ht, "{var:3}", "val")
|
||||||
|
uri_template_string (ht, "{var:30}", "value")
|
||||||
|
uri_template_string (ht, "{var^3}", "ue")
|
||||||
|
uri_template_string (ht, "{var^-3}", "va")
|
||||||
|
|
||||||
|
uri_template_string (ht, "{list}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{list*}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{keys}", "semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{keys*}", "semi=%%3B,dot=.,comma=%%2C")
|
||||||
|
--| Reserved expansion with value modifiers
|
||||||
|
uri_template_string (ht, "{+path:6}/here", "/foo/b/here")
|
||||||
|
uri_template_string (ht, "{+list}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{+list*}", "red,green,blue")
|
||||||
|
uri_template_string (ht, "{+keys}", "semi,;,dot,.,comma,,")
|
||||||
|
uri_template_string (ht, "{+keys*}", "semi=;,dot=.,comma=,")
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var:3}", "X.val")
|
||||||
|
uri_template_string (ht, "X{.list}", "X.red,green,blue")
|
||||||
|
uri_template_string (ht, "X{.list*}", "X.red.green.blue")
|
||||||
|
uri_template_string (ht, "X{.keys}", "X.semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "X{.keys*}", "X.semi=%%3B.dot=..comma=%%2C")
|
||||||
|
|
||||||
|
--| Path segments, slash-prefixed
|
||||||
|
uri_template_string (ht, "{/var:1,var}", "/v/value")
|
||||||
|
uri_template_string (ht, "{/list}", "/red,green,blue")
|
||||||
|
uri_template_string (ht, "{/list*}", "/red/green/blue")
|
||||||
|
uri_template_string (ht, "{/list*,path:4}", "/red/green/blue/%%2Ffoo")
|
||||||
|
uri_template_string (ht, "{/keys}", "/semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{/keys*}", "/semi=%%3B/dot=./comma=%%2C")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;hello:5}", ";hello=Hello")
|
||||||
|
uri_template_string (ht, "{;list}", ";red,green,blue")
|
||||||
|
uri_template_string (ht, "{;list*}", ";red;green;blue")
|
||||||
|
uri_template_string (ht, "{;keys}", ";semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{;keys*}", ";semi=%%3B;dot=.;comma=%%2C")
|
||||||
|
|
||||||
|
--| Form-style query, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?var:3}", "?var=val")
|
||||||
|
uri_template_string (ht, "{?list}", "?list=red,green,blue")
|
||||||
|
uri_template_string (ht, "{?list*}", "?list=red&list=green&list=blue")
|
||||||
|
uri_template_string (ht, "{?keys}", "?keys=semi,%%3B,dot,.,comma,%%2C")
|
||||||
|
uri_template_string (ht, "{?keys*}", "?semi=%%3B&dot=.&comma=%%2C")
|
||||||
|
|
||||||
|
assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
test_uri_template_string_builder_extra
|
||||||
|
note
|
||||||
|
testing: "uri-template"
|
||||||
|
local
|
||||||
|
ht: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
empty_keys: HASH_TABLE [STRING, STRING]
|
||||||
|
empty_list: ARRAY [STRING]
|
||||||
|
favs: HASH_TABLE [detachable ANY, STRING]
|
||||||
|
keys: HASH_TABLE [STRING, STRING]
|
||||||
|
colors: ARRAY [STRING]
|
||||||
|
names: ARRAY [STRING]
|
||||||
|
semi_dot: HASH_TABLE [STRING, STRING]
|
||||||
|
vals: ARRAY [STRING]
|
||||||
|
do
|
||||||
|
create ht.make (3)
|
||||||
|
ht.force ("FooBar", "foo_id")
|
||||||
|
ht.force ("That's right!", "extra")
|
||||||
|
ht.force ("123", "id")
|
||||||
|
ht.force ("California", "state")
|
||||||
|
ht.force ("Goleta", "city")
|
||||||
|
ht.force ("today", "day")
|
||||||
|
|
||||||
|
ht.force ("value", "var")
|
||||||
|
ht.force ("Hello World!", "hello")
|
||||||
|
ht.force ("", "empty")
|
||||||
|
ht.force ("/foo/bar", "path")
|
||||||
|
ht.force ("1024", "x")
|
||||||
|
ht.force ("768", "y")
|
||||||
|
ht.force ("fred", "foo")
|
||||||
|
ht.force ("That's right!", "foo2")
|
||||||
|
ht.force ("http://example.com/home/", "base")
|
||||||
|
|
||||||
|
names := <<"Fred", "Wilma", "Pebbles">>
|
||||||
|
ht.force (names, "name")
|
||||||
|
create favs.make (2)
|
||||||
|
favs.force ("red", "color")
|
||||||
|
favs.force ("high", "volume")
|
||||||
|
ht.force (favs, "favs")
|
||||||
|
|
||||||
|
create empty_list.make_empty
|
||||||
|
ht.force (empty_list,"empty_list")
|
||||||
|
|
||||||
|
create empty_keys.make (0)
|
||||||
|
ht.force (empty_keys,"empty_keys")
|
||||||
|
|
||||||
|
vals := <<"val1", "val2", "val3">>
|
||||||
|
ht.force (vals, "list")
|
||||||
|
create keys.make (2)
|
||||||
|
keys.force ("val1", "key1")
|
||||||
|
keys.force ("val2", "key2")
|
||||||
|
ht.force (keys, "keys")
|
||||||
|
|
||||||
|
colors := <<"red", "green", "blue">>
|
||||||
|
create semi_dot.make (3)
|
||||||
|
semi_dot.force (";", "semi")
|
||||||
|
semi_dot.force (".", "dot")
|
||||||
|
semi_dot.force (",", "comma")
|
||||||
|
|
||||||
|
create {ARRAYED_LIST [STRING]} uri_template_string_errors.make (10)
|
||||||
|
|
||||||
|
--| Addition to the spec
|
||||||
|
uri_template_string (ht, "api/foo/{foo_id}/{?id,extra}",
|
||||||
|
"api/foo/FooBar/?id=123&extra=That%%27s+right%%21")
|
||||||
|
|
||||||
|
uri_template_string (ht, "api/foo/{foo_id}/{?id,empty,undef,extra}",
|
||||||
|
"api/foo/FooBar/?id=123&empty=&extra=That%%27s+right%%21")
|
||||||
|
|
||||||
|
uri_template_string (ht, "weather/{state}/{city}?forecast={day}",
|
||||||
|
"weather/California/Goleta?forecast=today")
|
||||||
|
|
||||||
|
|
||||||
|
uri_template_string (ht, "{var=default}", "value")
|
||||||
|
uri_template_string (ht, "{undef=default}", "default")
|
||||||
|
uri_template_string (ht, "{undef:3=default}", "default")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty=_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{undef}y", "xy")
|
||||||
|
uri_template_string (ht, "x{undef=_}y", "x_y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{.name=none}", "x.Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{.name*=none}", "x.Fred.Wilma.Pebbles")
|
||||||
|
uri_template_string (ht, "x{.empty}", "x.")
|
||||||
|
uri_template_string (ht, "x{.empty=none}", "x.")
|
||||||
|
uri_template_string (ht, "x{.undef}", "x")
|
||||||
|
uri_template_string (ht, "x{.undef=none}", "x.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/name=none}", "x/Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name*=none}", "x/Fred/Wilma/Pebbles")
|
||||||
|
uri_template_string (ht, "x{/undef}", "x")
|
||||||
|
uri_template_string (ht, "x{/undef=none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty=none}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys=none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*=none}", "x/none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;name=none}", "x;name=Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{;favs=none}", "x;favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{;favs*=none}", "x;color=red;volume=high")
|
||||||
|
uri_template_string (ht, "x{;empty}", "x;empty")
|
||||||
|
uri_template_string (ht, "x{;empty=none}", "x;empty")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;undef}", "x")
|
||||||
|
uri_template_string (ht, "x{;undef=none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;undef=foo=y}", "x;foo=y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?var=none}", "x?var=value")
|
||||||
|
uri_template_string (ht, "x{?favs=none}", "x?favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{?favs*=none}", "x?color=red&volume=high")
|
||||||
|
uri_template_string (ht, "x{?empty}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?empty=foo=none}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?undef}", "x")
|
||||||
|
uri_template_string (ht, "x{?undef=foo=none}", "x?foo=none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys=none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys=y=z}", "x?y=z")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*=y=z}", "x?y=z")
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty_list}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list=_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list*}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list*=_}y", "x_y")
|
||||||
|
uri_template_string (ht, "x{empty_list+}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_list+=_}y", "xempty_list._y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{empty_keys}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys=_}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys*}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys*=_}y", "x_y")
|
||||||
|
uri_template_string (ht, "x{empty_keys+}y", "xy")
|
||||||
|
uri_template_string (ht, "x{empty_keys+=_}y", "xempty_keys._y")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?name=none}", "x?name=Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{?favs=none}", "x?favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{?favs*=none}", "x?color=red&volume=high")
|
||||||
|
uri_template_string (ht, "x{?favs+=none}", "x?favs.color=red&favs.volume=high")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?undef}", "x")
|
||||||
|
uri_template_string (ht, "x{?undef=none}", "x?undef=none")
|
||||||
|
uri_template_string (ht, "x{?empty}", "x?empty=")
|
||||||
|
uri_template_string (ht, "x{?empty=none}", "x?empty=")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list=none}", "x?empty_list=none")
|
||||||
|
uri_template_string (ht, "x{?empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list*=none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_list+=none}", "x?empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{?empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys=none}", "x?empty_keys=none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys*=none}", "x?none")
|
||||||
|
uri_template_string (ht, "x{?empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{?empty_keys+=none}", "x?empty_keys.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;name=none}", "x;name=Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{;favs=none}", "x;favs=color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{;favs*=none}", "x;color=red;volume=high")
|
||||||
|
uri_template_string (ht, "x{;favs+=none}", "x;favs.color=red;favs.volume=high")
|
||||||
|
uri_template_string (ht, "x{;undef}", "x")
|
||||||
|
uri_template_string (ht, "x{;undef=none}", "x;undef=none")
|
||||||
|
uri_template_string (ht, "x{;undef=none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty}", "x;empty")
|
||||||
|
uri_template_string (ht, "x{;empty=none}", "x;empty")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list=none}", "x;empty_list=none")
|
||||||
|
uri_template_string (ht, "x{;empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list*=none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_list+=none}", "x;empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{;empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys=none}", "x;empty_keys=none")
|
||||||
|
uri_template_string (ht, "x{;empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys*=none}", "x;none")
|
||||||
|
uri_template_string (ht, "x{;empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{;empty_keys+=none}", "x;empty_keys.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/name=none}", "x/Fred,Wilma,Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name*=none}", "x/Fred/Wilma/Pebbles")
|
||||||
|
uri_template_string (ht, "x{/name+=none}", "x/name.Fred/name.Wilma/name.Pebbles")
|
||||||
|
uri_template_string (ht, "x{/favs=none}", "x/color,red,volume,high")
|
||||||
|
uri_template_string (ht, "x{/favs*=none}", "x/color/red/volume/high")
|
||||||
|
uri_template_string (ht, "x{/favs+=none}", "x/favs.color/red/favs.volume/high")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/undef}", "x")
|
||||||
|
uri_template_string (ht, "x{/undef=none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty}", "x/")
|
||||||
|
uri_template_string (ht, "x{/empty=none}", "x/")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/empty_list}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list=none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_list*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list*=none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_list+}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_list+=none}", "x/empty_list.none")
|
||||||
|
|
||||||
|
uri_template_string (ht, "x{/empty_keys}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys=none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys*=none}", "x/none")
|
||||||
|
uri_template_string (ht, "x{/empty_keys+}", "x")
|
||||||
|
uri_template_string (ht, "x{/empty_keys+=none}", "x/empty_keys.none")
|
||||||
|
|
||||||
|
--| Simple expansion with comma-separated values
|
||||||
|
uri_template_string (ht, "{var}", "value")
|
||||||
|
uri_template_string (ht, "{hello}", "Hello+World%%21")
|
||||||
|
uri_template_string (ht, "{path}/here", "%%2Ffoo%%2Fbar/here")
|
||||||
|
uri_template_string (ht, "{x,y}", "1024,768")
|
||||||
|
uri_template_string (ht, "{var=default}", "value")
|
||||||
|
uri_template_string (ht, "{undef=default}", "default")
|
||||||
|
uri_template_string (ht, "{list}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{list*}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{list+}", "list.val1,list.val2,list.val3")
|
||||||
|
uri_template_string (ht, "{keys}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{keys*}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{keys+}", "keys.key1,val1,keys.key2,val2")
|
||||||
|
|
||||||
|
--| Reserved expansion with comma-separated values
|
||||||
|
uri_template_string (ht, "{+var}", "value")
|
||||||
|
uri_template_string (ht, "{+hello}", "Hello+World!")
|
||||||
|
uri_template_string (ht, "{+path}/here", "/foo/bar/here")
|
||||||
|
uri_template_string (ht, "{+path,x}/here", "/foo/bar,1024/here")
|
||||||
|
uri_template_string (ht, "{+path}{x}/here", "/foo/bar1024/here")
|
||||||
|
uri_template_string (ht, "{+empty}/here", "/here")
|
||||||
|
uri_template_string (ht, "{+undef}/here", "/here")
|
||||||
|
uri_template_string (ht, "{+list}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{+list*}", "val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{+list+}", "list.val1,list.val2,list.val3")
|
||||||
|
uri_template_string (ht, "{+keys}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{+keys*}", "key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{+keys+}", "keys.key1,val1,keys.key2,val2")
|
||||||
|
|
||||||
|
--| Path-style parameters, semicolon-prefixed
|
||||||
|
uri_template_string (ht, "{;x,y}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;x,y,empty}", ";x=1024;y=768;empty")
|
||||||
|
uri_template_string (ht, "{;x,y,undef}", ";x=1024;y=768")
|
||||||
|
uri_template_string (ht, "{;list}", ";list=val1,val2,val3") -- DIFF
|
||||||
|
uri_template_string (ht, "{;list*}", ";val1;val2;val3")
|
||||||
|
uri_template_string (ht, "{;list+}", ";list=val1;list=val2;list=val3")
|
||||||
|
uri_template_string (ht, "{;keys}", ";key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{;keys*}", ";key1=val1;key2=val2")
|
||||||
|
uri_template_string (ht, "{;keys+}", ";keys.key1=val1;keys.key2=val2")
|
||||||
|
|
||||||
|
--| Form-style parameters, ampersand-separated
|
||||||
|
uri_template_string (ht, "{?x,y}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?x,y,empty}", "?x=1024&y=768&empty=")
|
||||||
|
uri_template_string (ht, "{?x,y,undef}", "?x=1024&y=768")
|
||||||
|
uri_template_string (ht, "{?list}", "?list=val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{?list*}", "?val1&val2&val3")
|
||||||
|
uri_template_string (ht, "{?list+}", "?list=val1&list=val2&list=val3")
|
||||||
|
uri_template_string (ht, "{?keys}", "?keys=key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{?keys*}", "?key1=val1&key2=val2")
|
||||||
|
uri_template_string (ht, "{?keys+}", "?keys.key1=val1&keys.key2=val2")
|
||||||
|
|
||||||
|
--| Hierarchical path segments, slash-separated
|
||||||
|
uri_template_string (ht, "{/var}", "/value")
|
||||||
|
uri_template_string (ht, "{/var,empty}", "/value/")
|
||||||
|
uri_template_string (ht, "{/var,undef}", "/value")
|
||||||
|
uri_template_string (ht, "{/list}", "/val1,val2,val3")
|
||||||
|
uri_template_string (ht, "{/list*}", "/val1/val2/val3")
|
||||||
|
uri_template_string (ht, "{/list*,x}", "/val1/val2/val3/1024")
|
||||||
|
uri_template_string (ht, "{/list+}", "/list.val1/list.val2/list.val3")
|
||||||
|
uri_template_string (ht, "{/keys}", "/key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "{/keys*}", "/key1/val1/key2/val2")
|
||||||
|
uri_template_string (ht, "{/keys+}", "/keys.key1/val1/keys.key2/val2")
|
||||||
|
|
||||||
|
--| Label expansion, dot-prefixed
|
||||||
|
uri_template_string (ht, "X{.var}", "X.value")
|
||||||
|
uri_template_string (ht, "X{.empty}", "X.")
|
||||||
|
uri_template_string (ht, "X{.undef}", "X")
|
||||||
|
uri_template_string (ht, "X{.list}", "X.val1,val2,val3")
|
||||||
|
uri_template_string (ht, "X{.list*}", "X.val1.val2.val3")
|
||||||
|
uri_template_string (ht, "X{.list*,x}", "X.val1.val2.val3.1024")
|
||||||
|
uri_template_string (ht, "X{.list+}", "X.list.val1.list.val2.list.val3")
|
||||||
|
uri_template_string (ht, "X{.keys}", "X.key1,val1,key2,val2")
|
||||||
|
uri_template_string (ht, "X{.keys*}", "X.key1.val1.key2.val2")
|
||||||
|
uri_template_string (ht, "X{.keys+}", "X.keys.key1.val1.keys.key2.val2")
|
||||||
|
|
||||||
|
--| Simple Expansion
|
||||||
|
uri_template_string (ht, "{foo}", "fred")
|
||||||
|
uri_template_string (ht, "{foo,foo}", "fred,fred")
|
||||||
|
uri_template_string (ht, "{bar,foo}", "fred")
|
||||||
|
uri_template_string (ht, "{bar=wilma}", "wilma")
|
||||||
|
|
||||||
|
--| Reserved Expansion
|
||||||
|
uri_template_string (ht, "{foo2}", "That%%27s+right%%21")
|
||||||
|
uri_template_string (ht, "{+foo2}", "That%%27s+right!")
|
||||||
|
uri_template_string (ht, "{base}index", "http%%3A%%2F%%2Fexample.com%%2Fhome%%2Findex")
|
||||||
|
uri_template_string (ht, "{+base}index", "http://example.com/home/index")
|
||||||
|
|
||||||
|
assert ("all strings built", uri_template_string_errors = Void or (attached uri_template_string_errors as err and then err.is_empty))
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_string (a_ht: HASH_TABLE [detachable ANY, STRING]; a_expression: STRING; a_expected: STRING)
|
||||||
|
local
|
||||||
|
tpl: URI_TEMPLATE
|
||||||
|
s: STRING
|
||||||
|
m: STRING
|
||||||
|
do
|
||||||
|
create tpl.make (a_expression)
|
||||||
|
s := tpl.expanded_string (a_ht)
|
||||||
|
if not s.same_string (a_expected) then
|
||||||
|
m := "Expected string for %"" + a_expression + "%" expected=%""+ a_expected +"%" but got %"" + s + "%"%N"
|
||||||
|
if attached uri_template_string_errors as err then
|
||||||
|
print (m)
|
||||||
|
err.force (m)
|
||||||
|
else
|
||||||
|
assert (m, False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_parse (s: STRING_8; path_vars: ARRAY [STRING]; query_vars: ARRAY [STRING])
|
||||||
|
local
|
||||||
|
u: URI_TEMPLATE
|
||||||
|
matched: BOOLEAN
|
||||||
|
i: INTEGER
|
||||||
|
do
|
||||||
|
create u.make (s)
|
||||||
|
if attached u.path_variable_names as vars then
|
||||||
|
matched := vars.count = path_vars.count
|
||||||
|
from
|
||||||
|
i := path_vars.lower
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
not matched or i > path_vars.upper
|
||||||
|
loop
|
||||||
|
matched := vars.item.same_string (path_vars[i])
|
||||||
|
vars.forth
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
matched := path_vars.is_empty
|
||||||
|
end
|
||||||
|
assert ("path variables matched", matched)
|
||||||
|
|
||||||
|
if attached u.query_variable_names as vars then
|
||||||
|
matched := vars.count = query_vars.count
|
||||||
|
from
|
||||||
|
i := query_vars.lower
|
||||||
|
vars.start
|
||||||
|
until
|
||||||
|
not matched or i > query_vars.upper
|
||||||
|
loop
|
||||||
|
matched := vars.item.same_string (query_vars[i])
|
||||||
|
vars.forth
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
matched := query_vars.is_empty
|
||||||
|
end
|
||||||
|
assert ("query variables matched", matched)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_mismatch (a_uri_template: URI_TEMPLATE; a_uri: STRING)
|
||||||
|
local
|
||||||
|
l_match: detachable URI_TEMPLATE_MATCH_RESULT
|
||||||
|
do
|
||||||
|
l_match := a_uri_template.match (a_uri)
|
||||||
|
assert ("uri %"" + a_uri + "%" does not match template %"" + a_uri_template.template + "%"", l_match = Void)
|
||||||
|
end
|
||||||
|
|
||||||
|
uri_template_match (a_uri_template: URI_TEMPLATE; a_uri: STRING; path_res: ARRAY [TUPLE [name: STRING; value: STRING]]; query_res: ARRAY [TUPLE [name: STRING; value: STRING]])
|
||||||
|
local
|
||||||
|
b: BOOLEAN
|
||||||
|
i: INTEGER
|
||||||
|
l_match: detachable URI_TEMPLATE_MATCH_RESULT
|
||||||
|
do
|
||||||
|
l_match := a_uri_template.match (a_uri)
|
||||||
|
if l_match /= Void then
|
||||||
|
if attached l_match.path_variables as path_ht then
|
||||||
|
b := path_ht.count = path_res.count
|
||||||
|
from
|
||||||
|
i := path_res.lower
|
||||||
|
until
|
||||||
|
not b or i > path_res.upper
|
||||||
|
loop
|
||||||
|
b := attached path_ht.item (path_res[i].name) as s and then s.same_string (path_res[i].value)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
assert ("uri %"" + a_uri + "%" matched path variables", b)
|
||||||
|
end
|
||||||
|
if attached l_match.query_variables as query_ht then
|
||||||
|
b := query_ht.count >= query_res.count
|
||||||
|
from
|
||||||
|
i := query_res.lower
|
||||||
|
until
|
||||||
|
not b or i > query_res.upper
|
||||||
|
loop
|
||||||
|
b := attached query_ht.item (query_res[i].name) as s and then s.same_string (query_res[i].value)
|
||||||
|
i := i + 1
|
||||||
|
end
|
||||||
|
assert ("uri %"" + a_uri + "%" matched query variables", b)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
assert ("uri %"" + a_uri + "%" matched", False)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?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="uri_template" uuid="64B64199-7F12-4A33-A962-4AD314E9593D" library_target="uri_template">
|
||||||
|
<target name="uri_template">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="encoder" location="..\..\text\encoder\encoder-safe.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<cluster name="src" location="src\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/draft_05$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/uri_template_constants.e</exclude>
|
||||||
|
<condition>
|
||||||
|
<custom name="uri_template" value="draft_05"/>
|
||||||
|
</condition>
|
||||||
|
</file_rule>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="draft_05" location=".\src\draft_05\">
|
||||||
|
<condition>
|
||||||
|
<custom name="uri_template" value="draft_05"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
</target>
|
||||||
|
<target name="tests" extends="uri_template">
|
||||||
|
<root class="ANY" feature="default_create"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||||
|
<tests name="tests" location=".\tests\"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?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="uri_template" uuid="64B64199-7F12-4A33-A962-4AD314E9593D" library_target="uri_template">
|
||||||
|
<target name="uri_template">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="encoder" location="..\..\text\encoder\encoder.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time.ecf"/>
|
||||||
|
<cluster name="src" location="src\" recursive="true">
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/draft_05$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/uri_template_constants.e</exclude>
|
||||||
|
<condition>
|
||||||
|
<custom name="uri_template" value="draft_05"/>
|
||||||
|
</condition>
|
||||||
|
</file_rule>
|
||||||
|
</cluster>
|
||||||
|
<cluster name="draft_05" location=".\src\draft_05\">
|
||||||
|
<condition>
|
||||||
|
<custom name="uri_template" value="draft_05"/>
|
||||||
|
</condition>
|
||||||
|
</cluster>
|
||||||
|
</target>
|
||||||
|
<target name="tests" extends="uri_template">
|
||||||
|
<root class="ANY" feature="default_create"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/.git$</exclude>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
<assertions precondition="true"/>
|
||||||
|
</option>
|
||||||
|
<setting name="console_application" value="false"/>
|
||||||
|
<variable name="uri_template" value="draft_05"/>
|
||||||
|
<library name="testing" location="$ISE_LIBRARY\library\testing\testing.ecf"/>
|
||||||
|
<tests name="tests" location=".\tests\"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Copyright: 2011-2011, Eiffel Software and others
|
||||||
|
License: Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)
|
||||||
|
Source:
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?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="connector_cgi" uuid="3BCBC1C5-9D99-45BB-B15D-B03D2C069CED" library_target="connector_cgi">
|
||||||
|
<target name="connector_cgi">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||||
|
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?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="connector_cgi" uuid="3BCBC1C5-9D99-45BB-B15D-B03D2C069CED" library_target="connector_cgi">
|
||||||
|
<target name="connector_cgi">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||||
|
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
${NOTE_KEYWORD}
|
||||||
|
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {GW_CGI_CONNECTOR}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_CGI_CONNECTOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_CONNECTOR
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
launch
|
||||||
|
local
|
||||||
|
env: EWSGI_ENVIRONMENT_VARIABLES
|
||||||
|
do
|
||||||
|
create env.make_with_variables ((create {EXECUTION_ENVIRONMENT}).starting_environment_variables)
|
||||||
|
application.process (env, create {GW_CGI_INPUT_STREAM}.make, create {GW_CGI_OUTPUT_STREAM}.make)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for GW_CGI_INPUT_STREAM."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_CGI_INPUT_STREAM
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_INPUT_STREAM
|
||||||
|
|
||||||
|
CONSOLE
|
||||||
|
rename
|
||||||
|
make as console_make
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make
|
||||||
|
do
|
||||||
|
make_open_stdin ("stdin")
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for GW_CGI_OUTPUT_STREAM."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_CGI_OUTPUT_STREAM
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_OUTPUT_STREAM
|
||||||
|
undefine
|
||||||
|
flush
|
||||||
|
end
|
||||||
|
|
||||||
|
CONSOLE
|
||||||
|
rename
|
||||||
|
make as console_make
|
||||||
|
end
|
||||||
|
|
||||||
|
HTTP_STATUS_CODE_MESSAGES
|
||||||
|
export
|
||||||
|
{NONE} all
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make
|
||||||
|
do
|
||||||
|
make_open_stdout ("stdout")
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status writing
|
||||||
|
|
||||||
|
put_status_line (a_code: INTEGER)
|
||||||
|
-- Put status code line for `a_code'
|
||||||
|
--| Note this is a default implementation, and could be redefined
|
||||||
|
--| for instance in relation to NPH CGI script
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
create s.make (16)
|
||||||
|
s.append ({HTTP_CONSTANTS}.http_version_1_1)
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append_integer (a_code)
|
||||||
|
if attached http_status_code_message (a_code) as l_status_message then
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append_string (l_status_message)
|
||||||
|
end
|
||||||
|
put_header_line (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?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="connector_libfcgi" uuid="59C57E56-3EE6-4EF7-873F-7ED084B0EB22" library_target="connector_libfcgi">
|
||||||
|
<target name="connector_libfcgi">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||||
|
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi-safe.ecf" />
|
||||||
|
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?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="connector_libfcgi" uuid="59C57E56-3EE6-4EF7-873F-7ED084B0EB22" library_target="connector_libfcgi">
|
||||||
|
<target name="connector_libfcgi">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||||
|
<library name="libfcgi" location="..\..\..\libfcgi\libfcgi.ecf" />
|
||||||
|
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||||
|
<cluster name="src" location=".\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
${NOTE_KEYWORD}
|
||||||
|
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {GW_LIBFCGI_CONNECTOR}."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_LIBFCGI_CONNECTOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_CONNECTOR
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
do
|
||||||
|
create fcgi.make
|
||||||
|
create {GW_LIBFCGI_INPUT_STREAM} input.make (fcgi)
|
||||||
|
create {GW_LIBFCGI_OUTPUT_STREAM} output.make (fcgi)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Server
|
||||||
|
|
||||||
|
launch
|
||||||
|
local
|
||||||
|
res: INTEGER
|
||||||
|
do
|
||||||
|
from
|
||||||
|
res := fcgi.fcgi_listen
|
||||||
|
until
|
||||||
|
res < 0
|
||||||
|
loop
|
||||||
|
process_fcgi_request (fcgi.updated_environ_variables, input, output)
|
||||||
|
res := fcgi.fcgi_listen
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Execution
|
||||||
|
|
||||||
|
process_fcgi_request (vars: HASH_TABLE [STRING, STRING]; a_input: like input; a_output: like output)
|
||||||
|
local
|
||||||
|
gw_env: EWSGI_ENVIRONMENT_VARIABLES
|
||||||
|
do
|
||||||
|
create gw_env.make_with_variables (vars)
|
||||||
|
application.process (gw_env, a_input, a_output)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Input/Output
|
||||||
|
|
||||||
|
input: EWSGI_INPUT_STREAM
|
||||||
|
-- Input from client (from httpd server via FCGI)
|
||||||
|
|
||||||
|
output: EWSGI_OUTPUT_STREAM
|
||||||
|
-- Output to client (via httpd server/fcgi)
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
fcgi: FCGI
|
||||||
|
|
||||||
|
invariant
|
||||||
|
fcgi_attached: fcgi /= Void
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for GW_LIBFCGI_INPUT_STREAM."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_LIBFCGI_INPUT_STREAM
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_INPUT_STREAM
|
||||||
|
|
||||||
|
STRING_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_fcgi: like fcgi)
|
||||||
|
require
|
||||||
|
valid_fcgi: a_fcgi /= Void
|
||||||
|
do
|
||||||
|
fcgi := a_fcgi
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
initialize
|
||||||
|
-- Initialize Current
|
||||||
|
do
|
||||||
|
create last_string.make_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Basic operation
|
||||||
|
|
||||||
|
read_stream (nb_char: INTEGER)
|
||||||
|
-- Read a string of at most `nb_char' bound characters
|
||||||
|
-- or until end of file.
|
||||||
|
-- Make result available in `last_string'.
|
||||||
|
do
|
||||||
|
fcgi.fill_string_from_stdin (last_string, nb_char)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
last_string: STRING
|
||||||
|
-- Last string read
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
fcgi: FCGI;
|
||||||
|
-- Bridge to FCGI world
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {GW_LIBFCGI_OUTPUT_STREAM}."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_LIBFCGI_OUTPUT_STREAM
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_OUTPUT_STREAM
|
||||||
|
|
||||||
|
HTTP_STATUS_CODE_MESSAGES
|
||||||
|
export
|
||||||
|
{NONE} all
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_fcgi: like fcgi)
|
||||||
|
require
|
||||||
|
valid_fcgi: a_fcgi /= Void
|
||||||
|
do
|
||||||
|
fcgi := a_fcgi
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Status writing
|
||||||
|
|
||||||
|
put_status_line (a_code: INTEGER)
|
||||||
|
-- Put status code line for `a_code'
|
||||||
|
--| Note this is a default implementation, and could be redefined
|
||||||
|
--| for instance in relation to NPH CGI script
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
create s.make (16)
|
||||||
|
s.append ({HTTP_CONSTANTS}.http_version_1_1)
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append_integer (a_code)
|
||||||
|
if attached http_status_code_message (a_code) as l_status_message then
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append_string (l_status_message)
|
||||||
|
end
|
||||||
|
put_header_line (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Basic operation
|
||||||
|
|
||||||
|
put_string (s: STRING)
|
||||||
|
-- Send `s' to http client
|
||||||
|
do
|
||||||
|
fcgi.put_string (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Implementation
|
||||||
|
|
||||||
|
fcgi: FCGI
|
||||||
|
-- Bridge to FCGI world
|
||||||
|
|
||||||
|
invariant
|
||||||
|
fcgi_attached: fcgi /= Void
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
${NOTE_KEYWORD}
|
||||||
|
copyright: "2011-${YEAR}, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?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="connector_nino" uuid="F91861FB-4FEA-455F-9570-828D7903DC64" library_target="connector_nino">
|
||||||
|
<target name="connector_nino">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="ewsgi_spec" location="..\..\ewsgi_specification-safe.ecf" readonly="false"/>
|
||||||
|
<library name="http" location="..\..\..\..\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="nino" location="..\..\..\..\..\ext\server\nino\nino-safe.ecf" readonly="false">
|
||||||
|
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||||
|
</library>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?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="connector_nino" uuid="F91861FB-4FEA-455F-9570-828D7903DC64" library_target="connector_nino">
|
||||||
|
<target name="connector_nino">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||||
|
<library name="ewsgi_spec" location="..\..\ewsgi_specification.ecf" readonly="false"/>
|
||||||
|
<library name="http" location="..\..\..\..\protocol\http\http.ecf"/>
|
||||||
|
<library name="nino" location="..\..\..\..\..\ext\server\nino\nino.ecf" readonly="false">
|
||||||
|
<renaming old_name="HTTP_CONSTANTS" new_name="NINO_HTTP_CONSTANTS"/>
|
||||||
|
</library>
|
||||||
|
<cluster name="src" location=".\src\" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {GW_NINO_CONNECTOR}."
|
||||||
|
author: ""
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_NINO_CONNECTOR
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_CONNECTOR
|
||||||
|
redefine
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make,
|
||||||
|
make_with_base
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_with_base (a_app: like application; a_base: like base)
|
||||||
|
do
|
||||||
|
make (a_app)
|
||||||
|
base := a_base
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
initialize
|
||||||
|
local
|
||||||
|
cfg: HTTP_SERVER_CONFIGURATION
|
||||||
|
do
|
||||||
|
create cfg.make
|
||||||
|
create server.make (cfg)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
server: HTTP_SERVER
|
||||||
|
|
||||||
|
configuration: HTTP_SERVER_CONFIGURATION
|
||||||
|
do
|
||||||
|
Result := server.configuration
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
base: detachable STRING
|
||||||
|
-- Root url base
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
set_base (b: like base)
|
||||||
|
do
|
||||||
|
base := b
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Server
|
||||||
|
|
||||||
|
launch
|
||||||
|
local
|
||||||
|
l_http_handler : HTTP_HANDLER
|
||||||
|
do
|
||||||
|
create {GW_NINO_HANDLER} l_http_handler.make_with_callback (server, "NINO_HANDLER", Current)
|
||||||
|
debug ("nino")
|
||||||
|
if attached base as l_base then
|
||||||
|
print ("Base=" + l_base + "%N")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
server.setup (l_http_handler)
|
||||||
|
end
|
||||||
|
|
||||||
|
process_request (env: HASH_TABLE [STRING, STRING]; a_headers_text: STRING; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM)
|
||||||
|
local
|
||||||
|
gw_env: EWSGI_ENVIRONMENT_VARIABLES
|
||||||
|
do
|
||||||
|
create gw_env.make_with_variables (env)
|
||||||
|
gw_env.set_variable ("RAW_HEADER_DATA", a_headers_text)
|
||||||
|
application.process (gw_env, create {GW_NINO_INPUT_STREAM}.make (a_input), create {GW_NINO_OUTPUT_STREAM}.make (a_output))
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
note
|
||||||
|
description : "Objects that ..."
|
||||||
|
author : "$Author$"
|
||||||
|
date : "$Date$"
|
||||||
|
revision : "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_NINO_HANDLER
|
||||||
|
|
||||||
|
inherit
|
||||||
|
HTTP_CONNECTION_HANDLER
|
||||||
|
|
||||||
|
create
|
||||||
|
make_with_callback
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_with_callback (a_main_server: like main_server; a_name: STRING; a_callback: like callback)
|
||||||
|
-- Initialize `Current'.
|
||||||
|
do
|
||||||
|
base := a_callback.base
|
||||||
|
make (a_main_server, a_name)
|
||||||
|
callback := a_callback
|
||||||
|
end
|
||||||
|
|
||||||
|
callback: GW_NINO_CONNECTOR
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
base: detachable STRING
|
||||||
|
-- Root url base
|
||||||
|
|
||||||
|
feature -- Element change
|
||||||
|
|
||||||
|
set_base (a_uri: like base)
|
||||||
|
-- Set `base' to `a_uri'
|
||||||
|
do
|
||||||
|
base := a_uri
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Request processing
|
||||||
|
|
||||||
|
process_request (a_handler: HTTP_CONNECTION_HANDLER; a_input: HTTP_INPUT_STREAM; a_output: HTTP_OUTPUT_STREAM)
|
||||||
|
-- Process request ...
|
||||||
|
local
|
||||||
|
env, vars: HASH_TABLE [STRING, STRING]
|
||||||
|
p: INTEGER
|
||||||
|
l_request_uri, l_script_name, l_query_string, l_path_info: STRING
|
||||||
|
l_server_name, l_server_port: detachable STRING
|
||||||
|
a_headers_map: HASH_TABLE [STRING, STRING]
|
||||||
|
vn: STRING
|
||||||
|
|
||||||
|
e: EXECUTION_ENVIRONMENT
|
||||||
|
do
|
||||||
|
l_request_uri := a_handler.uri
|
||||||
|
a_headers_map := a_handler.request_header_map
|
||||||
|
create e
|
||||||
|
vars := e.starting_environment_variables
|
||||||
|
env := vars.twin
|
||||||
|
|
||||||
|
--| for Any Abc-Def-Ghi add (or replace) the HTTP_ABC_DEF_GHI variable to `env'
|
||||||
|
from
|
||||||
|
a_headers_map.start
|
||||||
|
until
|
||||||
|
a_headers_map.after
|
||||||
|
loop
|
||||||
|
vn := a_headers_map.key_for_iteration.as_upper
|
||||||
|
vn.replace_substring_all ("-", "_")
|
||||||
|
add_environment_variable (a_headers_map.item_for_iteration, vn, env)
|
||||||
|
a_headers_map.forth
|
||||||
|
end
|
||||||
|
|
||||||
|
--| Specific cases
|
||||||
|
|
||||||
|
p := l_request_uri.index_of ('?', 1)
|
||||||
|
if p > 0 then
|
||||||
|
l_script_name := l_request_uri.substring (1, p - 1)
|
||||||
|
l_query_string := l_request_uri.substring (p + 1, l_request_uri.count)
|
||||||
|
else
|
||||||
|
l_script_name := l_request_uri.string
|
||||||
|
l_query_string := ""
|
||||||
|
end
|
||||||
|
if attached a_headers_map.item ("Host") as l_host then
|
||||||
|
add_environment_variable (l_host, "HTTP_HOST", env)
|
||||||
|
p := l_host.index_of (':', 1)
|
||||||
|
if p > 0 then
|
||||||
|
l_server_name := l_host.substring (1, p - 1)
|
||||||
|
l_server_port := l_host.substring (p+1, l_host.count)
|
||||||
|
else
|
||||||
|
l_server_name := l_host
|
||||||
|
l_server_port := "80" -- Default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if attached a_headers_map.item ("Authorization") as l_authorization then
|
||||||
|
add_environment_variable (l_authorization, "HTTP_AUTHORIZATION", env)
|
||||||
|
p := l_authorization.index_of (' ', 1)
|
||||||
|
if p > 0 then
|
||||||
|
add_environment_variable (l_authorization.substring (1, p - 1), "AUTH_TYPE", env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
add_environment_variable ("CGI/1.1", "GATEWAY_INTERFACE", env)
|
||||||
|
add_environment_variable (l_query_string, "QUERY_STRING", env)
|
||||||
|
|
||||||
|
if attached a_handler.remote_info as l_remote_info then
|
||||||
|
add_environment_variable (l_remote_info.addr, "REMOTE_ADDR", env)
|
||||||
|
add_environment_variable (l_remote_info.hostname, "REMOTE_HOST", env)
|
||||||
|
add_environment_variable (l_remote_info.port.out, "REMOTE_PORT", env)
|
||||||
|
-- add_environment_variable (Void, "REMOTE_IDENT", env)
|
||||||
|
-- add_environment_variable (Void, "REMOTE_USER", env)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_environment_variable (l_request_uri, "REQUEST_URI", env)
|
||||||
|
add_environment_variable (a_handler.method, "REQUEST_METHOD", env)
|
||||||
|
|
||||||
|
add_environment_variable (l_script_name, "SCRIPT_NAME", env)
|
||||||
|
add_environment_variable (l_server_name, "SERVER_NAME", env)
|
||||||
|
add_environment_variable (l_server_port, "SERVER_PORT", env)
|
||||||
|
add_environment_variable (a_handler.version, "SERVER_PROTOCOL", env)
|
||||||
|
add_environment_variable ({HTTP_SERVER_CONFIGURATION}.Server_details, "SERVER_SOFTWARE", env)
|
||||||
|
|
||||||
|
--| Apply `base' value
|
||||||
|
if attached base as l_base and then l_request_uri /= Void then
|
||||||
|
if l_request_uri.starts_with (l_base) then
|
||||||
|
l_path_info := l_request_uri.substring (l_base.count + 1, l_request_uri.count)
|
||||||
|
p := l_path_info.index_of ('?', 1)
|
||||||
|
if p > 0 then
|
||||||
|
l_path_info.keep_head (p - 1)
|
||||||
|
end
|
||||||
|
env.force (l_path_info, "PATH_INFO")
|
||||||
|
env.force (l_base, "SCRIPT_NAME")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
callback.process_request (env, a_handler.request_header, a_input, a_output)
|
||||||
|
end
|
||||||
|
|
||||||
|
add_environment_variable (a_value: detachable STRING; a_var_name: STRING; env: HASH_TABLE [STRING, STRING])
|
||||||
|
-- Add variable `a_var_name => a_value' to `env'
|
||||||
|
do
|
||||||
|
if a_value /= Void then
|
||||||
|
env.force (a_value, a_var_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {GW_NINO_INPUT_STREAM}."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_NINO_INPUT_STREAM
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_INPUT_STREAM
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_nino_input: like nino_input)
|
||||||
|
do
|
||||||
|
create last_string.make_empty
|
||||||
|
set_nino_input (a_nino_input)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {GW_NINO_CONNECTOR, EWSGI_APPLICATION} -- Nino
|
||||||
|
|
||||||
|
set_nino_input (i: like nino_input)
|
||||||
|
do
|
||||||
|
nino_input := i
|
||||||
|
end
|
||||||
|
|
||||||
|
nino_input: HTTP_INPUT_STREAM
|
||||||
|
|
||||||
|
feature -- Basic operation
|
||||||
|
|
||||||
|
read_stream (nb_char: INTEGER)
|
||||||
|
-- Read a string of at most `nb_char' bound characters
|
||||||
|
-- or until end of file.
|
||||||
|
-- Make result available in `last_string'.
|
||||||
|
do
|
||||||
|
nino_input.read_stream (nb_char)
|
||||||
|
last_string := nino_input.last_string
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Access
|
||||||
|
|
||||||
|
last_string: STRING
|
||||||
|
-- Last string read
|
||||||
|
|
||||||
|
;note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {GW_NINO_OUTPUT_STREAM}."
|
||||||
|
legal: "See notice at end of class."
|
||||||
|
status: "See notice at end of class."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
class
|
||||||
|
GW_NINO_OUTPUT_STREAM
|
||||||
|
|
||||||
|
inherit
|
||||||
|
EWSGI_OUTPUT_STREAM
|
||||||
|
|
||||||
|
HTTP_STATUS_CODE_MESSAGES
|
||||||
|
export
|
||||||
|
{NONE} all
|
||||||
|
end
|
||||||
|
|
||||||
|
create
|
||||||
|
make
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make (a_nino_output: like nino_output)
|
||||||
|
do
|
||||||
|
set_nino_output (a_nino_output)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature {GW_NINO_CONNECTOR, EWSGI_APPLICATION} -- Nino
|
||||||
|
|
||||||
|
set_nino_output (o: like nino_output)
|
||||||
|
do
|
||||||
|
nino_output := o
|
||||||
|
end
|
||||||
|
|
||||||
|
nino_output: HTTP_OUTPUT_STREAM
|
||||||
|
|
||||||
|
feature -- Status writing
|
||||||
|
|
||||||
|
put_status_line (a_code: INTEGER)
|
||||||
|
-- Put status code line for `a_code'
|
||||||
|
--| Note this is a default implementation, and could be redefined
|
||||||
|
--| for instance in relation to NPH CGI script
|
||||||
|
local
|
||||||
|
s: STRING
|
||||||
|
do
|
||||||
|
create s.make (16)
|
||||||
|
s.append ({HTTP_CONSTANTS}.http_version_1_1)
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append_integer (a_code)
|
||||||
|
if attached http_status_code_message (a_code) as l_status_message then
|
||||||
|
s.append_character (' ')
|
||||||
|
s.append_string (l_status_message)
|
||||||
|
end
|
||||||
|
put_header_line (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
feature -- Basic operation
|
||||||
|
|
||||||
|
put_string (s: STRING_8)
|
||||||
|
-- Send `s' to http client
|
||||||
|
do
|
||||||
|
debug ("nino")
|
||||||
|
print (s)
|
||||||
|
end
|
||||||
|
nino_output.put_string (s)
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
note
|
||||||
|
description: "Summary description for {DEFAULT_EWSGI_APPLICATION}."
|
||||||
|
date: "$Date$"
|
||||||
|
revision: "$Revision$"
|
||||||
|
|
||||||
|
deferred class
|
||||||
|
DEFAULT_EWSGI_APPLICATION
|
||||||
|
|
||||||
|
inherit
|
||||||
|
GW_APPLICATION_IMP
|
||||||
|
|
||||||
|
feature {NONE} -- Initialization
|
||||||
|
|
||||||
|
make_and_launch
|
||||||
|
local
|
||||||
|
cgi: GW_CGI_CONNECTOR
|
||||||
|
do
|
||||||
|
create cgi.make (Current)
|
||||||
|
cgi.launch
|
||||||
|
end
|
||||||
|
|
||||||
|
note
|
||||||
|
copyright: "2011-2011, Eiffel Software and others"
|
||||||
|
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||||
|
source: "[
|
||||||
|
Eiffel Software
|
||||||
|
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||||
|
Telephone 805-685-1006, Fax 805-685-6869
|
||||||
|
Website http://www.eiffel.com
|
||||||
|
Customer support http://support.eiffel.com
|
||||||
|
]"
|
||||||
|
end
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?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="ewsgi_cgi" uuid="82D0E5BA-3EBD-4E0F-94D1-776375158DAA" library_target="ewsgi_cgi">
|
||||||
|
<target name="ewsgi_cgi">
|
||||||
|
<root all_classes="true"/>
|
||||||
|
<file_rule>
|
||||||
|
<exclude>/EIFGENs$</exclude>
|
||||||
|
<exclude>/\.git$</exclude>
|
||||||
|
<exclude>/\.svn$</exclude>
|
||||||
|
</file_rule>
|
||||||
|
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="provisional">
|
||||||
|
</option>
|
||||||
|
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||||
|
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
|
||||||
|
<library name="ewsgi_spec" location="../ewsgi_specification-safe.ecf"/>
|
||||||
|
<library name="ewsgi" location="../ewsgi-safe.ecf"/>
|
||||||
|
<library name="connector_cgi" location="../connectors/cgi/cgi-safe.ecf"/>
|
||||||
|
<library name="error" location="..\..\..\error\error-safe.ecf"/>
|
||||||
|
<library name="http" location="..\..\..\protocol\http\http-safe.ecf"/>
|
||||||
|
<library name="encoder" location="..\..\..\text\encoder\encoder-safe.ecf" readonly="false"/>
|
||||||
|
<cluster name="default_cgi" location="./cgi" recursive="true"/>
|
||||||
|
</target>
|
||||||
|
</system>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user