obf 0.6.1 → 0.6.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/obf/utils.rb +2 -3
  3. data/lib/obf/validator.rb +257 -81
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e249a35931e0186e77d7891dd62ea793e590029
4
- data.tar.gz: f5ac6ea76ef9258197bdc8668bfdc9eddbf4db6e
3
+ metadata.gz: e04159aa51fa8c477f23c58a9dc7eda8f1abca98
4
+ data.tar.gz: 7281b01429f081deb13970741a95b5ef025bb8fa
5
5
  SHA512:
6
- metadata.gz: 10eaf3229ebf54f38d81524a72729885a8a95645f66179595cd47d1cf5f232f8524b0be4eaad15aaf1efe103c66daf1bfd66d9a009ce0de3490a53b251e41375
7
- data.tar.gz: c34e9d79971e8aefba7de989d0bf45a861f37b30b4f796287d99456991d99627b4af4d4a6c98ffeaff56ac84682dc283bcac2d00852524c539e44f5e41111eb0
6
+ metadata.gz: b3527a3ff96333f841b662008533ff81a4a06ea1429551c604a4d232b61de6d9aa79caca2f735efba04adf178a534574ad50fe504ca30c76583bae8ffd7ed893
7
+ data.tar.gz: 75ab9ed7797c959ddc16589c302e2b75addb2b7460e91be9299464660198b423ce254fd31cf935ae547fb5821c4616674820f73efcda1b680c3bd7eb109fbb4d
@@ -73,9 +73,8 @@ module OBF::Utils
73
73
  end
74
74
  end
75
75
  return type if type
76
- # rescue => e
77
- # puts e.class.to_s
78
- # puts e.message.to_s
76
+ rescue => e
77
+ return :unknown
79
78
  end
80
79
  end
81
80
  return :unknown
@@ -35,13 +35,46 @@ module OBF
35
35
  @warnings || 0
36
36
  end
37
37
 
38
- def self.validate_obf(path)
38
+ def self.validate_file(path)
39
+ type = Utils::identify_file(path)
40
+ fn = File.basename(path)
41
+ filesize = File.size(path)
42
+ if type == :obf
43
+ validate_obf(path)
44
+ elsif type == :obz
45
+ validate_obz(path)
46
+ else
47
+ {
48
+ :filename => fn,
49
+ :filesize => filesize,
50
+ :valid => false,
51
+ :errors => 1,
52
+ :results => [{
53
+ 'type' => 'valid_file',
54
+ 'description' => 'valid .obf or .obz file',
55
+ 'valid' => false,
56
+ 'error' => 'file must be an .obf JSON file or a .obz zip package'
57
+ }]
58
+ }
59
+ end
60
+ end
61
+
62
+ def self.validate_obf(path, opts={})
39
63
  v = self.new
40
64
  fn = File.basename(path)
