Merge branch 'master' of https://github.com/xeipuuv/gojsonschema

Conflicts:
	README.md
diff --git a/README.md b/README.md
index bb571f4..123e673 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
 
 An implementation of JSON Schema, based on IETF's draft v4 - Go language
 
-References:
+References :
 
 * http://json-schema.org
 * http://json-schema.org/latest/json-schema-core.html
@@ -18,9 +18,14 @@
 go get github.com/xeipuuv/gojsonschema
 ```
 
+Dependencies :
+* https://github.com/xeipuuv/gojsonpointer
+* https://github.com/xeipuuv/gojsonreference
+* https://github.com/stretchr/testify/assert
+
 ## Usage 
 
-### A full working example
+### Example
 
 ```go
 
@@ -28,39 +33,26 @@
 
 import (
     "fmt"
-    gjs "github.com/xeipuuv/gojsonschema"
+    "github.com/xeipuuv/gojsonschema"
 )
 
 func main() {
 
-    schema, err := gjs.NewSchema("file:///home/me/schema.json")
-    if err != nil {
-        panic(err.Error())
-    }
+    schemaLoader := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
+    documentLoader := gojsonschema.NewReferenceLoader("file:///home/me/document.json")
 
-    document, err := gjs.GetFile("/home/me/document.json")
-    if err != nil {
-        panic(err.Error())
-    }
-
-    result, err := schema.Validate(document)
+    result, err := gojsonschema.Validate(schemaLoader, documentLoader)
     if err != nil {
         panic(err.Error())
     }
 
     if result.Valid() {
-    
         fmt.Printf("The document is valid\n")
-    
     } else {
-    
         fmt.Printf("The document is not valid. see errors :\n")
-    
-        // display validation errors
         for _, desc := range result.Errors() {
             fmt.Printf("- %s\n", desc)
         }
-    
     }
 
 }
@@ -68,108 +60,72 @@
 
 ```
 
-#### Loading a schema
+#### Loaders
 
-Schemas can be loaded remotely from a HTTP URL :
+There are various ways to load your JSON data.
+In order to load your schemas and documents, 
+first declare an appropriate loader :
+
+* Web / HTTP, using a reference :
 
 ```go
-    schema, err := gjs.NewSchema("http://myhost/schema.json")
+    loader, err := gojsonschema.NewReferenceLoader("http://www.some_host.com/schema.json")
 ```
 
-From a local file, using the file URI scheme:
+* Local file, using a reference :
 
 ```go
-	schema, err := gjs.NewSchema("file:///home/me/schema.json")
+    loader, err := gojsonschema.NewReferenceLoader("file:///home/me/schema.json")
 ```
 
+References use the URI scheme, the prefix (file://) and a full path to the file are required.
 
-You may also load the schema from within your code, using a map[string]interface{} variable or a JSON string.
-
-Note that schemas loaded from non-HTTP are subject to limitations, they need to be standalone schemas; 
-That means references to local files and/or remote files within these schemas will not work.
+* Custom Go types :
 
 ```go
-	m := map[string]interface{}{
-		"type": "string"}
-
-	schema, err := gjs.NewSchema(m)
+    m := map[string]interface{}{"type": "string"}
+    loader, err := gojsonschema.NewGoLoader(m)
 ```
 
-Or
+* JSON strings :
 
 ```go
-	schema, err := gjs.NewSchema(`{"type": "string"}`)
-```
-
-#### Loading a JSON
-
-The library virtually accepts any form of JSON since it uses reflection to validate against the schema.
-
-You may use and combine go types like :
-
-* string (JSON string)
-* bool (JSON boolean)
-* float64 (JSON number)
-* nil (JSON null)
-* slice (JSON array)
-* map[string]interface{} (JSON object)
-
-You can declare your JSON from within your code, using a map / interface{} :
-
-```go
-	document := map[string]interface{}{
-		"name": "john"}
-```
-
-Or a JSON string:
-
-```go
-	document := `{"name": "john"}`
-```
-
-Helper functions are also available to load from a HTTP URL :
-
-```go
-    document, err := gjs.GetHTTP("http://host/data.json")
-```
-
-Or a local file :
-
-```go
-	document, err := gjs.GetFile("/home/me/data.json")
+    loader, err := gojsonschema.NewStringLoader(`{"type": "string"}`)
 ```
 
 #### Validation
 
-Once the schema and the JSON to validate are loaded, validation phase becomes easy :
+Once the loaders are set, validation is easy :
 
 ```go
