Refactor rename error_500_cms_response to internal_server_error_cms_response

Added bad_request_error_cms_response
Updated code example to use the new internal_server_error_cms_response instead of error_500_cms_response class.
Removed class error_500_cms_response.

Updated cms setup and configuration design:
  Removed CMS_SETUP.configuration: CMS_CONFIGURATION
  Removed CMS_CONFIGURATION and replaced it by using the configuration library.
  Added CMS_DEFAULT_SETUP.configuration: CONFIG_READER
  Addec CMS_SETUP.text_item (name): detachable READABLE_STRING_32 ...
    in order to access option not publish by the CMS_SETUP interface.
Removed CMS_SERVICE.configuration: CMS_CONFIGURATION since it was not used.

Moved configuration library from eiffel-lang to cms libraries.
Fixed issue related to ini config when parsing from string content,
  and also issue related to section included in file via @include.
Updated cms setup and configuration design:
  Removed CMS_SETUP.configuration: CMS_CONFIGURATION
  Removed CMS_CONFIGURATION and replaced it by using the configuration library.
  Added CMS_DEFAULT_SETUP.configuration: CONFIG_READER
  Addec CMS_SETUP.text_item (name): detachable READABLE_STRING_32 ...
    in order to access option not publish by the CMS_SETUP interface.
Removed CMS_SERVICE.configuration: CMS_CONFIGURATION since it was not used.
Improved the email service and related.
This commit is contained in:
jvelilla
2014-12-19 18:03:52 -03:00
parent bd26deb6c1
commit e2f02953f4
22 changed files with 1117 additions and 363 deletions

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="config" uuid="A3762109-D650-40A1-B55A-7D236A17903F" library_target="config">
<target name="config">
<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" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="config" uuid="A3762109-D650-40A1-B55A-7D236A17903F" library_target="config">
<target name="config">
<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="false" void_safety="none" syntax="standard">
</option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json.ecf"/>
<cluster name="src" location=".\src\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1,10 @@
${NOTE_KEYWORD}
copyright: "2011-${YEAR}, Jocelyn Fiat, 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
]"

View File

