Compare commits

..

65 Commits

Author SHA1 Message Date
Jocelyn Fiat 8b33c77008 Added JSON_PRETTY_STRING_VISITOR
Added converter for ARRAYED_LIST
Fixed STRING_32 to JSON_VALUE issue in ejson.e
Added missing new line character at the end of some files.
Cosmetic
2012-08-08 08:51:00 +02:00
Jocelyn Fiat 6fa0d56465 cosmetic 2012-06-28 18:07:18 +02:00
Jocelyn Fiat 873f877530 Added TABLE_ITERABLE interface to JSON_OBJECT
Added JSON_OBJECT.replace (value, key)
2012-06-28 16:52:11 +02:00
jfiat c873d62efa added JSON_OBJECT.is_empty: BOOLEAN 2012-02-21 10:07:58 +00:00
jfiat a6c52c0a7e Renamed JSON_STRING.unescaped_string as unescaped_string_8
+ code cleaning
2012-01-13 17:57:49 +00:00
jfiat d67e01eea6 Better support for special character and unicode (\n \r \" ... and \uXXXX where XXXX is an hexadecimal value)
Added features to JSON_STRING
  - make_json_from_string_32 (READABLE_STRING_32)
  - escaped_string_8: STRING_8
  - escaped_string_32: STRING_32
Added associated autotests
2012-01-13 17:26:23 +00:00
jfiat 1b446caa27 Removing autotest dotnet target, since Autotest does not support .Net platform for now 2011-11-21 13:54:50 +00:00
jfiat 24b1be7482 Fixed code from autotest tests to remove warnings
Fixed getest ejson_test.ecf configuration file
Added script to allow using getest from Windows.

Note: I  did not fixed warning from getest tests, we should apply same change already made for autotest.
      it seems autotest and getests are doing the same checking, 
      I would suggest to either remove getest files or find a way to share test code between getest and autotest tests.
2011-11-21 09:20:46 +00:00
jfiat c836d75191 Added more conversion, and accept READABLE_STRING_8 as argument for make_json 2011-10-07 12:25:00 +00:00
jfiat 3739909e43 Minor changes + cosmetics
Added conversion from STRING to JSON_STRING to help users.
2011-10-07 12:19:27 +00:00
jvelilla 05b4bd90f5 Added test cases from getest to autotest. First version. 2011-07-11 12:07:05 +00:00
jfiat 6188f99615 added run_autotest.bat scripts 2011-07-08 10:10:40 +00:00
jfiat 28a699e5f2 Converted the autotest test suite to void-safety
+ cosmetics
2011-07-07 14:39:06 +00:00
jfiat 591cfb6cfa Now if you want to use the json utilities for gobo, you just need to include the json_gobo_extension.ecf (note that the related gobo classes are not void-safe)
+ cosmetics
2011-07-07 14:03:36 +00:00
jvelilla f4c472cb9f Updated eJSON to use Eiffel 6.8 version.
Basically the changes are:

Replace ? by detachable
indexing by note
removing `is' from features, and in some places replaced by =
In the ecf now we need to include every gobo library, because the gobo.ecf, exclude libraries that are needed.
TODO: the test-suite is not void-safety.
2011-07-07 12:03:25 +00:00
jvelilla 94c5c90eaa Updated History and Readme files. 2011-07-06 22:12:26 +00:00
jvelilla e638eeaae4 Updated skip_white_spaces, now check %U and %T codes 2010-03-16 00:08:37 +00:00
jvelilla 5d63c63a39 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. 2010-03-10 11:16:16 +00:00
jvelilla a863e495ae Updated test_json_fail18 , it's a valid JSON, maybe we need to rename this to test_json_pass4 and the file fail18.json to pass4.json 2010-03-10 11:07:33 +00:00
jvelilla 327196a3cf Removed obsolete cluster. 2010-03-09 11:41:08 +00:00
jvelilla 805874dc9c Added autotest test suite 2010-03-09 11:37:55 +00:00
paul.cohen 11256d697d Added getest based test program 2010-03-08 23:46:59 +00:00
jvelilla b389d532b7 Updated Eiffel configuration file, updated to the new clusters 2010-03-08 23:43:35 +00:00
paul.cohen a0e570226c Ported r75 (all JSON value classes) from POC_CONVERTERS_FACTORY branch to trunk 2010-03-08 22:45:41 +00:00
paul.cohen 2710cae1da Merged converters and factory classes from POC_CONVERTERS_FACTORY to trunk 2010-03-08 15:35:32 +00:00
paul.cohen 8cd53b87eb New directory layout created 2010-03-08 15:28:47 +00:00
paul.cohen 6bef8ec387 Added new top level directories; library, test, build and example 2010-03-08 15:08:37 +00:00
jvelilla f86abed2ff Added History, Readme and License files 2010-03-05 09:18:38 +00:00
jvelilla 7a31e80f90 Simples fixes to the parser, add is_valid_start_symbol and updated parse_json. 2009-08-14 11:19:54 +00:00
jvelilla aed8d1a516 Added set_representation feature. 2009-08-14 11:09:38 +00:00
jfiat ab19cc2b16 use item (i) instead [i] 2009-08-13 06:32:32 +00:00
jfiat d4da754a9c Optimized code, and removed extra dependencies.
Added void-safe version
2009-08-04 12:01:03 +00:00
jfiat f1f1f5fbf6 Fixed typo 2009-03-18 16:46:27 +00:00
jfiat 548a320448 Cosmetic + Optimization + Assertion + Void-safety
(no significant interface changes)
2009-03-18 15:29:41 +00:00
jvelilla 1359a1ceae Add descriptions.
Change in skip_withe_spaces to handle newline %N and carriage Return %R
2008-08-29 10:49:24 +00:00
jvelilla fc7c2d151f Change in the loop, to generate the correct answer (feature visit_json_object). 2008-08-29 10:45:04 +00:00
jvelilla 4e6935655f Add cluster visitor. 2008-08-29 10:40:12 +00:00
berend d940da7b13 SmartEiffel doesn't have is_space. 2008-08-27 04:29:42 +00:00
berend 31619fc88e JSON number is a double precision IEEE number, not a single precision. 2008-08-27 04:29:12 +00:00
berend bf781a9d25 Changed formatting a bit.
Made it compile with SE 1.2r7
2008-08-27 04:26:44 +00:00
jvelilla 31750efb8e Add accept method (JSON_VISITOR), remove is_xxx queries, remove to_json feature.
Improve comments
2008-08-25 01:13:35 +00:00
jvelilla f83c5d2643 Add Visitor Pattern , JSON_VISITOR and PRINT_JSON_VISITOR 2008-08-25 01:10:42 +00:00
jvelilla c59bc37a40 Fix Bug in quey 'is_a_valid_number'
Remove the space after :  in the regular expression "-?(?: 0|[1-9]\d*)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"
2008-08-08 11:17:32 +00:00
jvelilla b674dbddf7 Add precondition in query i_th
Remove infix "@" which is deprecated now.
Add invariant for values to show that it is always not Void.
Add postcondition of add.
2008-08-08 11:12:27 +00:00
jvelilla ed5f8a9740 Redefine the version of ANY of is_equal. 2008-08-08 11:08:51 +00:00
jvelilla 2c42c0dd1a Change void to Void.
Add invariant for 'object' , object_no_null /= Void
2008-08-08 11:04:33 +00:00
jvelilla d64e01641b Reformatted code to Eiffel Standard 2008-08-08 11:01:14 +00:00
berend fa35ab07a0 Fixed bug where a JSON string had to end with CRLF. But that's optional.
Reformatted code to Gobo standard.
2008-08-05 03:26:08 +00:00
berend 0bf10c633f Reformatted code to Gobo standard. 2008-08-05 03:25:14 +00:00
jvelilla bc1e6653ae Add Regular expression to check valid numbers and valid unicodes.
Add errors to the parser, under development
2008-07-13 03:30:54 +00:00
jvelilla b9ccf20d53 Add explicit control characters. 2008-07-13 03:19:20 +00:00
jvelilla 3e7f107b36 Update json.ecf,
Dependencies on Gobo Library. (Regular Expressions)
2008-07-13 03:17:37 +00:00
jvelilla aa8c2d0a95 Update parse_number 2008-07-09 02:40:38 +00:00
jvelilla 65cd9e8780 Add new files to test ejson, based on json t test material http://www.json.org/JSON_checker/test.zip 2008-06-09 02:24:33 +00:00
jvelilla cb595d27f4 Update JSON_OBJECT, put routine, now follows Eiffel Style based on HAST_TABLE 2008-06-09 02:18:34 +00:00
jvelilla aaa10d178a Update Parser with is_parsed.
Update parse_string
2008-06-09 01:32:28 +00:00
jvelilla 1052c10b8d Update test 2008-05-25 18:29:54 +00:00
jvelilla 3083f378a6 Update test 2008-05-25 18:28:40 +00:00
jvelilla 8357bf5d72 Update JSON_VALUE and JSON_OBJECT interface 2008-05-25 18:23:25 +00:00
jvelilla 8f3c7beba8 CDD classes 2008-05-25 00:03:46 +00:00
jvelilla 5a779fbb57 Add new test_json_object 2008-05-25 00:02:56 +00:00
jvelilla 4559b7fef5 Add new test_json_object 2008-05-25 00:00:43 +00:00
jvelilla 7dc33a52f6 Update JSON_STRING rutine is_equal
Update JSON_OBJECT new features (has_keys, item,get_keys), and fixed an incorrect use of HASH_TABLE
2008-05-24 23:57:04 +00:00
jvelilla de347f6c98 eJson tests initial import 2008-05-24 15:04:36 +00:00
jvelilla 308fa7f2e7 eJson initial import 2008-05-24 14:23:27 +00:00
253 changed files with 6206 additions and 16902 deletions
-2
View File
@@ -1,2 +0,0 @@
EIFGENs
tests/temp/
-9
View File
@@ -1,9 +0,0 @@
[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
View File
@@ -0,0 +1,26 @@
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
-20
View File
@@ -1,20 +0,0 @@
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
View File
@@ -0,0 +1,20 @@
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.
-1
View File
@@ -1 +0,0 @@
README.md
-30
View File
@@ -1,30 +0,0 @@
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
View File
@@ -0,0 +1,97 @@
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
View File
Submodule doc/wiki deleted from c7f4f45f5e
-1
View File
@@ -1 +0,0 @@
Examples ...
Submodule ext/server/nino deleted from 9dd1439a2f
Submodule ext/text/json deleted from e1c66b50ca
-16
View File
@@ -1,16 +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="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>
-16
View File
@@ -1,16 +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="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>
-10
View File
@@ -1,10 +0,0 @@
${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
]"
-80
View File
@@ -1,80 +0,0 @@
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
-57
View File
@@ -1,57 +0,0 @@
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
-75
View File
@@ -1,75 +0,0 @@
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
-92
View File
@@ -1,92 +0,0 @@
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
@@ -1,49 +0,0 @@
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
@@ -1,38 +0,0 @@
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
-35
View File
@@ -1,35 +0,0 @@
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
@@ -1,53 +0,0 @@
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
@@ -1,93 +0,0 @@
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
@@ -1,53 +0,0 @@
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
+38
View File
@@ -0,0 +1,38 @@
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
@@ -0,0 +1,175 @@
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
+59
View File
@@ -0,0 +1,59 @@
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
+102
View File
@@ -0,0 +1,102 @@
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
@@ -0,0 +1,81 @@
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
@@ -0,0 +1,62 @@
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
+32
View File
@@ -0,0 +1,32 @@
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
+28
View File
@@ -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="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>
+28
View File
@@ -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="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
View File
@@ -0,0 +1 @@
+17
View File
@@ -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="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>
@@ -0,0 +1,30 @@
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
@@ -0,0 +1,36 @@
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
@@ -0,0 +1,88 @@
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
@@ -0,0 +1,30 @@
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
@@ -0,0 +1,74 @@
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
+268
View File
@@ -0,0 +1,268 @@
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
+141
View File
@@ -0,0 +1,141 @@
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
+61
View File
@@ -0,0 +1,61 @@
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
+47
View File
@@ -0,0 +1,47 @@
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
+99
View File
@@ -0,0 +1,99 @@
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
+191
View File
@@ -0,0 +1,191 @@
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
+329
View File
@@ -0,0 +1,329 @@
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
+43
View File
@@ -0,0 +1,43 @@
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
+513
View File
@@ -0,0 +1,513 @@
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
+118
View File
@@ -0,0 +1,118 @@
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
+77
View File
@@ -0,0 +1,77 @@
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
+38
View File
@@ -0,0 +1,38 @@
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
-17
View File
@@ -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="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>
-18
View File
@@ -1,18 +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="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>
-10
View File
@@ -1,10 +0,0 @@
${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
]"
@@ -1,98 +0,0 @@
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
@@ -1,71 +0,0 @@
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
@@ -1,86 +0,0 @@
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
@@ -1,79 +0,0 @@
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
@@ -1,106 +0,0 @@
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
@@ -1,160 +0,0 @@
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
@@ -1,4 +0,0 @@
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
-10
View File
@@ -1,10 +0,0 @@
${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
]"
@@ -1,52 +0,0 @@
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
@@ -1,381 +0,0 @@
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
@@ -1,52 +0,0 @@
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
@@ -1,273 +0,0 @@
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
@@ -1,412 +0,0 @@
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
@@ -1,25 +0,0 @@
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
@@ -1,55 +0,0 @@
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
@@ -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="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>
@@ -1,638 +0,0 @@
note
description: "[
Eiffel tests that can be executed by testing tool.
]"
author: "EiffelStudio test wizard"
date: "$Date$"
revision: "$Revision$"
testing: "type/manual"
class
TEST_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
@@ -1,639 +0,0 @@
note
description: "[
Eiffel tests that can be executed by testing tool.
]"
author: "EiffelStudio test wizard"
date: "$Date$"
revision: "$Revision$"
testing: "type/manual"
class
TEST_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
@@ -1,46 +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="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>
@@ -1,51 +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="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>
-9
View File
@@ -1,9 +0,0 @@
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
@@ -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="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>
@@ -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="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>
@@ -1,10 +0,0 @@
${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
]"
@@ -1,36 +0,0 @@
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
@@ -1,39 +0,0 @@
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
@@ -1,67 +0,0 @@
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
@@ -1,18 +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="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>
@@ -1,18 +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="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>
@@ -1,10 +0,0 @@
${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
]"
@@ -1,81 +0,0 @@
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
@@ -1,65 +0,0 @@
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
@@ -1,78 +0,0 @@
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
@@ -1,10 +0,0 @@
${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
]"
@@ -1,20 +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="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>
@@ -1,20 +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="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>
@@ -1,93 +0,0 @@
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
@@ -1,157 +0,0 @@
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
@@ -1,61 +0,0 @@
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
@@ -1,79 +0,0 @@
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
@@ -1,32 +0,0 @@
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
@@ -1,22 +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="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