halidator 0.3.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/halidate CHANGED
@@ -1,10 +1,23 @@
1
1
  #! /usr/bin/env ruby
2
-
2
+ require 'optparse'
3
3
  require_relative '../lib/halidator'
4
4
 
5
+ options = {}
6
+ OptionParser.new do |o|
7
+ o.on('-j', '--json-schema', "Validate using the HAL JSON schema") { |b| options[:json_schema] = true }
8
+ o.on('-h', '--help', 'Output this help and exit') { puts o; exit }
9
+ o.on('-d', '--debug', "Output debugging info") {$DEBUG = true}
10
+ o.parse!
11
+ end
12
+
5
13
  input = ARGF.read
6
14
 
7
- hal = Halidator.new(input)
15
+ if options[:json_schema]
16
+ hal = Halidator.new(input, :json_schema)
17
+ else
18
+ hal = Halidator.new(input)
19
+ end
20
+
8
21
  res = hal.valid?
9
22
  if true == res
10
23
  $stdout.puts "true"
@@ -0,0 +1,100 @@
1
+ {
2
+ "id": "resource",
3
+ "type": "object",
4
+ "properties": {
5
+ "_links": {
6
+ "type": "object",
7
+ "title": "Hyperlink",
8
+ "description": "Represents a hyperlink from the containing resource to a URI.",
9
+ "additionalProperties": {
10
+ "type": [
11
+ {
12
+ "id": "link",
13
+ "type": "object",
14
+ "properties": {
15
+ "href": {
16
+ "type": "string",
17
+ "title": "URI of the target resource",
18
+ "description": "Either a URI [RFC3986] or URI Template [RFC6570] of the target resource."
19
+ },
20
+ "templated": {
21
+ "type": "boolean",
22
+ "optional": true,
23
+ "default": false,
24
+ "title": "URI Template",
25
+ "description": "Is true when the link object's href property is a URI Template. Defaults to false."
26
+ },
27
+ "type": {
28
+ "type": "string",
29
+ "pattern": "^(application|audio|example|image|message|model|multipart|text|video)\\/[a-zA-Z0-9!#\\$&\\.\\+-\\^_]{1,127}$",
30
+ "optional": true,
31
+ "title": "Media type indication of the target resource",
32
+ "description": "When present, used as a hint to indicate the media type expected when dereferencing the target resource."
33
+ },
34
+ "name": {
35
+ "type": "string",
36
+ "optional": true,
37
+ "title": "Secondary key",
38
+ "description": "When present, may be used as a secondary key for selecting link objects that contain the same relation type."
39
+ },
40
+ "profile": {
41
+ "type": "string",
42
+ "format": "uri",
43
+ "optional": true,
44
+ "title": "Additional semantics of the target resource",
45
+ "description": "A URI that, when dereferenced, results in a profile to allow clients to learn about additional semantics (constraints, conventions, extensions) that are associated with the target resource representation, in addition to those defined by the HAL media type and relations."
46
+ },
47
+ "title": {
48
+ "type": "string",
49
+ "optional": true,
50
+ "title": "Human-readable identifier",
51
+ "description": "When present, is used to label the destination of a link such that it can be used as a human-readable identifier (e.g. a menu entry) in the language indicated by the Content-Language header (if present)."
52
+ },
53
+ "hreflang": {
54
+ "type": "string",
55
+ "pattern": "^([a-zA-Z]{2,3}(-[a-zA-Z]{3}(-[a-zA-Z]{3}){0,2})?(-[a-zA-Z]{4})?(-([a-zA-Z]{2}|[0-9]{3}))?(-([a-zA-Z0-9]{5,8}|[0-9][a-zA-Z0-9]{3}))*([0-9A-WY-Za-wy-z](-[a-zA-Z0-9]{2,8}){1,})*(x-[a-zA-Z0-9]{2,8})?)|(x-[a-zA-Z0-9]{2,8})|(en-GB-oed)|(i-ami)|(i-bnn)|(i-default)|(i-enochian)|(i-hak)|(i-klingon)|(i-lux)|(i-mingo)|(i-navajo)|(i-pwn)|(i-tao)|(i-tay)|(i-tsu)|(sgn-BE-FR)|(sgn-BE-NL)|(sgn-CH-DE)|(art-lojban)|(cel-gaulish)|(no-bok)|(no-nyn)|(zh-guoyu)|(zh-hakka)|(zh-min)|(zh-min-nan)|(zh-xiang)$",
56
+ "optional": true,
57
+ "title": "Language indication of the target resource [RFC5988]",
58
+ "description": "When present, is a hint in RFC5646 format indicating what the language of the result of dereferencing the link should be. Note that this is only a hint; for example, it does not override the Content-Language header of a HTTP response obtained by actually following the link."
59
+ }
60
+ },
61
+ "additionalProperties": false
62
+ },
63
+ {
64
+ "type": "array",
65
+ "items": [
66
+ {
67
+ "$ref": "link"
68
+ }
69
+ ],
70
+ "uniqueItems": true,
71
+ "additionalProperties": false
72
+ }
73
+ ]
74
+ },
75
+ "optional": true
76
+ },
77
+ "_embedded": {
78
+ "type": "object",
79
+ "additionalProperties": {
80
+ "type": [
81
+ {
82
+ "$ref": "resource"
83
+ },
84
+ {
85
+ "type": "array",
86
+
87
+ "items": [
88
+ {
89
+ "$ref": "resource"
90
+ }
91
+ ],
92
+ "uniqueItems": true,
93
+ "additionalProperties": false
94
+ }
95
+ ]
96
+ },
97
+ "optional": true
98
+ }
99
+ }
100
+ }
@@ -0,0 +1,18 @@
1
+ require 'json-schema'
2
+
3
+ module Halidate
4
+ module JsonSchema
5
+ def validate_json_as_hal
6
+ @errors = JSON::Validator.fully_validate(@json, schema)
7
+ @errors.empty?
8
+ end
9
+
10
+ def hal_json_schema_file
11
+ File.dirname(__FILE__) + "/hal.json"
12
+ end
13
+
14
+ def schema
15
+ @schema ||= File.open(hal_json_schema_file){|f| JSON.parse(f.read)}
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,105 @@
1
+ module Halidate
2
+ module PureRuby
3
+ def validate_json_as_hal
4
+ meets_minimal_JSON_representation? && links_all_valid? && embedded_valid?
5
+ end
6
+
7
+ def links_all_valid?
8
+ _links.all? do |k, v|
9
+ debug "\n\n", k, v
10
+
11
+ case v
12
+ when Array # is an array of links
13
+ v.all?{|x| link_valid?(x)}
14
+ else
15
+ link_valid?(v)
16
+ end
17
+ end
18
+ end
19
+
20
+ def link_valid?(link)
21
+ debug " #{link}"
22
+
23
+ unless link['href']
24
+ errors << "no href in #{link}"
25
+ return false
26
+ end
27
+ unless template_valid?(link)
28
+ errors << "invalid template for #{link}"
29
+ return false
30
+ end
31
+ true
32
+ end
33
+
34
+ def template_valid?(link)
35
+ return true unless link['templated'] == true
36
+
37
+ pairs = 0
38
+ res = link['href'].each_char.all? do |c|
39
+ if '{' == c
40
+ pairs += 1
41
+ pairs == 1
42
+ elsif '}' == c
43
+ pairs -= 1
44
+ pairs == 0
45
+ else
46
+ true
47
+ end
48
+ end
49
+ res && (pairs == 0) && link['href'].include?('{')
50
+ end
51
+
52
+ def embedded_valid?
53
+ return true if _embedded.nil?
54
+
55
+ _embedded.all? do |resource_type, resource|
56
+ case resource
57
+ when Array
58
+ resource.all?{|x| Halidator.new(x).valid?}
59
+ else
60
+ Halidator.new(resource).valid?
61
+ end
62
+ end
63
+ end
64
+
65
+ def meets_minimal_JSON_representation?
66
+ has_links && links_has_self && self_has_href
67
+ end
68
+
69
+ def _embedded
70
+ @json['_embedded']
71
+ end
72
+
73
+ def _links
74
+ @json['_links']
75
+ end
76
+
77
+ def has_links
78
+ if _links
79
+ true
80
+ else
81
+ errors << '_links does not exist'
82
+ false
83
+ end
84
+ end
85
+
86
+ def links_has_self
87
+ if _links['self']
88
+ true
89
+ else
90
+ errors << "no self in #{_links.inspect}"
91
+ false
92
+ end
93
+ end
94
+
95
+ def self_has_href
96
+ if _links['self']['href']
97
+ true
98
+ else
99
+ errors << "no href in #{_links['self']}"
100
+ false
101
+ end
102
+ end
103
+
104
+ end
105
+ end
data/lib/halidator.rb CHANGED
@@ -1,137 +1,45 @@
1
1
  require 'json'