@@ -0,0 +1,121 @@
note
description: "Summary description for {CONFIG_READER}."
author: ""
date: "$Date: 2014-12-18 12:37:11 -0300 (ju. 18 de dic. de 2014) $"
revision: "$Revision: 96383 $"
deferred class
CONFIG_READER
inherit
SHARED_EXECUTION_ENVIRONMENT
feature -- Status report
has_item (k: READABLE_STRING_GENERAL): BOOLEAN
-- Has item associated with key `k'?
deferred
end
has_error: BOOLEAN
-- Has error?
--| Syntax error, source not found, ...
deferred
end
feature -- Query
resolved_text_item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
-- String item associated with key `k' and expanded to resolved variables ${varname}.
do
if attached text_item (k) as s then
Result := resolved_expression (s)
end
end
text_item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
-- String item associated with key `k'.
deferred
end
integer_item (k: READABLE_STRING_GENERAL): INTEGER
-- Integer item associated with key `k'.
deferred
ensure
not has_item (k) implies Result = 0
end
feature {NONE} -- Implementation
resolved_items: detachable STRING_TABLE [READABLE_STRING_32]
-- Resolved items indexed by expression.
resolved_expression (exp: READABLE_STRING_GENERAL): STRING_32
-- Resolved `exp' using `Current' or else environment variables.
local
i,n,b,e: INTEGER
k: detachable READABLE_STRING_GENERAL
c: CHARACTER_32
l_resolved_items: like resolved_items
l_text: detachable READABLE_STRING_GENERAL
do
from
i := 1
n := exp.count
create Result.make (n)
until
i > n
loop
c := exp[i]
if i + 1 < n and then c = '$' and then exp[i+1] = '{' then
b := i + 2
e := exp.index_of ('}', b) - 1
if e > 0 then
k := exp.substring (b, e)
l_text := Void
l_resolved_items := resolved_items
if
l_resolved_items /= Void and then
attached l_resolved_items.item (k) as s
then
-- Already resolved, reuse value.
l_text := s
elseif attached text_item (k) as s then
-- has such item
l_text := s
elseif attached execution_environment.item (k) as v then
-- Or from environment
l_text := v
else
l_text := exp.substring (i, e + 1)
end
i := e + 1
Result.append_string_general (l_text)
else
Result.extend (c)
end
else
Result.extend (c)
end
i := i + 1
end
end
feature -- Duplication
sub_config (k: READABLE_STRING_GENERAL): detachable CONFIG_READER
-- Configuration representing a subset of Current for key `k'.
deferred
end
note
copyright: "2011-2014, Jocelyn Fiat, 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

View File

@@ -0,0 +1,463 @@
note
description: "[
Object parsing a .ini file.
Lines starting by '#', or ';', or "--" are comments
Section are declared using brackets "[section_name]"
Values are declared as "key = value"
List values are declared as multiple lines "key[] = value"
example:
--------------------
[first_section]
one = abc
[second_section]
two = def
lst[] = a
lst[] = b
lst[] = c
[third_section]
three = ghi
table[a] = foo
table[b] = bar
--------------------
Values are accessible from `items' or by section from `sections'
`item' has smart support for '.'
item ("one") -> abc
item ("two") -> def
item ("second_section.two") -> def
item ("table[b]") -> foo
item ("table.b") -> foo
item ("third_section.table[b]") -> foo
item ("third_section.table.b") -> foo
notes:
it is considered that the .ini file is utf-8 encoded
keys are unicode string
values are stored UTF-8 string, but one can use unicode_string_item to convert to STRING_32
Additional features:
- Include other files:
@include=file-to-include
]"
date: "$Date: 2014-12-18 12:37:11 -0300 (ju. 18 de dic. de 2014) $"
revision: "$Revision: 96383 $"
class
INI_CONFIG
inherit
CONFIG_READER
TABLE_ITERABLE [ANY, READABLE_STRING_GENERAL]
SHARED_EXECUTION_ENVIRONMENT
create
make_from_file,
make_from_string,
make_from_items
feature {NONE} -- Initialization
make_from_file (p: PATH)
do
initialize
parse_file (p)
end
make_from_string (a_content: STRING_8)
do
initialize
parse_content (a_content)
end
make_from_items (a_items: like items)
do
initialize
across
a_items as ic
loop
items.force (ic.item, ic.key)
end
end
initialize
-- Initialize data.
do
associated_path := Void
create utf
create items.make (0)
create sections.make (0)
end
reset
-- Reset internal data.
do
has_error := False
items.wipe_out
sections.wipe_out
end
feature -- Status report
has_item (k: READABLE_STRING_GENERAL): BOOLEAN
-- Has item associated with key `k'?
do
Result := item (k) /= Void
end
has_error: BOOLEAN
-- Has error?
--| Syntax error, source not found, ...
feature -- Access: Config Reader
text_item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
-- String item associated with key `k'.
local
obj: like item
do
obj := item (k)
if attached {READABLE_STRING_32} obj as s32 then
Result := s32
elseif attached {READABLE_STRING_8} obj as s then
Result := utf.utf_8_string_8_to_escaped_string_32 (s)
end
end
integer_item (k: READABLE_STRING_GENERAL): INTEGER
-- Integer item associated with key `k'.
do
if attached {READABLE_STRING_GENERAL} item (k) as s then
Result := s.to_integer
end
end
associated_path: detachable PATH
-- If current was built from a filename, return this path.
feature -- Duplication
sub_config (k: READABLE_STRING_GENERAL): detachable CONFIG_READER
-- Configuration representing a subset of Current for key `k'.
do
if attached sections.item (k) as l_items then
create {INI_CONFIG} Result.make_from_items (l_items)
end
end
feature -- Access
item (k: READABLE_STRING_GENERAL): detachable ANY
-- Value associated with key `k'.
local
i: INTEGER
s,sk: detachable READABLE_STRING_GENERAL
do
-- Try first directly in values
Result := items.item (k)
if Result = Void then
--| If there is a dot
--| this could be
--| section.variable
--| variable.name or variable[name]
i := k.index_of ('.', 1)
if i > 0 then
s := k.head (i - 1)
-- then search first in section
if attached sections.item (s) as l_section then
sk := k.substring (i + 1, k.count)
Result := l_section.item (sk)
if Result = Void then
Result := item_from_values (l_section, sk)
end
end
if Result = Void then
i := k.index_of ('.', i + 1)
if i > 0 then
-- There is another dot .. could be due to include
across
sections as ic
until
Result /= Void
loop
s := ic.key
-- If has other dot, this may be in sub sections ...
if s.has ('.') and then k.starts_with (s) and then k[s.count + 1] = '.' then
if attached sections.item (s) as l_section then
sk := k.substring (s.count + 2, k.count)
Result := l_section.item (sk)
if Result = Void then
Result := item_from_values (l_section, sk)
end
end
end
end
end
if Result = Void then
-- otherwise in values object.
Result := item_from_values (items, k)
end
end
else
--| Could be
--| variable[name]
Result := item_from_values (items, k)
end
end
end
items: STRING_TABLE [ANY]
sections: STRING_TABLE [like items]
feature -- Access
new_cursor: TABLE_ITERATION_CURSOR [ANY, READABLE_STRING_GENERAL]
-- Fresh cursor associated with current structure
do
Result := items.new_cursor
end
feature {NONE} -- Implementation
item_from_values (a_values: STRING_TABLE [ANY]; k: READABLE_STRING_GENERAL): detachable ANY
local
i,j: INTEGER
s: READABLE_STRING_GENERAL
do
Result := a_values.item (k)
if Result = Void then
i := k.index_of ('.', 1)
if i > 0 then
s := k.head (i - 1)
if attached {STRING_TABLE [ANY]} a_values.item (s) as l_table then
Result := l_table.item (k.substring (i + 1, k.count))
end
else
i := k.index_of ('[', 1)
if i > 0 then
j := k.index_of (']', i + 1)
if j = k.count then
s := k.head (i - 1)
if attached {STRING_TABLE [ANY]} a_values.item (s) as l_table then
Result := l_table.item (k.substring (i + 1, j - 1))
end
end
end
end
end
end
record_in_section (obj: ANY; k: READABLE_STRING_GENERAL; a_section: READABLE_STRING_GENERAL)
local
v: detachable like items
do
v := sections.item (a_section)
if v = Void then
create v.make (1)
sections.force (v, a_section)
end
v.force (obj, k)
end
parse_content (a_content: STRING_8)
local
i,j,n: INTEGER
s: READABLE_STRING_8
do
last_section_name := Void
from
i := 1
n := a_content.count
until
i > n
loop
j := a_content.index_of ('%N', i)
if j > 0 then
s := a_content.substring (i, j - 1)
i := j + 1
if i <= n and then a_content[i] = '%R' then
i := i + 1
end
else
j := n
s := a_content.substring (i, j)
i := j + 1
end
analyze_line (s, Void)
variant
i
end
last_section_name := Void
rescue
last_section_name := Void
has_error := True
end
parse_file (p: PATH)
do
associated_path := p
last_section_name := Void
import_path (p, Void)
last_section_name := Void
end
import_path (p: PATH; a_section_prefix: detachable READABLE_STRING_32)
-- Import config from path `p'.
local
f: PLAIN_TEXT_FILE
l_last_section_name: like last_section_name
retried: BOOLEAN
do
if retried then
has_error := True
else
l_last_section_name := last_section_name
last_section_name := Void
create f.make_with_path (p)
if f.exists and then f.is_access_readable then
f.open_read
from
until
f.exhausted or f.end_of_file
loop
f.read_line_thread_aware
analyze_line (f.last_string, a_section_prefix)
end
f.close
else
-- File not readable
has_error := True
end
end
last_section_name := l_last_section_name
rescue
retried := True
retry
end
analyze_line (a_line: STRING_8; a_section_prefix: detachable READABLE_STRING_32)
-- Analyze line `a_line'.
local
k,sk: STRING_32
v: STRING_8
obj: detachable ANY
lst: LIST [STRING_8]
tb: STRING_TABLE [STRING_8]
i,j: INTEGER
l_section_name: like last_section_name
do
obj := Void
a_line.left_adjust
if
a_line.is_empty
or a_line.is_whitespace
or a_line.starts_with_general ("#")
or a_line.starts_with_general (";")
or a_line.starts_with_general ("--")
then
-- Ignore
elseif a_line.starts_with_general ("[") then
i := a_line.index_of (']', 1)
l_section_name := utf.utf_8_string_8_to_string_32 (a_line.substring (2, i - 1))
l_section_name.left_adjust
l_section_name.right_adjust
if a_section_prefix /= Void then
l_section_name.prepend_character ('.')
l_section_name.prepend (a_section_prefix)
end
last_section_name := l_section_name
else
i := a_line.index_of ('=', 1)
if i > 1 then
k := utf.utf_8_string_8_to_string_32 (a_line.head (i - 1))
k.right_adjust
v := a_line.substring (i + 1, a_line.count)
v.left_adjust
v.right_adjust
if k.is_case_insensitive_equal_general ("@include") then
import_path (create {PATH}.make_from_string (v), last_section_name)
else
i := k.index_of ('[', 1)
if i > 0 then
j := k.index_of (']', i + 1)
if j = i + 1 then -- ends_with "[]"
k.keep_head (i - 1)
if attached {LIST [STRING_8]} items.item (k) as l_list then
lst := l_list
else
create {ARRAYED_LIST [STRING_8]} lst.make (1)
record_item (lst, k, a_section_prefix)
end
lst.force (v)
obj := lst
elseif j > i then
-- table
sk := k.substring (i + 1, j - 1)
sk.left_adjust
sk.right_adjust
k.keep_head (i - 1)
if attached {STRING_TABLE [STRING_8]} items.item (k) as l_table then
tb := l_table
else
create tb.make (1)
record_item (tb, k, a_section_prefix)
end
tb.force (v, sk)
obj := tb
else
-- Error missing closing ']'
has_error := True
end
else
record_item (v, k, a_section_prefix)
obj := v
end
if attached last_section_name as l_session and then obj /= Void then
record_in_section (obj, k, l_session)
end
end
else
-- Error
has_error := True
end
end
end
record_item (v: ANY; k: READABLE_STRING_32; a_section_prefix: detachable READABLE_STRING_32)
do
if a_section_prefix /= Void then
items.force (v, a_section_prefix + {STRING_32} "." + k)
else
items.force (v, k)
end
end
feature {NONE} -- Implementation
last_section_name: detachable STRING_32
utf: UTF_CONVERTER
invariant
note
copyright: "2011-2014, Jocelyn Fiat, 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

