settings_spec 0.0.1
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 +23 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +108 -0
- data/Rakefile +7 -0
- data/lib/settings_spec/specs.rb +74 -0
- data/lib/settings_spec/version.rb +3 -0
- data/lib/settings_spec/visitor.rb +22 -0
- data/lib/settings_spec/visitors/array.rb +16 -0
- data/lib/settings_spec/visitors/common.rb +19 -0
- data/lib/settings_spec/visitors/number.rb +17 -0
- data/lib/settings_spec/visitors/string.rb +12 -0
- data/lib/settings_spec.rb +16 -0
- data/settings_spec.gemspec +27 -0
- data/spec/fixtures/invalid-settings-1.yml +21 -0
- data/spec/fixtures/invalid-settings-2.yml +10 -0
- data/spec/fixtures/settings_spec.yml +18 -0
- data/spec/fixtures/valid-settings-1.yml +24 -0
- data/spec/fixtures/valid-settings-2.yml +18 -0
- data/spec/libraries/app_config_spec.rb +19 -0
- data/spec/libraries/rails_config_spec.rb +27 -0
- data/spec/libraries/raw_yaml_spec.rb +17 -0
- data/spec/libraries/settingslogic_spec.rb +20 -0
- data/spec/library_specs.rb +35 -0
- data/spec/settings_spec/specs_spec.rb +171 -0
- data/spec/spec_helper.rb +2 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 73c75fa0d47ef93ab5ff71705e0ef6ed18d24ace
|
4
|
+
data.tar.gz: 53674bca88cba8e549beb27caa892178ad55ea59
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 06a40d1d51bf5497a05c65fb6de5a8a06c4822b83ffa63c2d110ee28f3a86ad38bd23028622e39e5517ffd22383bc5795878a3702924cfe1603706203dd6e03b
|
7
|
+
data.tar.gz: 054e05de667d00c3b51cd98c1d658d3e63489a491219138b0e836c1ac0eabe68735020764f17a8de6c460332a234962536a55b2f7d3bcbfe2ce9d0491df143cf
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
.DS_Store
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Yanhao
|
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,108 @@
|
|
1
|
+
# SettingsSpec
|
2
|
+
|
3
|
+
There are many tools to load configurations in Rails, such as
|
4
|
+
[rais\_config](https://github.com/railsconfig/rails_config),
|
5
|
+
[settingslogic](https://github.com/binarylogic/settingslogic).
|
6
|
+
Or you can just load your configurations in a YAML file directly,
|
7
|
+
`YAML.load_file("config.yml")`.
|
8
|
+
|
9
|
+
Normally, there will be a file named `config_sample.yml`, where
|
10
|
+
you write all configurations. When you deploy the application,
|
11
|
+
you make an copy of the sample file, change some values and launch
|
12
|
+
the application to see if it works or not.
|
13
|
+
|
14
|
+
And later, you add some new entries into the sample file as the
|
15
|
+
application grows. You must remember to add them to the configuration
|
16
|
+
file on production when you update the servers. Otherwise, the
|
17
|
+
application may refuse to work, complaining about missing configurations.
|
18
|
+
|
19
|
+
This gem is built to address the problem. It converts the sample
|
20
|
+
file into a specification file. Instead of giving some sample values,
|
21
|
+
you write rules to validate the configuration file, so that you know
|
22
|
+
the configuration file is all right before an invalid configuration
|
23
|
+
file breaks the application.
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
Add this line to your application's Gemfile:
|
28
|
+
|
29
|
+
gem 'settings_spec'
|
30
|
+
|
31
|
+
And then execute:
|
32
|
+
|
33
|
+
$ bundle
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
$ gem install settings_spec
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
It supports following rules in the specification file:
|
42
|
+
|
43
|
+
* `gt n`: the number should greater than n
|
44
|
+
* `lt n`: the number should less than n
|
45
|
+
* `match <regexp>`: match a string against a regexp
|
46
|
+
* `one_in <array_or_range>`: the value should be included in the given array\_or\_range
|
47
|
+
* `all_in <array_or_range>`: the value should be an array, which is a subset of the given array\_or\_range
|
48
|
+
* `is_a <class>`: the value should be a type of class
|
49
|
+
* `blank`: the value can be blank, meaning this entry is optional
|
50
|
+
* `call <proc>`: calls a proc to validate the value
|
51
|
+
* all above rules can be combined with `and`, `or`, and grouped with `()`
|
52
|
+
|
53
|
+
A specification file could look like this:
|
54
|
+
|
55
|
+
defaults: &defaults
|
56
|
+
api:
|
57
|
+
url: match /^https/
|
58
|
+
username: one_in %w{user1 user2}
|
59
|
+
password: blank or match /\A.{8,}\z/
|
60
|
+
retries: one_in 1..9
|
61
|
+
enabled_env: all_in %w{staging production}
|
62
|
+
reconnect: one_in [true false]
|
63
|
+
pool: gt 3
|
64
|
+
mod3: call ->(n){ n % 3 == 0}
|
65
|
+
|
66
|
+
development:
|
67
|
+
<<: *defaults
|
68
|
+
|
69
|
+
test:
|
70
|
+
<<: *defaults
|
71
|
+
|
72
|
+
It can validate any settings system which responds to `:<key>` or `:[]`.
|
73
|
+
|
74
|
+
Suppose the specification file is loaded this way:
|
75
|
+
|
76
|
+
spec_file = Rails.root.join('config', 'config_spec.yml')
|
77
|
+
specs = SettingsSpec.load(spec_file, Rails.env)
|
78
|
+
|
79
|
+
### Validate settingslogic
|
80
|
+
|
81
|
+
class Settings < Settingslogic
|
82
|
+
source Rails.root.join('config', 'config.yml')
|
83
|
+
namespace 'development'
|
84
|
+
end
|
85
|
+
specs.verify!(Settings)
|
86
|
+
|
87
|
+
### Validate rails\_config
|
88
|
+
|
89
|
+
RailsConfig.load_and_set_settings Rails.root.join('config', 'config.yml')
|
90
|
+
specs.verify!(Settings)
|
91
|
+
|
92
|
+
### Validate app\_config
|
93
|
+
|
94
|
+
AppConfig.setup!({yaml: Rails.root.join('config', 'config.yml'), env: Rails.env})
|
95
|
+
specs.verify!(AppConfig)
|
96
|
+
|
97
|
+
### Validate YAML
|
98
|
+
|
99
|
+
::AppConfig = YAML.load_file(Rails.root.join('config', 'config.yml'))['development']
|
100
|
+
specs.verify!(AppConfig)
|
101
|
+
|
102
|
+
## Contributing
|
103
|
+
|
104
|
+
1. Fork it ( https://github.com/YanhaoYang/settings\_spec/fork )
|
105
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
106
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
107
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
108
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module SettingsSpec
|
2
|
+
class Specs
|
3
|
+
|
4
|
+
attr_reader :errors
|
5
|
+
|
6
|
+
def initialize(specs)
|
7
|
+
@specs = specs
|
8
|
+
@errors = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def verify(settings)
|
12
|
+
if settings
|
13
|
+
check([], @specs, settings)
|
14
|
+
else
|
15
|
+
@errors['.'] = 'Settings is a nil?!'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def verify!(settings)
|
20
|
+
verify(settings)
|
21
|
+
unless @errors.empty?
|
22
|
+
error_messages = []
|
23
|
+
@errors.each do |k, v|
|
24
|
+
error_messages << %{ %s: "%s"} % [k, v]
|
25
|
+
end
|
26
|
+
raise StandardError, "Some settings do not pass verification:\n#{error_messages.join("\n")}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def check(path, spec_node, setting_node)
|
33
|
+
case spec_node
|
34
|
+
when Hash
|
35
|
+
else
|
36
|
+
end
|
37
|
+
case spec_node
|
38
|
+
when Hash
|
39
|
+
spec_node.each do |k, v|
|
40
|
+
check(path + [k], v, fetch(setting_node, k))
|
41
|
+
end
|
42
|
+
when String
|
43
|
+
begin
|
44
|
+
unless Visitor.new(setting_node).visit(spec_node)
|
45
|
+
@errors[path.join(':')] = "#{spec_node} [val: #{setting_node}]"
|
46
|
+
end
|
47
|
+
rescue
|
48
|
+
@errors[path.join(':')] = "#{spec_node} [exception: #{$!}]"
|
49
|
+
end
|
50
|
+
else
|
51
|
+
raise InvalidSpec, "#{path.join('.')}: #{spec_node.to_s} (It should be a String.)"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def getters
|
56
|
+
@getters ||= [
|
57
|
+
lambda { |obj, key| obj[key.to_s] rescue nil if obj.respond_to?(:'[]')},
|
58
|
+
lambda { |obj, key| obj[key.to_sym] rescue nil if obj.respond_to?(:'[]')},
|
59
|
+
lambda { |obj, key| obj.send(key.to_sym) rescue nil},
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
def fetch(settings, key)
|
64
|
+
return unless settings
|
65
|
+
|
66
|
+
getters.each do |getter|
|
67
|
+
val = getter.call(settings, key)
|
68
|
+
return val unless val.nil?
|
69
|
+
end
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "settings_spec/visitors/common"
|
2
|
+
require "settings_spec/visitors/number"
|
3
|
+
require "settings_spec/visitors/string"
|
4
|
+
require "settings_spec/visitors/array"
|
5
|
+
|
6
|
+
module SettingsSpec
|
7
|
+
class Visitor
|
8
|
+
include Visitors::Common
|
9
|
+
include Visitors::Number
|
10
|
+
include Visitors::String
|
11
|
+
include Visitors::Array
|
12
|
+
|
13
|
+
def initialize(setting)
|
14
|
+
@setting = setting
|
15
|
+
end
|
16
|
+
|
17
|
+
def visit(spec)
|
18
|
+
instance_eval(spec)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SettingsSpec
|
2
|
+
module Visitors
|
3
|
+
module Array
|
4
|
+
|
5
|
+
def one_in(array_or_range)
|
6
|
+
array_or_range.include?(@setting)
|
7
|
+
end
|
8
|
+
|
9
|
+
def all_in(array_or_range)
|
10
|
+
return false unless @setting.is_a? ::Array
|
11
|
+
@setting.all? { |i| array_or_range.include?(i) }
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SettingsSpec
|
2
|
+
module Visitors
|
3
|
+
module Common
|
4
|
+
|
5
|
+
def blank
|
6
|
+
@setting.respond_to?(:empty?) ? @setting.empty? : !@setting
|
7
|
+
end
|
8
|
+
|
9
|
+
def is_a(klass)
|
10
|
+
@setting.is_a? klass
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(proc)
|
14
|
+
proc.call(@setting)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "settings_spec/version"
|
2
|
+
require "settings_spec/specs"
|
3
|
+
require "settings_spec/visitor"
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module SettingsSpec
|
7
|
+
|
8
|
+
class InvalidSpec < StandardError; end
|
9
|
+
|
10
|
+
def self.load(spec_file, namespace)
|
11
|
+
specs = YAML.load_file(spec_file)
|
12
|
+
specs = specs[namespace] if namespace
|
13
|
+
Specs.new(specs)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'settings_spec/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "settings_spec"
|
8
|
+
spec.version = SettingsSpec::VERSION
|
9
|
+
spec.authors = ["Yanhao Yang"]
|
10
|
+
spec.email = ["yanhao.yang@gmail.com"]
|
11
|
+
spec.summary = %q{Verifies the configurations against the specifications in a YAML file}
|
12
|
+
spec.description = %q{Verifies the configurations against the specifications in a YAML file}
|
13
|
+
spec.homepage = "https://github.com/YanhaoYang/settings_spec"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.3.2"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3.0.0"
|
24
|
+
spec.add_development_dependency "settingslogic", "~> 2.0.9"
|
25
|
+
spec.add_development_dependency "rails_config", "~> 0.4.2"
|
26
|
+
spec.add_development_dependency "app_config", "~> 2.5.1"
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
l1a: one_in [2, 3, 4]
|
3
|
+
l1b:
|
4
|
+
l2a: match /^a/
|
5
|
+
l2b: gt 4
|
6
|
+
l2c: all_in %w{a b c d}
|
7
|
+
l2d: blank or lt 9
|
8
|
+
l1c:
|
9
|
+
l2e: blank or match /\d{4}/
|
10
|
+
l2f: blank or one_in [true, false]
|
11
|
+
l2g: blank or all_in %w{a b c}
|
12
|
+
l1d: call ->(n){ n % 3 == 0}
|
13
|
+
|
14
|
+
development:
|
15
|
+
<<: *defaults
|
16
|
+
|
17
|
+
test:
|
18
|
+
<<: *defaults
|
@@ -0,0 +1,24 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
l1a: 3
|
3
|
+
l1b:
|
4
|
+
l2a: abc
|
5
|
+
l2b: 5
|
6
|
+
l2c:
|
7
|
+
- a
|
8
|
+
- c
|
9
|
+
l2d:
|
10
|
+
l1c:
|
11
|
+
l2e: 1234
|
12
|
+
l2f: false
|
13
|
+
l2g:
|
14
|
+
- a
|
15
|
+
l1d: 9
|
16
|
+
|
17
|
+
development:
|
18
|
+
<<: *defaults
|
19
|
+
l1a: 4
|
20
|
+
l1c:
|
21
|
+
|
22
|
+
test:
|
23
|
+
<<: *defaults
|
24
|
+
l1a: 2
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'library_specs'
|
3
|
+
require 'app_config'
|
4
|
+
|
5
|
+
describe SettingsSpec do
|
6
|
+
|
7
|
+
let(:settings) do
|
8
|
+
->(name) do
|
9
|
+
fn = File.dirname(__FILE__) + "/../fixtures/#{name}.yml"
|
10
|
+
AppConfig.setup!({yaml: fn, env: 'development'})
|
11
|
+
AppConfig
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#AppConfig" do
|
16
|
+
include_examples 'configuration library'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'library_specs'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
class Engine
|
6
|
+
def self.isolate_namespace(mod)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rails_config'
|
12
|
+
|
13
|
+
describe SettingsSpec do
|
14
|
+
|
15
|
+
let(:settings) do
|
16
|
+
->(name) do
|
17
|
+
fn = File.dirname(__FILE__) + "/../fixtures/#{name}.yml"
|
18
|
+
RailsConfig.load_and_set_settings fn
|
19
|
+
Settings.development
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#RailsConfig" do
|
24
|
+
include_examples 'configuration library'
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'library_specs'
|
3
|
+
|
4
|
+
describe SettingsSpec do
|
5
|
+
|
6
|
+
let(:settings) do
|
7
|
+
->(name) do
|
8
|
+
fn = File.dirname(__FILE__) + "/../fixtures/#{name}.yml"
|
9
|
+
YAML.load_file(fn)['development']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#YAML" do
|
14
|
+
include_examples 'configuration library'
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'library_specs'
|
3
|
+
require 'settingslogic'
|
4
|
+
|
5
|
+
describe SettingsSpec do
|
6
|
+
|
7
|
+
let(:settings) do
|
8
|
+
->(name) do
|
9
|
+
Class.new(Settingslogic) do
|
10
|
+
source File.dirname(__FILE__) + "/../fixtures/#{name}.yml"
|
11
|
+
namespace 'development'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#Settingslogic" do
|
17
|
+
include_examples 'configuration library'
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
shared_examples "configuration library" do
|
2
|
+
spec_file = File.expand_path(File.dirname(__FILE__) + "/fixtures/settings_spec.yml")
|
3
|
+
let(:specs) { SettingsSpec.load(spec_file, 'development') }
|
4
|
+
|
5
|
+
it 'valid settings 1 should pass' do
|
6
|
+
specs.verify(settings.call('valid-settings-1'))
|
7
|
+
expect(specs.errors).to be_empty
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'valid settings 2 should pass' do
|
11
|
+
specs.verify(settings.call('valid-settings-2'))
|
12
|
+
expect(specs.errors).to be_empty
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'invalid settings 1 should fail' do
|
16
|
+
specs.verify(settings.call('invalid-settings-1'))
|
17
|
+
error_keys = [
|
18
|
+
"l1a",
|
19
|
+
"l1b:l2a",
|
20
|
+
"l1b:l2b",
|
21
|
+
"l1b:l2c",
|
22
|
+
"l1c:l2e",
|
23
|
+
"l1c:l2f",
|
24
|
+
"l1c:l2g",
|
25
|
+
"l1d",
|
26
|
+
]
|
27
|
+
expect(specs.errors.keys.sort).to eq(error_keys)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'invalid settings 2 should fail' do
|
31
|
+
specs.verify(settings.call('invalid-settings-2'))
|
32
|
+
error_keys = ["l1a", "l1b:l2a", "l1b:l2b", "l1b:l2c", "l1d"]
|
33
|
+
expect(specs.errors.keys.sort).to eq(error_keys)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SettingsSpec::Specs do
|
4
|
+
describe "#number" do
|
5
|
+
|
6
|
+
it "8 can pass 'gt 5'" do
|
7
|
+
specs = SettingsSpec::Specs.new({name: "gt 5"})
|
8
|
+
specs.verify({name: 8})
|
9
|
+
expect(specs.errors).to be_empty
|
10
|
+
end
|
11
|
+
|
12
|
+
it "2 cannot pass 'gt 5'" do
|
13
|
+
specs = SettingsSpec::Specs.new({name: "gt 5"})
|
14
|
+
specs.verify({name: 2})
|
15
|
+
expect(specs.errors).to have_key("name")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "3 can pass 'lt 5'" do
|
19
|
+
specs = SettingsSpec::Specs.new({name: "lt 5"})
|
20
|
+
specs.verify({name: 3})
|
21
|
+
expect(specs.errors).to be_empty
|
22
|
+
end
|
23
|
+
|
24
|
+
it "6 cannot pass 'lt 5'" do
|
25
|
+
specs = SettingsSpec::Specs.new({name: "lt 5"})
|
26
|
+
specs.verify({name: 6})
|
27
|
+
expect(specs.errors).to have_key("name")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can be in the array" do
|
31
|
+
specs = SettingsSpec::Specs.new({name: "one_in [1, 2, 3]"})
|
32
|
+
specs.verify({name: 3})
|
33
|
+
expect(specs.errors).to be_empty
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can be in the range" do
|
37
|
+
specs = SettingsSpec::Specs.new({name: "one_in 1..3"})
|
38
|
+
specs.verify({name: 3})
|
39
|
+
expect(specs.errors).to be_empty
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns an error when the number is not in the array" do
|
43
|
+
specs = SettingsSpec::Specs.new({name: "one_in [1, 2, 3]"})
|
44
|
+
specs.verify({name: 4})
|
45
|
+
expect(specs.errors).to have_key("name")
|
46
|
+
end
|
47
|
+
|
48
|
+
it "combines specs with 'or' and 'and'" do
|
49
|
+
specs = SettingsSpec::Specs.new({name: "blank or (gt 3 and lt 8)"})
|
50
|
+
specs.verify({name: nil})
|
51
|
+
expect(specs.errors).to be_empty
|
52
|
+
specs.verify({name: 5})
|
53
|
+
expect(specs.errors).to be_empty
|
54
|
+
specs.verify({name: 9})
|
55
|
+
expect(specs.errors).to have_key("name")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#string" do
|
60
|
+
|
61
|
+
it "returns no error when the setting matches the regexp" do
|
62
|
+
specs = SettingsSpec::Specs.new({name: "match /^a/"})
|
63
|
+
specs.verify({name: "abc"})
|
64
|
+
expect(specs.errors).to be_empty
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns an error when the setting does not match the regexp" do
|
68
|
+
specs = SettingsSpec::Specs.new({name: "match /^a/"})
|
69
|
+
specs.verify({name: "bcd"})
|
70
|
+
expect(specs.errors).to have_key("name")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "can be in the array" do
|
74
|
+
specs = SettingsSpec::Specs.new({name: "one_in %w{a b c}"})
|
75
|
+
specs.verify({name: 'b'})
|
76
|
+
expect(specs.errors).to be_empty
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns an error when the number is not in the array" do
|
80
|
+
specs = SettingsSpec::Specs.new({name: "one_in %w{a b c}"})
|
81
|
+
specs.verify({name: 'd'})
|
82
|
+
expect(specs.errors).to have_key("name")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "combines specs with 'or' and 'and'" do
|
86
|
+
specs = SettingsSpec::Specs.new({name: 'blank or one_in %w{a b c} or match /^\d{2}/'})
|
87
|
+
specs.verify({name: nil})
|
88
|
+
expect(specs.errors).to be_empty
|
89
|
+
specs.verify({name: 'a'})
|
90
|
+
expect(specs.errors).to be_empty
|
91
|
+
specs.verify({name: '99a'})
|
92
|
+
expect(specs.errors).to be_empty
|
93
|
+
specs.verify({name: '9a'})
|
94
|
+
expect(specs.errors).to have_key("name")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#array" do
|
99
|
+
it "can include any items from the array" do
|
100
|
+
specs = SettingsSpec::Specs.new({name: "all_in %w{a b c}"})
|
101
|
+
specs.verify({name: %w{a b}})
|
102
|
+
expect(specs.errors).to be_empty
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns an error when one or several items are not in the array" do
|
106
|
+
specs = SettingsSpec::Specs.new({name: "all_in %w{a b c}"})
|
107
|
+
specs.verify({name: %w{c d}})
|
108
|
+
expect(specs.errors).to have_key("name")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "nil can pass 'blank'" do
|
113
|
+
specs = SettingsSpec::Specs.new({name: "blank"})
|
114
|
+
specs.verify({name: nil})
|
115
|
+
expect(specs.errors).to be_empty
|
116
|
+
end
|
117
|
+
|
118
|
+
it "empty string can pass 'blank'" do
|
119
|
+
specs = SettingsSpec::Specs.new({name: "blank"})
|
120
|
+
specs.verify({name: ''})
|
121
|
+
expect(specs.errors).to be_empty
|
122
|
+
end
|
123
|
+
|
124
|
+
it "calls a proc" do
|
125
|
+
specs = SettingsSpec::Specs.new({name: 'call ->(v){ v % 3 == 0 }'})
|
126
|
+
specs.verify({name: 3})
|
127
|
+
expect(specs.errors).to be_empty
|
128
|
+
specs.verify({name: 4})
|
129
|
+
expect(specs.errors).to have_key("name")
|
130
|
+
end
|
131
|
+
|
132
|
+
it "raise an exception when 'verify!' fails" do
|
133
|
+
msg = %{Some settings do not pass verification:\n name: "match /^a/ [val: ]"}
|
134
|
+
specs = SettingsSpec::Specs.new({name: 'match /^a/'})
|
135
|
+
expect { specs.verify!({name: ''}) }.to raise_error(StandardError, msg)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "cannot be nil" do
|
139
|
+
specs = SettingsSpec::Specs.new({name: "blank"})
|
140
|
+
specs.verify(nil)
|
141
|
+
expect(specs.errors).to have_key(".")
|
142
|
+
end
|
143
|
+
|
144
|
+
it "can check the type of the value" do
|
145
|
+
specs = SettingsSpec::Specs.new({name: "is_a String"})
|
146
|
+
specs.verify(name: 'str')
|
147
|
+
expect(specs.errors).to be_empty
|
148
|
+
end
|
149
|
+
|
150
|
+
it "fails when the type mismatches" do
|
151
|
+
specs = SettingsSpec::Specs.new({name: "is_a String"})
|
152
|
+
specs.verify(name: 3)
|
153
|
+
expect(specs.errors).to have_key("name")
|
154
|
+
end
|
155
|
+
|
156
|
+
it "is optional if all its children are optional" do
|
157
|
+
specs = SettingsSpec::Specs.new({l1: {l2: {l2a: "blank", l2b: "blank"}}})
|
158
|
+
specs.verify({})
|
159
|
+
expect(specs.errors).to be_empty
|
160
|
+
specs.verify({l1: nil})
|
161
|
+
expect(specs.errors).to be_empty
|
162
|
+
end
|
163
|
+
|
164
|
+
it "handles `false` correctly" do
|
165
|
+
specs = SettingsSpec::Specs.new({name: "one_in [true, false]"})
|
166
|
+
specs.verify("name" => false)
|
167
|
+
expect(specs.errors).to be_empty
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: settings_spec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yanhao Yang
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 10.3.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 10.3.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.0.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: settingslogic
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.9
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.0.9
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rails_config
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.4.2
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.4.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: app_config
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.5.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.5.1
|
97
|
+
description: Verifies the configurations against the specifications in a YAML file
|
98
|
+
email:
|
99
|
+
- yanhao.yang@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- ".travis.yml"
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE.txt
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- lib/settings_spec.rb
|
112
|
+
- lib/settings_spec/specs.rb
|
113
|
+
- lib/settings_spec/version.rb
|
114
|
+
- lib/settings_spec/visitor.rb
|
115
|
+
- lib/settings_spec/visitors/array.rb
|
116
|
+
- lib/settings_spec/visitors/common.rb
|
117
|
+
- lib/settings_spec/visitors/number.rb
|
118
|
+
- lib/settings_spec/visitors/string.rb
|
119
|
+
- settings_spec.gemspec
|
120
|
+
- spec/fixtures/invalid-settings-1.yml
|
121
|
+
- spec/fixtures/invalid-settings-2.yml
|
122
|
+
- spec/fixtures/settings_spec.yml
|
123
|
+
- spec/fixtures/valid-settings-1.yml
|
124
|
+
- spec/fixtures/valid-settings-2.yml
|
125
|
+
- spec/libraries/app_config_spec.rb
|
126
|
+
- spec/libraries/rails_config_spec.rb
|
127
|
+
- spec/libraries/raw_yaml_spec.rb
|
128
|
+
- spec/libraries/settingslogic_spec.rb
|
129
|
+
- spec/library_specs.rb
|
130
|
+
- spec/settings_spec/specs_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
homepage: https://github.com/YanhaoYang/settings_spec
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.2.2
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Verifies the configurations against the specifications in a YAML file
|
156
|
+
test_files:
|
157
|
+
- spec/fixtures/invalid-settings-1.yml
|
158
|
+
- spec/fixtures/invalid-settings-2.yml
|
159
|
+
- spec/fixtures/settings_spec.yml
|
160
|
+
- spec/fixtures/valid-settings-1.yml
|
161
|
+
- spec/fixtures/valid-settings-2.yml
|
162
|
+
- spec/libraries/app_config_spec.rb
|
163
|
+
- spec/libraries/rails_config_spec.rb
|
164
|
+
- spec/libraries/raw_yaml_spec.rb
|
165
|
+
- spec/libraries/settingslogic_spec.rb
|
166
|
+
- spec/library_specs.rb
|
167
|
+
- spec/settings_spec/specs_spec.rb
|
168
|
+
- spec/spec_helper.rb
|