Merge remote-tracking branch 'jamesaimonetti/spec03-ref' into json-references

This commit is contained in:
Emil Falk 2015-05-21 09:04:50 +02:00
commit f34852794b
3 changed files with 70 additions and 10 deletions

View File

@ -27,6 +27,7 @@
, get_allowed_errors/1
, get_current_path/1
, get_current_schema/1
, get_original_schema/1
, get_default_schema_ver/1
, get_error_handler/1
, get_error_list/1
@ -35,11 +36,17 @@
, set_allowed_errors/2
, set_current_schema/2
, set_error_list/2
, find_schema/2
]).
-export_type([ state/0
]).
%% Includes
-include("jesse_schema_validator.hrl").
-define(schema_loader_fun, fun jesse_database:read/1).
%% Internal datastructures
-record( state
, { original_schema :: jesse:json_term()
@ -49,14 +56,12 @@
, error_list :: list()
, error_handler :: fun((#state{}) -> list() | no_return())
, default_schema_ver :: atom()
, schema_loader_fun :: fun((binary()) -> {ok, jesse:json_term()} | jesse:json_term() | ?not_found)
}
).
-opaque state() :: #state{}.
%% Includes
-include("jesse_schema_validator.hrl").
%%% API
%% @doc Adds `Property' to the `current_path' in `State'.
-spec add_to_path(State :: state(), Property :: binary()) -> state().
@ -79,6 +84,11 @@ get_current_path(#state{current_path = CurrentPath}) ->
get_current_schema(#state{current_schema = CurrentSchema}) ->
CurrentSchema.
%% @doc Getter for `original_schema'.
-spec get_original_schema(State :: state()) -> jesse:json_term().
get_original_schema(#state{original_schema = OriginalSchema}) ->
OriginalSchema.
%% @doc Getter for `default_schema_ver'.
-spec get_default_schema_ver(State :: state()) -> binary().
get_default_schema_ver(#state{default_schema_ver = SchemaVer}) ->
@ -113,6 +123,10 @@ new(JsonSchema, Options) ->
, Options
, ?default_schema_ver
),
LoaderFun = proplists:get_value( schema_loader_fun
, Options
, ?schema_loader_fun
),
#state{ current_schema = JsonSchema
, current_path = []
, original_schema = JsonSchema
@ -120,6 +134,7 @@ new(JsonSchema, Options) ->
, error_list = []
, error_handler = ErrorHandler
, default_schema_ver = DefaultSchemaVer
, schema_loader_fun = LoaderFun
}.
%% @doc Removes the last element from `current_path' in `State'.
@ -146,6 +161,20 @@ set_current_schema(State, NewSchema) ->
set_error_list(State, ErrorList) ->
State#state{error_list = ErrorList}.
%% @doc Find a schema based on URI
-spec find_schema(State :: state(), SchemaURI :: binary()) -> jesse:json_term() | ?not_found.
find_schema(#state{schema_loader_fun=LoaderFun}, SchemaURI) ->
try LoaderFun(SchemaURI) of
{ok, Schema} -> Schema;
Schema ->
case jesse_lib:is_json_object(Schema) of
true -> Schema;
false -> ?not_found
end
catch
_:_ -> ?not_found
end.
%%% Local Variables:
%%% erlang-indent-level: 2
%%% End:

View File

@ -185,6 +185,9 @@ check_value(Value, [{?DISALLOW, Disallow} | Attrs], State) ->
check_value(Value, [{?EXTENDS, Extends} | Attrs], State) ->
NewState = check_extends(Value, Extends, State),
check_value(Value, Attrs, NewState);
check_value(Value, [{?_REF, RefSchemaURI} | Attrs], State) ->
NewState = check_ref(Value, RefSchemaURI, State),
check_value(Value, Attrs, NewState);
check_value(_Value, [], State) ->
State;
check_value(Value, [_Attr | Attrs], State) ->
@ -861,6 +864,35 @@ check_extends_array(Value, Extends, State) ->
, Extends
).
%% @private
check_ref(Value, <<"#", LocalPath/binary>> = RefSchemaURI, State) ->
Keys = binary:split(LocalPath, <<"/">>, ['global']),
OriginalSchema = jesse_state:get_original_schema(State),
case local_schema(OriginalSchema, Keys) of
?not_found -> handle_schema_invalid({'schema_unsupported', RefSchemaURI}, State);
LocalSchema -> check_ref_schema(Value, LocalSchema, State)
end;
check_ref(Value, RefSchemaURI, State) ->
case jesse_state:find_schema(State, RefSchemaURI) of
?not_found -> handle_schema_invalid({'schema_unsupported', RefSchemaURI}, State);
RefSchema -> check_ref_schema(Value, RefSchema, State)
end.
%% @private
check_ref_schema(Value, RefSchema, State) ->
TmpState = check_value(Value, unwrap(RefSchema), set_current_schema(State, RefSchema)),
set_current_schema(TmpState, get_current_schema(State)).
local_schema(Schema, []) -> Schema;
local_schema(Schema, [<<>> | Keys]) -> local_schema(Schema, Keys);
local_schema(Schema, [Key | Keys]) ->
SubSchema = get_value(Key, Schema),
case jesse_lib:is_json_object(SubSchema) of
true -> local_schema(SubSchema, Keys);
false -> ?not_found
end.
%%=============================================================================
%% @doc Returns `true' if given values (instance) are equal, otherwise `false'
%% is returned.

View File

@ -43,7 +43,7 @@
, pattern/1
, patternProperties/1
, properties/1
%% , ref/1
, ref/1
, required/1
, type/1
, uniqueItems/1
@ -78,7 +78,7 @@ all() ->
, pattern
, patternProperties
, properties
%% , ref
, ref
, required
, type
, uniqueItems
@ -177,11 +177,10 @@ properties(Config) ->
Specs = ?config(Key, Config),
ok = run_tests(Specs).
%% not implemented yet
%% ref(Config) ->
%% Key = "ref",
%% Specs = ?config(Key, Config),
%% ok = run_tests(Specs).
ref(Config) ->
Key = "ref",
Specs = ?config(Key, Config),
ok = run_tests(Specs).
required(Config) ->
Key = "required",