View File

@@ -0,0 +1,175 @@
note
description: "Object parsing a JSON configuration file."
date: "$Date: 2014-12-18 12:37:11 -0300 (ju. 18 de dic. de 2014) $"
revision: "$Revision: 96383 $"
class
JSON_CONFIG
inherit
CONFIG_READER
create
make_from_file,
make_from_string,
make_from_json_object
feature {NONE} -- Initialization
make_from_file (p: PATH)
-- Create object from a file `p'
do
parse (p)
end
make_from_string (a_json: READABLE_STRING_8)
-- Create current config from string `a_json'.
local
l_parser: JSON_PARSER
do
create l_parser.make_with_string (a_json)
l_parser.parse_content
if
l_parser.is_valid and then
attached l_parser.parsed_json_object as j_o
then
make_from_json_object (j_o)
else
has_error := True
end
end
make_from_json_object (a_object: JSON_OBJECT)
-- Create current config from JSON `a_object'.
do
associated_path := Void
json_value := a_object
end
feature -- Status report
has_item (k: READABLE_STRING_GENERAL): BOOLEAN
-- Has item associated with key `k'?
do
Result := item (k) /= Void
end
has_error: BOOLEAN
-- Has error?
--| Syntax error, source not found, ...
feature -- Access: Config Reader
text_item (k: READABLE_STRING_GENERAL): detachable READABLE_STRING_32
-- String item associated with query `k'.
do
if attached {JSON_STRING} item (k) as l_string then
Result := l_string.unescaped_string_32
elseif attached {JSON_NUMBER} item (k) as l_number then
Result := l_number.item
end
end
integer_item (k: READABLE_STRING_GENERAL): INTEGER
-- Integer item associated with key `k'.
do
if attached {JSON_NUMBER} item (k) as l_number then
Result := l_number.item.to_integer
end
end
associated_path: detachable PATH
-- If current was built from a filename, return this path.
feature -- Duplication
sub_config (k: READABLE_STRING_GENERAL): detachable CONFIG_READER
-- Configuration representing a subset of Current for key `k'.
do
if attached {JSON_OBJECT} item (k) as j_o then
create {JSON_CONFIG} Result.make_from_json_object (j_o)
end
end
feature -- Access
item (k: READABLE_STRING_GENERAL): detachable JSON_VALUE
-- Item associated with query `k' if any.
-- `k' can be a single name such as "foo",
-- or a qualified name such as "foo.bar" (assuming that "foo" is associated with a JSON object).
do
if attached json_value as obj then
Result := object_json_value (obj, k.to_string_32)
end
end
feature {NONE} -- Implementation
object_json_value (a_object: JSON_OBJECT; a_query: READABLE_STRING_32): detachable JSON_VALUE
-- Item associated with query `a_query' from object `a_object' if any.
local
i: INTEGER
h: READABLE_STRING_32
do
i := a_query.index_of ('.', 1)
if i > 1 then
h := a_query.head (i - 1)
if attached {JSON_OBJECT} a_object.item (h) as l_obj then
Result := object_json_value (l_obj, a_query.substring (i + 1, a_query.count))
else
-- This is not an object...
Result := Void
end
else
Result := a_object.item (a_query)
end
end
parse (a_path: PATH)
local
l_parser: JSON_PARSER
do
associated_path := a_path
has_error := False
if attached json_file_from (a_path) as json_file then
l_parser := new_json_parser (json_file)
l_parser.parse_content
if
l_parser.is_valid and then
attached l_parser.parsed_json_object as jv
then
json_value := jv
else
has_error := True
end
else
has_error := True
end
end
feature {NONE} -- JSON
json_value: detachable JSON_OBJECT
-- Possible json object representation.
json_file_from (a_fn: PATH): detachable STRING
do
Result := (create {JSON_FILE_READER}).read_json_from (a_fn.name.out)
end
new_json_parser (a_string: STRING): JSON_PARSER
do
create Result.make_with_string (a_string)
end
note
copyright: "2011-2014, Jocelyn Fiat, 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

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="config_tests" uuid="AD1DE0F7-BC8A-4A17-9A44-56C917BD5604">
<target name="config_tests">
<root class="TEST_CONFIG_READER_SET" 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="transitional" syntax="standard">
</option>
<setting name="concurrency" value="none"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="config" location="..\config-safe.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<tests name="src" location=".\"/>
</target>
</system>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="config_tests" uuid="AD1DE0F7-BC8A-4A17-9A44-56C917BD5604">
<target name="config_tests">
<root class="TEST_CONFIG_READER_SET" feature="default_create"/>
<file_rule>
<exclude>/.git$</exclude>
<exclude>/EIFGENs$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
<option warning="true" full_class_checking="true" void_safety="none" syntax="standard">
</option>
<setting name="concurrency" value="none"/>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
<library name="config" location="..\config.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing.ecf"/>
<tests name="src" location=".\"/>
</target>
</system>