41
- results = v.validate_obf(path)
65
+ filesize = 0
66
+ content = nil
67
+ if opts['zipper']
68
+ content = opts['zipper'].read(path)
69
+ filesize = opts['zipper'].glob(path)[0].size
70
+ else
71
+ content = File.read(path)
72
+ filesize = File.size(path)
73
+ end
74
+ results = v.validate_obf(content, fn, opts)
42
75
  {
43
76
  :filename => fn,
44
- :filesize => File.size(path),
77
+ :filesize => filesize,
45
78
  :valid => v.errors == 0,
46
79
  :errors => v.errors,
47
80
  :warnings => v.warnings,
@@ -50,39 +83,176 @@ module OBF
50
83
  end
51
84
 
52
85
  def self.validate_obz(path)
86
+ v = self.new
87
+ fn = File.basename(path)
88
+ results, sub_results = v.validate_obz(path, fn)
89
+ errors = ([v.errors] + sub_results.map{|r| r[:errors] }).inject(:+)
90
+ warnings = ([v.warnings] + sub_results.map{|r| r[:warnings] }).inject(:+)
91
+ {
92
+ :filename => fn,
93
+ :filesize => File.size(path),
94
+ :valid => errors == 0,
95
+ :errors => errors,
96
+ :warnings => warnings,
97
+ :results => results,
98
+ :sub_results => sub_results
99
+ }
53
100
  end
54
-
55
- def validate_obf(path, opts={})
101
+
102
+ def setup
56
103
  @blocked = nil
57
104
  @errored = false
58
105
  @warnings = 0
59
106
  @errors = 0
60
107
  @checks = []
108
+ @sub_checks = []
109
+ end
110
+
111
+ def validate_obz(path, filename)
112
+ setup
113
+
114
+ add_check('filename', "file name") do
115
+ if !filename.match(/\.obz$/)
116
+ warn "filename should end with .obz"
117
+ end
118
+ end
119
+
120
+ valid_zip = false
121
+ add_check('zip', 'valid zip') do
122
+ begin
123
+ Utils::load_zip(path) do |zipper|
124
+ end
125
+ valid_zip = true
126
+ rescue Zip::Error => e
127
+ err "file is not a valid zip package"
128
+ end
129
+ end
130
+ if valid_zip
131
+ Utils::load_zip(path) do |zipper|
132
+ json = nil
133
+ add_check('manifest', 'manifest.json') do
134
+ if zipper.glob('manifest.json').length == 0
135
+ err "manifest.json is required in the zip package"
136
+ end
137
+ json = JSON.parse(zipper.read('manifest.json')) rescue nil
138
+ if !json
139
+ err "manifest.json must contain a valid JSON structure"
140
+ end
141
+ end
142
+ if json
143
+ add_check('manifest_format', 'manifest.json format version') do
144
+ if !json['format']
145
+ err "format attribute is required, set to #{OBF::FORMAT}"
146
+ end
147
+ version = json['format'].split(/-/, 3)[-1].to_f
148
+ if version > OBF::FORMAT_CURRENT_VERSION
149
+ err "format version (#{version}) is invalid, current version is #{OBF::FORMAT_CURRENT_VERSION}"
150
+ elsif version < OBF::FORMAT_CURRENT_VERSION
151
+ warn "format version (#{version}) is old, consider updating to #{OBF::FORMAT_CURRENT_VERSION}"
152
+ end
153
+ end
154
+
155
+ add_check('manifest_root', 'manifest.json root attribute') do
156
+ if !json['root']
157
+ err "root attribute is required"
158
+ end
159
+ if zipper.glob(json['root']).length == 0
160
+ err "root attribute must reference a file in the package"
161
+ end
162
+ end
163
+
164
+ paths = nil
165
+ add_check('manifest_paths', 'manifest.json paths attribute') do
166
+ if !json['paths'] || !json['paths'].is_a?(Hash)
167
+ err "paths attribute must be a valid hash"
168
+ end
169
+ if !json['paths']['boards'] || !json['paths']['boards'].is_a?(Hash)
170
+ err "paths.boards must be a valid hash"
171
+ end
172
+ if json['paths']['images'] && !json['paths']['images'].is_a?(Hash)
173
+ err "paths.images must be a valid hash if defined"
174
+ end
175
+ if json['paths']['sounds'] && !json['paths']['sounds'].is_a?(Hash)
176
+ err "paths.sounds must be a valid hash if defined"
177
+ end
178
+ end
179
+ add_check('manifest_extras', 'manifest.json extra attributes') do
180
+ attrs = ['format', 'root', 'paths']
181
+ json.keys.each do |key|
182
+ if !attrs.include?(key) && !key.match(/^ext_/)
183
+ warn "#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
184
+ end
185
+ end
186
+
187
+ attrs = ['boards', 'images', 'sounds']
188
+ json['paths'].keys.each do |key|
189
+ if !attrs.include?(key) && !key.match(/^ext_/)
190
+ warn "paths.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
191
+ end
192
+ end
193
+ end
194
+ add_check('manifest_boards', 'manifest.json referenced boards') do
195
+ end
196
+
197
+ add_check('manifest_images', 'manifest.json referenced images') do
198
+ end
199
+
200
+ add_check('manifest_sounds', 'manifest.json referenced sounds') do
201
+ end
202
+
203
+ sub_results = []
204
+ if json['paths']['boards'] && json['paths']['boards'].is_a?(Hash)
205
+ json['paths']['boards'].each do |key, path|
206
+ sub = Validator.validate_obf(path, {'zipper' => zipper})
207
+ sub_results << sub
208
+ end
209
+ end
210
+ @sub_checks = sub_results
211
+ end
212
+ if zipper.glob('manifest.json').length > 0
213
+ json = JSON.parse(zipper.read('manifest.json')) rescue nil
214
+ if json['root'] && json['format'] && json['format'].match(/^open-board-/)
215
+ type = :obz
216
+ end
217
+ end
218
+ end
219
+ end
220
+ return [@checks, @sub_checks]
221
+ end
222
+
223
+ def validate_obf(content, filename, opts={})
224
+ setup
61
225
 
62
226
  # TODO enforce extra attributes being defined with ext_
63
227
 
228
+ add_check('filename', "file name") do
229
+ if !filename.match(/\.obf$/)
230
+ warn "filename should end with .obf"
231
+ end
232
+ end
233
+
64
234
  json = nil
65
- add_check('valid_json', "JSON File") do
235
+ add_check('valid_json', "JSON file") do
66
236
  begin
67
- json = JSON.parse(File.read(path))
237
+ json = JSON.parse(content)
68
238
  rescue => e
69
239
  err "Couldn't parse as JSON", true
70
240
  end
71
241
  end
72
242
 
73
243
  ext = nil
74
- add_check('to_external', "OBF Structure") do
244
+ add_check('to_external', "OBF structure") do
75
245
  begin
76
- ext = External.from_obf(path, {})
246
+ External.from_obf(json, {})
247
+ ext = JSON.parse(content)
77
248
  rescue External::StructureError => e
78
249
  err "Couldn't parse structure: #{e.message}", true
79
250
  end
80
251
  end
81
- ext = json
82
-
252
+
83
253
  add_check('format_version', "format version") do
84
254
  if !ext['format']
85
- err "format attribute is required, set to #{FORMAT}"
255
+ err "format attribute is required, set to #{OBF::FORMAT}"
86
256
  end
87
257
  version = ext['format'].split(/-/, 3)[-1].to_f
88
258
  if version > OBF::FORMAT_CURRENT_VERSION
@@ -188,89 +358,95 @@ module OBF
188
358
  warn("not all defined buttons were included in the grid order (#{(button_ids - used_button_ids).join(',')})") if (button_ids - used_button_ids).length > 0
189
359
  end
190
360
 
191
- unless opts['obz']
192
- button_image_ids = []
193
- if ext['buttons'] && ext['buttons'].is_a?(Array)
194
- ext['buttons'].each{|b| button_image_ids << b['image_id'] if b.is_a?(Hash) && b['image_id'] }
195
- end
196
- add_check('images', "images attribute") do
197
-
198
- if !ext['images']
199
- err "images attribute is required"
200
- elsif !ext['images'].is_a?(Array)
201
- err "images attribute must be an array"
202
- end
203
- end
361
+ button_image_ids = []
362
+ if ext && ext['buttons'] && ext['buttons'].is_a?(Array)
363
+ ext['buttons'].each{|b| button_image_ids << b['image_id'] if b.is_a?(Hash) && b['image_id'] }
364
+ end
365
+ add_check('images', "images attribute") do
204
366
 
205
- if ext['images'] && ext['images'].is_a?(Array)
206
- ext['images'].each_with_index do |image, idx|
207
- add_check("image[#{idx}]", "image at images[#{idx}]") do
208
- if !image.is_a?(Hash)
209
- err "image must be a hash"
210
- elsif !image['id']
211
- err "image.id is required"
212
- elsif !image['width'] || !image['width'].is_a?(Fixnum)
213
- err "image.width must be a valid positive number"
214
- elsif !image['height'] || !image['height'].is_a?(Fixnum)
215
- err "image.height must be a valid positive number"
216
- elsif !image['content_type'] || !image['content_type'].match(/^image\/.+$/)
217
- err "image.content_type must be a valid image mime type"
218
- elsif !image['url'] && !image['data'] && !image['symbol']
219
- err "image must have data, url or symbol attribute defined"
220
- elsif image['data'] && !image['data'].match(/^data:image\/.+;base64,.+$/)
221
- err "image.data must be a valid data URI if defined"
222
- elsif image['symbol'] && !image['symbol'].is_a?(Hash)
223
- err "image.symbol must be a hash if defined"
224
- end
225
-
226
- attrs = ['id', 'width', 'height', 'content_type', 'data', 'url', 'symbol', 'path', 'data_url', 'license']
227
- image.keys.each do |key|
228
- if !attrs.include?(key) && !key.match(/^ext_/)
229
- warn "image.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
367
+ if !ext['images']
368
+ err "images attribute is required"
369
+ elsif !ext['images'].is_a?(Array)
370
+ err "images attribute must be an array"
371
+ end
372
+ end
373
+
374
+ if ext && ext['images'] && ext['images'].is_a?(Array)
375
+ ext['images'].each_with_index do |image, idx|
376
+ add_check("image[#{idx}]", "image at images[#{idx}]") do
377
+ if !image.is_a?(Hash)
378
+ err "image must be a hash"
379
+ elsif !image['id']
380
+ err "image.id is required"
381
+ elsif !image['width'] || !image['width'].is_a?(Fixnum)
382
+ err "image.width must be a valid positive number"
383
+ elsif !image['height'] || !image['height'].is_a?(Fixnum)
384
+ err "image.height must be a valid positive number"
385
+ elsif !image['content_type'] || !image['content_type'].match(/^image\/.+$/)
386
+ err "image.content_type must be a valid image mime type"
387
+ elsif !image['url'] && !image['data'] && !image['symbol']
388
+ err "image must have data, url or symbol attribute defined"
389
+ elsif image['data'] && !image['data'].match(/^data:image\/.+;base64,.+$/)
390
+ err "image.data must be a valid data URI if defined"
391
+ elsif image['symbol'] && !image['symbol'].is_a?(Hash)
392
+ err "image.symbol must be a hash if defined"
393
+ end
394
+ if image['path']
395
+ if opts['zipper']
396
+ if opts['zipper'].glob(image['path']).length == 0
397
+ err "image.path \"#{image['path']}\" not found in .obz package"
230
398
  end
399
+ else
400
+ err "image.path should not be defined outside of an .obz package"
401
+ end
402
+ end
403
+
404
+ attrs = ['id', 'width', 'height', 'content_type', 'data', 'url', 'symbol', 'path', 'data_url', 'license']
405
+ image.keys.each do |key|
406
+ if !attrs.include?(key) && !key.match(/^ext_/)
407
+ warn "image.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
231
408
  end
232
409
  end
233
410
  end
234
411
  end
412
+ end
235
413
 
236
- add_check('sounds', "sounds attribute") do
237
-
238
- if !ext['sounds']
239
- err "sounds attribute is required"
240
- elsif !ext['sounds'].is_a?(Array)
241
- err "sounds attribute must be an array"
242
- end
414
+ add_check('sounds', "sounds attribute") do
415
+ if !ext['sounds']
416
+ err "sounds attribute is required"
417
+ elsif !ext['sounds'].is_a?(Array)
418
+ err "sounds attribute must be an array"
243
419
  end
244
-
245
- if ext['sounds'] && ext['sounds'].is_a?(Array)
246
- ext['sounds'].each_with_index do |sound, idx|
247
- add_check("sounds[#{idx}]", "sound at sounds[#{idx}]") do
248
- if !sound.is_a?(Hash)
249
- err "sound must be a hash"
250
- elsif !sound['id']
251
- err "sound.id is required"
252
- elsif !sound['duration'] || !sound['duration'].is_a?(Fixnum)
253
- err "sound.duration must be a valid positive number"
254
- elsif !sound['content_type'] || !sound['content_type'].match(/^audio\/.+$/)
255
- err "sound.content_type must be a valid audio mime type"
256
- elsif !sound['url'] && !sound['data'] && !sound['symbol']
257
- err "sound must have data, url or symbol attribute defined"
258
- elsif sound['data'] && !sound['data'].match(/^data:audio\/.+;base64,.+$/)
259
- err "sound.data must be a valid data URI if defined"
260
- end
261
-
262
- attrs = ['id', 'duration', 'content_type', 'data', 'url', 'path', 'data_url', 'license']
263
- sound.keys.each do |key|
264
- if !attrs.include?(key) && !key.match(/^ext_/)
265
- warn "sound.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
266
- end
420
+ end
421
+
422
+ if ext && ext['sounds'] && ext['sounds'].is_a?(Array)
423
+ ext['sounds'].each_with_index do |sound, idx|
424
+ add_check("sounds[#{idx}]", "sound at sounds[#{idx}]") do
425
+ if !sound.is_a?(Hash)
426
+ err "sound must be a hash"
427
+ elsif !sound['id']
428
+ err "sound.id is required"
429
+ elsif !sound['duration'] || !sound['duration'].is_a?(Fixnum)
430
+ err "sound.duration must be a valid positive number"
431
+ elsif !sound['content_type'] || !sound['content_type'].match(/^audio\/.+$/)
432
+ err "sound.content_type must be a valid audio mime type"
433
+ elsif !sound['url'] && !sound['data'] && !sound['symbol']
434
+ err "sound must have data, url or symbol attribute defined"
435
+ elsif sound['data'] && !sound['data'].match(/^data:audio\/.+;base64,.+$/)
436
+ err "sound.data must be a valid data URI if defined"
437
+ end
438
+
439
+ attrs = ['id', 'duration', 'content_type', 'data', 'url', 'path', 'data_url', 'license']
440
+ sound.keys.each do |key|
441
+ if !attrs.include?(key) && !key.match(/^ext_/)
442
+ warn "sound.#{key} attribute is not defined in the spec, should be prefixed with ext_yourapp_"
267
443
  end
268
444
  end
269
445
  end
270
446
  end
271
447
  end
272
448
 
273
- if ext['buttons'] && ext['buttons'].is_a?(Array)
449
+ if ext && ext['buttons'] && ext['buttons'].is_a?(Array)
274
450
  ext['buttons'].each_with_index do |button, idx|
275
451
  add_check("buttons[#{idx}]", "button at buttons[#{idx}]") do
276
452
  if !button.is_a?(Hash)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: obf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Whitmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-04 00:00:00.000000000 Z
11
+ date: 2014-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json