2
+ require_relative './halidate/pure_ruby'
3
+ require_relative './halidate/json_schema'
2
4
 
3
5
  class Halidator
4
6
  attr_accessor :errors
5
- def initialize(hal)
7
+ def initialize(hal, engine = :pure_ruby)
6
8
  case hal
7
9
  when String
8
10
  @json_string = hal
11
+ parse_json
9
12
  else
10
13
  @json = hal
11
14
  end
12
-
13
15
  @errors = []
14
- end
15
-
16
- def valid?
17
- result = parse_json && validate_json_as_hal
18
- show_errors
19
- result
16
+ if engine == :json_schema
17
+ extend Halidate::JsonSchema
18
+ else
19
+ extend Halidate::PureRuby
20
+ end
20
21
  end
21
22
 
22
23
  def parse_json
23
- return true if @json
24
-
25
24
  @json = JSON.parse(@json_string)
26
25
  end
27
26
 
28
- def validate_json_as_hal
29
- meets_minimal_JSON_representation? && links_all_valid? && embedded_valid?
30
- end
31
-
32
- def links_all_valid?
33
- _links.all? do |k, v|
34
- if $DEBUG
35
- puts "\n\n", k, v
36
- end
37
- case v
38
- when Array # is an array of links
39
- v.all?{|x| link_valid?(x)}
40
- else
41
- link_valid?(v)
42
- end
43
- end
27
+ def valid?
28
+ result = validate_json_as_hal
29
+ show_errors
30
+ result
44
31
  end