View File

@@ -0,0 +1,177 @@
note
description: "[
Testing suite for CONFIG_READER .
]"
author: "$Author: jfiat $"
date: "$Date: 2014-12-18 12:37:11 -0300 (ju. 18 de dic. de 2014) $"
revision: "$Revision: 96383 $"
class
TEST_CONFIG_READER_SET
inherit
EQA_TEST_SET
feature -- Test
test_ini
local
cfg: CONFIG_READER
do
create {INI_CONFIG} cfg.make_from_string ("[
foo = bar
[first]
abc = 1
def = and so on
ghi = "path"
[ second ]
this = 1
is = 2
the = 3
end = 4
]")
assert ("is valid", not cfg.has_error)
assert ("has_item (foo)", cfg.has_item ("foo"))
assert ("has_item (abc)", cfg.has_item ("abc"))
assert ("has_item (def)", cfg.has_item ("def"))
assert ("has_item (ghi)", cfg.has_item ("ghi"))
assert ("has_item (this)", cfg.has_item ("this"))
assert ("has_item (is)", cfg.has_item ("is"))
assert ("has_item (the)", cfg.has_item ("the"))
assert ("has_item (end)", cfg.has_item ("end"))
assert ("item (foo)", attached cfg.text_item ("foo") as v and then v.same_string_general ("bar"))
assert ("item (abc)", attached cfg.text_item ("abc") as v and then v.same_string_general ("1"))
assert ("item (def)", attached cfg.text_item ("def") as v and then v.same_string_general ("and so on"))
assert ("item (ghi)", attached cfg.text_item ("ghi") as v and then v.same_string_general ("%"path%""))
assert ("item (this)", attached cfg.text_item ("this") as v and then v.same_string_general ("1"))
assert ("item (is)", attached cfg.text_item ("is") as v and then v.same_string_general ("2"))
assert ("item (the)", attached cfg.text_item ("the") as v and then v.same_string_general ("3"))
assert ("item (end)", attached cfg.text_item ("end") as v and then v.same_string_general ("4"))
assert ("has_item (first.abc)", cfg.has_item ("first.abc"))
assert ("item (first.abc)", attached cfg.text_item ("first.abc") as v and then v.same_string_general ("1"))
assert ("has_item (second.is)", cfg.has_item ("second.is"))
assert ("item (second.is)", attached cfg.text_item ("second.is") as v and then v.same_string_general ("2"))
if attached cfg.sub_config ("second") as cfg_second then
assert ("has_item (is)", cfg_second.has_item ("is"))
assert ("item (is)", attached cfg_second.text_item ("is") as v and then v.same_string_general ("2"))
else
assert ("has second", False)
end
end
test_resolver_ini
local
cfg: CONFIG_READER
do
create {INI_CONFIG} cfg.make_from_string ("[
foo = bar
[extra]
a.b.c = abc
[expression]
text = ${foo}/${a.b.c}
]")
assert ("is valid", not cfg.has_error)
assert ("has_item (extra.a.b.c)", cfg.has_item ("extra.a.b.c"))
assert ("has_item (extra.a.b.c)", cfg.has_item ("extra.a.b.c"))
assert ("has_item (expression.text)", cfg.has_item ("expression.text"))
assert ("item (expression.text)", attached cfg.resolved_text_item ("expression.text") as s and then s.same_string_general ("bar/abc"))
end
test_deep_ini
local
cfg: CONFIG_READER
f: RAW_FILE
do
create f.make_with_name ("test_deep.ini")
f.create_read_write
f.put_string ("[
test = extra
[new]
enabled = true
]"
)
f.close
create {INI_CONFIG} cfg.make_from_string ("[
foo = bar
[extra]
a.b.c = abc
[outside]
before = include
@include=test_deep.ini
]")
f.delete
assert ("is valid", not cfg.has_error)
assert ("has_item (extra.a.b.c)", cfg.has_item ("extra.a.b.c"))
assert ("has_item (extra.a.b.c)", cfg.has_item ("extra.a.b.c"))
assert ("has_item (outside.new.enabled)", cfg.has_item ("outside.new.enabled"))
end
test_json
local
cfg: CONFIG_READER
do
create {JSON_CONFIG} cfg.make_from_string ("[
{
"foo": "bar",
"first": {
"abc": 1,
"def": "and so on",
"ghi": "\"path\""
},
"second": {
"this": 1,
"is": 2,
"the": 3,
"end": 4
}
}
]")
assert ("is valid", not cfg.has_error)
assert ("has_item (foo)", cfg.has_item ("foo"))
assert ("has_item (first.abc)", cfg.has_item ("first.abc"))
assert ("has_item (first.def)", cfg.has_item ("first.def"))
assert ("has_item (first.ghi)", cfg.has_item ("first.ghi"))
assert ("has_item (second.this)", cfg.has_item ("second.this"))
assert ("has_item (second.is)", cfg.has_item ("second.is"))
assert ("has_item (second.the)", cfg.has_item ("second.the"))
assert ("has_item (second.end)", cfg.has_item ("second.end"))
assert ("item (foo)", attached cfg.text_item ("foo") as v and then v.same_string_general ("bar"))
assert ("item (first.abc)", attached cfg.text_item ("first.abc") as v and then v.same_string_general ("1"))
assert ("item (first.def)", attached cfg.text_item ("first.def") as v and then v.same_string_general ("and so on"))
assert ("item (first.ghi)", attached cfg.text_item ("first.ghi") as v and then v.same_string_general ("%"path%""))
assert ("item (second.this)", attached cfg.text_item ("second.this") as v and then v.same_string_general ("1"))
assert ("item (second.is)", attached cfg.text_item ("second.is") as v and then v.same_string_general ("2"))
assert ("item (second.the)", attached cfg.text_item ("second.the") as v and then v.same_string_general ("3"))
assert ("item (second.end)", attached cfg.text_item ("second.end") as v and then v.same_string_general ("4"))
if attached cfg.sub_config ("second") as cfg_second then
assert ("has_item (is)", cfg_second.has_item ("is"))
assert ("item (is)", attached cfg_second.text_item ("is") as v and then v.same_string_general ("2"))
else
assert ("has second", False)
end
end
end