hasmenu 0.1.4
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.
- 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: []
|