-	result, err := schema.Validate(document)
+	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
 ```
 
-Check the result with:
+Alternatively, you might want to load a schema only once and process to multiple validations :
+
+```go
+	schema, err := gojsonschema.NewSchema(schemaLoader)
+	...
+	result1, err := schema.Validate(documentLoader1)
+	...
+	result2, err := schema.Validate(documentLoader2)
+	...
+	// etc ...
+```
+
+To check the result :
 
 ```go
 	if result.Valid() {
-		// Your Json is valid
+		fmt.Printf("The document is valid\n")
+	} else {
+		fmt.Printf("The document is not valid. see errors :\n")
+		for _, desc := range result.Errors() {
+			fmt.Printf("- %s\n", desc)
+		}
 	}
 ```
 
-If not valid, you can loop through the error messages returned by the validation phase :
-
-```go
-	for _, desc := range result.Errors() {
-    	fmt.Printf("Error: %s\n", desc)
-	}
-```
-
-## Dependencies
-https://github.com/xeipuuv/gojsonpointer
-
-https://github.com/xeipuuv/gojsonreference
-
-https://github.com/stretchr/testify/assert
-
 ## Uses
 
 gojsonschema uses the following test suite :
diff --git a/getJson.go b/getJson.go
deleted file mode 100644
index 6a54788..0000000
--- a/getJson.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// author           xeipuuv
-// author-github    https://github.com/xeipuuv
-// author-mail      xeipuuv@gmail.com
-//
-// repository-name  gojsonschema
-// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
-//
-// description		Helper functions to load JSON files.
-//
-// created          26-02-2013
-
-package gojsonschema
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"net/http"
-)
-
-// Helper function to read a JSON from a HTTP request
-// Must return HTTP Status 200 OK
-func GetHTTP(url string) (interface{}, error) {
-
-	resp, err := http.Get(url)
-	if err != nil {
-		return nil, err
-	}
-
-	if resp.StatusCode != http.StatusOK {
-		return nil, errors.New(fmt.Sprintf(ERROR_MESSAGE_GET_HTTP_BAD_STATUS, resp.Status))
-	}
-
-	bodyBuff, err := ioutil.ReadAll(resp.Body)
-	if err != nil {
-		return nil, err
-	}
-
-	var document interface{}
-	err = json.Unmarshal(bodyBuff, &document)
-	if err != nil {
-		return nil, err
-	}
-
-	return document, nil
-}
-
-// Helper function to read a JSON from a path
-func GetFile(path string) (interface{}, error) {
-
-	bodyBuff, err := ioutil.ReadFile(path)
-	if err != nil {
-		return nil, err
-	}
-
-	var document interface{}
-	err = json.Unmarshal(bodyBuff, &document)
-	if err != nil {
-		return nil, err
-	}
-
-	return document, nil
-}
diff --git a/internalLog.go b/internalLog.go
index 2459fef..ee14ee6 100644
--- a/internalLog.go
+++ b/internalLog.go
@@ -30,7 +30,7 @@
 	"log"
 )
 
-const internalLogEnabled = false
+const internalLogEnabled = true
 
 func internalLog(format string, v ...interface{}) {
 
diff --git a/jsonLoader.go b/jsonLoader.go
new file mode 100644
index 0000000..2af72df
--- /dev/null
+++ b/jsonLoader.go
@@ -0,0 +1,280 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author           xeipuuv
+// author-github    https://github.com/xeipuuv
+// author-mail      xeipuuv@gmail.com
+//
+// repository-name  gojsonschema
+// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
+//
+// description		Different strategies to load JSON files.
+// 					Includes References (file and HTTP), JSON strings and Go types.
+//
+// created          01-02-2015
+
+package gojsonschema
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/xeipuuv/gojsonreference"
+	"io/ioutil"
+	"net/http"
+	"strings"
+)
+
+// JSON loader interface
+
+type jsonLoader interface {
+	jsonSource() interface{}
+	loadJSON() (interface{}, error)
+	loadSchema() (*Schema, error)
+}
+
+// JSON Reference loader
+// references are used to load JSONs from files and HTTP
+
+type jsonReferenceLoader struct {
+	source string
+}
+
+func (l *jsonReferenceLoader) jsonSource() interface{} {
+	return l.source
+}
+
+func NewReferenceLoader(source string) *jsonReferenceLoader {
+	return &jsonReferenceLoader{source: source}
+}
+
+func (l *jsonReferenceLoader) loadJSON() (interface{}, error) {
+
+	var err error
+
+	reference, err := gojsonreference.NewJsonReference(l.jsonSource().(string))
+	if err != nil {
+		return nil, err
+	}
+
+	refToUrl := reference
+	refToUrl.GetUrl().Fragment = ""
+
+	var document interface{}
+
+	if reference.HasFileScheme {
+
+		filename := strings.Replace(refToUrl.String(), "file://", "", -1)
+		document, err = l.loadFromFile(filename)
+		if err != nil {
+			return nil, err
+		}
+
+	} else {
+
+		document, err = l.loadFromHTTP(refToUrl.String())
+		if err != nil {
+			return nil, err
+		}
+
+	}
+
+	return document, nil
+
+}
+
+func (l *jsonReferenceLoader) loadSchema() (*Schema, error) {
+
+	var err error
+
+	d := Schema{}
+	d.pool = newSchemaPool()
+	d.referencePool = newSchemaReferencePool()
+
+	d.documentReference, err = gojsonreference.NewJsonReference(l.jsonSource().(string))
+	if err != nil {
+		return nil, err
+	}
+
+	spd, err := d.pool.GetDocument(d.documentReference)
+	if err != nil {
+		return nil, err
+	}
+
+	err = d.parse(spd.Document)
+	if err != nil {
+		return nil, err
+	}
+
+	return &d, nil
+
+}
+
+func (l *jsonReferenceLoader) loadFromHTTP(address string) (interface{}, error) {
+
+	resp, err := http.Get(address)
+	if err != nil {
+		return nil, err
+	}
+
+	// must return HTTP Status 200 OK
+	if resp.StatusCode != http.StatusOK {
+		return nil, errors.New(fmt.Sprintf(ERROR_MESSAGE_GET_HTTP_BAD_STATUS, resp.Status))
+	}
+
+	bodyBuff, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, err
+	}
+
+	var document interface{}
+	err = json.Unmarshal(bodyBuff, &document)
+	if err != nil {
+		return nil, err
+	}
+
+	return document, nil
+}
+
+func (l *jsonReferenceLoader) loadFromFile(path string) (interface{}, error) {
+
+	bodyBuff, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+
+	var document interface{}
+	err = json.Unmarshal(bodyBuff, &document)
+	if err != nil {
+		return nil, err
+	}
+
+	return document, nil
+}
+
+// JSON string loader
+
+type jsonStringLoader struct {
+	source string
+}
+
+func (l *jsonStringLoader) jsonSource() interface{} {
+	return l.source
+}
+
+func NewStringLoader(source string) *jsonStringLoader {
+	return &jsonStringLoader{source: source}
+}
+
+func (l *jsonStringLoader) loadJSON() (interface{}, error) {
+
+	var document interface{}
+
+	err := json.Unmarshal([]byte(l.jsonSource().(string)), &document)
+	if err != nil {
+		return nil, err
+	}
+
+	return document, nil
+
+}
+
+func (l *jsonStringLoader) loadSchema() (*Schema, error) {
+
+	var err error
+
+	document, err := l.loadJSON()
+	if err != nil {
+		return nil, err
+	}
+
+	d := Schema{}
+	d.pool = newSchemaPool()
+	d.referencePool = newSchemaReferencePool()
+	d.documentReference, err = gojsonreference.NewJsonReference("#")
+	d.pool.SetStandaloneDocument(document)
+	if err != nil {
+		return nil, err
+	}
+
+	err = d.parse(document)
+	if err != nil {
+		return nil, err
+	}
+
+	return &d, nil
+
+}
+
+// JSON Go (types) loader
+// used to load JSONs from the code as maps, interface{}, structs ...
+
+type jsonGoLoader struct {
+	source interface{}
+}
+
+func (l *jsonGoLoader) jsonSource() interface{} {
+	return l.source
+}
+
+func NewGoLoader(source interface{}) *jsonGoLoader {
+	return &jsonGoLoader{source: source}
+}
+
+func (l *jsonGoLoader) loadJSON() (interface{}, error) {
+
+	// convert it to a compliant JSON first to avoid types "mismatches"
+
+	jsonBytes, err := json.Marshal(l.jsonSource())
+	if err != nil {
+		return nil, err
+	}
+
+	var document interface{}
+
+	err = json.Unmarshal(jsonBytes, &document)
+	if err != nil {
+		return nil, err
+	}
+
+	return document, nil
+
+}
+
+func (l *jsonGoLoader) loadSchema() (*Schema, error) {
+
+	var err error
+
+	document, err := l.loadJSON()
+	if err != nil {
+		return nil, err
+	}
+
+	d := Schema{}
+	d.pool = newSchemaPool()
+	d.referencePool = newSchemaReferencePool()
+	d.documentReference, err = gojsonreference.NewJsonReference("#")
+	d.pool.SetStandaloneDocument(document)
+	if err != nil {
+		return nil, err
+	}
+
+	err = d.parse(document)
+	if err != nil {
+		return nil, err
+	}
+
+	return &d, nil
+
+}
diff --git a/schema.go b/schema.go
index 8777a3d..1d4e9da 100644
--- a/schema.go
+++ b/schema.go
@@ -27,7 +27,7 @@
 package gojsonschema
 
 import (
-	"encoding/json"
+	//	"encoding/json"
 	"errors"
 	"fmt"
 	"github.com/xeipuuv/gojsonreference"
@@ -35,104 +35,8 @@
 	"regexp"
 )
 
-func NewSchema(document interface{}) (*Schema, error) {
-
-	internalLog("New Schema")
-
-	switch document.(type) {
-
-	// document is a string:
-	// Could be a JSON string or a JSON reference string ( file or HTTP scheme )
-	// Use inferring to determine proper way to load this document
-
-	case string:
-
-		internalLog(" From string argument")
-
-		var m map[string]interface{}
-		err := json.Unmarshal([]byte(document.(string)), &m)
-		if err != nil {
-			internalLog("  Inferring JSON reference %s", document.(string))
-			return newSchemaDocumentFromReference(document.(string))
-		} else {
-			internalLog("  Inferring JSON string")
-			return newSchemaDocumentFromMap(m)
-		}
-
-	// document is a Go Map
-
-	case map[string]interface{}:
-
-		internalLog(" From map argument")
-
-		// convert the map to a compliant JSON map
-
-		jsonBytes, err := json.Marshal(document)
-		if err != nil {
-			return nil, err
-		}
-
-		var m map[string]interface{}
-		err = json.Unmarshal(jsonBytes, &m)
-		if err != nil {
-			return nil, err
-		}
-
-		return newSchemaDocumentFromMap(m)
-
-	default:
-
-		return nil, errors.New(ERROR_MESSAGE_NEW_SCHEMA_DOCUMENT_INVALID_ARGUMENT)
-
-	}
-
-	return nil, nil
-}
-
-func newSchemaDocumentFromMap(document map[string]interface{}) (*Schema, error) {
-
-	d := Schema{}
-	d.pool = newSchemaPool()
-	d.referencePool = newSchemaReferencePool()
-
-	var err error
-
-	d.documentReference, err = gojsonreference.NewJsonReference("#")
-	d.pool.SetStandaloneDocument(document)
-	if err != nil {
-		return nil, err
-	}
-
-	err = d.parse(document)
-	if err != nil {
-		return nil, err
-	}
-
-	return &d, nil
-
-}
-
-func newSchemaDocumentFromReference(document string) (*Schema, error) {
-
-	var err error
-
-	d := Schema{}
-	d.pool = newSchemaPool()
-	d.referencePool = newSchemaReferencePool()
-
-	d.documentReference, err = gojsonreference.NewJsonReference(document)
-	spd, err := d.pool.GetDocument(d.documentReference)
-	if err != nil {
-		return nil, err
-	}
-
-	err = d.parse(spd.Document)
-	if err != nil {
-		return nil, err
-	}
-
-	return &d, nil
-
+func NewSchema(l jsonLoader) (*Schema, error) {
+	return l.loadSchema()
 }
 
 type Schema struct {
diff --git a/schemaPool.go b/schemaPool.go
index dab2620..67e5fb8 100644
--- a/schemaPool.go
+++ b/schemaPool.go
@@ -29,8 +29,6 @@
 import (
 	"errors"
 	"fmt"
-	"strings"
-
 	"github.com/xeipuuv/gojsonreference"
 )
 
@@ -88,31 +86,10 @@
 		return spd, nil
 	}
 
-	// Load the document
-
-	var document interface{}
-
-	if reference.HasFileScheme {
-
-		internalLog(" From file")
-
-		// Load from file
-		filename := strings.Replace(refToUrl.String(), "file://", "", -1)
-		document, err = GetFile(filename)
-		if err != nil {
-			return nil, err
-		}
-
-	} else {
-
-		internalLog("  From HTTP")
-
-		// Load from HTTP
-		document, err = GetHTTP(refToUrl.String())
-		if err != nil {
-			return nil, err
-		}
-
+	jsonReferenceLoader := NewReferenceLoader(reference.String())
+	document, err := jsonReferenceLoader.loadJSON()
+	if err != nil {
+		return nil, err
 	}
 
 	spd = &schemaPoolDocument{Document: document}
diff --git a/schema_test.go b/schema_test.go
index 3866108..01ff133 100644
--- a/schema_test.go
+++ b/schema_test.go
@@ -314,27 +314,18 @@
 
 		fmt.Printf("Test (%d) | %s :: %s\n", testJsonIndex, testJson["phase"], testJson["test"])
 
-		// get schema
-		schemaDocument, err := NewSchema("file://" + testwd + "/" + testJson["schema"])
-		if err != nil {
-			t.Errorf("Cound not parse schema : %s\n", err.Error())
-		}
-
-		// get data
-		dataDocument, err := GetFile(testwd + "/" + testJson["data"])
-		if err != nil {
-			t.Errorf("Could not get test data : %s\n", err.Error())
-		}
+		schemaLoader := NewReferenceLoader("file://" + testwd + "/" + testJson["schema"])
+		documentLoader := NewReferenceLoader("file://" + testwd + "/" + testJson["data"])
 
 		// validate
-		validationResult, err := schemaDocument.Validate(dataDocument)
+		result, err := Validate(schemaLoader, documentLoader)
 		if err != nil {
 			t.Errorf("Error (%s)\n", err.Error())
 		}
-		givenValid := validationResult.Valid()
+		givenValid := result.Valid()
 
 		if displayErrorMessages {
-			for vErrI, vErr := range validationResult.Errors() {
+			for vErrI, vErr := range result.Errors() {
 				fmt.Printf("  Error (%d) | %s\n", vErrI, vErr)
 			}
 		}
diff --git a/validation.go b/validation.go
index 2d1dd6d..5dde0bf 100644
--- a/validation.go
+++ b/validation.go
@@ -26,7 +26,6 @@
 package gojsonschema
 
 import (
-	"encoding/json"
 	"fmt"
 	"reflect"
 	"regexp"
@@ -35,56 +34,30 @@
 	"unicode/utf8"
 )
 
-func (v *Schema) Validate(document interface{}) (*Result, error) {
+func Validate(ls jsonLoader, ld jsonLoader) (*Result, error) {
 
-	internalLog("Validate")
+	var err error
 
-	var root interface{}
+	// load schema
 
-	switch document.(type) {
+	schema, err := NewSchema(ls)
+	if err != nil {
+		return nil, err
+	}
 
-	// document is a JSON string or a single JSON string element
+	// begine validation
 
-	case string:
+	return schema.Validate(ld)
 
-		trimmedString := strings.TrimSpace(document.(string))
+}
 
-		// is a JSON string
-		if strings.HasPrefix(trimmedString, "{") || strings.HasPrefix(trimmedString, "[") {
+func (v *Schema) Validate(l jsonLoader) (*Result, error) {
 
-			internalLog(" From JSON string")
+	// load document
 
-			err := json.Unmarshal([]byte(document.(string)), &root)
-			if err != nil {
-				return nil, err
-			}
-
-		} else { // is a single JSON string element
-
-			internalLog(" From JSON string element")
-
-			root = document.(string)
-
-		}
-
-	// otherwise
-
-	default:
-
-		internalLog(" From JSON object")
-
-		// Turn it into a compliant JSON
-
-		jsonBytes, err := json.Marshal(document)
-		if err != nil {
-			return nil, err
-		}
-
-		err = json.Unmarshal(jsonBytes, &root)
-		if err != nil {
-			return nil, err
-		}
-
+	root, err := l.loadJSON()
+	if err != nil {
+		return nil, err
 	}
 
 	// begin validation