settings_spec 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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