optionable 0.1.0
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/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 [](http://travis-ci.org/durran/optionable) [](https://codeclimate.com/github/durran/optionable) [](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
|