45
32
 
46
- def link_valid?(link)
33
+ def debug(*str)
47
34
  if $DEBUG
48
- puts " #{link}"
35
+ $stderr.puts str
49
36
  end
50
- unless link['href']
51
- errors << "no href in #{link}"
52
- return false
53
- end
54
- unless template_valid?(link)
55
- errors << "invalid template for #{link}"
56
- return false
57
- end
58
- true
59
- end
60
-
61
- def template_valid?(link)
62
- return true unless link['templated'] == true
63
-
64
- pairs = 0
65
- res = link['href'].each_char.all? do |c|
66
- if '{' == c
67
- pairs += 1
68
- pairs == 1
69
- elsif '}' == c
70
- pairs -= 1
71
- pairs == 0
72
- else
73
- true
74
- end
75
- end
76
- res && (pairs == 0) && link['href'].include?('{')
77
- end
78
-
79
- def embedded_valid?
80
- return true if _embedded.nil?
81
-
82
- _embedded.all? do |resource_type, resource|
83
- case resource
84
- when Array
85
- resource.all?{|x| Halidator.new(x).valid?}
86
- else
87
- Halidator.new(resource).valid?
88
- end
89
- end
90
- end
91
-
92
- def meets_minimal_JSON_representation?
93
- has_links && links_has_self && self_has_href
94
37
  end
95
38
 
96
39
  def show_errors
97
- if $DEBUG
98
- puts "\n---------------", "ERRORS", errors.inspect, "---------------"
99
- end
100
- end
101
-
102
- def _embedded
103
- @json['_embedded']
104
- end
105
-
106
- def _links
107
- @json['_links']
108
- end
109
-
110
- def has_links
111
- if _links
112
- true
113
- else
114
- errors << '_links does not exist'
115
- false
116
- end
117
- end
118
-
119
- def links_has_self
120
- if _links['self']
121
- true
122
- else
123
- errors << "no self in #{_links.inspect}"
124
- false
125
- end
126
- end
127
-
128
- def self_has_href
129
- if _links['self']['href']
130
- true
131
- else
132
- errors << "no href in #{_links['self']}"
133
- false
134
- end
40
+ debug ["\nERRORS-VVVVVVVVVVVVVVVVVV",
41
+ *errors,
42
+ "ERRORS-^^^^^^^^^^^^^^^^^^"]
135
43
  end
136
44
 
137
45
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: halidator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,40 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-23 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-10-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: json
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.6.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.6.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: json-schema
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
14
46
  description: A small library to validate hal+json
15
47
  email: larrick@gmail.com
16
48
  executables:
@@ -19,6 +51,9 @@ extensions: []
19
51
  extra_rdoc_files: []
20
52
  files:
21
53
  - ./lib/halidator.rb
54
+ - ./lib/halidate/hal.json
55
+ - ./lib/halidate/pure_ruby.rb
56
+ - ./lib/halidate/json_schema.rb
22
57
  - bin/halidate
23
58
  homepage: https://github.com/deathbob/halidator
24
59
  licenses: []