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 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
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in settings_spec.gemspec
4
+ gemspec
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,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -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,3 @@
1
+ module SettingsSpec
2
+ VERSION = "0.0.1"
3
+ 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,17 @@
1
+ module SettingsSpec
2
+ module Visitors
3
+ module Number
4
+
5
+ def gt(n)
6
+ return false unless @setting.is_a? Integer
7
+ @setting > n
8
+ end
9
+
10
+ def lt(n)
11
+ return false unless @setting.is_a? Integer
12
+ @setting < n
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module SettingsSpec
2
+ module Visitors
3
+ module String
4
+
5
+ def match(regexp)
6
+ return false unless @setting.is_a? ::String
7
+ !!regexp.match(@setting)
8
+ end
9
+
10
+ end
11
+ end
12
+ 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,21 @@
1
+ defaults: &defaults
2
+ l1a: 5
3
+ l1b:
4
+ l2a: bc
5
+ l2b: 4
6
+ l2c:
7
+ - a
8
+ - e
9
+ l2d: 3
10
+ l1c:
11
+ l2e: 234
12
+ l2f: 1
13
+ l2g:
14
+ - d
15
+ l1d: 8
16
+
17
+ development:
18
+ <<: *defaults
19
+
20
+ test:
21
+ <<: *defaults
@@ -0,0 +1,10 @@
1
+ defaults: &defaults
2
+ l1b:
3
+ l2c:
4
+ l2d:
5
+
6
+ development:
7
+ <<: *defaults
8
+
9
+ test:
10
+ <<: *defaults
@@ -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,18 @@
1
+ defaults: &defaults
2
+ l1a: 3
3
+ l1b:
4
+ l2a: ace
5
+ l2b: 5
6
+ l2c:
7
+ - b
8
+ - c
9
+ l2d:
10
+ l1d: 6
11
+
12
+ development:
13
+ <<: *defaults
14
+ l1a: 4
15
+
16
+ test:
17
+ <<: *defaults
18
+ 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
+
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'settings_spec'
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