hasmenu 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +55 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +1 -0
- data/bin/hasmenu +10 -0
- data/hasmenu.gemspec +28 -0
- data/lib/hasmenu.rb +55 -0
- data/lib/hasmenu/builder.rb +59 -0
- data/lib/hasmenu/formatter.rb +41 -0
- data/lib/hasmenu/printer.rb +56 -0
- data/lib/hasmenu/reporter.rb +104 -0
- data/lib/hasmenu/spellchecker.rb +81 -0
- data/lib/hasmenu/validator.rb +121 -0
- data/lib/hasmenu/version.rb +3 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9fb66574b326404756bf6aa1d3d4122047251d4c
|
4
|
+
data.tar.gz: f88fc0acd29c7f5b393bbbcc248705d44263e80f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0be75e278d1345541d6cf8e2ad26e7faa77b7e34bff91354b7c1a8953e4fc5be5d2e381b296dcfa4040309cf28da864397768b84c0c15bd50cb0bd9071215d38
|
7
|
+
data.tar.gz: 397cefe3c973f82c51114468ce2355b35c4d066c0384155cefbab71d459cf1382f5fd0287fb4f79843e14ed00888b999efccdae9a0dfcfb356c143f4f0114a3b
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- bin/**
|
4
|
+
- db/schema.rb
|
5
|
+
- db/settings.rb
|
6
|
+
- db/migrate/**
|
7
|
+
|
8
|
+
Lint/AssignmentInCondition:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Lint/HandleExceptions:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Lint/UnusedBlockArgument:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Metrics/AbcSize:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/ClassLength:
|
21
|
+
Max: 160
|
22
|
+
|
23
|
+
Metrics/LineLength:
|
24
|
+
Max: 1500
|
25
|
+
|
26
|
+
Metrics/MethodLength:
|
27
|
+
Max: 160
|
28
|
+
|
29
|
+
Style/CaseIndentation:
|
30
|
+
IndentWhenRelativeTo: case
|
31
|
+
IndentOneStep: true
|
32
|
+
|
33
|
+
Style/Documentation:
|
34
|
+
Enabled: false
|
35
|
+
|
36
|
+
Style/GuardClause:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
Style/ModuleFunction:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
Style/MultilineOperationIndentation:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Style/StringLiterals:
|
46
|
+
EnforcedStyle: double_quotes
|
47
|
+
|
48
|
+
Style/RaiseArgs:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Style/RedundantSelf:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
Style/SymbolProc:
|
55
|
+
Enabled: false
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Samyukti
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Has.Menu
|
2
|
+
|
3
|
+
A utility to collect and process data for Has.Menu
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install hasmenu
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
### Spellcheck Menu
|
12
|
+
|
13
|
+
You can spellcheck an individual file
|
14
|
+
|
15
|
+
hasmenu spellcheck <file>
|
16
|
+
|
17
|
+
Or all the files in a directory
|
18
|
+
|
19
|
+
hasmenu spellcheck <directory>
|
20
|
+
|
21
|
+
### Validate Files
|
22
|
+
|
23
|
+
hasmenu validate chains <chains-file>
|
24
|
+
hasmenu validate restaurants <restaurants-file>
|
25
|
+
hasmenu validate menu/chain <chain-menu>
|
26
|
+
hasmenu validate menu/restaurant <restaurant-menu>
|
27
|
+
|
28
|
+
### Build Restaurant Menu
|
29
|
+
|
30
|
+
You may build menus for all restaurants
|
31
|
+
|
32
|
+
hasmenu build all
|
33
|
+
hasmenu build chain <chain-uid>
|
34
|
+
hasmenu build restaurant <restaurant-uid>
|
35
|
+
|
36
|
+
### Review Status & Reports
|
37
|
+
|
38
|
+
Review the status and progress of the data collection
|
39
|
+
|
40
|
+
hasmenu report chains
|
41
|
+
hasmenu report restaurants
|
42
|
+
hasmenu report available
|
43
|
+
hasmenu report unavailable
|
44
|
+
hasmenu report approved
|
45
|
+
hasmenu report unapproved
|
46
|
+
hasmenu report progress
|
47
|
+
hasmenu report done
|
48
|
+
hasmenu report all
|
49
|
+
|
50
|
+
## Notice
|
51
|
+
|
52
|
+
This utility is published by Samyukti to enable collection of data for Has.Menu.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/hasmenu
ADDED
data/hasmenu.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "hasmenu/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "hasmenu"
|
8
|
+
spec.version = Hasmenu::VERSION
|
9
|
+
spec.authors = ["Geordee Naliyath"]
|
10
|
+
spec.email = ["geordee@gmail.com"]
|
11
|
+
spec.summary = "A utility to collect and process data for Has.Menu"
|
12
|
+
spec.description = "Has.Menu is an online service to discover restaurant menus. This utility is used internally to build and validate menu in YAML format."
|
13
|
+
spec.homepage = "https://has.menu"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = %w(hasmenu)
|
18
|
+
# spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "thor"
|
23
|
+
spec.add_dependency "colorize"
|
24
|
+
spec.add_dependency "json_schema"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
end
|
data/lib/hasmenu.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "hasmenu/version"
|
3
|
+
require "hasmenu/printer"
|
4
|
+
require "hasmenu/formatter"
|
5
|
+
require "hasmenu/spellchecker"
|
6
|
+
require "hasmenu/validator"
|
7
|
+
require "hasmenu/builder"
|
8
|
+
require "hasmenu/reporter"
|
9
|
+
|
10
|
+
module Hasmenu
|
11
|
+
class Cli < Thor
|
12
|
+
map %w(--version -v) => :__print_version
|
13
|
+
|
14
|
+
desc "--version, -v", "Print the version"
|
15
|
+
def __print_version
|
16
|
+
puts Hasmenu::VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "format <path>", "Format Has.Menu data"
|
20
|
+
option :location, aliases: :l, desc: "Path to data repository"
|
21
|
+
def format(path)
|
22
|
+
Hasmenu::Formatter.new(options).format(path)
|
23
|
+
end
|
24
|
+
map "f" => :format
|
25
|
+
|
26
|
+
desc "spellcheck <path>", "Run spellcheck on Has.Menu data"
|
27
|
+
option :dicts, aliases: :d, desc: "Path to dictionary files"
|
28
|
+
option :except, aliases: :e, desc: "Exception file id"
|
29
|
+
def spellcheck(path)
|
30
|
+
Hasmenu::SpellChecker.new(options).check(path)
|
31
|
+
end
|
32
|
+
map "sc" => :spellcheck
|
33
|
+
|
34
|
+
desc "validate <type> <path>", "Run validation on Has.Menu data"
|
35
|
+
option :schema, aliases: :s, desc: "Path to schema files"
|
36
|
+
def validate(type, path)
|
37
|
+
Hasmenu::Validator.new(type, options).perform(path)
|
38
|
+
end
|
39
|
+
map "v" => :validate
|
40
|
+
|
41
|
+
desc "build <type> [uid] [menu-uid]", "Build one or more restaurant menus from chain menu"
|
42
|
+
option :location, aliases: :l, desc: "Path to data repository"
|
43
|
+
def build(type, uid = nil, menu_uid = nil)
|
44
|
+
Hasmenu::Builder.new(type, options).build(uid, menu_uid)
|
45
|
+
end
|
46
|
+
map "b" => :build
|
47
|
+
|
48
|
+
desc "report <type>", "Report the status and metrics from the repository"
|
49
|
+
option :location, aliases: :l, desc: "Path to data repository"
|
50
|
+
def report(type)
|
51
|
+
Hasmenu::Reporter.new(type, options).report
|
52
|
+
end
|
53
|
+
map "r" => :report
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module Hasmenu
|
4
|
+
class Builder
|
5
|
+
include Printer
|
6
|
+
|
7
|
+
def initialize(type, options)
|
8
|
+
@type = type
|
9
|
+
@location = options[:location] || Dir.pwd
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_menu(restaurant, menu_uid)
|
13
|
+
output = {}
|
14
|
+
|
15
|
+
output["restaurant"] = restaurant
|
16
|
+
|
17
|
+
chain = restaurant["chain"]
|
18
|
+
menus = menu_uid ? "#{menu_uid}.yml" : "*.yml"
|
19
|
+
pattern = File.join("#{@location}/menu/chain/#{chain}/#{menus}")
|
20
|
+
|
21
|
+
Dir.glob(pattern).each do |menu|
|
22
|
+
chain_menu = YAML.load_file(menu)
|
23
|
+
output["restaurant"]["menus"] = chain_menu["chain"]["menus"]
|
24
|
+
|
25
|
+
restaurant_dir = File.join(@location, "menu", "restaurant", restaurant["uid"])
|
26
|
+
FileUtils.mkdir_p(restaurant_dir) unless File.directory?(restaurant_dir)
|
27
|
+
|
28
|
+
menu_file = File.join(restaurant_dir, File.basename(menu))
|
29
|
+
File.open(menu_file, "w") { |f| f.write output.to_yaml }
|
30
|
+
print_build_for restaurant["uid"]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def build(uid, menu_uid)
|
35
|
+
restaurants_yml = "#{@location}/restaurants.yml"
|
36
|
+
unless File.exist? restaurants_yml
|
37
|
+
print_invalid_path
|
38
|
+
return
|
39
|
+
end
|
40
|
+
restaurants = YAML.load_file(restaurants_yml)
|
41
|
+
|
42
|
+
case @type
|
43
|
+
when "chain"
|
44
|
+
restaurants.select! { |r| r["chain"] == uid }
|
45
|
+
when "restaurant"
|
46
|
+
restaurants.select! { |r| r["uid"] == uid }
|
47
|
+
when "all"
|
48
|
+
restaurants
|
49
|
+
else
|
50
|
+
print_invalid_build
|
51
|
+
end
|
52
|
+
|
53
|
+
print_build_start
|
54
|
+
restaurants.each do |restaurant|
|
55
|
+
build_menu restaurant, menu_uid
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module Hasmenu
|
4
|
+
class Formatter
|
5
|
+
include Printer
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@location = options[:location] || Dir.pwd
|
9
|
+
end
|
10
|
+
|
11
|
+
def format_file(path)
|
12
|
+
file = YAML.load_file(path)
|
13
|
+
File.open(path, "w") { |f| f.write file.to_yaml }
|
14
|
+
print_format_for File.basename(File.dirname(path))
|
15
|
+
end
|
16
|
+
|
17
|
+
def format_files(path)
|
18
|
+
Dir.glob(path + "/**/*.yml") do |file|
|
19
|
+
format_file file
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def format(path)
|
24
|
+
path = File.join(@location, path)
|
25
|
+
|
26
|
+
unless File.exist? path
|
27
|
+
print_invalid_path
|
28
|
+
return
|
29
|
+
end
|
30
|
+
|
31
|
+
print_format_start
|
32
|
+
if File.file?(path) && File.extname(path) == ".yml"
|
33
|
+
format_file path
|
34
|
+
elsif File.directory? path
|
35
|
+
format_files path
|
36
|
+
else
|
37
|
+
print_invalid_path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "colorize"
|
2
|
+
|
3
|
+
module Hasmenu
|
4
|
+
module Printer
|
5
|
+
def print_header(title)
|
6
|
+
puts "--------------------------------------------------------------------------------".colorize(:green)
|
7
|
+
puts title.colorize(:green)
|
8
|
+
puts "--------------------------------------------------------------------------------".colorize(:green)
|
9
|
+
end
|
10
|
+
|
11
|
+
def print_invalid_path
|
12
|
+
puts "\n error: please provide a valid file or directory\n".colorize(:red)
|
13
|
+
end
|
14
|
+
|
15
|
+
def print_format_start
|
16
|
+
puts "formatting files".colorize(:green)
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_format_for(file)
|
20
|
+
puts " - #{file}".colorize(:green)
|
21
|
+
end
|
22
|
+
|
23
|
+
def print_warn_repeats
|
24
|
+
puts "warning: please review the use of repeat property".colorize(:yellow)
|
25
|
+
end
|
26
|
+
|
27
|
+
def print_invalid_sequence
|
28
|
+
puts "#: failed name #: filename sequence should be a number for active, and xa for inactive menu"
|
29
|
+
end
|
30
|
+
|
31
|
+
def print_invalid_version
|
32
|
+
puts "#: failed name #: filename should match with menu uid and version"
|
33
|
+
end
|
34
|
+
|
35
|
+
def print_invalid_build
|
36
|
+
puts "\n error: please provide a valid build type\n".colorize(:red)
|
37
|
+
end
|
38
|
+
|
39
|
+
def print_build_start
|
40
|
+
puts "building restaurant menus".colorize(:green)
|
41
|
+
end
|
42
|
+
|
43
|
+
def print_build_for(restaurant)
|
44
|
+
puts " - #{restaurant}".colorize(:green)
|
45
|
+
end
|
46
|
+
|
47
|
+
def print_invalid_report
|
48
|
+
puts "\n error: please provide a valid report type\n".colorize(:red)
|
49
|
+
end
|
50
|
+
|
51
|
+
def print_report(data)
|
52
|
+
data.each { |d| puts " - #{d}".colorize(:green) }
|
53
|
+
print_header "Count: #{data.count}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module Hasmenu
|
4
|
+
class Reporter
|
5
|
+
include Printer
|
6
|
+
|
7
|
+
def initialize(type, options)
|
8
|
+
@type = type
|
9
|
+
@location = options[:location] || Dir.pwd
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_data(file, field)
|
13
|
+
data = YAML.load_file(file)
|
14
|
+
data.map { |e| e[field] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_folder(files)
|
18
|
+
files.map { |f| File.basename(File.dirname(f)) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_data
|
22
|
+
@yaml_chains = get_data "chains.yml", "uid"
|
23
|
+
@yaml_restaurants = get_data "restaurants.yml", "uid"
|
24
|
+
@restaurant_chains = get_data "restaurants.yml", "chain"
|
25
|
+
@file_chains = get_folder Dir.glob("#{@location}/menu/chain/**/*.yml")
|
26
|
+
@file_restaurants = get_folder Dir.glob("#{@location}/menu/restaurant/**/*.yml")
|
27
|
+
end
|
28
|
+
|
29
|
+
def report_chains
|
30
|
+
print_header "List of Chains"
|
31
|
+
print_report(@yaml_chains.sort)
|
32
|
+
end
|
33
|
+
|
34
|
+
def report_available
|
35
|
+
print_header "Available Chain Menus"
|
36
|
+
print_report(@file_chains.sort)
|
37
|
+
end
|
38
|
+
|
39
|
+
def report_unavailable
|
40
|
+
print_header "Unavailable Chain Menus"
|
41
|
+
print_report(@restaurant_chains.sort - @file_chains.sort)
|
42
|
+
end
|
43
|
+
|
44
|
+
def report_approved
|
45
|
+
print_header "Approved Restaurants"
|
46
|
+
print_report(@yaml_restaurants.sort)
|
47
|
+
end
|
48
|
+
|
49
|
+
def report_unapproved
|
50
|
+
print_header "Unapproved Chains"
|
51
|
+
print_report(@yaml_chains.sort - @restaurant_chains.sort)
|
52
|
+
end
|
53
|
+
|
54
|
+
def report_progress
|
55
|
+
print_header "Chain Menus in Progress"
|
56
|
+
print_report(@yaml_chains.sort - @file_chains.sort)
|
57
|
+
end
|
58
|
+
|
59
|
+
def report_done
|
60
|
+
print_header "Restaurant Menus Completed"
|
61
|
+
print_report(@file_restaurants.sort)
|
62
|
+
end
|
63
|
+
|
64
|
+
def report_all
|
65
|
+
report_chains
|
66
|
+
report_available
|
67
|
+
report_unavailable
|
68
|
+
report_approved
|
69
|
+
report_unapproved
|
70
|
+
report_progress
|
71
|
+
report_done
|
72
|
+
end
|
73
|
+
|
74
|
+
def report
|
75
|
+
unless File.exist? @location
|
76
|
+
print_invalid_path
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
return unless load_data
|
81
|
+
|
82
|
+
case @type
|
83
|
+
when "chains"
|
84
|
+
report_chains
|
85
|
+
when "available"
|
86
|
+
report_available
|
87
|
+
when "unavailable"
|
88
|
+
report_unavailable
|
89
|
+
when "approved", "restaurants"
|
90
|
+
report_approved
|
91
|
+
when "unapproved"
|
92
|
+
report_unapproved
|
93
|
+
when "progress"
|
94
|
+
report_progress
|
95
|
+
when "done"
|
96
|
+
report_done
|
97
|
+
when "all"
|
98
|
+
report_all
|
99
|
+
else
|
100
|
+
print_invalid_report
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "active_support"
|
3
|
+
require "active_support/core_ext"
|
4
|
+
require "active_support/inflector"
|
5
|
+
|
6
|
+
# numeric test
|
7
|
+
class String
|
8
|
+
def number?
|
9
|
+
true if Float(self) rescue false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Hasmenu
|
14
|
+
class SpellChecker
|
15
|
+
include Printer
|
16
|
+
|
17
|
+
def initialize(options)
|
18
|
+
@dictd = options[:dicts] || File.join(Dir.pwd, ".meta", "dicts")
|
19
|
+
@xcept = options[:except]
|
20
|
+
@dicts = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def load_dicts
|
24
|
+
yamls = Dir.glob("#{@dictd}/*.yml")
|
25
|
+
yamls.each do |yaml|
|
26
|
+
@dicts << YAML.load_file(yaml)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def values_of(h)
|
31
|
+
h.values.flatten.map do |e|
|
32
|
+
if e.is_a?(Hash)
|
33
|
+
values_of(e)
|
34
|
+
else
|
35
|
+
e.to_s.parameterize.split(/[^\w]/)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def spell_check(path)
|
41
|
+
xcept = @xcept || File.basename(File.dirname(path))
|
42
|
+
xyaml = File.join(@dictd, "excepts", xcept + ".yml")
|
43
|
+
|
44
|
+
if File.file? xyaml
|
45
|
+
except = YAML.load_file(xyaml)
|
46
|
+
@dicts << except
|
47
|
+
end
|
48
|
+
|
49
|
+
data = YAML.load_file(path)
|
50
|
+
|
51
|
+
diff = values_of(data).flatten.sort.uniq - @dicts.flatten
|
52
|
+
diff = diff.compact.delete_if(&:number?)
|
53
|
+
|
54
|
+
print_header path
|
55
|
+
puts diff if diff.present?
|
56
|
+
end
|
57
|
+
|
58
|
+
def spell_check_all(path)
|
59
|
+
Dir.glob(path + "/**/*.yml") do |file|
|
60
|
+
spell_check file
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def check(path)
|
65
|
+
unless File.exist? path
|
66
|
+
print_invalid_path
|
67
|
+
return
|
68
|
+
end
|
69
|
+
|
70
|
+
load_dicts
|
71
|
+
|
72
|
+
if File.file? path
|
73
|
+
spell_check path
|
74
|
+
elsif File.directory? path
|
75
|
+
spell_check_all path
|
76
|
+
else
|
77
|
+
print_invalid_path
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "json"
|
3
|
+
require "json_schema"
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/core_ext"
|
6
|
+
|
7
|
+
module Hasmenu
|
8
|
+
class Validator
|
9
|
+
include Printer
|
10
|
+
|
11
|
+
def initialize(type, options)
|
12
|
+
@type = type.chomp("/")
|
13
|
+
@schemad = options[:schema] || File.join(Dir.pwd, ".meta", "schema")
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_schema
|
17
|
+
file = File.join(@schemad, "#{@type}-v4.json")
|
18
|
+
|
19
|
+
if File.file? file
|
20
|
+
schema_data = JSON.parse File.read(file)
|
21
|
+
@schema, error = JsonSchema.parse(schema_data)
|
22
|
+
if error
|
23
|
+
puts error
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
return true
|
27
|
+
else
|
28
|
+
print_invalid_path
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_uniqueness(data)
|
34
|
+
schema_data = JSON.parse '{"type": "array", "items": {"type": "string"}, "uniqueItems": true}'
|
35
|
+
schema = JsonSchema.parse!(schema_data)
|
36
|
+
|
37
|
+
validated, errors = schema.validate(data)
|
38
|
+
unless validated
|
39
|
+
puts errors
|
40
|
+
duplicates = data.group_by { |e| e }.select { |k, v| v.size > 1 }.map(&:first)
|
41
|
+
puts JSON.dump duplicates
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate(path)
|
46
|
+
print_header path
|
47
|
+
|
48
|
+
data = YAML.load_file(path)
|
49
|
+
|
50
|
+
# check valid schema
|
51
|
+
validated, errors = @schema.validate(data)
|
52
|
+
puts errors unless validated
|
53
|
+
|
54
|
+
# check unique columns
|
55
|
+
type, subtype = @type.split("/")
|
56
|
+
case type
|
57
|
+
when "chains", "restaurants"
|
58
|
+
validate_uniqueness(data.map { |x| x["uid"] })
|
59
|
+
when "menu"
|
60
|
+
case subtype
|
61
|
+
when "chain"
|
62
|
+
menus = data["chain"]["menus"] if data["chain"]
|
63
|
+
when "restaurant"
|
64
|
+
menus = data["restaurant"]["menus"] if data["restaurant"]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if menus
|
69
|
+
validate_uniqueness(menus.map { |m| m["uid"] })
|
70
|
+
menus.each do |menu|
|
71
|
+
sections = menu["sections"]
|
72
|
+
validate_uniqueness(sections.map { |s| s["uid"] })
|
73
|
+
|
74
|
+
items = sections.map { |s| s["items"].reject { |i| i["repeat"] } }.flatten
|
75
|
+
validate_uniqueness(items.map { |i| i["uid"] })
|
76
|
+
validate_uniqueness(items.map { |i| i["name"] })
|
77
|
+
|
78
|
+
print_warn_repeats \
|
79
|
+
if sections.map { |s| s["items"].select { |i| i["repeat"] } }.flatten.present?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# check file naming conventions
|
84
|
+
if menus
|
85
|
+
menu = menus.first
|
86
|
+
filename = File.basename(path, ".yml")
|
87
|
+
# sequence
|
88
|
+
if menu && menu.key?("active") && !menu["active"]
|
89
|
+
print_invalid_sequence unless filename[0..2] == "xa-"
|
90
|
+
else
|
91
|
+
print_invalid_sequence unless filename[0..2] =~ /[0-9][0-9]-/
|
92
|
+
end
|
93
|
+
# version
|
94
|
+
print_invalid_version unless filename[3..-1] == "#{menu['uid']}-v#{menu['version']}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_all(path)
|
99
|
+
Dir.glob(path + "/**/*.yml") do |file|
|
100
|
+
validate file
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def perform(path)
|
105
|
+
unless File.exist? path
|
106
|
+
print_invalid_path
|
107
|
+
return
|
108
|
+
end
|
109
|
+
|
110
|
+
return unless load_schema
|
111
|
+
|
112
|
+
if File.file? path
|
113
|
+
validate path
|
114
|
+
elsif File.directory? path
|
115
|
+
validate_all path
|
116
|
+
else
|
117
|
+
print_invalid_path
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hasmenu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Geordee Naliyath
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: colorize
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: json_schema
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
description: Has.Menu is an online service to discover restaurant menus. This utility
|
84
|
+
is used internally to build and validate menu in YAML format.
|
85
|
+
email:
|
86
|
+
- geordee@gmail.com
|
87
|
+
executables:
|
88
|
+
- hasmenu
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rubocop.yml"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- bin/hasmenu
|
99
|
+
- hasmenu.gemspec
|
100
|
+
- lib/hasmenu.rb
|
101
|
+
- lib/hasmenu/builder.rb
|
102
|
+
- lib/hasmenu/formatter.rb
|
103
|
+
- lib/hasmenu/printer.rb
|
104
|
+
- lib/hasmenu/reporter.rb
|
105
|
+
- lib/hasmenu/spellchecker.rb
|
106
|
+
- lib/hasmenu/validator.rb
|
107
|
+
- lib/hasmenu/version.rb
|
108
|
+
homepage: https://has.menu
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 2.2.2
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: A utility to collect and process data for Has.Menu
|
132
|
+
test_files: []
|