grayskull 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 <Your Name Here>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
data/bin/grayskull ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "grayskull"
4
+ require "optparse"
5
+
6
+ Grayskull::CLI.start
data/lib/grayskull.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'grayskull/version'
2
+
3
+ # Base module for gem.
4
+ module Grayskull
5
+ autoload :Formats, 'grayskull/formats'
6
+ autoload :Validator, 'grayskull/validator'
7
+ autoload :CLI, 'grayskull/cli'
8
+ end
@@ -0,0 +1,27 @@
1
+ require 'thor'
2
+
3
+ module Grayskull
4
+
5
+ # The *CLI* class provides an interface for the command line functions
6
+ class CLI < Thor
7
+
8
+ desc "validate FILE SCHEMA" ,"Checks TEMPLATE is a valid file and matches SCHEMA."
9
+ # Creates a new *Validator* and validates the file
10
+ def validate(file,schema)
11
+ validator = Grayskull::Validator.new(file,schema)
12
+ results = validator.validate
13
+
14
+ if !results['result']
15
+ puts 'Validation Failed!'
16
+ results['errors'].each{
17
+ |error|
18
+ puts error
19
+ }
20
+ else
21
+ puts 'Validated Successfully!'
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,29 @@
1
+ module Grayskull
2
+
3
+ module Formats
4
+
5
+ autoload :YAMLHandler, 'grayskull/formats/yaml_handler'
6
+ autoload :JSONHandler, 'grayskull/formats/json_handler'
7
+
8
+ FILENAME_PATTERN = /(.+)\.([^\/\.]+)/
9
+
10
+ def self.detect_format(filename)
11
+ matches = FILENAME_PATTERN.match(filename.downcase).to_a
12
+ if matches
13
+ ext = matches[2]
14
+ case ext
15
+ when 'json'
16
+ return 'json'
17
+ when 'yml'
18
+ return 'yaml'
19
+ else
20
+ raise TypeError, "Not a supported file format: " + ext
21
+ end
22
+ else
23
+ raise LoadError, "Not a valid filename: " + filename
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,23 @@
1
+ require 'json'
2
+
3
+ module Grayskull
4
+
5
+ module Formats
6
+
7
+ class JSONHandler
8
+
9
+ def self.load(file)
10
+ loaded = File.open(file)
11
+ content = loaded.gets nil
12
+ begin
13
+ return JSON.parse(content)
14
+ rescue Exception => e
15
+ raise e.class, 'File could not be parsed as valid JSON'
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'yaml'
2
+
3
+ module Grayskull
4
+
5
+ module Formats
6
+
7
+ class YAMLHandler
8
+
9
+ def self.load(file)
10
+ begin
11
+ return YAML.load_file(file)
12
+ rescue Exception => e
13
+ raise e.class, 'File could not be parsed as valid YAML'
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,184 @@
1
+ module Grayskull
2
+
3
+ class Validator
4
+
5
+ def initialize(file,schema)
6
+
7
+ @file = file
8
+ @schema = schema
9
+
10
+ @loaded_file = self.load(file)
11
+ @loaded_schema = self.load(schema)
12
+ @types = @loaded_schema['types'] || {}
13
+
14
+ @errors = []
15
+ end
16
+
17
+ def load(file)
18
+
19
+ format = Formats::detect_format File.basename(file)
20
+
21
+ case format
22
+ when 'yaml'
23
+ return Formats::YAMLHandler.load(file)
24
+ when 'json'
25
+ return Formats::JSONHandler.load(file)
26
+ end
27
+
28
+ end
29
+
30
+ def validate()
31
+ failed = []
32
+
33
+ @loaded_schema['sections'].each{
34
+ |section|
35
+
36
+ #check required sections are there
37
+ if (section['required'] && !@loaded_file.has_key?(section['name']))
38
+ @errors.push('Error: missing required section - ' + section['name'])
39
+ failed.push(section['name'])
40
+ elsif @loaded_file.has_key?(section['name'])
41
+ node = @loaded_file[section['name']]
42
+ validated = match_node(node,section,section['name'])
43
+ if(!validated)
44
+ failed.push(section['name'])
45
+ end
46
+ end
47
+
48
+ }
49
+
50
+ result = {}
51
+ result["result"] = failed.empty?
52
+
53
+ if !failed.empty? && !@errors.empty?
54
+ result["errors"] = @errors
55
+ end
56
+
57
+ return result
58
+ end
59
+
60
+ # Checks template node matches the schema.
61
+ #
62
+ # Checks type of node against expected type and
63
+ # checks any children are of the accepted types.
64
+ def match_node(node,expected,label)
65
+
66
+ #check type
67
+ if !check_type(node,expected['type'],label,expected['ok_empty'])
68
+ return false
69
+ end
70
+
71
+ if (node.kind_of?(Hash) || node.kind_of?(Array))
72
+
73
+ if node.empty? && !expected['ok_empty']
74
+ @errors.push('Error: node ' + label + ' cannot be empty')
75
+ return false
76
+ elsif !node.empty? && expected.has_key?('accepts')
77
+ valid_content = false
78
+
79
+ if node.kind_of?(Hash)
80
+ matched = []
81
+ unmatched = []
82
+ node.each_pair{
83
+ |key,value|
84
+
85
+ expected['accepts'].each{
86
+ |accepts|
87
+
88
+ result = check_type(value,accepts,key)
89
+
90
+ if result
91
+ matched.push(key)
92
+ if !unmatched.find_index(key).nil?
93
+ unmatched.slice(unmatched.find_index(key))
94
+ end
95
+ break
96
+ else
97
+ unmatched.push(key)
98
+ end
99
+
100
+ }
101
+
102
+ }
103
+
104
+ if(matched.count==node.count)
105
+ valid_content = true
106
+ else
107
+ unmatched.each{
108
+ |node|
109
+
110
+ @errors.push('Error: node ' + node + ' is not of an accepted type. Should be one of ' + expected['accepts'].join(', '))
111
+ }
112
+ end
113
+
114
+ elsif node.kind_of?(Array)
115
+ matched = []
116
+ unmatched = []
117
+ node.each_index{
118
+ |n|
119
+
120
+ expected['accepts'].each{
121
+ |accepts|
122
+
123
+ key = label + '[' + n.to_s + ']'
124
+ result = check_type(node[n],accepts,key)
125
+
126
+ if result
127
+
128
+ matched.push(key)
129
+ if !unmatched.find_index(key).nil?
130
+ unmatched.slice(unmatched.find_index(key))
131
+ end
132
+ break
133
+ else
134
+ unmatched.push(key)
135
+ end
136
+
137
+ }
138
+ }
139
+
140
+ if(matched.count==node.count)
141
+ valid_content = true
142
+ else
143
+ unmatched.each{
144
+ |node|
145
+
146
+ @errors.push('Error: node ' + node + ' is not of an accepted type. Should be one of ' + expected['accepts'].join(', '))
147
+ }
148
+ end
149
+
150
+ end
151
+
152
+ if !valid_content
153
+ @errors.push('Error: node ' + label + ' contains an unaccepted type.')
154
+ return false
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ return true
161
+
162
+ end
163
+
164
+ # Checks that the node is of the correct type
165
+ #
166
+ # If the expected node is a custom node type as defined in the schema
167
+ # It will run `match_node` to check that the node schema matches the
168
+ # custom type.
169
+ def check_type(node,expected_type,label,accept_nil = false)
170
+
171
+ valid_type = true;
172
+ if(@types.has_key?(expected_type))
173
+ valid_type = match_node(node,@types[expected_type],label)
174
+ elsif node.class.to_s != expected_type && !(node.kind_of?(NilClass) && (expected_type=='empty' || accept_nil))
175
+ valid_type = false
176
+ end
177
+
178
+ return valid_type
179
+
180
+ end
181
+
182
+ end
183
+
184
+ end
@@ -0,0 +1,3 @@
1
+ module Grayskull
2
+ Grayskull::VERSION = "0.1.2"
3
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grayskull
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 2
9
+ version: 0.1.2
10
+ platform: ruby
11
+ authors:
12
+ - Will McKenzie
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-10-01 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thor
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: json
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ description: Will validate YAML and JSON files based on a provided schema
47
+ email:
48
+ - will@oinutter.co.uk
49
+ executables:
50
+ - grayskull
51
+ extensions: []
52
+
53
+ extra_rdoc_files: []
54
+
55
+ files:
56
+ - README
57
+ - LICENSE
58
+ - lib/grayskull/cli.rb
59
+ - lib/grayskull/formats/json_handler.rb
60
+ - lib/grayskull/formats/yaml_handler.rb
61
+ - lib/grayskull/formats.rb
62
+ - lib/grayskull/validator.rb
63
+ - lib/grayskull/version.rb
64
+ - lib/grayskull.rb
65
+ - bin/grayskull
66
+ has_rdoc: true
67
+ homepage: http://github.com/OiNutter/grayskull
68
+ licenses:
69
+ - MIT
70
+ post_install_message:
71
+ rdoc_options: []
72
+
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project: grayskull
94
+ rubygems_version: 1.3.7
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Validates data files based on a provided schema
98
+ test_files: []
99
+