optionable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.md +20 -0
- data/README.md +83 -0
- data/Rakefile +30 -0
- data/lib/optionable.rb +68 -0
- data/lib/optionable/any.rb +49 -0
- data/lib/optionable/dsl.rb +35 -0
- data/lib/optionable/invalid.rb +47 -0
- data/lib/optionable/validator.rb +75 -0
- data/lib/optionable/version.rb +4 -0
- data/spec/optionable/any_spec.rb +47 -0
- data/spec/optionable/invalid_spec.rb +46 -0
- data/spec/optionable/validator_spec.rb +89 -0
- data/spec/optionable_spec.rb +118 -0
- data/spec/spec_helper.rb +14 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 05abcff0632b217f377d6b25eca962591f2e6b0f
|
4
|
+
data.tar.gz: c64a040f884e222841a93e796194e3648b17aeab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c9a204f1685ea3090b229f4d54e5c926d99b9810d75cb3d76a3ae28c59da5768363d34942e2a62bddbfbf601f1976aed9ad40de91249b3bd8338815256161a14
|
7
|
+
data.tar.gz: f5655b60fb44aaf901a63d2abcf41bd3be2aaca506fb72d0a67dbbbb250eb50df49d0107218ebdbd92b6dbbb684cca70cb8e0eb1c7f4e6fd53d9f72564b97a97
|
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Durran Jordan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
BSON [![Build Status](https://secure.travis-ci.org/durran/optionable.png?branch=master&.png)](http://travis-ci.org/durran/optionable) [![Code Climate](https://codeclimate.com/github/durran/optionable.png)](https://codeclimate.com/github/durran/optionable) [![Coverage Status](https://coveralls.io/repos/durran/optionable/badge.png?branch=master)](https://coveralls.io/r/durran/optionable?branch=master)
|
2
|
+
====
|
3
|
+
|
4
|
+
Robust validation of options passed to Ruby methods.
|
5
|
+
|
6
|
+
Compatibility
|
7
|
+
-------------
|
8
|
+
|
9
|
+
BSON is tested against MRI (1.9.2+), JRuby (1.7.0+), Rubinius (2.0.0+).
|
10
|
+
|
11
|
+
Installation
|
12
|
+
------------
|
13
|
+
|
14
|
+
With bundler, add the `optionable` gem to your `Gemfile`.
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem "optionable",
|
18
|
+
```
|
19
|
+
|
20
|
+
Require the `optionable` gem in your application.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require "optionable"
|
24
|
+
```
|
25
|
+
|
26
|
+
Usage
|
27
|
+
-----
|
28
|
+
|
29
|
+
Include the optional module in your object, and use the DSL for define what values
|
30
|
+
are valid for the specified options. Currently you can match on exact values or
|
31
|
+
values of a specific type. Then to validate your options, simply call `validate_strict`
|
32
|
+
and pass it the hash of options.
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class Parser
|
36
|
+
include Optionable
|
37
|
+
|
38
|
+
option(:streaming).allow(true, false)
|
39
|
+
option(:timeout).allow(Optionable.any(Integer))
|
40
|
+
|
41
|
+
def initialize(options = {})
|
42
|
+
validate_strict(options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
If the options are invalid, an `Optionable::Invalid` error will be raised.
|
48
|
+
|
49
|
+
|
50
|
+
API Documentation
|
51
|
+
-----------------
|
52
|
+
|
53
|
+
The [API Documentation](http://rdoc.info/github/durran/optionable/master/frames) is
|
54
|
+
located at rdoc.info.
|
55
|
+
|
56
|
+
Versioning
|
57
|
+
----------
|
58
|
+
|
59
|
+
This project adheres to the [Semantic Versioning Specification](http://semver.org/).
|
60
|
+
|
61
|
+
License
|
62
|
+
-------
|
63
|
+
|
64
|
+
Copyright (c) 2013 Durran Jordan
|
65
|
+
|
66
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
67
|
+
a copy of this software and associated documentation files (the
|
68
|
+
"Software"), to deal in the Software without restriction, including
|
69
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
70
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
71
|
+
permit persons to whom the Software is furnished to do so, subject to
|
72
|
+
the following conditions:
|
73
|
+
|
74
|
+
The above copyright notice and this permission notice shall be
|
75
|
+
included in all copies or substantial portions of the Software.
|
76
|
+
|
77
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
78
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
79
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
80
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
81
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
82
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
83
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "bundler"
|
2
|
+
Bundler.setup
|
3
|
+
|
4
|
+
require "rake"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
8
|
+
require "optionable/version"
|
9
|
+
|
10
|
+
task :gem => :build
|
11
|
+
task :build do
|
12
|
+
system "gem build optionable.gemspec"
|
13
|
+
end
|
14
|
+
|
15
|
+
task :install => :build do
|
16
|
+
system "sudo gem install optionable-#{Optionable::VERSION}.gem"
|
17
|
+
end
|
18
|
+
|
19
|
+
task :release => :build do
|
20
|
+
system "git tag -a v#{Optionable::VERSION} -m 'Tagging #{Optionable::VERSION}'"
|
21
|
+
system "git push --tags"
|
22
|
+
system "gem push optionable-#{Optionable::VERSION}.gem"
|
23
|
+
system "rm optionable-#{Optionable::VERSION}.gem"
|
24
|
+
end
|
25
|
+
|
26
|
+
RSpec::Core::RakeTask.new("spec") do |spec|
|
27
|
+
spec.pattern = "spec/**/*_spec.rb"
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => :spec
|
data/lib/optionable.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "optionable/any"
|
3
|
+
require "optionable/dsl"
|
4
|
+
require "optionable/invalid"
|
5
|
+
require "optionable/validator"
|
6
|
+
require "optionable/version"
|
7
|
+
|
8
|
+
# This module is to be included in objects that require some nifty options
|
9
|
+
# validation.
|
10
|
+
#
|
11
|
+
# @since 0.0.0
|
12
|
+
module Optionable
|
13
|
+
|
14
|
+
# Validate the provided options against the defined acceptable values.
|
15
|
+
#
|
16
|
+
# @example Validate the options.
|
17
|
+
# optionable.validate_strict(read: "test")
|
18
|
+
#
|
19
|
+
# @param [ Hash ] options The options to validate.
|
20
|
+
#
|
21
|
+
# @raise [ Optionable::Invalid ] If the options are wack.
|
22
|
+
#
|
23
|
+
# @since 0.0.0
|
24
|
+
def validate_strict(options)
|
25
|
+
(options || {}).each_pair do |key, value|
|
26
|
+
validator = optionable_validators[key]
|
27
|
+
validator.validate!(value) if validator
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Get the optionable validators from the class.
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
# @since 0.0.0
|
38
|
+
def optionable_validators
|
39
|
+
self.class.optionable_validators
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
|
44
|
+
# Provides a convenience method for creating a new option acceptance for
|
45
|
+
# values of a certain type.
|
46
|
+
#
|
47
|
+
# @example Create the any type.
|
48
|
+
# Optionable.any(Integer)
|
49
|
+
#
|
50
|
+
# @param [ Class ] type The type of supported value.
|
51
|
+
#
|
52
|
+
# @since 0.0.0
|
53
|
+
def any(type)
|
54
|
+
Any.new(type)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Extend the DSL methods when the module is included.
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
#
|
63
|
+
# @since 0.0.0
|
64
|
+
def included(klass)
|
65
|
+
klass.extend(DSL)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Optionable
|
3
|
+
|
4
|
+
# Represents an option that can be of any value of a certain type.
|
5
|
+
#
|
6
|
+
# @since 0.0.0
|
7
|
+
class Any
|
8
|
+
|
9
|
+
# @!attribute type
|
10
|
+
# @return [ Class ] The class type.
|
11
|
+
attr_reader :type
|
12
|
+
|
13
|
+
# Check equality of the value for this type.
|
14
|
+
#
|
15
|
+
# @example Check if the value equals this type.
|
16
|
+
# any == 10
|
17
|
+
#
|
18
|
+
# @param [ Object ] other The object to check against.
|
19
|
+
#
|
20
|
+
# @since 0.0.0
|
21
|
+
def ==(other)
|
22
|
+
other.is_a?(type)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Initialize the new any value object.
|
26
|
+
#
|
27
|
+
# @example Initialize the any value object.
|
28
|
+
# Optionable::Any.new(Integer)
|
29
|
+
#
|
30
|
+
# @param [ Class ] type The class type.
|
31
|
+
#
|
32
|
+
# @since 0.0.0
|
33
|
+
def initialize(type)
|
34
|
+
@type = type
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return the pretty inspected type.
|
38
|
+
#
|
39
|
+
# @example Get the any as an inspection.
|
40
|
+
# any.inspect
|
41
|
+
#
|
42
|
+
# @return [ String ] any + the class type.
|
43
|
+
#
|
44
|
+
# @since 0.0.0
|
45
|
+
def inspect
|
46
|
+
"any #{type}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Optionable
|
3
|
+
|
4
|
+
# Provides the entry point to the optionable DSL.
|
5
|
+
#
|
6
|
+
# @since 0.0.0
|
7
|
+
module DSL
|
8
|
+
|
9
|
+
# Defines an option to be validated.
|
10
|
+
#
|
11
|
+
# @example Define the option.
|
12
|
+
# option(:read).allow(:primary, :secondary)
|
13
|
+
#
|
14
|
+
# @param [ Symbol ] key The name of the option.
|
15
|
+
#
|
16
|
+
# @return [ Optionable::Validator ] The associated validator for the option.
|
17
|
+
#
|
18
|
+
# @since 0.0.0
|
19
|
+
def option(key)
|
20
|
+
optionable_validators[key] ||= Validator.new(key)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get all the validators for all options.
|
24
|
+
#
|
25
|
+
# @example Get all the validators.
|
26
|
+
# dsl.optionable_validators
|
27
|
+
#
|
28
|
+
# @return [ Hash<Symbol, Optionable::Validator> ] The validators.
|
29
|
+
#
|
30
|
+
# @since 0.0.0
|
31
|
+
def optionable_validators
|
32
|
+
@optionable_validators ||= {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Optionable
|
3
|
+
|
4
|
+
# This exception is raised whenever invalid options are found during
|
5
|
+
# validation.
|
6
|
+
#
|
7
|
+
# @since 0.0.0
|
8
|
+
class Invalid < RuntimeError
|
9
|
+
|
10
|
+
# @!attribute key
|
11
|
+
# @return [ Symbol ] The name of the option.
|
12
|
+
# @!attribute value
|
13
|
+
# @return [ Object ] The value provided for the option.
|
14
|
+
# @!attribute allowed
|
15
|
+
# @return [ Array<Object> ] The allowed values for the option.
|
16
|
+
attr_reader :key, :value, :allowed
|
17
|
+
|
18
|
+
# Initialize the Invalid option exception.
|
19
|
+
#
|
20
|
+
# @example Initialize the exception.
|
21
|
+
# Optionable::Invalid.new(:test, 10, [ 11, 12 ])
|
22
|
+
#
|
23
|
+
# @param [ Symbol ] key The name of the option.
|
24
|
+
# @param [ Object ] value The value provided for the option.
|
25
|
+
# @param [ Array<Object> ] allowed The allowed values for the option.
|
26
|
+
#
|
27
|
+
# @since 0.0.0
|
28
|
+
def initialize(key, value, allowed)
|
29
|
+
@key = key
|
30
|
+
@value = value
|
31
|
+
@allowed = allowed
|
32
|
+
super(generate_message)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Generate the message that will be used in the exception.
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
# @since 0.0.0
|
42
|
+
def generate_message
|
43
|
+
"#{value.inspect} is not acceptable for option #{key.inspect}. " +
|
44
|
+
"Valid values are: #{allowed.map(&:inspect).join(", ")}."
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Optionable
|
3
|
+
|
4
|
+
# This is responsible for the actual validation of the options.
|
5
|
+
#
|
6
|
+
# @since 0.0.0
|
7
|
+
class Validator
|
8
|
+
|
9
|
+
# @!attribute key
|
10
|
+
# @return [ Symbol ] The name of the option.
|
11
|
+
attr_reader :key
|
12
|
+
|
13
|
+
# Tells the validator what values are acceptable for the option.
|
14
|
+
#
|
15
|
+
# @example Specify allowed values.
|
16
|
+
# validator.allow(:test, :testing)
|
17
|
+
#
|
18
|
+
# @param [ Array<Object> ] values The allowed values.
|
19
|
+
#
|
20
|
+
# @return [ Array<Object> ] The full list of allowed values.
|
21
|
+
#
|
22
|
+
# @since 0.0.0
|
23
|
+
def allow(*values)
|
24
|
+
allowed_values.concat(values)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Initialize the new validator.
|
28
|
+
#
|
29
|
+
# @example Initialize the validator.
|
30
|
+
# Optionable::Validator.new(:test)
|
31
|
+
#
|
32
|
+
# @param [ Symbol ] key The name of the option.
|
33
|
+
#
|
34
|
+
# @since 0.0.0
|
35
|
+
def initialize(key)
|
36
|
+
@key = key
|
37
|
+
end
|
38
|
+
|
39
|
+
# Validate the provided value against the acceptable values.
|
40
|
+
#
|
41
|
+
# @example Validate the provided value.
|
42
|
+
# validator.validate!("test")
|
43
|
+
#
|
44
|
+
# @param [ Object ] value The value for the option.
|
45
|
+
#
|
46
|
+
# @raise [ Optionable::Invalid ] If the value is invalid.
|
47
|
+
#
|
48
|
+
# @since 0.0.0
|
49
|
+
def validate!(value)
|
50
|
+
raise Invalid.new(key, value, allowed_values) unless match?(value)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Get the allowed values for the option.
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
# @since 0.0.0
|
60
|
+
def allowed_values
|
61
|
+
@allowed_values ||= []
|
62
|
+
end
|
63
|
+
|
64
|
+
# Does the value match an allowed value?
|
65
|
+
#
|
66
|
+
# @api private
|
67
|
+
#
|
68
|
+
# @since 0.0.0
|
69
|
+
def match?(value)
|
70
|
+
allowed_values.any? do |allowed|
|
71
|
+
value == allowed
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Optionable::Any do
|
4
|
+
|
5
|
+
describe "#==" do
|
6
|
+
|
7
|
+
let(:any) do
|
8
|
+
described_class.new(Integer)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when the value is of the correct type" do
|
12
|
+
|
13
|
+
it "returns true" do
|
14
|
+
expect(any).to eq(10)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when the value is an incorrect type" do
|
19
|
+
|
20
|
+
it "returns false" do
|
21
|
+
expect(any).to_not eq(10.5)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#initialize" do
|
27
|
+
|
28
|
+
let(:any) do
|
29
|
+
described_class.new(Integer)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "sets the type" do
|
33
|
+
expect(any.type).to eq(Integer)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#inspect" do
|
38
|
+
|
39
|
+
let(:any) do
|
40
|
+
described_class.new(Integer)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns any + the name of the class" do
|
44
|
+
expect(any.inspect).to eq("any Integer")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Optionable::Invalid do
|
4
|
+
|
5
|
+
describe "#message" do
|
6
|
+
|
7
|
+
context "when a single value is provided" do
|
8
|
+
|
9
|
+
let(:invalid) do
|
10
|
+
described_class.new(:test, 10, [ 15 ])
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns the single value error message" do
|
14
|
+
expect(invalid.message).to eq(
|
15
|
+
"10 is not acceptable for option :test. Valid values are: 15."
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when multiple values are provided" do
|
21
|
+
|
22
|
+
let(:invalid) do
|
23
|
+
described_class.new(:test, 10, [ 15, "something" ])
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns the single value error message" do
|
27
|
+
expect(invalid.message).to eq(
|
28
|
+
"10 is not acceptable for option :test. Valid values are: 15, \"something\"."
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when multiple values are provided with type" do
|
34
|
+
|
35
|
+
let(:invalid) do
|
36
|
+
described_class.new(:test, "test", [ Optionable.any(Integer) ])
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns the single value error message" do
|
40
|
+
expect(invalid.message).to eq(
|
41
|
+
"\"test\" is not acceptable for option :test. Valid values are: any Integer."
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Optionable::Validator do
|
4
|
+
|
5
|
+
describe "#allow" do
|
6
|
+
|
7
|
+
let(:validator) do
|
8
|
+
described_class.new(:test)
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:allowed) do
|
12
|
+
validator.send(:allowed_values)
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when no values exist" do
|
16
|
+
|
17
|
+
before do
|
18
|
+
validator.allow(:test)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets the valid options" do
|
22
|
+
expect(allowed).to eq([ :test ])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when sending multiple values" do
|
27
|
+
|
28
|
+
before do
|
29
|
+
validator.allow(:test, :testing)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "sets the valid options" do
|
33
|
+
expect(allowed).to eq([ :test, :testing ])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when existing values are present" do
|
38
|
+
|
39
|
+
before do
|
40
|
+
validator.allow(:test)
|
41
|
+
validator.allow(:testing)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "sets the valid options" do
|
45
|
+
expect(allowed).to eq([ :test, :testing ])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#initialize" do
|
51
|
+
|
52
|
+
let(:validator) do
|
53
|
+
described_class.new(:test)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets the key of the option" do
|
57
|
+
expect(validator.key).to eq(:test)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#validate!" do
|
62
|
+
|
63
|
+
let(:validator) do
|
64
|
+
described_class.new(:test)
|
65
|
+
end
|
66
|
+
|
67
|
+
context "when the value is acceptable" do
|
68
|
+
|
69
|
+
before do
|
70
|
+
validator.allow(:testing)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "raises no error" do
|
74
|
+
expect {
|
75
|
+
validator.validate!(:testing)
|
76
|
+
}.to_not raise_error
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when the value is invalid" do
|
81
|
+
|
82
|
+
it "raises an error" do
|
83
|
+
expect {
|
84
|
+
validator.validate!(:testing)
|
85
|
+
}.to raise_error(Optionable::Invalid)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Optionable do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
class Model
|
7
|
+
include Optionable
|
8
|
+
|
9
|
+
option(:read).allow(:primary, :secondary)
|
10
|
+
option(:write).allow(Optionable.any(Integer))
|
11
|
+
option(:update).allow(int: Optionable.any(Integer))
|
12
|
+
option(:update).allow(str: "exact")
|
13
|
+
option(:update).allow(flt: 10.5)
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
validate_strict(options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
after(:all) do
|
22
|
+
Object.send(:remove_const, :Model)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#validate_strict" do
|
26
|
+
|
27
|
+
context "when options are empty" do
|
28
|
+
|
29
|
+
it "does not raise an error" do
|
30
|
+
expect {
|
31
|
+
Model.new
|
32
|
+
}.to_not raise_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "when options are nil" do
|
37
|
+
|
38
|
+
it "does not raise an error" do
|
39
|
+
expect {
|
40
|
+
Model.new(nil)
|
41
|
+
}.to_not raise_error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when the options are valid" do
|
46
|
+
|
47
|
+
context "when options are allowed specific values" do
|
48
|
+
|
49
|
+
it "does not raise an error for any value" do
|
50
|
+
expect {
|
51
|
+
Model.new(read: :primary)
|
52
|
+
Model.new(read: :secondary)
|
53
|
+
}.to_not raise_error
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when options allow types" do
|
58
|
+
|
59
|
+
it "does not raise an error for correct type" do
|
60
|
+
expect {
|
61
|
+
Model.new(write: 10)
|
62
|
+
}.to_not raise_error
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "when options are mixed" do
|
67
|
+
|
68
|
+
it "does not raise an error for correct type" do
|
69
|
+
expect {
|
70
|
+
Model.new(update: { int: 10 })
|
71
|
+
}.to_not raise_error
|
72
|
+
end
|
73
|
+
|
74
|
+
it "does not raise an error for correct value" do
|
75
|
+
expect {
|
76
|
+
Model.new(update: { str: "exact" })
|
77
|
+
}.to_not raise_error
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when the options are not valid" do
|
83
|
+
|
84
|
+
context "when options are allowed specific values" do
|
85
|
+
|
86
|
+
it "raises an error for any bad value" do
|
87
|
+
expect {
|
88
|
+
Model.new(read: :tertiary)
|
89
|
+
}.to raise_error(Optionable::Invalid)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "when options allow types" do
|
94
|
+
|
95
|
+
it "raises an error for incorrect type" do
|
96
|
+
expect {
|
97
|
+
Model.new(write: 14.5)
|
98
|
+
}.to raise_error(Optionable::Invalid)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when options are mixed" do
|
103
|
+
|
104
|
+
it "raises an error for incorrect type" do
|
105
|
+
expect {
|
106
|
+
Model.new(update: { int: 14.5 })
|
107
|
+
}.to raise_error(Optionable::Invalid)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "raises an error for incorrect value" do
|
111
|
+
expect {
|
112
|
+
Model.new(update: { str: "blah" })
|
113
|
+
}.to raise_error(Optionable::Invalid)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
|
4
|
+
if ENV["CI"]
|
5
|
+
require "simplecov"
|
6
|
+
require "coveralls"
|
7
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
8
|
+
SimpleCov.start do
|
9
|
+
add_filter "spec"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require "optionable"
|
14
|
+
require "rspec"
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: optionable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Durran Jordan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Robust options validation for methods.
|
14
|
+
email:
|
15
|
+
- durran@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/optionable/any.rb
|
21
|
+
- lib/optionable/dsl.rb
|
22
|
+
- lib/optionable/invalid.rb
|
23
|
+
- lib/optionable/validator.rb
|
24
|
+
- lib/optionable/version.rb
|
25
|
+
- lib/optionable.rb
|
26
|
+
- README.md
|
27
|
+
- LICENSE.md
|
28
|
+
- Rakefile
|
29
|
+
- spec/optionable/any_spec.rb
|
30
|
+
- spec/optionable/invalid_spec.rb
|
31
|
+
- spec/optionable/validator_spec.rb
|
32
|
+
- spec/optionable_spec.rb
|
33
|
+
- spec/spec_helper.rb
|
34
|
+
homepage:
|
35
|
+
licenses: []
|
36
|
+
metadata: {}
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.9.2
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 1.3.6
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 2.0.3
|
54
|
+
signing_key:
|
55
|
+
specification_version: 4
|
56
|
+
summary: Robust options validation for methods.
|
57
|
+
test_files:
|
58
|
+
- spec/optionable/any_spec.rb
|
59
|
+
- spec/optionable/invalid_spec.rb
|
60
|
+
- spec/optionable/validator_spec.rb
|
61
|
+
- spec/optionable_spec.rb
|
62
|
+
- spec/spec_helper.rb
|